skill-seekers 2.7.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- skill_seekers/__init__.py +22 -0
- skill_seekers/cli/__init__.py +39 -0
- skill_seekers/cli/adaptors/__init__.py +120 -0
- skill_seekers/cli/adaptors/base.py +221 -0
- skill_seekers/cli/adaptors/claude.py +485 -0
- skill_seekers/cli/adaptors/gemini.py +453 -0
- skill_seekers/cli/adaptors/markdown.py +269 -0
- skill_seekers/cli/adaptors/openai.py +503 -0
- skill_seekers/cli/ai_enhancer.py +310 -0
- skill_seekers/cli/api_reference_builder.py +373 -0
- skill_seekers/cli/architectural_pattern_detector.py +525 -0
- skill_seekers/cli/code_analyzer.py +1462 -0
- skill_seekers/cli/codebase_scraper.py +1225 -0
- skill_seekers/cli/config_command.py +563 -0
- skill_seekers/cli/config_enhancer.py +431 -0
- skill_seekers/cli/config_extractor.py +871 -0
- skill_seekers/cli/config_manager.py +452 -0
- skill_seekers/cli/config_validator.py +394 -0
- skill_seekers/cli/conflict_detector.py +528 -0
- skill_seekers/cli/constants.py +72 -0
- skill_seekers/cli/dependency_analyzer.py +757 -0
- skill_seekers/cli/doc_scraper.py +2332 -0
- skill_seekers/cli/enhance_skill.py +488 -0
- skill_seekers/cli/enhance_skill_local.py +1096 -0
- skill_seekers/cli/enhance_status.py +194 -0
- skill_seekers/cli/estimate_pages.py +433 -0
- skill_seekers/cli/generate_router.py +1209 -0
- skill_seekers/cli/github_fetcher.py +534 -0
- skill_seekers/cli/github_scraper.py +1466 -0
- skill_seekers/cli/guide_enhancer.py +723 -0
- skill_seekers/cli/how_to_guide_builder.py +1267 -0
- skill_seekers/cli/install_agent.py +461 -0
- skill_seekers/cli/install_skill.py +178 -0
- skill_seekers/cli/language_detector.py +614 -0
- skill_seekers/cli/llms_txt_detector.py +60 -0
- skill_seekers/cli/llms_txt_downloader.py +104 -0
- skill_seekers/cli/llms_txt_parser.py +150 -0
- skill_seekers/cli/main.py +558 -0
- skill_seekers/cli/markdown_cleaner.py +132 -0
- skill_seekers/cli/merge_sources.py +806 -0
- skill_seekers/cli/package_multi.py +77 -0
- skill_seekers/cli/package_skill.py +241 -0
- skill_seekers/cli/pattern_recognizer.py +1825 -0
- skill_seekers/cli/pdf_extractor_poc.py +1166 -0
- skill_seekers/cli/pdf_scraper.py +617 -0
- skill_seekers/cli/quality_checker.py +519 -0
- skill_seekers/cli/rate_limit_handler.py +438 -0
- skill_seekers/cli/resume_command.py +160 -0
- skill_seekers/cli/run_tests.py +230 -0
- skill_seekers/cli/setup_wizard.py +93 -0
- skill_seekers/cli/split_config.py +390 -0
- skill_seekers/cli/swift_patterns.py +560 -0
- skill_seekers/cli/test_example_extractor.py +1081 -0
- skill_seekers/cli/test_unified_simple.py +179 -0
- skill_seekers/cli/unified_codebase_analyzer.py +572 -0
- skill_seekers/cli/unified_scraper.py +932 -0
- skill_seekers/cli/unified_skill_builder.py +1605 -0
- skill_seekers/cli/upload_skill.py +162 -0
- skill_seekers/cli/utils.py +432 -0
- skill_seekers/mcp/__init__.py +33 -0
- skill_seekers/mcp/agent_detector.py +316 -0
- skill_seekers/mcp/git_repo.py +273 -0
- skill_seekers/mcp/server.py +231 -0
- skill_seekers/mcp/server_fastmcp.py +1249 -0
- skill_seekers/mcp/server_legacy.py +2302 -0
- skill_seekers/mcp/source_manager.py +285 -0
- skill_seekers/mcp/tools/__init__.py +115 -0
- skill_seekers/mcp/tools/config_tools.py +251 -0
- skill_seekers/mcp/tools/packaging_tools.py +826 -0
- skill_seekers/mcp/tools/scraping_tools.py +842 -0
- skill_seekers/mcp/tools/source_tools.py +828 -0
- skill_seekers/mcp/tools/splitting_tools.py +212 -0
- skill_seekers/py.typed +0 -0
- skill_seekers-2.7.3.dist-info/METADATA +2027 -0
- skill_seekers-2.7.3.dist-info/RECORD +79 -0
- skill_seekers-2.7.3.dist-info/WHEEL +5 -0
- skill_seekers-2.7.3.dist-info/entry_points.txt +19 -0
- skill_seekers-2.7.3.dist-info/licenses/LICENSE +21 -0
- skill_seekers-2.7.3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Claude AI Adaptor
|
|
4
|
+
|
|
5
|
+
Implements platform-specific handling for Claude AI (Anthropic) skills.
|
|
6
|
+
Refactored from upload_skill.py and enhance_skill.py.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import zipfile
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from .base import SkillAdaptor, SkillMetadata
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ClaudeAdaptor(SkillAdaptor):
|
|
17
|
+
"""
|
|
18
|
+
Claude AI platform adaptor.
|
|
19
|
+
|
|
20
|
+
Handles:
|
|
21
|
+
- YAML frontmatter format for SKILL.md
|
|
22
|
+
- ZIP packaging with standard Claude skill structure
|
|
23
|
+
- Upload to Anthropic Skills API
|
|
24
|
+
- AI enhancement using Claude API
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
PLATFORM = "claude"
|
|
28
|
+
PLATFORM_NAME = "Claude AI (Anthropic)"
|
|
29
|
+
DEFAULT_API_ENDPOINT = "https://api.anthropic.com/v1/skills"
|
|
30
|
+
|
|
31
|
+
def format_skill_md(self, skill_dir: Path, metadata: SkillMetadata) -> str:
|
|
32
|
+
"""
|
|
33
|
+
Format SKILL.md with Claude's YAML frontmatter.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
skill_dir: Path to skill directory
|
|
37
|
+
metadata: Skill metadata
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
Formatted SKILL.md content with YAML frontmatter
|
|
41
|
+
"""
|
|
42
|
+
# Read existing content (if any)
|
|
43
|
+
existing_content = self._read_existing_content(skill_dir)
|
|
44
|
+
|
|
45
|
+
# If existing content already has proper structure, use it
|
|
46
|
+
if existing_content and len(existing_content) > 100:
|
|
47
|
+
content_body = existing_content
|
|
48
|
+
else:
|
|
49
|
+
# Generate default content
|
|
50
|
+
content_body = f"""# {metadata.name.title()} Documentation Skill
|
|
51
|
+
|
|
52
|
+
{metadata.description}
|
|
53
|
+
|
|
54
|
+
## When to use this skill
|
|
55
|
+
|
|
56
|
+
Use this skill when the user asks about {metadata.name} documentation, including API references, tutorials, examples, and best practices.
|
|
57
|
+
|
|
58
|
+
## What's included
|
|
59
|
+
|
|
60
|
+
This skill contains comprehensive documentation organized into categorized reference files.
|
|
61
|
+
|
|
62
|
+
{self._generate_toc(skill_dir)}
|
|
63
|
+
|
|
64
|
+
## Quick Reference
|
|
65
|
+
|
|
66
|
+
{self._extract_quick_reference(skill_dir)}
|
|
67
|
+
|
|
68
|
+
## Navigation
|
|
69
|
+
|
|
70
|
+
See `references/index.md` for complete documentation structure.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
# Format with YAML frontmatter
|
|
74
|
+
return f"""---
|
|
75
|
+
name: {metadata.name}
|
|
76
|
+
description: {metadata.description}
|
|
77
|
+
version: {metadata.version}
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
{content_body}
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
def package(self, skill_dir: Path, output_path: Path) -> Path:
|
|
84
|
+
"""
|
|
85
|
+
Package skill into ZIP file for Claude.
|
|
86
|
+
|
|
87
|
+
Creates standard Claude skill structure:
|
|
88
|
+
- SKILL.md
|
|
89
|
+
- references/*.md
|
|
90
|
+
- scripts/ (optional)
|
|
91
|
+
- assets/ (optional)
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
skill_dir: Path to skill directory
|
|
95
|
+
output_path: Output path/filename for ZIP
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
Path to created ZIP file
|
|
99
|
+
"""
|
|
100
|
+
skill_dir = Path(skill_dir)
|
|
101
|
+
|
|
102
|
+
# Determine output filename
|
|
103
|
+
if output_path.is_dir() or str(output_path).endswith("/"):
|
|
104
|
+
output_path = Path(output_path) / f"{skill_dir.name}.zip"
|
|
105
|
+
elif not str(output_path).endswith(".zip"):
|
|
106
|
+
output_path = Path(str(output_path) + ".zip")
|
|
107
|
+
|
|
108
|
+
output_path = Path(output_path)
|
|
109
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
110
|
+
|
|
111
|
+
# Create ZIP file
|
|
112
|
+
with zipfile.ZipFile(output_path, "w", zipfile.ZIP_DEFLATED) as zf:
|
|
113
|
+
# Add SKILL.md (required)
|
|
114
|
+
skill_md = skill_dir / "SKILL.md"
|
|
115
|
+
if skill_md.exists():
|
|
116
|
+
zf.write(skill_md, "SKILL.md")
|
|
117
|
+
|
|
118
|
+
# Add references directory (if exists)
|
|
119
|
+
refs_dir = skill_dir / "references"
|
|
120
|
+
if refs_dir.exists():
|
|
121
|
+
for ref_file in refs_dir.rglob("*"):
|
|
122
|
+
if ref_file.is_file() and not ref_file.name.startswith("."):
|
|
123
|
+
arcname = ref_file.relative_to(skill_dir)
|
|
124
|
+
zf.write(ref_file, str(arcname))
|
|
125
|
+
|
|
126
|
+
# Add scripts directory (if exists)
|
|
127
|
+
scripts_dir = skill_dir / "scripts"
|
|
128
|
+
if scripts_dir.exists():
|
|
129
|
+
for script_file in scripts_dir.rglob("*"):
|
|
130
|
+
if script_file.is_file() and not script_file.name.startswith("."):
|
|
131
|
+
arcname = script_file.relative_to(skill_dir)
|
|
132
|
+
zf.write(script_file, str(arcname))
|
|
133
|
+
|
|
134
|
+
# Add assets directory (if exists)
|
|
135
|
+
assets_dir = skill_dir / "assets"
|
|
136
|
+
if assets_dir.exists():
|
|
137
|
+
for asset_file in assets_dir.rglob("*"):
|
|
138
|
+
if asset_file.is_file() and not asset_file.name.startswith("."):
|
|
139
|
+
arcname = asset_file.relative_to(skill_dir)
|
|
140
|
+
zf.write(asset_file, str(arcname))
|
|
141
|
+
|
|
142
|
+
return output_path
|
|
143
|
+
|
|
144
|
+
def upload(self, package_path: Path, api_key: str, **kwargs) -> dict[str, Any]:
|
|
145
|
+
"""
|
|
146
|
+
Upload skill ZIP to Anthropic Skills API.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
package_path: Path to skill ZIP file
|
|
150
|
+
api_key: Anthropic API key
|
|
151
|
+
**kwargs: Additional arguments (timeout, etc.)
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
Dictionary with upload result
|
|
155
|
+
"""
|
|
156
|
+
# Check for requests library
|
|
157
|
+
try:
|
|
158
|
+
import requests
|
|
159
|
+
except ImportError:
|
|
160
|
+
return {
|
|
161
|
+
"success": False,
|
|
162
|
+
"skill_id": None,
|
|
163
|
+
"url": None,
|
|
164
|
+
"message": "requests library not installed. Run: pip install requests",
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
# Validate ZIP file
|
|
168
|
+
package_path = Path(package_path)
|
|
169
|
+
if not package_path.exists():
|
|
170
|
+
return {
|
|
171
|
+
"success": False,
|
|
172
|
+
"skill_id": None,
|
|
173
|
+
"url": None,
|
|
174
|
+
"message": f"File not found: {package_path}",
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if package_path.suffix != ".zip":
|
|
178
|
+
return {
|
|
179
|
+
"success": False,
|
|
180
|
+
"skill_id": None,
|
|
181
|
+
"url": None,
|
|
182
|
+
"message": f"Not a ZIP file: {package_path}",
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
# Prepare API request
|
|
186
|
+
api_url = self.DEFAULT_API_ENDPOINT
|
|
187
|
+
headers = {
|
|
188
|
+
"x-api-key": api_key,
|
|
189
|
+
"anthropic-version": "2023-06-01",
|
|
190
|
+
"anthropic-beta": "skills-2025-10-02",
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
timeout = kwargs.get("timeout", 60)
|
|
194
|
+
|
|
195
|
+
try:
|
|
196
|
+
# Read ZIP file
|
|
197
|
+
with open(package_path, "rb") as f:
|
|
198
|
+
zip_data = f.read()
|
|
199
|
+
|
|
200
|
+
# Upload skill
|
|
201
|
+
files = {"files[]": (package_path.name, zip_data, "application/zip")}
|
|
202
|
+
|
|
203
|
+
response = requests.post(api_url, headers=headers, files=files, timeout=timeout)
|
|
204
|
+
|
|
205
|
+
# Check response
|
|
206
|
+
if response.status_code == 200:
|
|
207
|
+
# Extract skill ID if available
|
|
208
|
+
try:
|
|
209
|
+
response_data = response.json()
|
|
210
|
+
skill_id = response_data.get("id")
|
|
211
|
+
except Exception:
|
|
212
|
+
skill_id = None
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
"success": True,
|
|
216
|
+
"skill_id": skill_id,
|
|
217
|
+
"url": "https://claude.ai/skills",
|
|
218
|
+
"message": "Skill uploaded successfully to Claude AI",
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
elif response.status_code == 401:
|
|
222
|
+
return {
|
|
223
|
+
"success": False,
|
|
224
|
+
"skill_id": None,
|
|
225
|
+
"url": None,
|
|
226
|
+
"message": "Authentication failed. Check your ANTHROPIC_API_KEY",
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
elif response.status_code == 400:
|
|
230
|
+
try:
|
|
231
|
+
error_msg = response.json().get("error", {}).get("message", "Unknown error")
|
|
232
|
+
except Exception:
|
|
233
|
+
error_msg = "Invalid skill format"
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
"success": False,
|
|
237
|
+
"skill_id": None,
|
|
238
|
+
"url": None,
|
|
239
|
+
"message": f"Invalid skill format: {error_msg}",
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
else:
|
|
243
|
+
try:
|
|
244
|
+
error_msg = response.json().get("error", {}).get("message", "Unknown error")
|
|
245
|
+
except Exception:
|
|
246
|
+
error_msg = f"HTTP {response.status_code}"
|
|
247
|
+
|
|
248
|
+
return {
|
|
249
|
+
"success": False,
|
|
250
|
+
"skill_id": None,
|
|
251
|
+
"url": None,
|
|
252
|
+
"message": f"Upload failed: {error_msg}",
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
except requests.exceptions.Timeout:
|
|
256
|
+
return {
|
|
257
|
+
"success": False,
|
|
258
|
+
"skill_id": None,
|
|
259
|
+
"url": None,
|
|
260
|
+
"message": "Upload timed out. Try again or use manual upload",
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
except requests.exceptions.ConnectionError:
|
|
264
|
+
return {
|
|
265
|
+
"success": False,
|
|
266
|
+
"skill_id": None,
|
|
267
|
+
"url": None,
|
|
268
|
+
"message": "Connection error. Check your internet connection",
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
except Exception as e:
|
|
272
|
+
return {
|
|
273
|
+
"success": False,
|
|
274
|
+
"skill_id": None,
|
|
275
|
+
"url": None,
|
|
276
|
+
"message": f"Unexpected error: {str(e)}",
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
def validate_api_key(self, api_key: str) -> bool:
|
|
280
|
+
"""
|
|
281
|
+
Validate Anthropic API key format.
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
api_key: API key to validate
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
True if key starts with 'sk-ant-'
|
|
288
|
+
"""
|
|
289
|
+
return api_key.strip().startswith("sk-ant-")
|
|
290
|
+
|
|
291
|
+
def get_env_var_name(self) -> str:
|
|
292
|
+
"""
|
|
293
|
+
Get environment variable name for Anthropic API key.
|
|
294
|
+
|
|
295
|
+
Returns:
|
|
296
|
+
'ANTHROPIC_API_KEY'
|
|
297
|
+
"""
|
|
298
|
+
return "ANTHROPIC_API_KEY"
|
|
299
|
+
|
|
300
|
+
def supports_enhancement(self) -> bool:
|
|
301
|
+
"""
|
|
302
|
+
Claude supports AI enhancement via Anthropic API.
|
|
303
|
+
|
|
304
|
+
Returns:
|
|
305
|
+
True
|
|
306
|
+
"""
|
|
307
|
+
return True
|
|
308
|
+
|
|
309
|
+
def enhance(self, skill_dir: Path, api_key: str) -> bool:
|
|
310
|
+
"""
|
|
311
|
+
Enhance SKILL.md using Claude API.
|
|
312
|
+
|
|
313
|
+
Reads reference files, sends them to Claude, and generates
|
|
314
|
+
an improved SKILL.md with real examples and better organization.
|
|
315
|
+
|
|
316
|
+
Args:
|
|
317
|
+
skill_dir: Path to skill directory
|
|
318
|
+
api_key: Anthropic API key
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
True if enhancement succeeded
|
|
322
|
+
"""
|
|
323
|
+
# Check for anthropic library
|
|
324
|
+
try:
|
|
325
|
+
import anthropic
|
|
326
|
+
except ImportError:
|
|
327
|
+
print("ā Error: anthropic package not installed")
|
|
328
|
+
print("Install with: pip install anthropic")
|
|
329
|
+
return False
|
|
330
|
+
|
|
331
|
+
skill_dir = Path(skill_dir)
|
|
332
|
+
references_dir = skill_dir / "references"
|
|
333
|
+
skill_md_path = skill_dir / "SKILL.md"
|
|
334
|
+
|
|
335
|
+
# Read reference files
|
|
336
|
+
print("š Reading reference documentation...")
|
|
337
|
+
references = self._read_reference_files(references_dir)
|
|
338
|
+
|
|
339
|
+
if not references:
|
|
340
|
+
print("ā No reference files found to analyze")
|
|
341
|
+
return False
|
|
342
|
+
|
|
343
|
+
print(f" ā Read {len(references)} reference files")
|
|
344
|
+
total_size = sum(len(c) for c in references.values())
|
|
345
|
+
print(f" ā Total size: {total_size:,} characters\n")
|
|
346
|
+
|
|
347
|
+
# Read current SKILL.md
|
|
348
|
+
current_skill_md = None
|
|
349
|
+
if skill_md_path.exists():
|
|
350
|
+
current_skill_md = skill_md_path.read_text(encoding="utf-8")
|
|
351
|
+
print(f" ā¹ Found existing SKILL.md ({len(current_skill_md)} chars)")
|
|
352
|
+
else:
|
|
353
|
+
print(" ā¹ No existing SKILL.md, will create new one")
|
|
354
|
+
|
|
355
|
+
# Build enhancement prompt
|
|
356
|
+
prompt = self._build_enhancement_prompt(skill_dir.name, references, current_skill_md)
|
|
357
|
+
|
|
358
|
+
print("\nš¤ Asking Claude to enhance SKILL.md...")
|
|
359
|
+
print(f" Input: {len(prompt):,} characters")
|
|
360
|
+
|
|
361
|
+
try:
|
|
362
|
+
client = anthropic.Anthropic(api_key=api_key)
|
|
363
|
+
|
|
364
|
+
message = client.messages.create(
|
|
365
|
+
model="claude-sonnet-4-20250514",
|
|
366
|
+
max_tokens=4096,
|
|
367
|
+
temperature=0.3,
|
|
368
|
+
messages=[{"role": "user", "content": prompt}],
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
enhanced_content = message.content[0].text
|
|
372
|
+
print(f" ā Generated enhanced SKILL.md ({len(enhanced_content)} chars)\n")
|
|
373
|
+
|
|
374
|
+
# Backup original
|
|
375
|
+
if skill_md_path.exists():
|
|
376
|
+
backup_path = skill_md_path.with_suffix(".md.backup")
|
|
377
|
+
skill_md_path.rename(backup_path)
|
|
378
|
+
print(f" š¾ Backed up original to: {backup_path.name}")
|
|
379
|
+
|
|
380
|
+
# Save enhanced version
|
|
381
|
+
skill_md_path.write_text(enhanced_content, encoding="utf-8")
|
|
382
|
+
print(" ā
Saved enhanced SKILL.md")
|
|
383
|
+
|
|
384
|
+
return True
|
|
385
|
+
|
|
386
|
+
except Exception as e:
|
|
387
|
+
print(f"ā Error calling Claude API: {e}")
|
|
388
|
+
return False
|
|
389
|
+
|
|
390
|
+
def _read_reference_files(
|
|
391
|
+
self, references_dir: Path, max_chars: int = 200000
|
|
392
|
+
) -> dict[str, str]:
|
|
393
|
+
"""
|
|
394
|
+
Read reference markdown files from skill directory.
|
|
395
|
+
|
|
396
|
+
Args:
|
|
397
|
+
references_dir: Path to references directory
|
|
398
|
+
max_chars: Maximum total characters to read
|
|
399
|
+
|
|
400
|
+
Returns:
|
|
401
|
+
Dictionary mapping filename to content
|
|
402
|
+
"""
|
|
403
|
+
if not references_dir.exists():
|
|
404
|
+
return {}
|
|
405
|
+
|
|
406
|
+
references = {}
|
|
407
|
+
total_chars = 0
|
|
408
|
+
|
|
409
|
+
# Read all .md files
|
|
410
|
+
for ref_file in sorted(references_dir.glob("*.md")):
|
|
411
|
+
if total_chars >= max_chars:
|
|
412
|
+
break
|
|
413
|
+
|
|
414
|
+
try:
|
|
415
|
+
content = ref_file.read_text(encoding="utf-8")
|
|
416
|
+
# Limit individual file size
|
|
417
|
+
if len(content) > 30000:
|
|
418
|
+
content = content[:30000] + "\n\n...(truncated)"
|
|
419
|
+
|
|
420
|
+
references[ref_file.name] = content
|
|
421
|
+
total_chars += len(content)
|
|
422
|
+
|
|
423
|
+
except Exception as e:
|
|
424
|
+
print(f" ā ļø Could not read {ref_file.name}: {e}")
|
|
425
|
+
|
|
426
|
+
return references
|
|
427
|
+
|
|
428
|
+
def _build_enhancement_prompt(
|
|
429
|
+
self, skill_name: str, references: dict[str, str], current_skill_md: str = None
|
|
430
|
+
) -> str:
|
|
431
|
+
"""
|
|
432
|
+
Build Claude API prompt for enhancement.
|
|
433
|
+
|
|
434
|
+
Args:
|
|
435
|
+
skill_name: Name of the skill
|
|
436
|
+
references: Dictionary of reference content
|
|
437
|
+
current_skill_md: Existing SKILL.md content (optional)
|
|
438
|
+
|
|
439
|
+
Returns:
|
|
440
|
+
Enhancement prompt for Claude
|
|
441
|
+
"""
|
|
442
|
+
prompt = f"""You are enhancing a Claude skill's SKILL.md file. This skill is about: {skill_name}
|
|
443
|
+
|
|
444
|
+
I've scraped documentation and organized it into reference files. Your job is to create an EXCELLENT SKILL.md that will help Claude use this documentation effectively.
|
|
445
|
+
|
|
446
|
+
CURRENT SKILL.MD:
|
|
447
|
+
{"```markdown" if current_skill_md else "(none - create from scratch)"}
|
|
448
|
+
{current_skill_md or "No existing SKILL.md"}
|
|
449
|
+
{"```" if current_skill_md else ""}
|
|
450
|
+
|
|
451
|
+
REFERENCE DOCUMENTATION:
|
|
452
|
+
"""
|
|
453
|
+
|
|
454
|
+
for filename, content in references.items():
|
|
455
|
+
prompt += f"\n\n## {filename}\n```markdown\n{content[:30000]}\n```\n"
|
|
456
|
+
|
|
457
|
+
prompt += """
|
|
458
|
+
|
|
459
|
+
YOUR TASK:
|
|
460
|
+
Create an enhanced SKILL.md that includes:
|
|
461
|
+
|
|
462
|
+
1. **Clear "When to Use This Skill" section** - Be specific about trigger conditions
|
|
463
|
+
2. **Excellent Quick Reference section** - Extract 5-10 of the BEST, most practical code examples from the reference docs
|
|
464
|
+
- Choose SHORT, clear examples that demonstrate common tasks
|
|
465
|
+
- Include both simple and intermediate examples
|
|
466
|
+
- Annotate examples with clear descriptions
|
|
467
|
+
- Use proper language tags (cpp, python, javascript, json, etc.)
|
|
468
|
+
3. **Detailed Reference Files description** - Explain what's in each reference file
|
|
469
|
+
4. **Practical "Working with This Skill" section** - Give users clear guidance on how to navigate the skill
|
|
470
|
+
5. **Key Concepts section** (if applicable) - Explain core concepts
|
|
471
|
+
6. **Keep the frontmatter** (---\nname: ...\n---) intact
|
|
472
|
+
|
|
473
|
+
IMPORTANT:
|
|
474
|
+
- Extract REAL examples from the reference docs, don't make them up
|
|
475
|
+
- Prioritize SHORT, clear examples (5-20 lines max)
|
|
476
|
+
- Make it actionable and practical
|
|
477
|
+
- Don't be too verbose - be concise but useful
|
|
478
|
+
- Maintain the markdown structure for Claude skills
|
|
479
|
+
- Keep code examples properly formatted with language tags
|
|
480
|
+
|
|
481
|
+
OUTPUT:
|
|
482
|
+
Return ONLY the complete SKILL.md content, starting with the frontmatter (---).
|
|
483
|
+
"""
|
|
484
|
+
|
|
485
|
+
return prompt
|