@elizaos/skills 2.0.0-alpha.3
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/README.md +126 -0
- package/package.json +53 -0
- package/skills/1password/SKILL.md +70 -0
- package/skills/1password/references/cli-examples.md +29 -0
- package/skills/1password/references/get-started.md +17 -0
- package/skills/apple-notes/SKILL.md +77 -0
- package/skills/apple-reminders/SKILL.md +96 -0
- package/skills/bear-notes/SKILL.md +107 -0
- package/skills/bird/SKILL.md +224 -0
- package/skills/blogwatcher/SKILL.md +69 -0
- package/skills/blucli/SKILL.md +47 -0
- package/skills/bluebubbles/SKILL.md +131 -0
- package/skills/camsnap/SKILL.md +45 -0
- package/skills/canvas/SKILL.md +203 -0
- package/skills/clawhub/SKILL.md +77 -0
- package/skills/coding-agent/SKILL.md +284 -0
- package/skills/discord/SKILL.md +578 -0
- package/skills/eightctl/SKILL.md +50 -0
- package/skills/food-order/SKILL.md +48 -0
- package/skills/gemini/SKILL.md +43 -0
- package/skills/gifgrep/SKILL.md +79 -0
- package/skills/github/SKILL.md +77 -0
- package/skills/gog/SKILL.md +116 -0
- package/skills/goplaces/SKILL.md +52 -0
- package/skills/healthcheck/SKILL.md +245 -0
- package/skills/himalaya/SKILL.md +257 -0
- package/skills/himalaya/references/configuration.md +184 -0
- package/skills/himalaya/references/message-composition.md +199 -0
- package/skills/imsg/SKILL.md +74 -0
- package/skills/local-places/SERVER_README.md +101 -0
- package/skills/local-places/SKILL.md +102 -0
- package/skills/local-places/pyproject.toml +21 -0
- package/skills/local-places/src/local_places/__init__.py +2 -0
- package/skills/local-places/src/local_places/google_places.py +314 -0
- package/skills/local-places/src/local_places/main.py +65 -0
- package/skills/local-places/src/local_places/schemas.py +107 -0
- package/skills/mcporter/SKILL.md +61 -0
- package/skills/model-usage/SKILL.md +69 -0
- package/skills/model-usage/references/codexbar-cli.md +33 -0
- package/skills/model-usage/scripts/model_usage.py +310 -0
- package/skills/nano-banana-pro/SKILL.md +58 -0
- package/skills/nano-banana-pro/scripts/generate_image.py +184 -0
- package/skills/nano-pdf/SKILL.md +38 -0
- package/skills/notion/SKILL.md +172 -0
- package/skills/obsidian/SKILL.md +81 -0
- package/skills/openai-image-gen/SKILL.md +89 -0
- package/skills/openai-image-gen/scripts/gen.py +240 -0
- package/skills/openai-whisper/SKILL.md +38 -0
- package/skills/openai-whisper-api/SKILL.md +52 -0
- package/skills/openai-whisper-api/scripts/transcribe.sh +85 -0
- package/skills/openhue/SKILL.md +51 -0
- package/skills/oracle/SKILL.md +125 -0
- package/skills/ordercli/SKILL.md +78 -0
- package/skills/peekaboo/SKILL.md +190 -0
- package/skills/sag/SKILL.md +87 -0
- package/skills/security-ask-questions-if-underspecified/.claude-plugin/plugin.json +10 -0
- package/skills/security-ask-questions-if-underspecified/README.md +24 -0
- package/skills/security-ask-questions-if-underspecified/skills/ask-questions-if-underspecified/SKILL.md +85 -0
- package/skills/security-audit-context-building/.claude-plugin/plugin.json +10 -0
- package/skills/security-audit-context-building/README.md +58 -0
- package/skills/security-audit-context-building/commands/audit-context.md +21 -0
- package/skills/security-audit-context-building/skills/audit-context-building/SKILL.md +297 -0
- package/skills/security-audit-context-building/skills/audit-context-building/resources/COMPLETENESS_CHECKLIST.md +47 -0
- package/skills/security-audit-context-building/skills/audit-context-building/resources/FUNCTION_MICRO_ANALYSIS_EXAMPLE.md +355 -0
- package/skills/security-audit-context-building/skills/audit-context-building/resources/OUTPUT_REQUIREMENTS.md +71 -0
- package/skills/security-building-secure-contracts/.claude-plugin/plugin.json +10 -0
- package/skills/security-building-secure-contracts/README.md +241 -0
- package/skills/security-building-secure-contracts/skills/algorand-vulnerability-scanner/SKILL.md +284 -0
- package/skills/security-building-secure-contracts/skills/algorand-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +405 -0
- package/skills/security-building-secure-contracts/skills/audit-prep-assistant/SKILL.md +409 -0
- package/skills/security-building-secure-contracts/skills/cairo-vulnerability-scanner/SKILL.md +329 -0
- package/skills/security-building-secure-contracts/skills/cairo-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +722 -0
- package/skills/security-building-secure-contracts/skills/code-maturity-assessor/SKILL.md +218 -0
- package/skills/security-building-secure-contracts/skills/code-maturity-assessor/resources/ASSESSMENT_CRITERIA.md +355 -0
- package/skills/security-building-secure-contracts/skills/code-maturity-assessor/resources/EXAMPLE_REPORT.md +248 -0
- package/skills/security-building-secure-contracts/skills/code-maturity-assessor/resources/REPORT_FORMAT.md +33 -0
- package/skills/security-building-secure-contracts/skills/cosmos-vulnerability-scanner/SKILL.md +334 -0
- package/skills/security-building-secure-contracts/skills/cosmos-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +740 -0
- package/skills/security-building-secure-contracts/skills/guidelines-advisor/SKILL.md +252 -0
- package/skills/security-building-secure-contracts/skills/guidelines-advisor/resources/ASSESSMENT_AREAS.md +329 -0
- package/skills/security-building-secure-contracts/skills/guidelines-advisor/resources/DELIVERABLES.md +118 -0
- package/skills/security-building-secure-contracts/skills/guidelines-advisor/resources/EXAMPLE_REPORT.md +298 -0
- package/skills/security-building-secure-contracts/skills/secure-workflow-guide/SKILL.md +161 -0
- package/skills/security-building-secure-contracts/skills/secure-workflow-guide/resources/EXAMPLE_REPORT.md +279 -0
- package/skills/security-building-secure-contracts/skills/secure-workflow-guide/resources/WORKFLOW_STEPS.md +132 -0
- package/skills/security-building-secure-contracts/skills/solana-vulnerability-scanner/SKILL.md +389 -0
- package/skills/security-building-secure-contracts/skills/solana-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +669 -0
- package/skills/security-building-secure-contracts/skills/substrate-vulnerability-scanner/SKILL.md +298 -0
- package/skills/security-building-secure-contracts/skills/substrate-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +791 -0
- package/skills/security-building-secure-contracts/skills/token-integration-analyzer/SKILL.md +362 -0
- package/skills/security-building-secure-contracts/skills/token-integration-analyzer/resources/ASSESSMENT_CATEGORIES.md +571 -0
- package/skills/security-building-secure-contracts/skills/token-integration-analyzer/resources/REPORT_TEMPLATES.md +141 -0
- package/skills/security-building-secure-contracts/skills/ton-vulnerability-scanner/SKILL.md +388 -0
- package/skills/security-building-secure-contracts/skills/ton-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +595 -0
- package/skills/security-burpsuite-project-parser/.claude-plugin/plugin.json +10 -0
- package/skills/security-burpsuite-project-parser/README.md +103 -0
- package/skills/security-burpsuite-project-parser/commands/burp-search.md +18 -0
- package/skills/security-burpsuite-project-parser/skills/SKILL.md +358 -0
- package/skills/security-burpsuite-project-parser/skills/scripts/burp-search.sh +99 -0
- package/skills/security-claude-in-chrome-troubleshooting/.claude-plugin/plugin.json +8 -0
- package/skills/security-claude-in-chrome-troubleshooting/README.md +31 -0
- package/skills/security-claude-in-chrome-troubleshooting/skills/claude-in-chrome-troubleshooting/SKILL.md +251 -0
- package/skills/security-constant-time-analysis/.claude-plugin/plugin.json +9 -0
- package/skills/security-constant-time-analysis/README.md +381 -0
- package/skills/security-constant-time-analysis/commands/ct-check.md +20 -0
- package/skills/security-constant-time-analysis/ct_analyzer/__init__.py +49 -0
- package/skills/security-constant-time-analysis/ct_analyzer/analyzer.py +1284 -0
- package/skills/security-constant-time-analysis/ct_analyzer/script_analyzers.py +3081 -0
- package/skills/security-constant-time-analysis/ct_analyzer/tests/__init__.py +1 -0
- package/skills/security-constant-time-analysis/ct_analyzer/tests/test_analyzer.py +1397 -0
- package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/bn_excerpt.js +205 -0
- package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/decompose_constant_time.c +181 -0
- package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/decompose_vulnerable.c +74 -0
- package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/decompose_vulnerable.go +78 -0
- package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/decompose_vulnerable.rs +92 -0
- package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.cs +174 -0
- package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.java +161 -0
- package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.kt +181 -0
- package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.php +140 -0
- package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.py +252 -0
- package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.rb +188 -0
- package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.swift +199 -0
- package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.ts +154 -0
- package/skills/security-constant-time-analysis/pyproject.toml +52 -0
- package/skills/security-constant-time-analysis/skills/constant-time-analysis/README.md +90 -0
- package/skills/security-constant-time-analysis/skills/constant-time-analysis/SKILL.md +219 -0
- package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/compiled.md +129 -0
- package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/javascript.md +136 -0
- package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/kotlin.md +252 -0
- package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/php.md +172 -0
- package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/python.md +179 -0
- package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/ruby.md +198 -0
- package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/swift.md +288 -0
- package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/vm-compiled.md +354 -0
- package/skills/security-constant-time-analysis/uv.lock +8 -0
- package/skills/security-culture-index/.claude-plugin/plugin.json +8 -0
- package/skills/security-culture-index/README.md +79 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/SKILL.md +293 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/references/anti-patterns.md +255 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/references/conversation-starters.md +408 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/references/interview-trait-signals.md +253 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/references/motivators.md +158 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/references/patterns-archetypes.md +147 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/references/primary-traits.md +307 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/references/secondary-traits.md +228 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/references/team-composition.md +148 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/scripts/check_deps.py +108 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/__init__.py +20 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/constants.py +122 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/extract.py +187 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/models.py +16 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/opencv_extractor.py +520 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/scripts/extract_pdf.py +237 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/scripts/pyproject.toml +18 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/templates/burnout-report.md +113 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/templates/comparison-report.md +103 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/templates/hiring-profile.md +127 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/templates/individual-report.md +85 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/templates/predicted-profile.md +165 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/templates/team-report.md +109 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/workflows/analyze-team.md +188 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/workflows/coach-manager.md +267 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/workflows/compare-profiles.md +188 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/workflows/define-hiring-profile.md +220 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/workflows/detect-burnout.md +206 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/workflows/extract-from-pdf.md +121 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/workflows/interpret-individual.md +183 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/workflows/interview-debrief.md +234 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/workflows/mediate-conflict.md +306 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/workflows/plan-onboarding.md +322 -0
- package/skills/security-culture-index/skills/interpreting-culture-index/workflows/predict-from-interview.md +250 -0
- package/skills/security-differential-review/.claude-plugin/plugin.json +10 -0
- package/skills/security-differential-review/README.md +109 -0
- package/skills/security-differential-review/commands/diff-review.md +21 -0
- package/skills/security-differential-review/skills/differential-review/SKILL.md +220 -0
- package/skills/security-differential-review/skills/differential-review/adversarial.md +203 -0
- package/skills/security-differential-review/skills/differential-review/methodology.md +234 -0
- package/skills/security-differential-review/skills/differential-review/patterns.md +300 -0
- package/skills/security-differential-review/skills/differential-review/reporting.md +369 -0
- package/skills/security-dwarf-expert/.claude-plugin/plugin.json +10 -0
- package/skills/security-dwarf-expert/README.md +38 -0
- package/skills/security-dwarf-expert/skills/dwarf-expert/SKILL.md +93 -0
- package/skills/security-dwarf-expert/skills/dwarf-expert/reference/coding.md +31 -0
- package/skills/security-dwarf-expert/skills/dwarf-expert/reference/dwarfdump.md +50 -0
- package/skills/security-dwarf-expert/skills/dwarf-expert/reference/readelf.md +8 -0
- package/skills/security-entry-point-analyzer/.claude-plugin/plugin.json +10 -0
- package/skills/security-entry-point-analyzer/README.md +74 -0
- package/skills/security-entry-point-analyzer/commands/entry-points.md +18 -0
- package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/SKILL.md +251 -0
- package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/cosmwasm.md +182 -0
- package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/move-aptos.md +107 -0
- package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/move-sui.md +87 -0
- package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/solana.md +155 -0
- package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/solidity.md +135 -0
- package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/ton.md +185 -0
- package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/vyper.md +141 -0
- package/skills/security-firebase-apk-scanner/.claude-plugin/plugin.json +10 -0
- package/skills/security-firebase-apk-scanner/README.md +85 -0
- package/skills/security-firebase-apk-scanner/commands/scan-apk.md +18 -0
- package/skills/security-firebase-apk-scanner/scanner.sh +1408 -0
- package/skills/security-firebase-apk-scanner/skills/firebase-apk-scanner/SKILL.md +197 -0
- package/skills/security-firebase-apk-scanner/skills/firebase-apk-scanner/references/vulnerabilities.md +803 -0
- package/skills/security-fix-review/.claude-plugin/plugin.json +13 -0
- package/skills/security-fix-review/README.md +118 -0
- package/skills/security-fix-review/commands/fix-review.md +24 -0
- package/skills/security-fix-review/skills/fix-review/SKILL.md +264 -0
- package/skills/security-fix-review/skills/fix-review/references/bug-detection.md +408 -0
- package/skills/security-fix-review/skills/fix-review/references/finding-matching.md +298 -0
- package/skills/security-fix-review/skills/fix-review/references/report-parsing.md +398 -0
- package/skills/security-insecure-defaults/.claude-plugin/plugin.json +10 -0
- package/skills/security-insecure-defaults/README.md +45 -0
- package/skills/security-insecure-defaults/skills/insecure-defaults/SKILL.md +117 -0
- package/skills/security-insecure-defaults/skills/insecure-defaults/references/examples.md +409 -0
- package/skills/security-modern-python/.claude-plugin/plugin.json +10 -0
- package/skills/security-modern-python/README.md +58 -0
- package/skills/security-modern-python/hooks/hooks.json +16 -0
- package/skills/security-modern-python/hooks/intercept-legacy-python.bats +388 -0
- package/skills/security-modern-python/hooks/intercept-legacy-python.sh +109 -0
- package/skills/security-modern-python/hooks/test_helper.bash +75 -0
- package/skills/security-modern-python/skills/modern-python/SKILL.md +333 -0
- package/skills/security-modern-python/skills/modern-python/references/dependabot.md +43 -0
- package/skills/security-modern-python/skills/modern-python/references/migration-checklist.md +141 -0
- package/skills/security-modern-python/skills/modern-python/references/pep723-scripts.md +259 -0
- package/skills/security-modern-python/skills/modern-python/references/prek.md +211 -0
- package/skills/security-modern-python/skills/modern-python/references/pyproject.md +254 -0
- package/skills/security-modern-python/skills/modern-python/references/ruff-config.md +240 -0
- package/skills/security-modern-python/skills/modern-python/references/security-setup.md +255 -0
- package/skills/security-modern-python/skills/modern-python/references/testing.md +284 -0
- package/skills/security-modern-python/skills/modern-python/references/uv-commands.md +200 -0
- package/skills/security-modern-python/skills/modern-python/templates/dependabot.yml +36 -0
- package/skills/security-modern-python/skills/modern-python/templates/pre-commit-config.yaml +66 -0
- package/skills/security-property-based-testing/.claude-plugin/plugin.json +9 -0
- package/skills/security-property-based-testing/README.md +47 -0
- package/skills/security-property-based-testing/skills/property-based-testing/README.md +88 -0
- package/skills/security-property-based-testing/skills/property-based-testing/SKILL.md +109 -0
- package/skills/security-property-based-testing/skills/property-based-testing/references/design.md +191 -0
- package/skills/security-property-based-testing/skills/property-based-testing/references/generating.md +200 -0
- package/skills/security-property-based-testing/skills/property-based-testing/references/libraries.md +130 -0
- package/skills/security-property-based-testing/skills/property-based-testing/references/refactoring.md +181 -0
- package/skills/security-property-based-testing/skills/property-based-testing/references/reviewing.md +209 -0
- package/skills/security-property-based-testing/skills/property-based-testing/references/strategies.md +124 -0
- package/skills/semgrep-rule-creator/.claude-plugin/plugin.json +8 -0
- package/skills/semgrep-rule-creator/README.md +43 -0
- package/skills/semgrep-rule-creator/commands/semgrep-rule.md +26 -0
- package/skills/semgrep-rule-creator/skills/semgrep-rule-creator/SKILL.md +168 -0
- package/skills/semgrep-rule-creator/skills/semgrep-rule-creator/references/quick-reference.md +203 -0
- package/skills/semgrep-rule-creator/skills/semgrep-rule-creator/references/workflow.md +240 -0
- package/skills/semgrep-rule-variant-creator/.claude-plugin/plugin.json +9 -0
- package/skills/semgrep-rule-variant-creator/README.md +86 -0
- package/skills/semgrep-rule-variant-creator/skills/semgrep-rule-variant-creator/SKILL.md +205 -0
- package/skills/semgrep-rule-variant-creator/skills/semgrep-rule-variant-creator/references/applicability-analysis.md +250 -0
- package/skills/semgrep-rule-variant-creator/skills/semgrep-rule-variant-creator/references/language-syntax-guide.md +324 -0
- package/skills/semgrep-rule-variant-creator/skills/semgrep-rule-variant-creator/references/workflow.md +518 -0
- package/skills/session-logs/SKILL.md +115 -0
- package/skills/sharp-edges/.claude-plugin/plugin.json +10 -0
- package/skills/sharp-edges/README.md +48 -0
- package/skills/sharp-edges/skills/sharp-edges/SKILL.md +292 -0
- package/skills/sharp-edges/skills/sharp-edges/references/auth-patterns.md +252 -0
- package/skills/sharp-edges/skills/sharp-edges/references/case-studies.md +274 -0
- package/skills/sharp-edges/skills/sharp-edges/references/config-patterns.md +333 -0
- package/skills/sharp-edges/skills/sharp-edges/references/crypto-apis.md +190 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-c.md +205 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-csharp.md +285 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-go.md +270 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-java.md +263 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-javascript.md +269 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-kotlin.md +265 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-php.md +245 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-python.md +274 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-ruby.md +273 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-rust.md +272 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-swift.md +287 -0
- package/skills/sharp-edges/skills/sharp-edges/references/language-specific.md +588 -0
- package/skills/sherpa-onnx-tts/SKILL.md +103 -0
- package/skills/sherpa-onnx-tts/bin/sherpa-onnx-tts +178 -0
- package/skills/skill-creator/SKILL.md +370 -0
- package/skills/skill-creator/license.txt +202 -0
- package/skills/skill-creator/scripts/init_skill.py +378 -0
- package/skills/skill-creator/scripts/package_skill.py +111 -0
- package/skills/skill-creator/scripts/quick_validate.py +101 -0
- package/skills/slack/SKILL.md +144 -0
- package/skills/songsee/SKILL.md +49 -0
- package/skills/sonoscli/SKILL.md +46 -0
- package/skills/spec-to-code-compliance/.claude-plugin/plugin.json +10 -0
- package/skills/spec-to-code-compliance/README.md +67 -0
- package/skills/spec-to-code-compliance/commands/spec-compliance.md +22 -0
- package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/SKILL.md +349 -0
- package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/resources/COMPLETENESS_CHECKLIST.md +69 -0
- package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/resources/IR_EXAMPLES.md +417 -0
- package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/resources/OUTPUT_REQUIREMENTS.md +105 -0
- package/skills/spotify-player/SKILL.md +64 -0
- package/skills/static-analysis/.claude-plugin/plugin.json +8 -0
- package/skills/static-analysis/README.md +59 -0
- package/skills/static-analysis/skills/codeql/SKILL.md +315 -0
- package/skills/static-analysis/skills/sarif-parsing/SKILL.md +479 -0
- package/skills/static-analysis/skills/sarif-parsing/resources/jq-queries.md +162 -0
- package/skills/static-analysis/skills/sarif-parsing/resources/sarif_helpers.py +331 -0
- package/skills/static-analysis/skills/semgrep/SKILL.md +337 -0
- package/skills/summarize/SKILL.md +87 -0
- package/skills/testing-handbook-skills/.claude-plugin/plugin.json +8 -0
- package/skills/testing-handbook-skills/README.md +241 -0
- package/skills/testing-handbook-skills/scripts/pyproject.toml +8 -0
- package/skills/testing-handbook-skills/scripts/validate-skills.py +657 -0
- package/skills/testing-handbook-skills/skills/address-sanitizer/SKILL.md +341 -0
- package/skills/testing-handbook-skills/skills/aflpp/SKILL.md +640 -0
- package/skills/testing-handbook-skills/skills/atheris/SKILL.md +515 -0
- package/skills/testing-handbook-skills/skills/cargo-fuzz/SKILL.md +454 -0
- package/skills/testing-handbook-skills/skills/codeql/SKILL.md +549 -0
- package/skills/testing-handbook-skills/skills/constant-time-testing/SKILL.md +507 -0
- package/skills/testing-handbook-skills/skills/coverage-analysis/SKILL.md +607 -0
- package/skills/testing-handbook-skills/skills/fuzzing-dictionary/SKILL.md +297 -0
- package/skills/testing-handbook-skills/skills/fuzzing-obstacles/SKILL.md +426 -0
- package/skills/testing-handbook-skills/skills/harness-writing/SKILL.md +614 -0
- package/skills/testing-handbook-skills/skills/libafl/SKILL.md +625 -0
- package/skills/testing-handbook-skills/skills/libfuzzer/SKILL.md +795 -0
- package/skills/testing-handbook-skills/skills/ossfuzz/SKILL.md +426 -0
- package/skills/testing-handbook-skills/skills/ruzzy/SKILL.md +443 -0
- package/skills/testing-handbook-skills/skills/semgrep/SKILL.md +601 -0
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/SKILL.md +372 -0
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/agent-prompt.md +280 -0
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/discovery.md +452 -0
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/domain-skill.md +504 -0
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/fuzzer-skill.md +454 -0
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/technique-skill.md +527 -0
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/tool-skill.md +366 -0
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/testing.md +482 -0
- package/skills/testing-handbook-skills/skills/wycheproof/SKILL.md +533 -0
- package/skills/things-mac/SKILL.md +86 -0
- package/skills/tmux/SKILL.md +135 -0
- package/skills/tmux/scripts/find-sessions.sh +112 -0
- package/skills/tmux/scripts/wait-for-text.sh +83 -0
- package/skills/trello/SKILL.md +95 -0
- package/skills/variant-analysis/.claude-plugin/plugin.json +8 -0
- package/skills/variant-analysis/README.md +41 -0
- package/skills/variant-analysis/commands/variants.md +23 -0
- package/skills/variant-analysis/skills/variant-analysis/METHODOLOGY.md +327 -0
- package/skills/variant-analysis/skills/variant-analysis/SKILL.md +142 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/codeql/cpp.ql +119 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/codeql/go.ql +69 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/codeql/java.ql +71 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/codeql/javascript.ql +63 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/codeql/python.ql +80 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/cpp.yaml +98 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/go.yaml +63 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/java.yaml +61 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/javascript.yaml +60 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/python.yaml +72 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/variant-report-template.md +75 -0
- package/skills/video-frames/SKILL.md +46 -0
- package/skills/video-frames/scripts/frame.sh +81 -0
- package/skills/voice-call/SKILL.md +45 -0
- package/skills/wacli/SKILL.md +72 -0
- package/skills/weather/SKILL.md +54 -0
- package/skills/yara-authoring/.claude-plugin/plugin.json +9 -0
- package/skills/yara-authoring/README.md +131 -0
- package/skills/yara-authoring/skills/yara-rule-authoring/SKILL.md +645 -0
- package/skills/yara-authoring/skills/yara-rule-authoring/examples/MAL_Mac_ProtonRAT_Jan25.yar +99 -0
- package/skills/yara-authoring/skills/yara-rule-authoring/examples/MAL_NPM_SupplyChain_Jan25.yar +170 -0
- package/skills/yara-authoring/skills/yara-rule-authoring/examples/MAL_Win_Remcos_Jan25.yar +103 -0
- package/skills/yara-authoring/skills/yara-rule-authoring/examples/SUSP_CRX_SuspiciousPermissions.yar +134 -0
- package/skills/yara-authoring/skills/yara-rule-authoring/examples/SUSP_JS_Obfuscation_Jan25.yar +185 -0
- package/skills/yara-authoring/skills/yara-rule-authoring/references/crx-module.md +214 -0
- package/skills/yara-authoring/skills/yara-rule-authoring/references/dex-module.md +383 -0
- package/skills/yara-authoring/skills/yara-rule-authoring/references/performance.md +333 -0
- package/skills/yara-authoring/skills/yara-rule-authoring/references/strings.md +433 -0
- package/skills/yara-authoring/skills/yara-rule-authoring/references/style-guide.md +257 -0
- package/skills/yara-authoring/skills/yara-rule-authoring/references/testing.md +399 -0
- package/skills/yara-authoring/skills/yara-rule-authoring/scripts/atom_analyzer.py +526 -0
- package/skills/yara-authoring/skills/yara-rule-authoring/scripts/pyproject.toml +25 -0
- package/skills/yara-authoring/skills/yara-rule-authoring/scripts/yara_lint.py +631 -0
- package/skills/yara-authoring/skills/yara-rule-authoring/workflows/rule-development.md +493 -0
|
@@ -0,0 +1,657 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# /// script
|
|
3
|
+
# requires-python = ">=3.11"
|
|
4
|
+
# dependencies = ["pyyaml>=6.0"]
|
|
5
|
+
# ///
|
|
6
|
+
"""Validate generated skills for the testing-handbook-generator.
|
|
7
|
+
|
|
8
|
+
Performs comprehensive validation including:
|
|
9
|
+
- YAML frontmatter parsing and field validation
|
|
10
|
+
- Required sections presence by skill type
|
|
11
|
+
- Line count limits
|
|
12
|
+
- Hugo shortcode detection
|
|
13
|
+
- Escaped backtick detection (from template artifacts)
|
|
14
|
+
- Cross-reference validation (related skills exist)
|
|
15
|
+
- Internal link resolution
|
|
16
|
+
|
|
17
|
+
Usage:
|
|
18
|
+
# Validate all skills
|
|
19
|
+
uv run scripts/validate-skills.py
|
|
20
|
+
|
|
21
|
+
# Validate specific skill
|
|
22
|
+
uv run scripts/validate-skills.py --skill libfuzzer
|
|
23
|
+
|
|
24
|
+
# Output JSON for CI
|
|
25
|
+
uv run scripts/validate-skills.py --json
|
|
26
|
+
|
|
27
|
+
# Verbose output
|
|
28
|
+
uv run scripts/validate-skills.py -v
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
|
|
33
|
+
import argparse
|
|
34
|
+
import json
|
|
35
|
+
import re
|
|
36
|
+
import sys
|
|
37
|
+
from dataclasses import dataclass, field
|
|
38
|
+
from pathlib import Path
|
|
39
|
+
from typing import Literal
|
|
40
|
+
|
|
41
|
+
import yaml
|
|
42
|
+
|
|
43
|
+
# Configuration
|
|
44
|
+
MAX_LINES = 500
|
|
45
|
+
MAX_NAME_LENGTH = 64
|
|
46
|
+
MAX_DESCRIPTION_LENGTH = 1024
|
|
47
|
+
RESERVED_WORDS = frozenset({"anthropic", "claude"})
|
|
48
|
+
VALID_SKILL_TYPES = frozenset({"tool", "fuzzer", "technique", "domain"})
|
|
49
|
+
NAME_PATTERN = re.compile(r"^[a-z0-9-]{1,64}$")
|
|
50
|
+
SHORTCODE_PATTERN = re.compile(r"\{\{[<%]")
|
|
51
|
+
ESCAPED_BACKTICKS_PATTERN = re.compile(r"\\`{3}")
|
|
52
|
+
HTML_TAG_PATTERN = re.compile(r"<[^>]+>")
|
|
53
|
+
|
|
54
|
+
# Required sections by skill type
|
|
55
|
+
REQUIRED_SECTIONS: dict[str, list[str]] = {
|
|
56
|
+
"tool": ["When to Use", "Quick Reference", "Installation", "Core Workflow"],
|
|
57
|
+
"fuzzer": ["When to Use", "Quick Start", "Writing a Harness", "Related Skills"],
|
|
58
|
+
"technique": ["When to Apply", "Quick Reference", "Tool-Specific Guidance", "Related Skills"],
|
|
59
|
+
"domain": ["Background", "Quick Reference", "Testing Workflow", "Related Skills"],
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# Skill type detection patterns (from directory structure or content)
|
|
63
|
+
SKILL_TYPE_INDICATORS = {
|
|
64
|
+
"fuzzer": ["fuzzing", "harness", "corpus", "sanitizer"],
|
|
65
|
+
"technique": ["technique", "pattern", "apply", "tool-specific"],
|
|
66
|
+
"domain": ["methodology", "workflow", "background", "domain"],
|
|
67
|
+
"tool": [], # Default fallback
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass
|
|
72
|
+
class ValidationResult:
|
|
73
|
+
"""Result of validating a single skill."""
|
|
74
|
+
|
|
75
|
+
skill_name: str
|
|
76
|
+
skill_path: Path
|
|
77
|
+
valid: bool = True
|
|
78
|
+
errors: list[str] = field(default_factory=list)
|
|
79
|
+
warnings: list[str] = field(default_factory=list)
|
|
80
|
+
info: dict[str, str | int | list[str]] = field(default_factory=dict)
|
|
81
|
+
|
|
82
|
+
def add_error(self, message: str) -> None:
|
|
83
|
+
"""Add an error and mark as invalid."""
|
|
84
|
+
self.errors.append(message)
|
|
85
|
+
self.valid = False
|
|
86
|
+
|
|
87
|
+
def add_warning(self, message: str) -> None:
|
|
88
|
+
"""Add a warning (doesn't affect validity)."""
|
|
89
|
+
self.warnings.append(message)
|
|
90
|
+
|
|
91
|
+
def to_dict(self) -> dict:
|
|
92
|
+
"""Convert to dictionary for JSON output."""
|
|
93
|
+
return {
|
|
94
|
+
"skill_name": self.skill_name,
|
|
95
|
+
"skill_path": str(self.skill_path),
|
|
96
|
+
"valid": self.valid,
|
|
97
|
+
"errors": self.errors,
|
|
98
|
+
"warnings": self.warnings,
|
|
99
|
+
"info": self.info,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@dataclass
|
|
104
|
+
class ValidationReport:
|
|
105
|
+
"""Aggregate report for all validated skills."""
|
|
106
|
+
|
|
107
|
+
results: list[ValidationResult] = field(default_factory=list)
|
|
108
|
+
total: int = 0
|
|
109
|
+
passed: int = 0
|
|
110
|
+
failed: int = 0
|
|
111
|
+
with_warnings: int = 0
|
|
112
|
+
|
|
113
|
+
def add_result(self, result: ValidationResult) -> None:
|
|
114
|
+
"""Add a validation result and update counts."""
|
|
115
|
+
self.results.append(result)
|
|
116
|
+
self.total += 1
|
|
117
|
+
if result.valid:
|
|
118
|
+
self.passed += 1
|
|
119
|
+
else:
|
|
120
|
+
self.failed += 1
|
|
121
|
+
if result.warnings:
|
|
122
|
+
self.with_warnings += 1
|
|
123
|
+
|
|
124
|
+
def to_dict(self) -> dict:
|
|
125
|
+
"""Convert to dictionary for JSON output."""
|
|
126
|
+
return {
|
|
127
|
+
"summary": {
|
|
128
|
+
"total": self.total,
|
|
129
|
+
"passed": self.passed,
|
|
130
|
+
"failed": self.failed,
|
|
131
|
+
"with_warnings": self.with_warnings,
|
|
132
|
+
},
|
|
133
|
+
"results": [r.to_dict() for r in self.results],
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def extract_frontmatter(content: str) -> tuple[dict | None, str | None]:
|
|
138
|
+
"""Extract YAML frontmatter from markdown content.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
content: Full markdown file content.
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
Tuple of (parsed YAML dict, error message if parsing failed).
|
|
145
|
+
"""
|
|
146
|
+
lines = content.split("\n")
|
|
147
|
+
if not lines or lines[0].strip() != "---":
|
|
148
|
+
return None, "No frontmatter found (file must start with ---)"
|
|
149
|
+
|
|
150
|
+
end_idx = None
|
|
151
|
+
for i, line in enumerate(lines[1:], start=1):
|
|
152
|
+
if line.strip() == "---":
|
|
153
|
+
end_idx = i
|
|
154
|
+
break
|
|
155
|
+
|
|
156
|
+
if end_idx is None:
|
|
157
|
+
return None, "Frontmatter not closed (missing closing ---)"
|
|
158
|
+
|
|
159
|
+
frontmatter_text = "\n".join(lines[1:end_idx])
|
|
160
|
+
try:
|
|
161
|
+
return yaml.safe_load(frontmatter_text), None
|
|
162
|
+
except yaml.YAMLError as e:
|
|
163
|
+
return None, f"YAML parse error: {e}"
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def detect_skill_type(
|
|
167
|
+
content: str,
|
|
168
|
+
frontmatter: dict | None,
|
|
169
|
+
) -> Literal["tool", "fuzzer", "technique", "domain"]:
|
|
170
|
+
"""Detect skill type from content and frontmatter.
|
|
171
|
+
|
|
172
|
+
Prefers explicit `type` field in frontmatter. Falls back to heuristics
|
|
173
|
+
if not specified.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
content: Full markdown content.
|
|
177
|
+
frontmatter: Parsed frontmatter dict.
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
Detected skill type.
|
|
181
|
+
"""
|
|
182
|
+
# Prefer explicit type field in frontmatter (authoritative)
|
|
183
|
+
if frontmatter:
|
|
184
|
+
explicit_type = frontmatter.get("type")
|
|
185
|
+
if explicit_type and str(explicit_type).lower() in VALID_SKILL_TYPES:
|
|
186
|
+
return str(explicit_type).lower() # type: ignore[return-value]
|
|
187
|
+
|
|
188
|
+
# Fallback: infer from description keywords
|
|
189
|
+
if frontmatter:
|
|
190
|
+
desc = str(frontmatter.get("description", "")).lower()
|
|
191
|
+
if "fuzzing" in desc or "fuzzer" in desc:
|
|
192
|
+
return "fuzzer"
|
|
193
|
+
if "technique" in desc or "pattern" in desc:
|
|
194
|
+
return "technique"
|
|
195
|
+
if "methodology" in desc or "domain" in desc:
|
|
196
|
+
return "domain"
|
|
197
|
+
|
|
198
|
+
# Fallback: infer from section headers
|
|
199
|
+
content_lower = content.lower()
|
|
200
|
+
if "## writing a harness" in content_lower or "## quick start" in content_lower:
|
|
201
|
+
return "fuzzer"
|
|
202
|
+
if "## tool-specific guidance" in content_lower or "## when to apply" in content_lower:
|
|
203
|
+
return "technique"
|
|
204
|
+
if "## background" in content_lower and "## testing workflow" in content_lower:
|
|
205
|
+
return "domain"
|
|
206
|
+
|
|
207
|
+
# Default to tool
|
|
208
|
+
return "tool"
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def validate_frontmatter(
|
|
212
|
+
frontmatter: dict | None,
|
|
213
|
+
result: ValidationResult,
|
|
214
|
+
) -> None:
|
|
215
|
+
"""Validate frontmatter fields.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
frontmatter: Parsed frontmatter dict.
|
|
219
|
+
result: ValidationResult to update.
|
|
220
|
+
"""
|
|
221
|
+
if frontmatter is None:
|
|
222
|
+
return # Error already added during extraction
|
|
223
|
+
|
|
224
|
+
# Validate name field
|
|
225
|
+
name = frontmatter.get("name")
|
|
226
|
+
if not name:
|
|
227
|
+
result.add_error("Missing required field: name")
|
|
228
|
+
else:
|
|
229
|
+
name_str = str(name)
|
|
230
|
+
result.info["name"] = name_str
|
|
231
|
+
|
|
232
|
+
if not NAME_PATTERN.match(name_str):
|
|
233
|
+
result.add_error(
|
|
234
|
+
f"Invalid name '{name_str}': must be lowercase alphanumeric with hyphens, "
|
|
235
|
+
f"max {MAX_NAME_LENGTH} chars"
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
if any(word in name_str.lower() for word in RESERVED_WORDS):
|
|
239
|
+
result.add_error(f"Name contains reserved word: {name_str}")
|
|
240
|
+
|
|
241
|
+
if HTML_TAG_PATTERN.search(name_str):
|
|
242
|
+
result.add_error(f"Name contains HTML/XML tags: {name_str}")
|
|
243
|
+
|
|
244
|
+
# Validate description field
|
|
245
|
+
description = frontmatter.get("description")
|
|
246
|
+
if not description:
|
|
247
|
+
result.add_error("Missing required field: description")
|
|
248
|
+
else:
|
|
249
|
+
desc_str = str(description).strip()
|
|
250
|
+
result.info["description_length"] = len(desc_str)
|
|
251
|
+
|
|
252
|
+
if len(desc_str) > MAX_DESCRIPTION_LENGTH:
|
|
253
|
+
result.add_error(
|
|
254
|
+
f"Description too long: {len(desc_str)} chars (max {MAX_DESCRIPTION_LENGTH})"
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
if not re.search(r"Use (when|for)", desc_str, re.IGNORECASE):
|
|
258
|
+
result.add_error("Description must include trigger phrase ('Use when' or 'Use for')")
|
|
259
|
+
|
|
260
|
+
if HTML_TAG_PATTERN.search(desc_str):
|
|
261
|
+
result.add_error("Description contains HTML/XML tags")
|
|
262
|
+
|
|
263
|
+
if SHORTCODE_PATTERN.search(desc_str):
|
|
264
|
+
result.add_error("Description contains Hugo shortcodes")
|
|
265
|
+
|
|
266
|
+
# Validate type field (recommended but not strictly required for backwards compat)
|
|
267
|
+
skill_type = frontmatter.get("type")
|
|
268
|
+
if not skill_type:
|
|
269
|
+
result.add_warning("Missing recommended field: type (tool|fuzzer|technique|domain)")
|
|
270
|
+
else:
|
|
271
|
+
type_str = str(skill_type).lower()
|
|
272
|
+
result.info["explicit_type"] = type_str
|
|
273
|
+
if type_str not in VALID_SKILL_TYPES:
|
|
274
|
+
result.add_error(
|
|
275
|
+
f"Invalid type '{skill_type}': must be one of {sorted(VALID_SKILL_TYPES)}"
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def validate_sections(
|
|
280
|
+
content: str,
|
|
281
|
+
skill_type: str,
|
|
282
|
+
result: ValidationResult,
|
|
283
|
+
) -> None:
|
|
284
|
+
"""Validate required sections are present.
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
content: Full markdown content.
|
|
288
|
+
skill_type: Detected skill type.
|
|
289
|
+
result: ValidationResult to update.
|
|
290
|
+
"""
|
|
291
|
+
required = REQUIRED_SECTIONS.get(skill_type, REQUIRED_SECTIONS["tool"])
|
|
292
|
+
result.info["skill_type"] = skill_type
|
|
293
|
+
result.info["required_sections"] = required
|
|
294
|
+
|
|
295
|
+
# Find all H2 sections
|
|
296
|
+
sections_found = re.findall(r"^## (.+)$", content, re.MULTILINE)
|
|
297
|
+
result.info["sections_found"] = sections_found
|
|
298
|
+
|
|
299
|
+
missing = []
|
|
300
|
+
for section in required:
|
|
301
|
+
# Check for exact match or case-insensitive match
|
|
302
|
+
found = any(
|
|
303
|
+
s.lower() == section.lower() or section.lower() in s.lower() for s in sections_found
|
|
304
|
+
)
|
|
305
|
+
if not found:
|
|
306
|
+
missing.append(section)
|
|
307
|
+
|
|
308
|
+
if missing:
|
|
309
|
+
result.add_error(f"Missing required sections for {skill_type} skill: {missing}")
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def validate_line_count(content: str, result: ValidationResult) -> None:
|
|
313
|
+
"""Validate line count is under limit.
|
|
314
|
+
|
|
315
|
+
Args:
|
|
316
|
+
content: Full markdown content.
|
|
317
|
+
result: ValidationResult to update.
|
|
318
|
+
"""
|
|
319
|
+
line_count = content.count("\n") + 1
|
|
320
|
+
result.info["line_count"] = line_count
|
|
321
|
+
|
|
322
|
+
if line_count >= MAX_LINES:
|
|
323
|
+
result.add_error(f"Line count {line_count} exceeds limit of {MAX_LINES}")
|
|
324
|
+
elif line_count >= MAX_LINES * 0.9: # 90% threshold
|
|
325
|
+
result.add_warning(f"Line count {line_count} approaching limit of {MAX_LINES}")
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def validate_shortcodes(content: str, result: ValidationResult) -> None:
|
|
329
|
+
"""Check for remaining Hugo shortcodes.
|
|
330
|
+
|
|
331
|
+
Args:
|
|
332
|
+
content: Full markdown content.
|
|
333
|
+
result: ValidationResult to update.
|
|
334
|
+
"""
|
|
335
|
+
matches = SHORTCODE_PATTERN.findall(content)
|
|
336
|
+
if matches:
|
|
337
|
+
result.add_error(f"Found {len(matches)} Hugo shortcodes that should be stripped")
|
|
338
|
+
|
|
339
|
+
# Find specific shortcodes for better error messages
|
|
340
|
+
specific_patterns = [
|
|
341
|
+
(r"\{\{<\s*hint", "hint"),
|
|
342
|
+
(r"\{\{<\s*tabs", "tabs"),
|
|
343
|
+
(r"\{\{<\s*tab\s", "tab"),
|
|
344
|
+
(r"\{\{%\s*relref", "relref"),
|
|
345
|
+
(r"\{\{<\s*customFigure", "customFigure"),
|
|
346
|
+
]
|
|
347
|
+
found_types = []
|
|
348
|
+
for pattern, name in specific_patterns:
|
|
349
|
+
if re.search(pattern, content):
|
|
350
|
+
found_types.append(name)
|
|
351
|
+
if found_types:
|
|
352
|
+
result.info["shortcode_types"] = found_types
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
def validate_escaped_backticks(content: str, result: ValidationResult) -> None:
|
|
356
|
+
"""Check for escaped backticks from templates.
|
|
357
|
+
|
|
358
|
+
Templates use \\``` to show code blocks in examples. These should be
|
|
359
|
+
unescaped to ``` in generated skills.
|
|
360
|
+
|
|
361
|
+
Args:
|
|
362
|
+
content: Full markdown content.
|
|
363
|
+
result: ValidationResult to update.
|
|
364
|
+
"""
|
|
365
|
+
matches = ESCAPED_BACKTICKS_PATTERN.findall(content)
|
|
366
|
+
if matches:
|
|
367
|
+
result.add_error(f"Found {len(matches)} escaped backticks (\\```) that should be unescaped")
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def validate_internal_links(
|
|
371
|
+
content: str,
|
|
372
|
+
skill_path: Path,
|
|
373
|
+
result: ValidationResult,
|
|
374
|
+
) -> None:
|
|
375
|
+
"""Validate internal markdown links resolve.
|
|
376
|
+
|
|
377
|
+
Args:
|
|
378
|
+
content: Full markdown content.
|
|
379
|
+
skill_path: Path to the skill file.
|
|
380
|
+
result: ValidationResult to update.
|
|
381
|
+
"""
|
|
382
|
+
skill_dir = skill_path.parent
|
|
383
|
+
|
|
384
|
+
# Find all markdown links [text](path)
|
|
385
|
+
link_pattern = re.compile(r"\[([^\]]+)\]\(([^)]+)\)")
|
|
386
|
+
broken_links = []
|
|
387
|
+
|
|
388
|
+
for match in link_pattern.finditer(content):
|
|
389
|
+
link_text, link_path = match.groups()
|
|
390
|
+
|
|
391
|
+
# Skip external URLs
|
|
392
|
+
if link_path.startswith(("http://", "https://", "mailto:")):
|
|
393
|
+
continue
|
|
394
|
+
|
|
395
|
+
# Skip anchor-only links
|
|
396
|
+
if link_path.startswith("#"):
|
|
397
|
+
continue
|
|
398
|
+
|
|
399
|
+
# Handle relative paths
|
|
400
|
+
target = skill_dir / link_path.split("#")[0] # Remove anchor
|
|
401
|
+
if not target.exists():
|
|
402
|
+
broken_links.append(link_path)
|
|
403
|
+
|
|
404
|
+
if broken_links:
|
|
405
|
+
result.add_warning(f"Broken internal links: {broken_links}")
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def validate_related_skills(
|
|
409
|
+
content: str,
|
|
410
|
+
skills_dir: Path,
|
|
411
|
+
result: ValidationResult,
|
|
412
|
+
) -> None:
|
|
413
|
+
"""Validate referenced skills exist.
|
|
414
|
+
|
|
415
|
+
Args:
|
|
416
|
+
content: Full markdown content.
|
|
417
|
+
skills_dir: Path to skills directory.
|
|
418
|
+
result: ValidationResult to update.
|
|
419
|
+
"""
|
|
420
|
+
# Find skill references in bold (e.g., **libfuzzer**)
|
|
421
|
+
skill_refs = re.findall(r"\*\*([a-z0-9-]+)\*\*", content)
|
|
422
|
+
skill_refs = list(set(skill_refs)) # Dedupe
|
|
423
|
+
|
|
424
|
+
if not skill_refs:
|
|
425
|
+
return
|
|
426
|
+
|
|
427
|
+
result.info["referenced_skills"] = skill_refs
|
|
428
|
+
|
|
429
|
+
# Check which exist (excluding the generator itself)
|
|
430
|
+
existing_skills = {
|
|
431
|
+
d.name
|
|
432
|
+
for d in skills_dir.iterdir()
|
|
433
|
+
if d.is_dir() and d.name != "testing-handbook-generator"
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
missing_refs = [ref for ref in skill_refs if ref not in existing_skills]
|
|
437
|
+
|
|
438
|
+
if missing_refs:
|
|
439
|
+
# This is a warning, not error - skills may be planned for future generation
|
|
440
|
+
result.add_warning(f"Referenced skills not found (may be planned): {missing_refs}")
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def validate_skill(
|
|
444
|
+
skill_path: Path,
|
|
445
|
+
skills_dir: Path,
|
|
446
|
+
verbose: bool = False,
|
|
447
|
+
) -> ValidationResult:
|
|
448
|
+
"""Validate a single skill file.
|
|
449
|
+
|
|
450
|
+
Args:
|
|
451
|
+
skill_path: Path to SKILL.md file.
|
|
452
|
+
skills_dir: Path to skills directory.
|
|
453
|
+
verbose: Whether to print verbose output.
|
|
454
|
+
|
|
455
|
+
Returns:
|
|
456
|
+
ValidationResult with all findings.
|
|
457
|
+
"""
|
|
458
|
+
skill_name = skill_path.parent.name
|
|
459
|
+
result = ValidationResult(skill_name=skill_name, skill_path=skill_path)
|
|
460
|
+
|
|
461
|
+
if verbose:
|
|
462
|
+
print(f"Validating: {skill_name}")
|
|
463
|
+
|
|
464
|
+
# Read file
|
|
465
|
+
try:
|
|
466
|
+
content = skill_path.read_text(encoding="utf-8")
|
|
467
|
+
except Exception as e:
|
|
468
|
+
result.add_error(f"Failed to read file: {e}")
|
|
469
|
+
return result
|
|
470
|
+
|
|
471
|
+
# Extract and validate frontmatter
|
|
472
|
+
frontmatter, error = extract_frontmatter(content)
|
|
473
|
+
if error:
|
|
474
|
+
result.add_error(error)
|
|
475
|
+
else:
|
|
476
|
+
validate_frontmatter(frontmatter, result)
|
|
477
|
+
|
|
478
|
+
# Detect skill type
|
|
479
|
+
skill_type = detect_skill_type(content, frontmatter)
|
|
480
|
+
|
|
481
|
+
# Run all validations
|
|
482
|
+
validate_sections(content, skill_type, result)
|
|
483
|
+
validate_line_count(content, result)
|
|
484
|
+
validate_shortcodes(content, result)
|
|
485
|
+
validate_escaped_backticks(content, result)
|
|
486
|
+
validate_internal_links(content, skill_path, result)
|
|
487
|
+
validate_related_skills(content, skills_dir, result)
|
|
488
|
+
|
|
489
|
+
return result
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
def find_skills(skills_dir: Path, specific_skill: str | None = None) -> list[Path]:
|
|
493
|
+
"""Find all skill files to validate.
|
|
494
|
+
|
|
495
|
+
Args:
|
|
496
|
+
skills_dir: Path to skills directory.
|
|
497
|
+
specific_skill: Optional specific skill name to validate.
|
|
498
|
+
|
|
499
|
+
Returns:
|
|
500
|
+
List of paths to SKILL.md files.
|
|
501
|
+
"""
|
|
502
|
+
skills = []
|
|
503
|
+
|
|
504
|
+
for item in skills_dir.iterdir():
|
|
505
|
+
if not item.is_dir():
|
|
506
|
+
continue
|
|
507
|
+
|
|
508
|
+
# Skip the generator itself
|
|
509
|
+
if item.name == "testing-handbook-generator":
|
|
510
|
+
continue
|
|
511
|
+
|
|
512
|
+
# If specific skill requested, only include that one
|
|
513
|
+
if specific_skill and item.name != specific_skill:
|
|
514
|
+
continue
|
|
515
|
+
|
|
516
|
+
skill_file = item / "SKILL.md"
|
|
517
|
+
if skill_file.exists():
|
|
518
|
+
skills.append(skill_file)
|
|
519
|
+
|
|
520
|
+
return sorted(skills)
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
def print_result(result: ValidationResult, verbose: bool = False) -> None:
|
|
524
|
+
"""Print validation result to console.
|
|
525
|
+
|
|
526
|
+
Args:
|
|
527
|
+
result: ValidationResult to print.
|
|
528
|
+
verbose: Whether to print verbose info.
|
|
529
|
+
"""
|
|
530
|
+
status = "✓" if result.valid else "✗"
|
|
531
|
+
warning_indicator = " ⚠" if result.warnings else ""
|
|
532
|
+
|
|
533
|
+
print(f"{status} {result.skill_name}{warning_indicator}")
|
|
534
|
+
|
|
535
|
+
if result.errors:
|
|
536
|
+
for error in result.errors:
|
|
537
|
+
print(f" ERROR: {error}")
|
|
538
|
+
|
|
539
|
+
if result.warnings:
|
|
540
|
+
for warning in result.warnings:
|
|
541
|
+
print(f" WARNING: {warning}")
|
|
542
|
+
|
|
543
|
+
if verbose and result.info:
|
|
544
|
+
print(
|
|
545
|
+
f" Info: lines={result.info.get('line_count', '?')}, "
|
|
546
|
+
f"type={result.info.get('skill_type', '?')}"
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
def print_report(report: ValidationReport, verbose: bool = False) -> None:
|
|
551
|
+
"""Print validation report to console.
|
|
552
|
+
|
|
553
|
+
Args:
|
|
554
|
+
report: ValidationReport to print.
|
|
555
|
+
verbose: Whether to print verbose info.
|
|
556
|
+
"""
|
|
557
|
+
print("\n" + "=" * 50)
|
|
558
|
+
print("VALIDATION REPORT")
|
|
559
|
+
print("=" * 50)
|
|
560
|
+
|
|
561
|
+
for result in report.results:
|
|
562
|
+
print_result(result, verbose)
|
|
563
|
+
|
|
564
|
+
print("\n" + "-" * 50)
|
|
565
|
+
print(f"Total: {report.total}")
|
|
566
|
+
print(f"Passed: {report.passed}")
|
|
567
|
+
print(f"Failed: {report.failed}")
|
|
568
|
+
print(f"Warnings: {report.with_warnings}")
|
|
569
|
+
print("-" * 50)
|
|
570
|
+
|
|
571
|
+
if report.failed == 0:
|
|
572
|
+
print("✓ All skills passed validation")
|
|
573
|
+
else:
|
|
574
|
+
print(f"✗ {report.failed} skill(s) failed validation")
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
def main() -> int:
|
|
578
|
+
"""Main entry point.
|
|
579
|
+
|
|
580
|
+
Returns:
|
|
581
|
+
Exit code (0 for success, 1 for validation failures).
|
|
582
|
+
"""
|
|
583
|
+
parser = argparse.ArgumentParser(
|
|
584
|
+
description="Validate generated skills for testing-handbook-generator",
|
|
585
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
586
|
+
epilog=__doc__,
|
|
587
|
+
)
|
|
588
|
+
parser.add_argument(
|
|
589
|
+
"--skill",
|
|
590
|
+
"-s",
|
|
591
|
+
help="Validate specific skill by name",
|
|
592
|
+
)
|
|
593
|
+
parser.add_argument(
|
|
594
|
+
"--json",
|
|
595
|
+
"-j",
|
|
596
|
+
action="store_true",
|
|
597
|
+
help="Output JSON report",
|
|
598
|
+
)
|
|
599
|
+
parser.add_argument(
|
|
600
|
+
"--verbose",
|
|
601
|
+
"-v",
|
|
602
|
+
action="store_true",
|
|
603
|
+
help="Verbose output",
|
|
604
|
+
)
|
|
605
|
+
parser.add_argument(
|
|
606
|
+
"--skills-dir",
|
|
607
|
+
type=Path,
|
|
608
|
+
default=None,
|
|
609
|
+
help="Path to skills directory (auto-detected if not specified)",
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
args = parser.parse_args()
|
|
613
|
+
|
|
614
|
+
# Find skills directory
|
|
615
|
+
if args.skills_dir:
|
|
616
|
+
skills_dir = args.skills_dir
|
|
617
|
+
else:
|
|
618
|
+
# Auto-detect: look for skills directory relative to script
|
|
619
|
+
# Script is in plugins/testing-handbook-skills/scripts/
|
|
620
|
+
# Skills are in plugins/testing-handbook-skills/skills/
|
|
621
|
+
script_dir = Path(__file__).parent.parent
|
|
622
|
+
skills_dir = script_dir / "skills"
|
|
623
|
+
if not skills_dir.exists():
|
|
624
|
+
# Try from current working directory
|
|
625
|
+
skills_dir = Path.cwd() / "skills"
|
|
626
|
+
|
|
627
|
+
if not skills_dir.exists():
|
|
628
|
+
print(f"ERROR: Skills directory not found: {skills_dir}", file=sys.stderr)
|
|
629
|
+
return 1
|
|
630
|
+
|
|
631
|
+
# Find skills to validate
|
|
632
|
+
skill_files = find_skills(skills_dir, args.skill)
|
|
633
|
+
|
|
634
|
+
if not skill_files:
|
|
635
|
+
if args.skill:
|
|
636
|
+
print(f"ERROR: Skill not found: {args.skill}", file=sys.stderr)
|
|
637
|
+
else:
|
|
638
|
+
print("No generated skills found to validate", file=sys.stderr)
|
|
639
|
+
return 1
|
|
640
|
+
|
|
641
|
+
# Validate all skills
|
|
642
|
+
report = ValidationReport()
|
|
643
|
+
for skill_path in skill_files:
|
|
644
|
+
result = validate_skill(skill_path, skills_dir, args.verbose)
|
|
645
|
+
report.add_result(result)
|
|
646
|
+
|
|
647
|
+
# Output results
|
|
648
|
+
if args.json:
|
|
649
|
+
print(json.dumps(report.to_dict(), indent=2))
|
|
650
|
+
else:
|
|
651
|
+
print_report(report, args.verbose)
|
|
652
|
+
|
|
653
|
+
return 0 if report.failed == 0 else 1
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
if __name__ == "__main__":
|
|
657
|
+
sys.exit(main())
|