@rfxlamia/skillkit 1.1.0 → 1.2.0
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.
- package/agents/agents/creative-copywriter.md +212 -0
- package/agents/agents/dario-amodei.md +135 -0
- package/agents/agents/doc-simplifier.md +63 -0
- package/agents/agents/kotlin-pro.md +433 -0
- package/agents/agents/red-team.md +136 -0
- package/agents/agents/sam-altman.md +121 -0
- package/agents/agents/seo-manager.md +184 -0
- package/package.json +1 -1
- package/skills/skillkit-help/SKILL.md +81 -0
- package/skills/skillkit-help/knowledge/application/09-case-studies.md +257 -0
- package/skills/skillkit-help/knowledge/application/12-testing-and-validation.md +276 -0
- package/skills/skillkit-help/knowledge/foundation/01-why-skills-exist.md +246 -0
- package/skills/skillkit-help/knowledge/foundation/02-skills-vs-subagents-comparison.md +312 -0
- package/skills/skillkit-help/knowledge/foundation/03-skills-vs-subagents-decision-tree.md +346 -0
- package/skills/skillkit-help/knowledge/foundation/06-platform-constraints.md +237 -0
- package/skills/skillkit-help/knowledge/foundation/08-when-not-to-use-skills.md +270 -0
- package/skills/skillkit-help/template/SKILL.md +52 -0
- package/skills/skills/adversarial-review/SKILL.md +219 -0
- package/skills/skills/baby-education/SKILL.md +260 -0
- package/skills/skills/baby-education/references/advanced-techniques.md +323 -0
- package/skills/skills/baby-education/references/transformations.md +345 -0
- package/skills/skills/been-there-done-that/SKILL.md +455 -0
- package/skills/skills/been-there-done-that/references/analysis-patterns.md +162 -0
- package/skills/skills/been-there-done-that/references/git-commands.md +132 -0
- package/skills/skills/been-there-done-that/references/tree-insertion-logic.md +145 -0
- package/skills/skills/coolhunter/SKILL.md +270 -0
- package/skills/skills/coolhunter/assets/elicitation-methods.csv +51 -0
- package/skills/skills/coolhunter/knowledge/elicitation-methods.md +312 -0
- package/skills/skills/coolhunter/references/workflow-execution.md +238 -0
- package/skills/skills/coolhunter/workflow-plan-coolhunter.md +232 -0
- package/skills/skills/creative-copywriting/SKILL.md +324 -0
- package/skills/skills/creative-copywriting/databases/README.md +60 -0
- package/skills/skills/creative-copywriting/databases/carousel-structures.csv +16 -0
- package/skills/skills/creative-copywriting/databases/emotional-arcs.csv +11 -0
- package/skills/skills/creative-copywriting/databases/hook-formulas.csv +51 -0
- package/skills/skills/creative-copywriting/databases/power-words.csv +201 -0
- package/skills/skills/creative-copywriting/databases/psychological-triggers.csv +21 -0
- package/skills/skills/creative-copywriting/databases/read-more-patterns.csv +26 -0
- package/skills/skills/creative-copywriting/databases/swipe-triggers.csv +31 -0
- package/skills/skills/creative-copywriting/references/carousel-psychology.md +223 -0
- package/skills/skills/creative-copywriting/references/hook-anatomy.md +169 -0
- package/skills/skills/creative-copywriting/references/power-word-science.md +134 -0
- package/skills/skills/creative-copywriting/references/storytelling-frameworks.md +157 -0
- package/skills/skills/diverse-content-gen/SKILL.md +201 -0
- package/skills/skills/diverse-content-gen/references/advanced-techniques.md +320 -0
- package/skills/skills/diverse-content-gen/references/research-findings.md +379 -0
- package/skills/skills/diverse-content-gen/references/task-workflows.md +241 -0
- package/skills/skills/diverse-content-gen/references/tool-integration.md +419 -0
- package/skills/skills/diverse-content-gen/references/troubleshooting.md +426 -0
- package/skills/skills/diverse-content-gen/references/vs-core-technique.md +240 -0
- package/skills/skills/framework-critical-thinking/SKILL.md +220 -0
- package/skills/skills/framework-critical-thinking/references/bias_detector.md +375 -0
- package/skills/skills/framework-critical-thinking/references/fallback_handler.md +239 -0
- package/skills/skills/framework-critical-thinking/references/memory_curator.md +161 -0
- package/skills/skills/framework-critical-thinking/references/metacognitive_monitor.md +297 -0
- package/skills/skills/framework-critical-thinking/references/producer_critic_orchestrator.md +333 -0
- package/skills/skills/framework-critical-thinking/references/reasoning_router.md +235 -0
- package/skills/skills/framework-critical-thinking/references/reasoning_validator.md +97 -0
- package/skills/skills/framework-critical-thinking/references/reflection_trigger.md +78 -0
- package/skills/skills/framework-critical-thinking/references/self_verification.md +388 -0
- package/skills/skills/framework-critical-thinking/references/uncertainty_quantifier.md +207 -0
- package/skills/skills/framework-initiative/SKILL.md +231 -0
- package/skills/skills/framework-initiative/references/examples.md +150 -0
- package/skills/skills/framework-initiative/references/impact-analysis.md +157 -0
- package/skills/skills/framework-initiative/references/intent-patterns.md +145 -0
- package/skills/skills/framework-initiative/references/star-framework.md +165 -0
- package/skills/skills/humanize-docs/SKILL.md +203 -0
- package/skills/skills/humanize-docs/references/advanced-techniques.md +13 -0
- package/skills/skills/humanize-docs/references/core-transformations.md +368 -0
- package/skills/skills/humanize-docs/references/detection-patterns.md +400 -0
- package/skills/skills/humanize-docs/references/examples-gallery.md +374 -0
- package/skills/skills/imagine/SKILL.md +190 -0
- package/skills/skills/imagine/references/artstyle-corporate-memphis.md +625 -0
- package/skills/skills/imagine/references/artstyle-crewdson-hyperrealism.md +295 -0
- package/skills/skills/imagine/references/artstyle-iphone-social-media.md +426 -0
- package/skills/skills/imagine/references/artstyle-sciencesaru.md +276 -0
- package/skills/skills/pre-deploy-checklist/README.md +26 -0
- package/skills/skills/pre-deploy-checklist/SKILL.md +153 -0
- package/skills/skills/pre-deploy-checklist/references/checklist-categories.md +174 -0
- package/skills/skills/pre-deploy-checklist/references/domain-prompts.md +216 -0
- package/skills/skills/prompt-engineering/SKILL.md +209 -0
- package/skills/skills/prompt-engineering/references/advanced-combinations.md +444 -0
- package/skills/skills/prompt-engineering/references/chain-of-thought.md +140 -0
- package/skills/skills/prompt-engineering/references/decision_matrix.md +220 -0
- package/skills/skills/prompt-engineering/references/few-shot.md +346 -0
- package/skills/skills/prompt-engineering/references/json-format.md +270 -0
- package/skills/skills/prompt-engineering/references/natural-language.md +420 -0
- package/skills/skills/prompt-engineering/references/pitfalls.md +365 -0
- package/skills/skills/prompt-engineering/references/prompt-chaining.md +498 -0
- package/skills/skills/prompt-engineering/references/react.md +108 -0
- package/skills/skills/prompt-engineering/references/self-consistency.md +322 -0
- package/skills/skills/prompt-engineering/references/tree-of-thoughts.md +386 -0
- package/skills/skills/prompt-engineering/references/xml-format.md +220 -0
- package/skills/skills/prompt-engineering/references/yaml-format.md +488 -0
- package/skills/skills/prompt-engineering/references/zero-shot.md +74 -0
- package/skills/skills/quick-spec/SKILL.md +280 -0
- package/skills/skills/quick-spec/assets/tech-spec-template.md +74 -0
- package/skills/skills/quick-spec/references/step-01-understand.md +189 -0
- package/skills/skills/quick-spec/references/step-02-investigate.md +144 -0
- package/skills/skills/quick-spec/references/step-03-generate.md +128 -0
- package/skills/skills/quick-spec/references/step-04-review.md +173 -0
- package/skills/skills/quick-spec/tests/__pycache__/test_skill.cpython-314-pytest-9.0.2.pyc +0 -0
- package/skills/skills/quick-spec/tests/test_scenarios.md +83 -0
- package/skills/skills/quick-spec/tests/test_skill.py +136 -0
- package/skills/skills/readme-expert/SKILL.md +538 -0
- package/skills/skills/readme-expert/knowledge/INDEX.md +192 -0
- package/skills/skills/readme-expert/knowledge/application/quality-standards.md +470 -0
- package/skills/skills/readme-expert/knowledge/application/script-executor.md +604 -0
- package/skills/skills/readme-expert/knowledge/application/template-library.md +822 -0
- package/skills/skills/readme-expert/knowledge/foundation/codebase-scanner.md +361 -0
- package/skills/skills/readme-expert/knowledge/foundation/validation-checklist.md +481 -0
- package/skills/skills/red-teaming/SKILL.md +321 -0
- package/skills/skills/red-teaming/references/ai-llm-redteam.md +517 -0
- package/skills/skills/red-teaming/references/attack-techniques.md +410 -0
- package/skills/skills/red-teaming/references/cybersecurity-redteam.md +383 -0
- package/skills/skills/red-teaming/references/tools-frameworks.md +446 -0
- package/skills/skills/releasing/.skillkit-mode +1 -0
- package/skills/skills/releasing/SKILL.md +225 -0
- package/skills/skills/releasing/references/version-detection.md +108 -0
- package/skills/skills/screenwriter/SKILL.md +273 -0
- package/skills/skills/screenwriter/references/advanced-techniques.md +216 -0
- package/skills/skills/screenwriter/references/pipeline-integration.md +266 -0
- package/skills/skills/skillkit/.claude/settings.local.json +7 -0
- package/skills/skills/skillkit/.claude-plugin/plugin.json +27 -0
- package/skills/skills/skillkit/CHANGELOG.md +484 -0
- package/skills/skills/skillkit/SKILL.md +511 -0
- package/skills/skills/skillkit/commands/skillkit.md +6 -0
- package/skills/skills/skillkit/commands/validate-plan.md +6 -0
- package/skills/skills/skillkit/commands/verify.md +6 -0
- package/skills/skills/skillkit/knowledge/INDEX.md +352 -0
- package/skills/skills/skillkit/knowledge/application/09-case-studies.md +257 -0
- package/skills/skills/skillkit/knowledge/application/10-technical-architecture.md +324 -0
- package/skills/skills/skillkit/knowledge/application/11-adoption-strategy.md +267 -0
- package/skills/skills/skillkit/knowledge/application/12-testing-and-validation.md +276 -0
- package/skills/skills/skillkit/knowledge/application/13-competitive-landscape.md +198 -0
- package/skills/skills/skillkit/knowledge/foundation/01-why-skills-exist.md +246 -0
- package/skills/skills/skillkit/knowledge/foundation/02-skills-vs-subagents-comparison.md +312 -0
- package/skills/skills/skillkit/knowledge/foundation/03-skills-vs-subagents-decision-tree.md +346 -0
- package/skills/skills/skillkit/knowledge/foundation/04-hybrid-patterns.md +308 -0
- package/skills/skills/skillkit/knowledge/foundation/05-token-economics.md +275 -0
- package/skills/skills/skillkit/knowledge/foundation/06-platform-constraints.md +237 -0
- package/skills/skills/skillkit/knowledge/foundation/07-security-concerns.md +322 -0
- package/skills/skills/skillkit/knowledge/foundation/08-when-not-to-use-skills.md +270 -0
- package/skills/skills/skillkit/knowledge/plugin-guide.md +614 -0
- package/skills/skills/skillkit/knowledge/tools/14-validation-tools-guide.md +150 -0
- package/skills/skills/skillkit/knowledge/tools/15-cost-tools-guide.md +157 -0
- package/skills/skills/skillkit/knowledge/tools/16-security-tools-guide.md +122 -0
- package/skills/skills/skillkit/knowledge/tools/17-pattern-tools-guide.md +161 -0
- package/skills/skills/skillkit/knowledge/tools/18-decision-helper-guide.md +243 -0
- package/skills/skills/skillkit/knowledge/tools/19-test-generator-guide.md +275 -0
- package/skills/skills/skillkit/knowledge/tools/20-split-skill-guide.md +149 -0
- package/skills/skills/skillkit/knowledge/tools/21-quality-scorer-guide.md +226 -0
- package/skills/skills/skillkit/knowledge/tools/22-migration-helper-guide.md +356 -0
- package/skills/skills/skillkit/knowledge/tools/23-subagent-creation-guide.md +448 -0
- package/skills/skills/skillkit/knowledge/tools/24-behavioral-testing-guide.md +122 -0
- package/skills/skills/skillkit/references/proposal-generation.md +982 -0
- package/skills/skills/skillkit/references/rationalization-catalog.md +75 -0
- package/skills/skills/skillkit/references/research-methodology.md +661 -0
- package/skills/skills/skillkit/references/section-2-full-creation-workflow.md +452 -0
- package/skills/skills/skillkit/references/section-3-validation-workflow-existing-skill.md +63 -0
- package/skills/skills/skillkit/references/section-4-decision-workflow-skills-vs-subagents.md +64 -0
- package/skills/skills/skillkit/references/section-5-migration-workflow-doc-to-skill.md +58 -0
- package/skills/skills/skillkit/references/section-6-subagent-creation-workflow.md +499 -0
- package/skills/skills/skillkit/references/section-7-knowledge-reference-map.md +72 -0
- package/skills/skills/skillkit/scripts/__pycache__/decision_helper.cpython-314.pyc +0 -0
- package/skills/skills/skillkit/scripts/__pycache__/quick_validate.cpython-312.pyc +0 -0
- package/skills/skills/skillkit/scripts/__pycache__/quick_validate.cpython-314.pyc +0 -0
- package/skills/skills/skillkit/scripts/__pycache__/test_generator.cpython-314-pytest-9.0.2.pyc +0 -0
- package/skills/skills/skillkit/scripts/decision_helper.py +799 -0
- package/skills/skills/skillkit/scripts/init_skill.py +400 -0
- package/skills/skills/skillkit/scripts/init_subagent.py +231 -0
- package/skills/skills/skillkit/scripts/migration_helper.py +669 -0
- package/skills/skills/skillkit/scripts/package_skill.py +211 -0
- package/skills/skills/skillkit/scripts/pattern_detector.py +381 -0
- package/skills/skills/skillkit/scripts/pattern_detector_new.py +382 -0
- package/skills/skills/skillkit/scripts/pressure_tester.py +157 -0
- package/skills/skills/skillkit/scripts/quality_scorer.py +999 -0
- package/skills/skills/skillkit/scripts/quick_validate.py +100 -0
- package/skills/skills/skillkit/scripts/security_scanner.py +474 -0
- package/skills/skills/skillkit/scripts/split_skill.py +540 -0
- package/skills/skills/skillkit/scripts/test_generator.py +695 -0
- package/skills/skills/skillkit/scripts/token_estimator.py +493 -0
- package/skills/skills/skillkit/scripts/utils/__init__.py +49 -0
- package/skills/skills/skillkit/scripts/utils/__pycache__/__init__.cpython-312.pyc +0 -0
- package/skills/skills/skillkit/scripts/utils/__pycache__/__init__.cpython-314.pyc +0 -0
- package/skills/skills/skillkit/scripts/utils/__pycache__/budget_tracker.cpython-312.pyc +0 -0
- package/skills/skills/skillkit/scripts/utils/__pycache__/budget_tracker.cpython-314.pyc +0 -0
- package/skills/skills/skillkit/scripts/utils/__pycache__/output_formatter.cpython-312.pyc +0 -0
- package/skills/skills/skillkit/scripts/utils/__pycache__/output_formatter.cpython-314.pyc +0 -0
- package/skills/skills/skillkit/scripts/utils/__pycache__/reference_validator.cpython-312.pyc +0 -0
- package/skills/skills/skillkit/scripts/utils/__pycache__/reference_validator.cpython-314.pyc +0 -0
- package/skills/skills/skillkit/scripts/utils/budget_tracker.py +388 -0
- package/skills/skills/skillkit/scripts/utils/output_formatter.py +263 -0
- package/skills/skills/skillkit/scripts/utils/reference_validator.py +401 -0
- package/skills/skills/skillkit/scripts/validate_skill.py +594 -0
- package/skills/skills/skillkit/tests/test_behavioral.py +39 -0
- package/skills/skills/skillkit/tests/test_scenarios.md +83 -0
- package/skills/skills/skillkit/tests/test_skill.py +136 -0
- package/skills/skills/skillkit-help/SKILL.md +81 -0
- package/skills/skills/skillkit-help/knowledge/application/09-case-studies.md +257 -0
- package/skills/skills/skillkit-help/knowledge/application/12-testing-and-validation.md +276 -0
- package/skills/skills/skillkit-help/knowledge/foundation/01-why-skills-exist.md +246 -0
- package/skills/skills/skillkit-help/knowledge/foundation/02-skills-vs-subagents-comparison.md +312 -0
- package/skills/skills/skillkit-help/knowledge/foundation/03-skills-vs-subagents-decision-tree.md +346 -0
- package/skills/skills/skillkit-help/knowledge/foundation/06-platform-constraints.md +237 -0
- package/skills/skills/skillkit-help/knowledge/foundation/08-when-not-to-use-skills.md +270 -0
- package/skills/skills/skillkit-help/template/SKILL.md +52 -0
- package/skills/skills/social-media-seo/SKILL.md +278 -0
- package/skills/skills/social-media-seo/databases/caption-styles.csv +31 -0
- package/skills/skills/social-media-seo/databases/engagement-tactics.csv +16 -0
- package/skills/skills/social-media-seo/databases/hashtag-strategies.csv +21 -0
- package/skills/skills/social-media-seo/databases/hook-formulas.csv +26 -0
- package/skills/skills/social-media-seo/databases/keyword-clusters.csv +11 -0
- package/skills/skills/social-media-seo/databases/thread-structures.csv +26 -0
- package/skills/skills/social-media-seo/databases/viral-patterns.csv +21 -0
- package/skills/skills/social-media-seo/references/analytics-guide.md +321 -0
- package/skills/skills/social-media-seo/references/instagram-seo.md +235 -0
- package/skills/skills/social-media-seo/references/threads-seo.md +305 -0
- package/skills/skills/social-media-seo/references/x-twitter-seo.md +337 -0
- package/skills/skills/social-media-seo/scripts/query_database.py +191 -0
- package/skills/skills/storyteller/SKILL.md +241 -0
- package/skills/skills/storyteller/references/transformation-methodology.md +293 -0
- package/skills/skills/storyteller/references/visual-vocabulary.md +177 -0
- package/skills/skills/thread-pro/SKILL.md +162 -0
- package/skills/skills/thread-pro/anti-ai-patterns.md +120 -0
- package/skills/skills/thread-pro/hook-formulas.md +138 -0
- package/skills/skills/thread-pro/references/anti-ai-patterns.md +120 -0
- package/skills/skills/thread-pro/references/hook-formulas.md +138 -0
- package/skills/skills/thread-pro/references/thread-structures.md +240 -0
- package/skills/skills/thread-pro/references/voice-injection.md +130 -0
- package/skills/skills/thread-pro/thread-structures.md +240 -0
- package/skills/skills/thread-pro/voice-injection.md +130 -0
- package/skills/skills/tinkering/SKILL.md +251 -0
- package/skills/skills/tinkering/references/graduation-checklist.md +100 -0
- package/skills/skills/validate-plan/.skillkit-mode +1 -0
- package/skills/skills/validate-plan/SKILL.md +406 -0
- package/skills/skills/validate-plan/references/dry-principles.md +251 -0
- package/skills/skills/validate-plan/references/gap-analysis-guide.md +320 -0
- package/skills/skills/validate-plan/references/tdd-patterns.md +413 -0
- package/skills/skills/validate-plan/references/yagni-checklist.md +330 -0
- package/skills/skills/verify-before-ship/.skillkit-mode +1 -0
- package/skills/skills/verify-before-ship/SKILL.md +116 -0
- package/skills/skills/verify-before-ship/references/anti-rationalization.md +212 -0
- package/skills/skills/verify-before-ship/references/verification-gates.md +305 -0
- package/skills-manifest.json +8 -2
- package/src/picker.js +11 -5
- package/src/picker.test.js +36 -1
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Comprehensive skill validation tool.
|
|
4
|
+
Validates skills against best practices from Files 02, 07, 10, 12.
|
|
5
|
+
|
|
6
|
+
v1.2 Update: Enhanced cross-reference validation
|
|
7
|
+
- Comprehensive file reference detection (markdown links, code refs, paths)
|
|
8
|
+
- File existence verification
|
|
9
|
+
- Orphaned file detection
|
|
10
|
+
- Uses CrossReferenceValidator utility
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
python validate_skill.py <skill_path> [--strict] [--format text|json]
|
|
14
|
+
|
|
15
|
+
References:
|
|
16
|
+
- File 02: Description engineering patterns
|
|
17
|
+
- File 07: Security best practices
|
|
18
|
+
- File 10: Progressive disclosure architecture
|
|
19
|
+
- File 12: Testing and validation checklist
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import os
|
|
23
|
+
import re
|
|
24
|
+
import sys
|
|
25
|
+
import json
|
|
26
|
+
import yaml
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
from typing import Dict, List, Tuple
|
|
29
|
+
from dataclasses import dataclass
|
|
30
|
+
from enum import Enum
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
from utils.reference_validator import CrossReferenceValidator
|
|
34
|
+
except ImportError:
|
|
35
|
+
CrossReferenceValidator = None # Graceful fallback
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class Severity(Enum):
|
|
39
|
+
"""Validation result severity levels."""
|
|
40
|
+
PASS = "pass"
|
|
41
|
+
WARNING = "warning"
|
|
42
|
+
FAIL = "fail"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class ValidationResult:
|
|
47
|
+
"""Single validation check result."""
|
|
48
|
+
check_name: str
|
|
49
|
+
severity: Severity
|
|
50
|
+
message: str
|
|
51
|
+
suggestion: str = ""
|
|
52
|
+
line_number: int = None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class SkillValidator:
|
|
56
|
+
"""Main validator implementing 10 comprehensive checks."""
|
|
57
|
+
|
|
58
|
+
def __init__(self, skill_path: str, strict: bool = False):
|
|
59
|
+
"""
|
|
60
|
+
Initialize validator.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
skill_path: Path to skill directory
|
|
64
|
+
strict: If True, warnings become failures
|
|
65
|
+
"""
|
|
66
|
+
self.skill_path = Path(skill_path)
|
|
67
|
+
self.strict = strict
|
|
68
|
+
self.results: List[ValidationResult] = []
|
|
69
|
+
|
|
70
|
+
# Load SKILL.md content once
|
|
71
|
+
self.skill_md_path = self.skill_path / "SKILL.md"
|
|
72
|
+
self.skill_content = ""
|
|
73
|
+
self.frontmatter = {}
|
|
74
|
+
|
|
75
|
+
if self.skill_md_path.exists():
|
|
76
|
+
self.skill_content = self.skill_md_path.read_text(encoding='utf-8')
|
|
77
|
+
self._parse_frontmatter()
|
|
78
|
+
|
|
79
|
+
def _parse_frontmatter(self):
|
|
80
|
+
"""Extract and parse YAML frontmatter."""
|
|
81
|
+
if self.skill_content.startswith('---'):
|
|
82
|
+
parts = self.skill_content.split('---', 2)
|
|
83
|
+
if len(parts) >= 3:
|
|
84
|
+
try:
|
|
85
|
+
self.frontmatter = yaml.safe_load(parts[1])
|
|
86
|
+
except yaml.YAMLError:
|
|
87
|
+
self.frontmatter = {}
|
|
88
|
+
|
|
89
|
+
# ========== STRUCTURAL VALIDATION ==========
|
|
90
|
+
|
|
91
|
+
def validate_yaml_frontmatter(self) -> ValidationResult:
|
|
92
|
+
"""Validate YAML frontmatter structure and required fields."""
|
|
93
|
+
if not self.skill_md_path.exists():
|
|
94
|
+
return ValidationResult(
|
|
95
|
+
"YAML Frontmatter",
|
|
96
|
+
Severity.FAIL,
|
|
97
|
+
"SKILL.md not found",
|
|
98
|
+
"Create SKILL.md in skill directory"
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
if not self.frontmatter:
|
|
102
|
+
return ValidationResult(
|
|
103
|
+
"YAML Frontmatter",
|
|
104
|
+
Severity.FAIL,
|
|
105
|
+
"Invalid or missing YAML frontmatter",
|
|
106
|
+
"Add valid YAML frontmatter between --- markers"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Check required fields
|
|
110
|
+
required_fields = ['name', 'description']
|
|
111
|
+
missing = [f for f in required_fields if f not in self.frontmatter]
|
|
112
|
+
|
|
113
|
+
if missing:
|
|
114
|
+
return ValidationResult(
|
|
115
|
+
"YAML Frontmatter",
|
|
116
|
+
Severity.FAIL,
|
|
117
|
+
f"Missing required fields: {', '.join(missing)}",
|
|
118
|
+
"Add required fields to frontmatter"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
return ValidationResult(
|
|
122
|
+
"YAML Frontmatter",
|
|
123
|
+
Severity.PASS,
|
|
124
|
+
"Valid YAML frontmatter with required fields"
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
def validate_file_structure(self) -> ValidationResult:
|
|
128
|
+
"""Validate skill directory structure."""
|
|
129
|
+
if not self.skill_md_path.exists():
|
|
130
|
+
return ValidationResult(
|
|
131
|
+
"File Structure",
|
|
132
|
+
Severity.FAIL,
|
|
133
|
+
"SKILL.md missing",
|
|
134
|
+
"Create SKILL.md file"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
issues = []
|
|
138
|
+
|
|
139
|
+
# Check for scripts directory if any .py files exist
|
|
140
|
+
scripts_dir = self.skill_path / "scripts"
|
|
141
|
+
py_files = list(self.skill_path.glob("*.py"))
|
|
142
|
+
|
|
143
|
+
if py_files and not scripts_dir.exists():
|
|
144
|
+
issues.append("Python files found but no scripts/ directory")
|
|
145
|
+
|
|
146
|
+
# Check for references directory if SKILL.md is large
|
|
147
|
+
line_count = len(self.skill_content.splitlines())
|
|
148
|
+
references_dir = self.skill_path / "references"
|
|
149
|
+
|
|
150
|
+
if line_count > 500 and not references_dir.exists():
|
|
151
|
+
issues.append(f"SKILL.md has {line_count} lines (>500), consider using references/")
|
|
152
|
+
|
|
153
|
+
if issues:
|
|
154
|
+
severity = Severity.WARNING if not self.strict else Severity.FAIL
|
|
155
|
+
return ValidationResult(
|
|
156
|
+
"File Structure",
|
|
157
|
+
severity,
|
|
158
|
+
"; ".join(issues),
|
|
159
|
+
"Organize files according to progressive disclosure pattern (File 10)"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
return ValidationResult(
|
|
163
|
+
"File Structure",
|
|
164
|
+
Severity.PASS,
|
|
165
|
+
"Proper file organization"
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
# ========== DESCRIPTION QUALITY ==========
|
|
169
|
+
|
|
170
|
+
def validate_description_quality(self) -> ValidationResult:
|
|
171
|
+
"""Validate description includes WHAT + WHEN."""
|
|
172
|
+
description = self.frontmatter.get('description', '')
|
|
173
|
+
|
|
174
|
+
if not description:
|
|
175
|
+
return ValidationResult(
|
|
176
|
+
"Description Quality",
|
|
177
|
+
Severity.FAIL,
|
|
178
|
+
"Description is empty",
|
|
179
|
+
"Add description with WHAT (capability) and WHEN (triggers)"
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# Check length
|
|
183
|
+
if len(description) < 20:
|
|
184
|
+
return ValidationResult(
|
|
185
|
+
"Description Quality",
|
|
186
|
+
Severity.WARNING,
|
|
187
|
+
f"Description too short ({len(description)} chars)",
|
|
188
|
+
"Expand to 20-100 words with clear capabilities"
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
if len(description) > 1024:
|
|
192
|
+
return ValidationResult(
|
|
193
|
+
"Description Quality",
|
|
194
|
+
Severity.FAIL,
|
|
195
|
+
f"Description too long ({len(description)} chars, max 1024)",
|
|
196
|
+
"Condense to essential WHAT and WHEN information"
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
# Check for trigger phrases (WHEN)
|
|
200
|
+
trigger_phrases = [
|
|
201
|
+
'use when', 'trigger on', 'for tasks involving',
|
|
202
|
+
'when claude needs to', 'activate when', 'applies to'
|
|
203
|
+
]
|
|
204
|
+
|
|
205
|
+
has_trigger = any(phrase in description.lower() for phrase in trigger_phrases)
|
|
206
|
+
|
|
207
|
+
if not has_trigger:
|
|
208
|
+
severity = Severity.WARNING if not self.strict else Severity.FAIL
|
|
209
|
+
return ValidationResult(
|
|
210
|
+
"Description Quality",
|
|
211
|
+
severity,
|
|
212
|
+
"Description missing WHEN trigger phrases",
|
|
213
|
+
"Add phrases like 'Use when...' or 'Trigger on...' (File 02)"
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
return ValidationResult(
|
|
217
|
+
"Description Quality",
|
|
218
|
+
Severity.PASS,
|
|
219
|
+
"Description includes WHAT and WHEN triggers"
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
# ========== TOKEN EFFICIENCY ==========
|
|
223
|
+
|
|
224
|
+
def validate_token_count(self) -> ValidationResult:
|
|
225
|
+
"""Validate token efficiency."""
|
|
226
|
+
line_count = len(self.skill_content.splitlines())
|
|
227
|
+
|
|
228
|
+
# Estimate tokens (average method: 1 line ≈ 8 tokens)
|
|
229
|
+
estimated_tokens = int(line_count * 8)
|
|
230
|
+
|
|
231
|
+
issues = []
|
|
232
|
+
|
|
233
|
+
# SKILL.md size checks
|
|
234
|
+
if line_count > 800:
|
|
235
|
+
issues.append(f"SKILL.md too large ({line_count} lines, max 800)")
|
|
236
|
+
elif line_count > 500:
|
|
237
|
+
issues.append(f"SKILL.md large ({line_count} lines), consider splitting at 500+")
|
|
238
|
+
|
|
239
|
+
# Token estimate checks
|
|
240
|
+
if estimated_tokens > 6000:
|
|
241
|
+
issues.append(f"Estimated {estimated_tokens} tokens (critical >6000)")
|
|
242
|
+
elif estimated_tokens > 4500:
|
|
243
|
+
issues.append(f"Estimated {estimated_tokens} tokens (warning >4500)")
|
|
244
|
+
|
|
245
|
+
if not issues:
|
|
246
|
+
return ValidationResult(
|
|
247
|
+
"Token Efficiency",
|
|
248
|
+
Severity.PASS,
|
|
249
|
+
f"Efficient: {line_count} lines (~{estimated_tokens} tokens)"
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
severity = Severity.FAIL if line_count > 800 else Severity.WARNING
|
|
253
|
+
|
|
254
|
+
return ValidationResult(
|
|
255
|
+
"Token Efficiency",
|
|
256
|
+
severity,
|
|
257
|
+
"; ".join(issues),
|
|
258
|
+
"Apply progressive disclosure: move details to references/ (File 10)"
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
# ========== SECURITY VALIDATION ==========
|
|
262
|
+
|
|
263
|
+
def validate_security_basics(self) -> ValidationResult:
|
|
264
|
+
"""Basic security checks (see security_scanner.py for comprehensive audit)."""
|
|
265
|
+
issues = []
|
|
266
|
+
|
|
267
|
+
# Check SKILL.md for obvious secrets
|
|
268
|
+
secret_patterns = [
|
|
269
|
+
(r'api_key\s*=\s*["\'][^"\']+["\']', 'Hardcoded API key'),
|
|
270
|
+
(r'password\s*=\s*["\'][^"\']+["\']', 'Hardcoded password'),
|
|
271
|
+
(r'secret\s*=\s*["\'][^"\']+["\']', 'Hardcoded secret'),
|
|
272
|
+
(r'token\s*=\s*["\'][^"\']+["\']', 'Hardcoded token'),
|
|
273
|
+
]
|
|
274
|
+
|
|
275
|
+
for pattern, desc in secret_patterns:
|
|
276
|
+
if re.search(pattern, self.skill_content, re.IGNORECASE):
|
|
277
|
+
issues.append(f"{desc} detected in SKILL.md")
|
|
278
|
+
|
|
279
|
+
# Check scripts for dangerous patterns
|
|
280
|
+
scripts_dir = self.skill_path / "scripts"
|
|
281
|
+
if scripts_dir.exists():
|
|
282
|
+
for script_file in scripts_dir.glob("*.py"):
|
|
283
|
+
script_content = script_file.read_text(encoding='utf-8')
|
|
284
|
+
|
|
285
|
+
if 'shell=True' in script_content:
|
|
286
|
+
issues.append(f"shell=True found in {script_file.name}")
|
|
287
|
+
|
|
288
|
+
if re.search(r'\beval\s*\(', script_content):
|
|
289
|
+
issues.append(f"eval() usage in {script_file.name}")
|
|
290
|
+
|
|
291
|
+
if re.search(r'\bexec\s*\(', script_content):
|
|
292
|
+
issues.append(f"exec() usage in {script_file.name}")
|
|
293
|
+
|
|
294
|
+
if issues:
|
|
295
|
+
return ValidationResult(
|
|
296
|
+
"Security Basics",
|
|
297
|
+
Severity.FAIL,
|
|
298
|
+
"; ".join(issues),
|
|
299
|
+
"Remove hardcoded secrets, avoid shell=True/eval/exec (File 07). Run security_scanner.py for full audit."
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
return ValidationResult(
|
|
303
|
+
"Security Basics",
|
|
304
|
+
Severity.PASS,
|
|
305
|
+
"No obvious security issues (run security_scanner.py for comprehensive audit)"
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
# ========== BEST PRACTICES ==========
|
|
309
|
+
|
|
310
|
+
def validate_writing_style(self) -> ValidationResult:
|
|
311
|
+
"""Validate agent-layer writing style."""
|
|
312
|
+
body = self.skill_content.split('---', 2)[-1] if '---' in self.skill_content else self.skill_content
|
|
313
|
+
|
|
314
|
+
issues = []
|
|
315
|
+
|
|
316
|
+
# Check for non-imperative patterns
|
|
317
|
+
weak_patterns = [
|
|
318
|
+
'you can', 'you may', 'you should', 'you might',
|
|
319
|
+
'it is possible', 'one could', 'consider'
|
|
320
|
+
]
|
|
321
|
+
|
|
322
|
+
weak_count = sum(body.lower().count(pattern) for pattern in weak_patterns)
|
|
323
|
+
|
|
324
|
+
if weak_count > 5:
|
|
325
|
+
issues.append(f"Too many weak phrases ({weak_count} instances)")
|
|
326
|
+
|
|
327
|
+
# Check for section headers (good sign of organization)
|
|
328
|
+
header_count = len(re.findall(r'^#+\s+', body, re.MULTILINE))
|
|
329
|
+
|
|
330
|
+
if header_count < 3 and len(body.splitlines()) > 100:
|
|
331
|
+
issues.append("Few section headers (improves scannability)")
|
|
332
|
+
|
|
333
|
+
if issues:
|
|
334
|
+
severity = Severity.WARNING
|
|
335
|
+
return ValidationResult(
|
|
336
|
+
"Writing Style",
|
|
337
|
+
severity,
|
|
338
|
+
"; ".join(issues),
|
|
339
|
+
"Use imperative form ('Use X' not 'You can use X'), add clear headers"
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
return ValidationResult(
|
|
343
|
+
"Writing Style",
|
|
344
|
+
Severity.PASS,
|
|
345
|
+
"Agent-layer writing style maintained"
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
def validate_progressive_disclosure(self) -> ValidationResult:
|
|
349
|
+
"""Validate progressive disclosure implementation."""
|
|
350
|
+
line_count = len(self.skill_content.splitlines())
|
|
351
|
+
references_dir = self.skill_path / "references"
|
|
352
|
+
|
|
353
|
+
# If SKILL.md is large but no references, suggest splitting
|
|
354
|
+
if line_count > 350 and not references_dir.exists():
|
|
355
|
+
return ValidationResult(
|
|
356
|
+
"Progressive Disclosure",
|
|
357
|
+
Severity.WARNING,
|
|
358
|
+
f"SKILL.md has {line_count} lines, no references/ directory",
|
|
359
|
+
"Move optional details to references/ for better progressive disclosure (File 10)"
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
# Check reference files have TOC if >100 lines
|
|
363
|
+
if references_dir.exists():
|
|
364
|
+
for ref_file in references_dir.glob("*.md"):
|
|
365
|
+
ref_content = ref_file.read_text(encoding='utf-8')
|
|
366
|
+
ref_lines = len(ref_content.splitlines())
|
|
367
|
+
|
|
368
|
+
if ref_lines > 100:
|
|
369
|
+
# Simple TOC check: look for list of links to headers
|
|
370
|
+
has_toc = bool(re.search(r'\[.*\]\(#.*\)', ref_content[:500]))
|
|
371
|
+
|
|
372
|
+
if not has_toc:
|
|
373
|
+
return ValidationResult(
|
|
374
|
+
"Progressive Disclosure",
|
|
375
|
+
Severity.WARNING,
|
|
376
|
+
f"{ref_file.name} has {ref_lines} lines but no TOC",
|
|
377
|
+
"Add table of contents at top of reference files >100 lines"
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
return ValidationResult(
|
|
381
|
+
"Progressive Disclosure",
|
|
382
|
+
Severity.PASS,
|
|
383
|
+
"Progressive disclosure properly implemented"
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
def validate_cross_references(self) -> ValidationResult:
|
|
387
|
+
"""
|
|
388
|
+
Validate cross-reference integrity with comprehensive file checking.
|
|
389
|
+
|
|
390
|
+
v1.2 Enhanced: Uses CrossReferenceValidator for:
|
|
391
|
+
- Markdown links: [text](path)
|
|
392
|
+
- Code references: `file.md`
|
|
393
|
+
- Path patterns: "file: path.md"
|
|
394
|
+
- File existence verification
|
|
395
|
+
- Orphaned file detection
|
|
396
|
+
"""
|
|
397
|
+
# Try to use comprehensive CrossReferenceValidator
|
|
398
|
+
if CrossReferenceValidator:
|
|
399
|
+
try:
|
|
400
|
+
validator = CrossReferenceValidator(str(self.skill_path))
|
|
401
|
+
ref_result = validator.validate_skill_md()
|
|
402
|
+
|
|
403
|
+
if ref_result.status == 'fail':
|
|
404
|
+
# Comprehensive failure message with all issues
|
|
405
|
+
issues = []
|
|
406
|
+
if ref_result.missing_files:
|
|
407
|
+
issues.append(f"Missing: {', '.join(ref_result.missing_files[:3])}")
|
|
408
|
+
if ref_result.orphaned_files:
|
|
409
|
+
issues.append(f"Orphaned: {', '.join(ref_result.orphaned_files[:3])}")
|
|
410
|
+
|
|
411
|
+
return ValidationResult(
|
|
412
|
+
"Cross-References",
|
|
413
|
+
Severity.FAIL,
|
|
414
|
+
f"{'; '.join(issues)}{'...' if len(issues) > 2 else ''}",
|
|
415
|
+
ref_result.suggestion or "Fix or remove broken cross-references"
|
|
416
|
+
)
|
|
417
|
+
else:
|
|
418
|
+
return ValidationResult(
|
|
419
|
+
"Cross-References",
|
|
420
|
+
Severity.PASS,
|
|
421
|
+
f"All {len(ref_result.valid_references)} cross-references valid"
|
|
422
|
+
)
|
|
423
|
+
except Exception as e:
|
|
424
|
+
# Fallback to original simple validation
|
|
425
|
+
pass
|
|
426
|
+
|
|
427
|
+
# Fallback: Original simple validation (backward compatibility)
|
|
428
|
+
link_pattern = r'\[([^\]]+)\]\(([^)]+)\)'
|
|
429
|
+
links = re.findall(link_pattern, self.skill_content)
|
|
430
|
+
|
|
431
|
+
broken = []
|
|
432
|
+
|
|
433
|
+
for link_text, link_target in links:
|
|
434
|
+
# Skip external URLs
|
|
435
|
+
if link_target.startswith(('http://', 'https://', '#')):
|
|
436
|
+
continue
|
|
437
|
+
|
|
438
|
+
# Check if file exists
|
|
439
|
+
target_path = self.skill_path / link_target
|
|
440
|
+
if not target_path.exists():
|
|
441
|
+
broken.append(f"'{link_text}' -> {link_target}")
|
|
442
|
+
|
|
443
|
+
if broken:
|
|
444
|
+
return ValidationResult(
|
|
445
|
+
"Cross-References",
|
|
446
|
+
Severity.FAIL,
|
|
447
|
+
f"Broken links found: {'; '.join(broken[:3])}{'...' if len(broken) > 3 else ''}",
|
|
448
|
+
"Fix or remove broken cross-references"
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
return ValidationResult(
|
|
452
|
+
"Cross-References",
|
|
453
|
+
Severity.PASS,
|
|
454
|
+
"All cross-references valid"
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
# ========== UTILITY METHODS ==========
|
|
458
|
+
|
|
459
|
+
def run_all_validations(self) -> List[ValidationResult]:
|
|
460
|
+
"""Run all validation checks."""
|
|
461
|
+
self.results = [
|
|
462
|
+
self.validate_yaml_frontmatter(),
|
|
463
|
+
self.validate_file_structure(),
|
|
464
|
+
self.validate_description_quality(),
|
|
465
|
+
self.validate_token_count(),
|
|
466
|
+
self.validate_security_basics(),
|
|
467
|
+
self.validate_writing_style(),
|
|
468
|
+
self.validate_progressive_disclosure(),
|
|
469
|
+
self.validate_cross_references(),
|
|
470
|
+
]
|
|
471
|
+
return self.results
|
|
472
|
+
|
|
473
|
+
def generate_report(self, format: str = 'text') -> str:
|
|
474
|
+
"""Generate validation report."""
|
|
475
|
+
if format == 'json':
|
|
476
|
+
return self._generate_json_report()
|
|
477
|
+
return self._generate_text_report()
|
|
478
|
+
|
|
479
|
+
def _generate_text_report(self) -> str:
|
|
480
|
+
"""Generate human-readable text report."""
|
|
481
|
+
lines = []
|
|
482
|
+
lines.append(f"\n{'='*60}")
|
|
483
|
+
lines.append(f"Skill Validation Report: {self.skill_path.name}")
|
|
484
|
+
lines.append('='*60 + '\n')
|
|
485
|
+
|
|
486
|
+
# Categorize results
|
|
487
|
+
passed = [r for r in self.results if r.severity == Severity.PASS]
|
|
488
|
+
warnings = [r for r in self.results if r.severity == Severity.WARNING]
|
|
489
|
+
failed = [r for r in self.results if r.severity == Severity.FAIL]
|
|
490
|
+
|
|
491
|
+
# Display results
|
|
492
|
+
for result in self.results:
|
|
493
|
+
icon = {
|
|
494
|
+
Severity.PASS: '✓',
|
|
495
|
+
Severity.WARNING: 'âš ',
|
|
496
|
+
Severity.FAIL: '✗'
|
|
497
|
+
}[result.severity]
|
|
498
|
+
|
|
499
|
+
lines.append(f"{icon} {result.check_name}")
|
|
500
|
+
|
|
501
|
+
if result.severity != Severity.PASS:
|
|
502
|
+
lines.append(f" {result.message}")
|
|
503
|
+
if result.suggestion:
|
|
504
|
+
lines.append(f" → {result.suggestion}")
|
|
505
|
+
|
|
506
|
+
lines.append('')
|
|
507
|
+
|
|
508
|
+
# Summary
|
|
509
|
+
lines.append('-'*60)
|
|
510
|
+
lines.append(f"Validation Score: {len(passed)}/{len(self.results)} checks passed")
|
|
511
|
+
lines.append(f"Severity: {len(failed)} critical, {len(warnings)} warnings, {len(passed)} passed")
|
|
512
|
+
lines.append('')
|
|
513
|
+
|
|
514
|
+
if failed:
|
|
515
|
+
lines.append("⌠Fix critical issues before packaging.")
|
|
516
|
+
elif warnings:
|
|
517
|
+
lines.append("âš ï¸ Address warnings to improve quality.")
|
|
518
|
+
else:
|
|
519
|
+
lines.append("✅ All validations passed! Skill ready for deployment.")
|
|
520
|
+
|
|
521
|
+
return '\n'.join(lines)
|
|
522
|
+
|
|
523
|
+
def _generate_json_report(self) -> str:
|
|
524
|
+
"""Generate machine-readable JSON report."""
|
|
525
|
+
report = {
|
|
526
|
+
'skill_name': self.skill_path.name,
|
|
527
|
+
'timestamp': str(Path.cwd()),
|
|
528
|
+
'results': [
|
|
529
|
+
{
|
|
530
|
+
'check': r.check_name,
|
|
531
|
+
'severity': r.severity.value,
|
|
532
|
+
'message': r.message,
|
|
533
|
+
'suggestion': r.suggestion
|
|
534
|
+
}
|
|
535
|
+
for r in self.results
|
|
536
|
+
],
|
|
537
|
+
'summary': {
|
|
538
|
+
'total': len(self.results),
|
|
539
|
+
'passed': len([r for r in self.results if r.severity == Severity.PASS]),
|
|
540
|
+
'warnings': len([r for r in self.results if r.severity == Severity.WARNING]),
|
|
541
|
+
'failed': len([r for r in self.results if r.severity == Severity.FAIL])
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return json.dumps(report, indent=2)
|
|
545
|
+
|
|
546
|
+
def get_exit_code(self) -> int:
|
|
547
|
+
"""Get appropriate exit code based on results."""
|
|
548
|
+
if any(r.severity == Severity.FAIL for r in self.results):
|
|
549
|
+
return 2 # Critical failures
|
|
550
|
+
if any(r.severity == Severity.WARNING for r in self.results):
|
|
551
|
+
return 1 # Warnings only
|
|
552
|
+
return 0 # All passed
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
def main():
|
|
556
|
+
"""CLI entry point."""
|
|
557
|
+
import argparse
|
|
558
|
+
|
|
559
|
+
parser = argparse.ArgumentParser(
|
|
560
|
+
description='Comprehensive skill validation tool',
|
|
561
|
+
epilog='References: Files 02, 07, 10, 12 for validation rules'
|
|
562
|
+
)
|
|
563
|
+
parser.add_argument('skill_path', help='Path to skill directory')
|
|
564
|
+
parser.add_argument('--strict', action='store_true',
|
|
565
|
+
help='Treat warnings as failures')
|
|
566
|
+
parser.add_argument('--format', choices=['text', 'json'], default='text',
|
|
567
|
+
help='Output format (default: text)')
|
|
568
|
+
|
|
569
|
+
args = parser.parse_args()
|
|
570
|
+
|
|
571
|
+
# Validate skill path
|
|
572
|
+
skill_path = Path(args.skill_path)
|
|
573
|
+
if not skill_path.exists():
|
|
574
|
+
print(f"Error: Skill path '{skill_path}' does not exist", file=sys.stderr)
|
|
575
|
+
sys.exit(2)
|
|
576
|
+
|
|
577
|
+
if not skill_path.is_dir():
|
|
578
|
+
print(f"Error: '{skill_path}' is not a directory", file=sys.stderr)
|
|
579
|
+
sys.exit(2)
|
|
580
|
+
|
|
581
|
+
# Run validation
|
|
582
|
+
validator = SkillValidator(skill_path, strict=args.strict)
|
|
583
|
+
validator.run_all_validations()
|
|
584
|
+
|
|
585
|
+
# Generate report
|
|
586
|
+
report = validator.generate_report(format=args.format)
|
|
587
|
+
print(report)
|
|
588
|
+
|
|
589
|
+
# Exit with appropriate code
|
|
590
|
+
sys.exit(validator.get_exit_code())
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
if __name__ == '__main__':
|
|
594
|
+
main()
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Behavioral tests for
|
|
3
|
+
Generated by test_generator.py --behavioral
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
# RED Phase: Baseline tests (run WITHOUT skill)
|
|
9
|
+
class TestBaselineBehavior:
|
|
10
|
+
"""Document how agents behave without skill."""
|
|
11
|
+
|
|
12
|
+
def test_time_pressure_rationalization(self):
|
|
13
|
+
"""Under time pressure, agents typically..."""
|
|
14
|
+
# Document expected failure
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
def test_sunk_cost_rationalization(self):
|
|
18
|
+
"""With sunk cost, agents typically..."""
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
# GREEN Phase: Verification tests (run WITH skill)
|
|
22
|
+
class TestSkillCompliance:
|
|
23
|
+
"""Verify agents comply WITH skill."""
|
|
24
|
+
|
|
25
|
+
def test_resists_time_pressure(self):
|
|
26
|
+
"""Skill helps agent resist time pressure."""
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
def test_resists_sunk_cost(self):
|
|
30
|
+
"""Skill helps agent resist sunk cost fallacy."""
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
# REFACTOR Phase: Combined pressure
|
|
34
|
+
class TestCombinedPressure:
|
|
35
|
+
"""All pressures at once."""
|
|
36
|
+
|
|
37
|
+
def test_combined_pressure_compliance(self):
|
|
38
|
+
"""Agent complies under maximum pressure."""
|
|
39
|
+
pass
|