@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.
Files changed (371) hide show
  1. package/README.md +126 -0
  2. package/package.json +53 -0
  3. package/skills/1password/SKILL.md +70 -0
  4. package/skills/1password/references/cli-examples.md +29 -0
  5. package/skills/1password/references/get-started.md +17 -0
  6. package/skills/apple-notes/SKILL.md +77 -0
  7. package/skills/apple-reminders/SKILL.md +96 -0
  8. package/skills/bear-notes/SKILL.md +107 -0
  9. package/skills/bird/SKILL.md +224 -0
  10. package/skills/blogwatcher/SKILL.md +69 -0
  11. package/skills/blucli/SKILL.md +47 -0
  12. package/skills/bluebubbles/SKILL.md +131 -0
  13. package/skills/camsnap/SKILL.md +45 -0
  14. package/skills/canvas/SKILL.md +203 -0
  15. package/skills/clawhub/SKILL.md +77 -0
  16. package/skills/coding-agent/SKILL.md +284 -0
  17. package/skills/discord/SKILL.md +578 -0
  18. package/skills/eightctl/SKILL.md +50 -0
  19. package/skills/food-order/SKILL.md +48 -0
  20. package/skills/gemini/SKILL.md +43 -0
  21. package/skills/gifgrep/SKILL.md +79 -0
  22. package/skills/github/SKILL.md +77 -0
  23. package/skills/gog/SKILL.md +116 -0
  24. package/skills/goplaces/SKILL.md +52 -0
  25. package/skills/healthcheck/SKILL.md +245 -0
  26. package/skills/himalaya/SKILL.md +257 -0
  27. package/skills/himalaya/references/configuration.md +184 -0
  28. package/skills/himalaya/references/message-composition.md +199 -0
  29. package/skills/imsg/SKILL.md +74 -0
  30. package/skills/local-places/SERVER_README.md +101 -0
  31. package/skills/local-places/SKILL.md +102 -0
  32. package/skills/local-places/pyproject.toml +21 -0
  33. package/skills/local-places/src/local_places/__init__.py +2 -0
  34. package/skills/local-places/src/local_places/google_places.py +314 -0
  35. package/skills/local-places/src/local_places/main.py +65 -0
  36. package/skills/local-places/src/local_places/schemas.py +107 -0
  37. package/skills/mcporter/SKILL.md +61 -0
  38. package/skills/model-usage/SKILL.md +69 -0
  39. package/skills/model-usage/references/codexbar-cli.md +33 -0
  40. package/skills/model-usage/scripts/model_usage.py +310 -0
  41. package/skills/nano-banana-pro/SKILL.md +58 -0
  42. package/skills/nano-banana-pro/scripts/generate_image.py +184 -0
  43. package/skills/nano-pdf/SKILL.md +38 -0
  44. package/skills/notion/SKILL.md +172 -0
  45. package/skills/obsidian/SKILL.md +81 -0
  46. package/skills/openai-image-gen/SKILL.md +89 -0
  47. package/skills/openai-image-gen/scripts/gen.py +240 -0
  48. package/skills/openai-whisper/SKILL.md +38 -0
  49. package/skills/openai-whisper-api/SKILL.md +52 -0
  50. package/skills/openai-whisper-api/scripts/transcribe.sh +85 -0
  51. package/skills/openhue/SKILL.md +51 -0
  52. package/skills/oracle/SKILL.md +125 -0
  53. package/skills/ordercli/SKILL.md +78 -0
  54. package/skills/peekaboo/SKILL.md +190 -0
  55. package/skills/sag/SKILL.md +87 -0
  56. package/skills/security-ask-questions-if-underspecified/.claude-plugin/plugin.json +10 -0
  57. package/skills/security-ask-questions-if-underspecified/README.md +24 -0
  58. package/skills/security-ask-questions-if-underspecified/skills/ask-questions-if-underspecified/SKILL.md +85 -0
  59. package/skills/security-audit-context-building/.claude-plugin/plugin.json +10 -0
  60. package/skills/security-audit-context-building/README.md +58 -0
  61. package/skills/security-audit-context-building/commands/audit-context.md +21 -0
  62. package/skills/security-audit-context-building/skills/audit-context-building/SKILL.md +297 -0
  63. package/skills/security-audit-context-building/skills/audit-context-building/resources/COMPLETENESS_CHECKLIST.md +47 -0
  64. package/skills/security-audit-context-building/skills/audit-context-building/resources/FUNCTION_MICRO_ANALYSIS_EXAMPLE.md +355 -0
  65. package/skills/security-audit-context-building/skills/audit-context-building/resources/OUTPUT_REQUIREMENTS.md +71 -0
  66. package/skills/security-building-secure-contracts/.claude-plugin/plugin.json +10 -0
  67. package/skills/security-building-secure-contracts/README.md +241 -0
  68. package/skills/security-building-secure-contracts/skills/algorand-vulnerability-scanner/SKILL.md +284 -0
  69. package/skills/security-building-secure-contracts/skills/algorand-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +405 -0
  70. package/skills/security-building-secure-contracts/skills/audit-prep-assistant/SKILL.md +409 -0
  71. package/skills/security-building-secure-contracts/skills/cairo-vulnerability-scanner/SKILL.md +329 -0
  72. package/skills/security-building-secure-contracts/skills/cairo-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +722 -0
  73. package/skills/security-building-secure-contracts/skills/code-maturity-assessor/SKILL.md +218 -0
  74. package/skills/security-building-secure-contracts/skills/code-maturity-assessor/resources/ASSESSMENT_CRITERIA.md +355 -0
  75. package/skills/security-building-secure-contracts/skills/code-maturity-assessor/resources/EXAMPLE_REPORT.md +248 -0
  76. package/skills/security-building-secure-contracts/skills/code-maturity-assessor/resources/REPORT_FORMAT.md +33 -0
  77. package/skills/security-building-secure-contracts/skills/cosmos-vulnerability-scanner/SKILL.md +334 -0
  78. package/skills/security-building-secure-contracts/skills/cosmos-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +740 -0
  79. package/skills/security-building-secure-contracts/skills/guidelines-advisor/SKILL.md +252 -0
  80. package/skills/security-building-secure-contracts/skills/guidelines-advisor/resources/ASSESSMENT_AREAS.md +329 -0
  81. package/skills/security-building-secure-contracts/skills/guidelines-advisor/resources/DELIVERABLES.md +118 -0
  82. package/skills/security-building-secure-contracts/skills/guidelines-advisor/resources/EXAMPLE_REPORT.md +298 -0
  83. package/skills/security-building-secure-contracts/skills/secure-workflow-guide/SKILL.md +161 -0
  84. package/skills/security-building-secure-contracts/skills/secure-workflow-guide/resources/EXAMPLE_REPORT.md +279 -0
  85. package/skills/security-building-secure-contracts/skills/secure-workflow-guide/resources/WORKFLOW_STEPS.md +132 -0
  86. package/skills/security-building-secure-contracts/skills/solana-vulnerability-scanner/SKILL.md +389 -0
  87. package/skills/security-building-secure-contracts/skills/solana-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +669 -0
  88. package/skills/security-building-secure-contracts/skills/substrate-vulnerability-scanner/SKILL.md +298 -0
  89. package/skills/security-building-secure-contracts/skills/substrate-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +791 -0
  90. package/skills/security-building-secure-contracts/skills/token-integration-analyzer/SKILL.md +362 -0
  91. package/skills/security-building-secure-contracts/skills/token-integration-analyzer/resources/ASSESSMENT_CATEGORIES.md +571 -0
  92. package/skills/security-building-secure-contracts/skills/token-integration-analyzer/resources/REPORT_TEMPLATES.md +141 -0
  93. package/skills/security-building-secure-contracts/skills/ton-vulnerability-scanner/SKILL.md +388 -0
  94. package/skills/security-building-secure-contracts/skills/ton-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +595 -0
  95. package/skills/security-burpsuite-project-parser/.claude-plugin/plugin.json +10 -0
  96. package/skills/security-burpsuite-project-parser/README.md +103 -0
  97. package/skills/security-burpsuite-project-parser/commands/burp-search.md +18 -0
  98. package/skills/security-burpsuite-project-parser/skills/SKILL.md +358 -0
  99. package/skills/security-burpsuite-project-parser/skills/scripts/burp-search.sh +99 -0
  100. package/skills/security-claude-in-chrome-troubleshooting/.claude-plugin/plugin.json +8 -0
  101. package/skills/security-claude-in-chrome-troubleshooting/README.md +31 -0
  102. package/skills/security-claude-in-chrome-troubleshooting/skills/claude-in-chrome-troubleshooting/SKILL.md +251 -0
  103. package/skills/security-constant-time-analysis/.claude-plugin/plugin.json +9 -0
  104. package/skills/security-constant-time-analysis/README.md +381 -0
  105. package/skills/security-constant-time-analysis/commands/ct-check.md +20 -0
  106. package/skills/security-constant-time-analysis/ct_analyzer/__init__.py +49 -0
  107. package/skills/security-constant-time-analysis/ct_analyzer/analyzer.py +1284 -0
  108. package/skills/security-constant-time-analysis/ct_analyzer/script_analyzers.py +3081 -0
  109. package/skills/security-constant-time-analysis/ct_analyzer/tests/__init__.py +1 -0
  110. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_analyzer.py +1397 -0
  111. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/bn_excerpt.js +205 -0
  112. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/decompose_constant_time.c +181 -0
  113. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/decompose_vulnerable.c +74 -0
  114. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/decompose_vulnerable.go +78 -0
  115. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/decompose_vulnerable.rs +92 -0
  116. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.cs +174 -0
  117. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.java +161 -0
  118. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.kt +181 -0
  119. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.php +140 -0
  120. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.py +252 -0
  121. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.rb +188 -0
  122. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.swift +199 -0
  123. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.ts +154 -0
  124. package/skills/security-constant-time-analysis/pyproject.toml +52 -0
  125. package/skills/security-constant-time-analysis/skills/constant-time-analysis/README.md +90 -0
  126. package/skills/security-constant-time-analysis/skills/constant-time-analysis/SKILL.md +219 -0
  127. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/compiled.md +129 -0
  128. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/javascript.md +136 -0
  129. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/kotlin.md +252 -0
  130. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/php.md +172 -0
  131. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/python.md +179 -0
  132. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/ruby.md +198 -0
  133. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/swift.md +288 -0
  134. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/vm-compiled.md +354 -0
  135. package/skills/security-constant-time-analysis/uv.lock +8 -0
  136. package/skills/security-culture-index/.claude-plugin/plugin.json +8 -0
  137. package/skills/security-culture-index/README.md +79 -0
  138. package/skills/security-culture-index/skills/interpreting-culture-index/SKILL.md +293 -0
  139. package/skills/security-culture-index/skills/interpreting-culture-index/references/anti-patterns.md +255 -0
  140. package/skills/security-culture-index/skills/interpreting-culture-index/references/conversation-starters.md +408 -0
  141. package/skills/security-culture-index/skills/interpreting-culture-index/references/interview-trait-signals.md +253 -0
  142. package/skills/security-culture-index/skills/interpreting-culture-index/references/motivators.md +158 -0
  143. package/skills/security-culture-index/skills/interpreting-culture-index/references/patterns-archetypes.md +147 -0
  144. package/skills/security-culture-index/skills/interpreting-culture-index/references/primary-traits.md +307 -0
  145. package/skills/security-culture-index/skills/interpreting-culture-index/references/secondary-traits.md +228 -0
  146. package/skills/security-culture-index/skills/interpreting-culture-index/references/team-composition.md +148 -0
  147. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/check_deps.py +108 -0
  148. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/__init__.py +20 -0
  149. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/constants.py +122 -0
  150. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/extract.py +187 -0
  151. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/models.py +16 -0
  152. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/opencv_extractor.py +520 -0
  153. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/extract_pdf.py +237 -0
  154. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/pyproject.toml +18 -0
  155. package/skills/security-culture-index/skills/interpreting-culture-index/templates/burnout-report.md +113 -0
  156. package/skills/security-culture-index/skills/interpreting-culture-index/templates/comparison-report.md +103 -0
  157. package/skills/security-culture-index/skills/interpreting-culture-index/templates/hiring-profile.md +127 -0
  158. package/skills/security-culture-index/skills/interpreting-culture-index/templates/individual-report.md +85 -0
  159. package/skills/security-culture-index/skills/interpreting-culture-index/templates/predicted-profile.md +165 -0
  160. package/skills/security-culture-index/skills/interpreting-culture-index/templates/team-report.md +109 -0
  161. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/analyze-team.md +188 -0
  162. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/coach-manager.md +267 -0
  163. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/compare-profiles.md +188 -0
  164. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/define-hiring-profile.md +220 -0
  165. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/detect-burnout.md +206 -0
  166. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/extract-from-pdf.md +121 -0
  167. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/interpret-individual.md +183 -0
  168. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/interview-debrief.md +234 -0
  169. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/mediate-conflict.md +306 -0
  170. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/plan-onboarding.md +322 -0
  171. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/predict-from-interview.md +250 -0
  172. package/skills/security-differential-review/.claude-plugin/plugin.json +10 -0
  173. package/skills/security-differential-review/README.md +109 -0
  174. package/skills/security-differential-review/commands/diff-review.md +21 -0
  175. package/skills/security-differential-review/skills/differential-review/SKILL.md +220 -0
  176. package/skills/security-differential-review/skills/differential-review/adversarial.md +203 -0
  177. package/skills/security-differential-review/skills/differential-review/methodology.md +234 -0
  178. package/skills/security-differential-review/skills/differential-review/patterns.md +300 -0
  179. package/skills/security-differential-review/skills/differential-review/reporting.md +369 -0
  180. package/skills/security-dwarf-expert/.claude-plugin/plugin.json +10 -0
  181. package/skills/security-dwarf-expert/README.md +38 -0
  182. package/skills/security-dwarf-expert/skills/dwarf-expert/SKILL.md +93 -0
  183. package/skills/security-dwarf-expert/skills/dwarf-expert/reference/coding.md +31 -0
  184. package/skills/security-dwarf-expert/skills/dwarf-expert/reference/dwarfdump.md +50 -0
  185. package/skills/security-dwarf-expert/skills/dwarf-expert/reference/readelf.md +8 -0
  186. package/skills/security-entry-point-analyzer/.claude-plugin/plugin.json +10 -0
  187. package/skills/security-entry-point-analyzer/README.md +74 -0
  188. package/skills/security-entry-point-analyzer/commands/entry-points.md +18 -0
  189. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/SKILL.md +251 -0
  190. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/cosmwasm.md +182 -0
  191. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/move-aptos.md +107 -0
  192. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/move-sui.md +87 -0
  193. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/solana.md +155 -0
  194. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/solidity.md +135 -0
  195. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/ton.md +185 -0
  196. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/vyper.md +141 -0
  197. package/skills/security-firebase-apk-scanner/.claude-plugin/plugin.json +10 -0
  198. package/skills/security-firebase-apk-scanner/README.md +85 -0
  199. package/skills/security-firebase-apk-scanner/commands/scan-apk.md +18 -0
  200. package/skills/security-firebase-apk-scanner/scanner.sh +1408 -0
  201. package/skills/security-firebase-apk-scanner/skills/firebase-apk-scanner/SKILL.md +197 -0
  202. package/skills/security-firebase-apk-scanner/skills/firebase-apk-scanner/references/vulnerabilities.md +803 -0
  203. package/skills/security-fix-review/.claude-plugin/plugin.json +13 -0
  204. package/skills/security-fix-review/README.md +118 -0
  205. package/skills/security-fix-review/commands/fix-review.md +24 -0
  206. package/skills/security-fix-review/skills/fix-review/SKILL.md +264 -0
  207. package/skills/security-fix-review/skills/fix-review/references/bug-detection.md +408 -0
  208. package/skills/security-fix-review/skills/fix-review/references/finding-matching.md +298 -0
  209. package/skills/security-fix-review/skills/fix-review/references/report-parsing.md +398 -0
  210. package/skills/security-insecure-defaults/.claude-plugin/plugin.json +10 -0
  211. package/skills/security-insecure-defaults/README.md +45 -0
  212. package/skills/security-insecure-defaults/skills/insecure-defaults/SKILL.md +117 -0
  213. package/skills/security-insecure-defaults/skills/insecure-defaults/references/examples.md +409 -0
  214. package/skills/security-modern-python/.claude-plugin/plugin.json +10 -0
  215. package/skills/security-modern-python/README.md +58 -0
  216. package/skills/security-modern-python/hooks/hooks.json +16 -0
  217. package/skills/security-modern-python/hooks/intercept-legacy-python.bats +388 -0
  218. package/skills/security-modern-python/hooks/intercept-legacy-python.sh +109 -0
  219. package/skills/security-modern-python/hooks/test_helper.bash +75 -0
  220. package/skills/security-modern-python/skills/modern-python/SKILL.md +333 -0
  221. package/skills/security-modern-python/skills/modern-python/references/dependabot.md +43 -0
  222. package/skills/security-modern-python/skills/modern-python/references/migration-checklist.md +141 -0
  223. package/skills/security-modern-python/skills/modern-python/references/pep723-scripts.md +259 -0
  224. package/skills/security-modern-python/skills/modern-python/references/prek.md +211 -0
  225. package/skills/security-modern-python/skills/modern-python/references/pyproject.md +254 -0
  226. package/skills/security-modern-python/skills/modern-python/references/ruff-config.md +240 -0
  227. package/skills/security-modern-python/skills/modern-python/references/security-setup.md +255 -0
  228. package/skills/security-modern-python/skills/modern-python/references/testing.md +284 -0
  229. package/skills/security-modern-python/skills/modern-python/references/uv-commands.md +200 -0
  230. package/skills/security-modern-python/skills/modern-python/templates/dependabot.yml +36 -0
  231. package/skills/security-modern-python/skills/modern-python/templates/pre-commit-config.yaml +66 -0
  232. package/skills/security-property-based-testing/.claude-plugin/plugin.json +9 -0
  233. package/skills/security-property-based-testing/README.md +47 -0
  234. package/skills/security-property-based-testing/skills/property-based-testing/README.md +88 -0
  235. package/skills/security-property-based-testing/skills/property-based-testing/SKILL.md +109 -0
  236. package/skills/security-property-based-testing/skills/property-based-testing/references/design.md +191 -0
  237. package/skills/security-property-based-testing/skills/property-based-testing/references/generating.md +200 -0
  238. package/skills/security-property-based-testing/skills/property-based-testing/references/libraries.md +130 -0
  239. package/skills/security-property-based-testing/skills/property-based-testing/references/refactoring.md +181 -0
  240. package/skills/security-property-based-testing/skills/property-based-testing/references/reviewing.md +209 -0
  241. package/skills/security-property-based-testing/skills/property-based-testing/references/strategies.md +124 -0
  242. package/skills/semgrep-rule-creator/.claude-plugin/plugin.json +8 -0
  243. package/skills/semgrep-rule-creator/README.md +43 -0
  244. package/skills/semgrep-rule-creator/commands/semgrep-rule.md +26 -0
  245. package/skills/semgrep-rule-creator/skills/semgrep-rule-creator/SKILL.md +168 -0
  246. package/skills/semgrep-rule-creator/skills/semgrep-rule-creator/references/quick-reference.md +203 -0
  247. package/skills/semgrep-rule-creator/skills/semgrep-rule-creator/references/workflow.md +240 -0
  248. package/skills/semgrep-rule-variant-creator/.claude-plugin/plugin.json +9 -0
  249. package/skills/semgrep-rule-variant-creator/README.md +86 -0
  250. package/skills/semgrep-rule-variant-creator/skills/semgrep-rule-variant-creator/SKILL.md +205 -0
  251. package/skills/semgrep-rule-variant-creator/skills/semgrep-rule-variant-creator/references/applicability-analysis.md +250 -0
  252. package/skills/semgrep-rule-variant-creator/skills/semgrep-rule-variant-creator/references/language-syntax-guide.md +324 -0
  253. package/skills/semgrep-rule-variant-creator/skills/semgrep-rule-variant-creator/references/workflow.md +518 -0
  254. package/skills/session-logs/SKILL.md +115 -0
  255. package/skills/sharp-edges/.claude-plugin/plugin.json +10 -0
  256. package/skills/sharp-edges/README.md +48 -0
  257. package/skills/sharp-edges/skills/sharp-edges/SKILL.md +292 -0
  258. package/skills/sharp-edges/skills/sharp-edges/references/auth-patterns.md +252 -0
  259. package/skills/sharp-edges/skills/sharp-edges/references/case-studies.md +274 -0
  260. package/skills/sharp-edges/skills/sharp-edges/references/config-patterns.md +333 -0
  261. package/skills/sharp-edges/skills/sharp-edges/references/crypto-apis.md +190 -0
  262. package/skills/sharp-edges/skills/sharp-edges/references/lang-c.md +205 -0
  263. package/skills/sharp-edges/skills/sharp-edges/references/lang-csharp.md +285 -0
  264. package/skills/sharp-edges/skills/sharp-edges/references/lang-go.md +270 -0
  265. package/skills/sharp-edges/skills/sharp-edges/references/lang-java.md +263 -0
  266. package/skills/sharp-edges/skills/sharp-edges/references/lang-javascript.md +269 -0
  267. package/skills/sharp-edges/skills/sharp-edges/references/lang-kotlin.md +265 -0
  268. package/skills/sharp-edges/skills/sharp-edges/references/lang-php.md +245 -0
  269. package/skills/sharp-edges/skills/sharp-edges/references/lang-python.md +274 -0
  270. package/skills/sharp-edges/skills/sharp-edges/references/lang-ruby.md +273 -0
  271. package/skills/sharp-edges/skills/sharp-edges/references/lang-rust.md +272 -0
  272. package/skills/sharp-edges/skills/sharp-edges/references/lang-swift.md +287 -0
  273. package/skills/sharp-edges/skills/sharp-edges/references/language-specific.md +588 -0
  274. package/skills/sherpa-onnx-tts/SKILL.md +103 -0
  275. package/skills/sherpa-onnx-tts/bin/sherpa-onnx-tts +178 -0
  276. package/skills/skill-creator/SKILL.md +370 -0
  277. package/skills/skill-creator/license.txt +202 -0
  278. package/skills/skill-creator/scripts/init_skill.py +378 -0
  279. package/skills/skill-creator/scripts/package_skill.py +111 -0
  280. package/skills/skill-creator/scripts/quick_validate.py +101 -0
  281. package/skills/slack/SKILL.md +144 -0
  282. package/skills/songsee/SKILL.md +49 -0
  283. package/skills/sonoscli/SKILL.md +46 -0
  284. package/skills/spec-to-code-compliance/.claude-plugin/plugin.json +10 -0
  285. package/skills/spec-to-code-compliance/README.md +67 -0
  286. package/skills/spec-to-code-compliance/commands/spec-compliance.md +22 -0
  287. package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/SKILL.md +349 -0
  288. package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/resources/COMPLETENESS_CHECKLIST.md +69 -0
  289. package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/resources/IR_EXAMPLES.md +417 -0
  290. package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/resources/OUTPUT_REQUIREMENTS.md +105 -0
  291. package/skills/spotify-player/SKILL.md +64 -0
  292. package/skills/static-analysis/.claude-plugin/plugin.json +8 -0
  293. package/skills/static-analysis/README.md +59 -0
  294. package/skills/static-analysis/skills/codeql/SKILL.md +315 -0
  295. package/skills/static-analysis/skills/sarif-parsing/SKILL.md +479 -0
  296. package/skills/static-analysis/skills/sarif-parsing/resources/jq-queries.md +162 -0
  297. package/skills/static-analysis/skills/sarif-parsing/resources/sarif_helpers.py +331 -0
  298. package/skills/static-analysis/skills/semgrep/SKILL.md +337 -0
  299. package/skills/summarize/SKILL.md +87 -0
  300. package/skills/testing-handbook-skills/.claude-plugin/plugin.json +8 -0
  301. package/skills/testing-handbook-skills/README.md +241 -0
  302. package/skills/testing-handbook-skills/scripts/pyproject.toml +8 -0
  303. package/skills/testing-handbook-skills/scripts/validate-skills.py +657 -0
  304. package/skills/testing-handbook-skills/skills/address-sanitizer/SKILL.md +341 -0
  305. package/skills/testing-handbook-skills/skills/aflpp/SKILL.md +640 -0
  306. package/skills/testing-handbook-skills/skills/atheris/SKILL.md +515 -0
  307. package/skills/testing-handbook-skills/skills/cargo-fuzz/SKILL.md +454 -0
  308. package/skills/testing-handbook-skills/skills/codeql/SKILL.md +549 -0
  309. package/skills/testing-handbook-skills/skills/constant-time-testing/SKILL.md +507 -0
  310. package/skills/testing-handbook-skills/skills/coverage-analysis/SKILL.md +607 -0
  311. package/skills/testing-handbook-skills/skills/fuzzing-dictionary/SKILL.md +297 -0
  312. package/skills/testing-handbook-skills/skills/fuzzing-obstacles/SKILL.md +426 -0
  313. package/skills/testing-handbook-skills/skills/harness-writing/SKILL.md +614 -0
  314. package/skills/testing-handbook-skills/skills/libafl/SKILL.md +625 -0
  315. package/skills/testing-handbook-skills/skills/libfuzzer/SKILL.md +795 -0
  316. package/skills/testing-handbook-skills/skills/ossfuzz/SKILL.md +426 -0
  317. package/skills/testing-handbook-skills/skills/ruzzy/SKILL.md +443 -0
  318. package/skills/testing-handbook-skills/skills/semgrep/SKILL.md +601 -0
  319. package/skills/testing-handbook-skills/skills/testing-handbook-generator/SKILL.md +372 -0
  320. package/skills/testing-handbook-skills/skills/testing-handbook-generator/agent-prompt.md +280 -0
  321. package/skills/testing-handbook-skills/skills/testing-handbook-generator/discovery.md +452 -0
  322. package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/domain-skill.md +504 -0
  323. package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/fuzzer-skill.md +454 -0
  324. package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/technique-skill.md +527 -0
  325. package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/tool-skill.md +366 -0
  326. package/skills/testing-handbook-skills/skills/testing-handbook-generator/testing.md +482 -0
  327. package/skills/testing-handbook-skills/skills/wycheproof/SKILL.md +533 -0
  328. package/skills/things-mac/SKILL.md +86 -0
  329. package/skills/tmux/SKILL.md +135 -0
  330. package/skills/tmux/scripts/find-sessions.sh +112 -0
  331. package/skills/tmux/scripts/wait-for-text.sh +83 -0
  332. package/skills/trello/SKILL.md +95 -0
  333. package/skills/variant-analysis/.claude-plugin/plugin.json +8 -0
  334. package/skills/variant-analysis/README.md +41 -0
  335. package/skills/variant-analysis/commands/variants.md +23 -0
  336. package/skills/variant-analysis/skills/variant-analysis/METHODOLOGY.md +327 -0
  337. package/skills/variant-analysis/skills/variant-analysis/SKILL.md +142 -0
  338. package/skills/variant-analysis/skills/variant-analysis/resources/codeql/cpp.ql +119 -0
  339. package/skills/variant-analysis/skills/variant-analysis/resources/codeql/go.ql +69 -0
  340. package/skills/variant-analysis/skills/variant-analysis/resources/codeql/java.ql +71 -0
  341. package/skills/variant-analysis/skills/variant-analysis/resources/codeql/javascript.ql +63 -0
  342. package/skills/variant-analysis/skills/variant-analysis/resources/codeql/python.ql +80 -0
  343. package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/cpp.yaml +98 -0
  344. package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/go.yaml +63 -0
  345. package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/java.yaml +61 -0
  346. package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/javascript.yaml +60 -0
  347. package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/python.yaml +72 -0
  348. package/skills/variant-analysis/skills/variant-analysis/resources/variant-report-template.md +75 -0
  349. package/skills/video-frames/SKILL.md +46 -0
  350. package/skills/video-frames/scripts/frame.sh +81 -0
  351. package/skills/voice-call/SKILL.md +45 -0
  352. package/skills/wacli/SKILL.md +72 -0
  353. package/skills/weather/SKILL.md +54 -0
  354. package/skills/yara-authoring/.claude-plugin/plugin.json +9 -0
  355. package/skills/yara-authoring/README.md +131 -0
  356. package/skills/yara-authoring/skills/yara-rule-authoring/SKILL.md +645 -0
  357. package/skills/yara-authoring/skills/yara-rule-authoring/examples/MAL_Mac_ProtonRAT_Jan25.yar +99 -0
  358. package/skills/yara-authoring/skills/yara-rule-authoring/examples/MAL_NPM_SupplyChain_Jan25.yar +170 -0
  359. package/skills/yara-authoring/skills/yara-rule-authoring/examples/MAL_Win_Remcos_Jan25.yar +103 -0
  360. package/skills/yara-authoring/skills/yara-rule-authoring/examples/SUSP_CRX_SuspiciousPermissions.yar +134 -0
  361. package/skills/yara-authoring/skills/yara-rule-authoring/examples/SUSP_JS_Obfuscation_Jan25.yar +185 -0
  362. package/skills/yara-authoring/skills/yara-rule-authoring/references/crx-module.md +214 -0
  363. package/skills/yara-authoring/skills/yara-rule-authoring/references/dex-module.md +383 -0
  364. package/skills/yara-authoring/skills/yara-rule-authoring/references/performance.md +333 -0
  365. package/skills/yara-authoring/skills/yara-rule-authoring/references/strings.md +433 -0
  366. package/skills/yara-authoring/skills/yara-rule-authoring/references/style-guide.md +257 -0
  367. package/skills/yara-authoring/skills/yara-rule-authoring/references/testing.md +399 -0
  368. package/skills/yara-authoring/skills/yara-rule-authoring/scripts/atom_analyzer.py +526 -0
  369. package/skills/yara-authoring/skills/yara-rule-authoring/scripts/pyproject.toml +25 -0
  370. package/skills/yara-authoring/skills/yara-rule-authoring/scripts/yara_lint.py +631 -0
  371. 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())