docs(A1.9): Add comprehensive git source documentation and example repository
Phase 4 Complete: - Updated README.md with git source usage examples and use cases - Created docs/GIT_CONFIG_SOURCES.md (800+ lines comprehensive guide) - Updated CHANGELOG.md with v2.2.0 release notes - Added configs/example-team/ example repository with E2E test Documentation covers: - Quick start and architecture - MCP tools reference (4 tools with examples) - Authentication for GitHub, GitLab, Bitbucket - Use cases (small teams, enterprise, open source) - Best practices, troubleshooting, advanced topics - Complete API reference Example repository includes: - 3 example configs (react-custom, vue-internal, company-api) - README with usage guide - E2E test script (7 steps, 100% passing) 🤖 Generated with Claude Code Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
136
configs/example-team/README.md
Normal file
136
configs/example-team/README.md
Normal file
@@ -0,0 +1,136 @@
|
||||
# Example Team Config Repository
|
||||
|
||||
This is an **example config repository** demonstrating how teams can share custom configs via git.
|
||||
|
||||
## Purpose
|
||||
|
||||
This repository shows how to:
|
||||
- Structure a custom config repository
|
||||
- Share team-specific documentation configs
|
||||
- Use git-based config sources with Skill Seekers
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
example-team/
|
||||
├── README.md # This file
|
||||
├── react-custom.json # Custom React config (modified selectors)
|
||||
├── vue-internal.json # Internal Vue docs config
|
||||
└── company-api.json # Company API documentation config
|
||||
```
|
||||
|
||||
## Usage with Skill Seekers
|
||||
|
||||
### Option 1: Use this repo directly (for testing)
|
||||
|
||||
```python
|
||||
# Using MCP tools (recommended)
|
||||
add_config_source(
|
||||
name="example-team",
|
||||
git_url="file:///path/to/Skill_Seekers/configs/example-team"
|
||||
)
|
||||
|
||||
fetch_config(source="example-team", config_name="react-custom")
|
||||
```
|
||||
|
||||
### Option 2: Create your own team repo
|
||||
|
||||
```bash
|
||||
# 1. Create new repo
|
||||
mkdir my-team-configs
|
||||
cd my-team-configs
|
||||
git init
|
||||
|
||||
# 2. Add configs
|
||||
cp /path/to/configs/react.json ./react-custom.json
|
||||
# Edit configs as needed...
|
||||
|
||||
# 3. Commit and push
|
||||
git add .
|
||||
git commit -m "Initial team configs"
|
||||
git remote add origin https://github.com/myorg/team-configs.git
|
||||
git push -u origin main
|
||||
|
||||
# 4. Register with Skill Seekers
|
||||
add_config_source(
|
||||
name="team",
|
||||
git_url="https://github.com/myorg/team-configs.git",
|
||||
token_env="GITHUB_TOKEN"
|
||||
)
|
||||
|
||||
# 5. Use it
|
||||
fetch_config(source="team", config_name="react-custom")
|
||||
```
|
||||
|
||||
## Config Naming Best Practices
|
||||
|
||||
- Use descriptive names: `react-custom.json`, `vue-internal.json`
|
||||
- Avoid name conflicts with official configs
|
||||
- Include version if needed: `api-v2.json`
|
||||
- Group by category: `frontend/`, `backend/`, `mobile/`
|
||||
|
||||
## Private Repositories
|
||||
|
||||
For private repos, set the appropriate token environment variable:
|
||||
|
||||
```bash
|
||||
# GitHub
|
||||
export GITHUB_TOKEN=ghp_xxxxxxxxxxxxx
|
||||
|
||||
# GitLab
|
||||
export GITLAB_TOKEN=glpat-xxxxxxxxxxxxx
|
||||
|
||||
# Bitbucket
|
||||
export BITBUCKET_TOKEN=xxxxxxxxxxxxx
|
||||
```
|
||||
|
||||
Then register the source:
|
||||
|
||||
```python
|
||||
add_config_source(
|
||||
name="private-team",
|
||||
git_url="https://github.com/myorg/private-configs.git",
|
||||
source_type="github",
|
||||
token_env="GITHUB_TOKEN"
|
||||
)
|
||||
```
|
||||
|
||||
## Testing This Example
|
||||
|
||||
```bash
|
||||
# From Skill_Seekers root directory
|
||||
cd /mnt/1ece809a-2821-4f10-aecb-fcdf34760c0b/Git/Skill_Seekers
|
||||
|
||||
# Test with file:// URL (no auth needed)
|
||||
python3 -c "
|
||||
from skill_seekers.mcp.source_manager import SourceManager
|
||||
from skill_seekers.mcp.git_repo import GitConfigRepo
|
||||
|
||||
# Add source
|
||||
sm = SourceManager()
|
||||
sm.add_source(
|
||||
name='example-team',
|
||||
git_url='file://$(pwd)/configs/example-team',
|
||||
branch='main'
|
||||
)
|
||||
|
||||
# Clone and fetch config
|
||||
gr = GitConfigRepo()
|
||||
repo_path = gr.clone_or_pull('example-team', 'file://$(pwd)/configs/example-team')
|
||||
config = gr.get_config(repo_path, 'react-custom')
|
||||
print(f'✅ Loaded config: {config[\"name\"]}')
|
||||
"
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
This is just an example! Create your own team repo with:
|
||||
- Your team's custom selectors
|
||||
- Internal documentation configs
|
||||
- Company-specific configurations
|
||||
|
||||
## See Also
|
||||
|
||||
- [GIT_CONFIG_SOURCES.md](../../docs/GIT_CONFIG_SOURCES.md) - Complete guide
|
||||
- [MCP_SETUP.md](../../docs/MCP_SETUP.md) - MCP server setup
|
||||
- [README.md](../../README.md) - Main documentation
|
||||
42
configs/example-team/company-api.json
Normal file
42
configs/example-team/company-api.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "company-api",
|
||||
"description": "Internal company API documentation (example)",
|
||||
"base_url": "https://docs.example.com/api/",
|
||||
"selectors": {
|
||||
"main_content": "div.documentation",
|
||||
"title": "h1.page-title",
|
||||
"code_blocks": "pre.highlight"
|
||||
},
|
||||
"url_patterns": {
|
||||
"include": [
|
||||
"/api/v2"
|
||||
],
|
||||
"exclude": [
|
||||
"/api/v1",
|
||||
"/changelog",
|
||||
"/deprecated"
|
||||
]
|
||||
},
|
||||
"categories": {
|
||||
"authentication": ["api/v2/auth", "api/v2/oauth"],
|
||||
"users": ["api/v2/users"],
|
||||
"payments": ["api/v2/payments", "api/v2/billing"],
|
||||
"webhooks": ["api/v2/webhooks"],
|
||||
"rate_limits": ["api/v2/rate-limits"]
|
||||
},
|
||||
"rate_limit": 1.0,
|
||||
"max_pages": 100,
|
||||
"metadata": {
|
||||
"team": "platform",
|
||||
"api_version": "v2",
|
||||
"last_updated": "2025-12-21",
|
||||
"maintainer": "platform-team@example.com",
|
||||
"internal": true,
|
||||
"notes": "Only includes v2 API - v1 is deprecated. Requires VPN access to docs.example.com",
|
||||
"example_urls": [
|
||||
"https://docs.example.com/api/v2/auth/oauth",
|
||||
"https://docs.example.com/api/v2/users/create",
|
||||
"https://docs.example.com/api/v2/payments/charge"
|
||||
]
|
||||
}
|
||||
}
|
||||
35
configs/example-team/react-custom.json
Normal file
35
configs/example-team/react-custom.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "react-custom",
|
||||
"description": "Custom React config for team with modified selectors",
|
||||
"base_url": "https://react.dev/",
|
||||
"selectors": {
|
||||
"main_content": "article",
|
||||
"title": "h1",
|
||||
"code_blocks": "pre code"
|
||||
},
|
||||
"url_patterns": {
|
||||
"include": [
|
||||
"/learn",
|
||||
"/reference"
|
||||
],
|
||||
"exclude": [
|
||||
"/blog",
|
||||
"/community",
|
||||
"/_next/"
|
||||
]
|
||||
},
|
||||
"categories": {
|
||||
"getting_started": ["learn/start", "learn/installation"],
|
||||
"hooks": ["reference/react/hooks", "learn/state"],
|
||||
"components": ["reference/react/components"],
|
||||
"api": ["reference/react-dom"]
|
||||
},
|
||||
"rate_limit": 0.5,
|
||||
"max_pages": 300,
|
||||
"metadata": {
|
||||
"team": "frontend",
|
||||
"last_updated": "2025-12-21",
|
||||
"maintainer": "team-lead@example.com",
|
||||
"notes": "Excludes blog and community pages to focus on technical docs"
|
||||
}
|
||||
}
|
||||
131
configs/example-team/test_e2e.py
Normal file
131
configs/example-team/test_e2e.py
Normal file
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
E2E Test Script for Example Team Config Repository
|
||||
|
||||
Tests the complete workflow:
|
||||
1. Register the example-team source
|
||||
2. Fetch a config from it
|
||||
3. Verify the config was loaded correctly
|
||||
4. Clean up
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Add parent directory to path
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
||||
|
||||
from skill_seekers.mcp.source_manager import SourceManager
|
||||
from skill_seekers.mcp.git_repo import GitConfigRepo
|
||||
|
||||
|
||||
def test_example_team_repo():
|
||||
"""Test the example-team repository end-to-end."""
|
||||
print("🧪 E2E Test: Example Team Config Repository\n")
|
||||
|
||||
# Get absolute path to example-team directory
|
||||
example_team_path = Path(__file__).parent.absolute()
|
||||
git_url = f"file://{example_team_path}"
|
||||
|
||||
print(f"📁 Repository: {git_url}\n")
|
||||
|
||||
# Step 1: Add source
|
||||
print("1️⃣ Registering source...")
|
||||
sm = SourceManager()
|
||||
try:
|
||||
source = sm.add_source(
|
||||
name="example-team-test",
|
||||
git_url=git_url,
|
||||
source_type="custom",
|
||||
branch="master" # Git init creates 'master' by default
|
||||
)
|
||||
print(f" ✅ Source registered: {source['name']}")
|
||||
except Exception as e:
|
||||
print(f" ❌ Failed to register source: {e}")
|
||||
return False
|
||||
|
||||
# Step 2: Clone/pull repository
|
||||
print("\n2️⃣ Cloning repository...")
|
||||
gr = GitConfigRepo()
|
||||
try:
|
||||
repo_path = gr.clone_or_pull(
|
||||
source_name="example-team-test",
|
||||
git_url=git_url,
|
||||
branch="master"
|
||||
)
|
||||
print(f" ✅ Repository cloned to: {repo_path}")
|
||||
except Exception as e:
|
||||
print(f" ❌ Failed to clone repository: {e}")
|
||||
return False
|
||||
|
||||
# Step 3: List available configs
|
||||
print("\n3️⃣ Discovering configs...")
|
||||
try:
|
||||
configs = gr.find_configs(repo_path)
|
||||
print(f" ✅ Found {len(configs)} configs:")
|
||||
for config_file in configs:
|
||||
print(f" - {config_file.name}")
|
||||
except Exception as e:
|
||||
print(f" ❌ Failed to discover configs: {e}")
|
||||
return False
|
||||
|
||||
# Step 4: Fetch a specific config
|
||||
print("\n4️⃣ Fetching 'react-custom' config...")
|
||||
try:
|
||||
config = gr.get_config(repo_path, "react-custom")
|
||||
print(f" ✅ Config loaded successfully!")
|
||||
print(f" Name: {config['name']}")
|
||||
print(f" Description: {config['description']}")
|
||||
print(f" Base URL: {config['base_url']}")
|
||||
print(f" Max Pages: {config['max_pages']}")
|
||||
if 'metadata' in config:
|
||||
print(f" Team: {config['metadata'].get('team', 'N/A')}")
|
||||
except Exception as e:
|
||||
print(f" ❌ Failed to fetch config: {e}")
|
||||
return False
|
||||
|
||||
# Step 5: Verify config content
|
||||
print("\n5️⃣ Verifying config content...")
|
||||
try:
|
||||
assert config['name'] == 'react-custom', "Config name mismatch"
|
||||
assert 'selectors' in config, "Missing selectors"
|
||||
assert 'url_patterns' in config, "Missing url_patterns"
|
||||
assert 'categories' in config, "Missing categories"
|
||||
print(" ✅ Config structure validated")
|
||||
except AssertionError as e:
|
||||
print(f" ❌ Validation failed: {e}")
|
||||
return False
|
||||
|
||||
# Step 6: List all sources
|
||||
print("\n6️⃣ Listing all sources...")
|
||||
try:
|
||||
sources = sm.list_sources()
|
||||
print(f" ✅ Total sources: {len(sources)}")
|
||||
for src in sources:
|
||||
print(f" - {src['name']} ({src['type']})")
|
||||
except Exception as e:
|
||||
print(f" ❌ Failed to list sources: {e}")
|
||||
return False
|
||||
|
||||
# Step 7: Clean up
|
||||
print("\n7️⃣ Cleaning up...")
|
||||
try:
|
||||
removed = sm.remove_source("example-team-test")
|
||||
if removed:
|
||||
print(" ✅ Source removed successfully")
|
||||
else:
|
||||
print(" ⚠️ Source was not found (already removed?)")
|
||||
except Exception as e:
|
||||
print(f" ❌ Failed to remove source: {e}")
|
||||
return False
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("✅ E2E TEST PASSED - All steps completed successfully!")
|
||||
print("="*60)
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
success = test_example_team_repo()
|
||||
sys.exit(0 if success else 1)
|
||||
36
configs/example-team/vue-internal.json
Normal file
36
configs/example-team/vue-internal.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "vue-internal",
|
||||
"description": "Vue.js config for internal team documentation",
|
||||
"base_url": "https://vuejs.org/",
|
||||
"selectors": {
|
||||
"main_content": "main",
|
||||
"title": "h1",
|
||||
"code_blocks": "pre"
|
||||
},
|
||||
"url_patterns": {
|
||||
"include": [
|
||||
"/guide",
|
||||
"/api"
|
||||
],
|
||||
"exclude": [
|
||||
"/examples",
|
||||
"/sponsor"
|
||||
]
|
||||
},
|
||||
"categories": {
|
||||
"essentials": ["guide/essentials", "guide/introduction"],
|
||||
"components": ["guide/components"],
|
||||
"reactivity": ["guide/extras/reactivity"],
|
||||
"composition_api": ["api/composition-api"],
|
||||
"options_api": ["api/options-api"]
|
||||
},
|
||||
"rate_limit": 0.3,
|
||||
"max_pages": 200,
|
||||
"metadata": {
|
||||
"team": "frontend",
|
||||
"version": "Vue 3",
|
||||
"last_updated": "2025-12-21",
|
||||
"maintainer": "vue-team@example.com",
|
||||
"notes": "Focuses on Vue 3 Composition API for our projects"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user