@softspark/ai-toolkit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (327) hide show
  1. package/AGENTS.md +412 -0
  2. package/CHANGELOG.md +68 -0
  3. package/LICENSE +21 -0
  4. package/README.md +632 -0
  5. package/action.yml +53 -0
  6. package/app/.claude-plugin/plugin.json +44 -0
  7. package/app/ARCHITECTURE.md +306 -0
  8. package/app/CLAUDE.md.template +23 -0
  9. package/app/agents/ai-engineer.md +128 -0
  10. package/app/agents/backend-specialist.md +193 -0
  11. package/app/agents/business-intelligence.md +54 -0
  12. package/app/agents/chaos-monkey.md +67 -0
  13. package/app/agents/chief-of-staff.md +51 -0
  14. package/app/agents/code-archaeologist.md +127 -0
  15. package/app/agents/code-reviewer.md +184 -0
  16. package/app/agents/command-expert.md +131 -0
  17. package/app/agents/data-analyst.md +205 -0
  18. package/app/agents/data-scientist.md +151 -0
  19. package/app/agents/database-architect.md +317 -0
  20. package/app/agents/debugger.md +238 -0
  21. package/app/agents/devops-implementer.md +194 -0
  22. package/app/agents/documenter.md +364 -0
  23. package/app/agents/explorer-agent.md +145 -0
  24. package/app/agents/fact-checker.md +172 -0
  25. package/app/agents/frontend-specialist.md +209 -0
  26. package/app/agents/game-developer.md +216 -0
  27. package/app/agents/incident-responder.md +226 -0
  28. package/app/agents/infrastructure-architect.md +127 -0
  29. package/app/agents/infrastructure-validator.md +247 -0
  30. package/app/agents/llm-ops-engineer.md +237 -0
  31. package/app/agents/mcp-expert.md +228 -0
  32. package/app/agents/mcp-server-architect.md +195 -0
  33. package/app/agents/mcp-testing-engineer.md +292 -0
  34. package/app/agents/meta-architect.md +58 -0
  35. package/app/agents/ml-engineer.md +136 -0
  36. package/app/agents/mobile-developer.md +190 -0
  37. package/app/agents/night-watchman.md +55 -0
  38. package/app/agents/nlp-engineer.md +154 -0
  39. package/app/agents/orchestrator.md +437 -0
  40. package/app/agents/performance-optimizer.md +254 -0
  41. package/app/agents/predictive-analyst.md +57 -0
  42. package/app/agents/product-manager.md +194 -0
  43. package/app/agents/project-planner.md +287 -0
  44. package/app/agents/prompt-engineer.md +103 -0
  45. package/app/agents/qa-automation-engineer.md +182 -0
  46. package/app/agents/rag-engineer.md +201 -0
  47. package/app/agents/research-synthesizer.md +138 -0
  48. package/app/agents/search-specialist.md +101 -0
  49. package/app/agents/security-architect.md +62 -0
  50. package/app/agents/security-auditor.md +293 -0
  51. package/app/agents/seo-specialist.md +111 -0
  52. package/app/agents/system-governor.md +57 -0
  53. package/app/agents/tech-lead.md +62 -0
  54. package/app/agents/technical-researcher.md +103 -0
  55. package/app/agents/test-engineer.md +264 -0
  56. package/app/constitution.md +38 -0
  57. package/app/hooks/_profile-check.sh +11 -0
  58. package/app/hooks/guard-destructive.sh +74 -0
  59. package/app/hooks/guard-path.sh +73 -0
  60. package/app/hooks/post-tool-use.sh +35 -0
  61. package/app/hooks/pre-compact.sh +31 -0
  62. package/app/hooks/quality-check.sh +22 -0
  63. package/app/hooks/quality-gate.sh +49 -0
  64. package/app/hooks/save-session.sh +24 -0
  65. package/app/hooks/session-end.sh +37 -0
  66. package/app/hooks/session-start.sh +29 -0
  67. package/app/hooks/subagent-start.sh +16 -0
  68. package/app/hooks/subagent-stop.sh +16 -0
  69. package/app/hooks/track-usage.sh +50 -0
  70. package/app/hooks/user-prompt-submit.sh +25 -0
  71. package/app/hooks.json +178 -0
  72. package/app/mcp-defaults.json +23 -0
  73. package/app/output-styles/golden-rules.md +43 -0
  74. package/app/plugins/README.md +19 -0
  75. package/app/plugins/csharp-pack/README.md +11 -0
  76. package/app/plugins/csharp-pack/plugin.json +18 -0
  77. package/app/plugins/enterprise-pack/README.md +16 -0
  78. package/app/plugins/enterprise-pack/hooks/output-style.sh +6 -0
  79. package/app/plugins/enterprise-pack/hooks/status-line.sh +8 -0
  80. package/app/plugins/enterprise-pack/plugin.json +24 -0
  81. package/app/plugins/frontend-pack/README.md +14 -0
  82. package/app/plugins/frontend-pack/plugin.json +22 -0
  83. package/app/plugins/java-pack/README.md +11 -0
  84. package/app/plugins/java-pack/plugin.json +18 -0
  85. package/app/plugins/kotlin-pack/README.md +11 -0
  86. package/app/plugins/kotlin-pack/plugin.json +18 -0
  87. package/app/plugins/memory-pack/README.md +24 -0
  88. package/app/plugins/memory-pack/hooks/observation-capture.sh +67 -0
  89. package/app/plugins/memory-pack/hooks/session-summary.sh +71 -0
  90. package/app/plugins/memory-pack/plugin.json +22 -0
  91. package/app/plugins/memory-pack/scripts/init_db.py +81 -0
  92. package/app/plugins/memory-pack/scripts/strip_private.py +22 -0
  93. package/app/plugins/memory-pack/skills/mem-search/SKILL.md +70 -0
  94. package/app/plugins/research-pack/README.md +14 -0
  95. package/app/plugins/research-pack/plugin.json +22 -0
  96. package/app/plugins/ruby-pack/README.md +11 -0
  97. package/app/plugins/ruby-pack/plugin.json +18 -0
  98. package/app/plugins/rust-pack/README.md +11 -0
  99. package/app/plugins/rust-pack/plugin.json +18 -0
  100. package/app/plugins/security-pack/README.md +15 -0
  101. package/app/plugins/security-pack/plugin.json +23 -0
  102. package/app/plugins/swift-pack/README.md +11 -0
  103. package/app/plugins/swift-pack/plugin.json +18 -0
  104. package/app/rules/claude-toolkit-rules.md +21 -0
  105. package/app/rules/git-conventions.md +5 -0
  106. package/app/rules/quality-gates.md +10 -0
  107. package/app/skills/_lib/__init__.py +1 -0
  108. package/app/skills/_lib/detect_utils.py +150 -0
  109. package/app/skills/agent-creator/SKILL.md +82 -0
  110. package/app/skills/analyze/SKILL.md +92 -0
  111. package/app/skills/analyze/scripts/complexity.py +165 -0
  112. package/app/skills/api-patterns/SKILL.md +305 -0
  113. package/app/skills/app-builder/SKILL.md +187 -0
  114. package/app/skills/architecture-audit/SKILL.md +141 -0
  115. package/app/skills/architecture-decision/SKILL.md +55 -0
  116. package/app/skills/architecture-decision/templates/adr-template.md +36 -0
  117. package/app/skills/biz-scan/SKILL.md +30 -0
  118. package/app/skills/briefing/SKILL.md +27 -0
  119. package/app/skills/build/SKILL.md +97 -0
  120. package/app/skills/build/scripts/detect-build.py +151 -0
  121. package/app/skills/chaos/SKILL.md +32 -0
  122. package/app/skills/ci/SKILL.md +77 -0
  123. package/app/skills/ci/scripts/ci-detect.py +135 -0
  124. package/app/skills/ci/templates/github-actions-node.yml +38 -0
  125. package/app/skills/ci/templates/github-actions-python.yml +42 -0
  126. package/app/skills/ci-cd-patterns/SKILL.md +299 -0
  127. package/app/skills/clean-code/SKILL.md +110 -0
  128. package/app/skills/clean-code/reference/dart.md +18 -0
  129. package/app/skills/clean-code/reference/go.md +23 -0
  130. package/app/skills/clean-code/reference/php.md +32 -0
  131. package/app/skills/clean-code/reference/python.md +180 -0
  132. package/app/skills/clean-code/reference/typescript.md +26 -0
  133. package/app/skills/command-creator/SKILL.md +83 -0
  134. package/app/skills/commit/SKILL.md +98 -0
  135. package/app/skills/commit/scripts/pre-commit-check.py +87 -0
  136. package/app/skills/commit/templates/conventional-commit.md +52 -0
  137. package/app/skills/csharp-patterns/SKILL.md +450 -0
  138. package/app/skills/database-patterns/SKILL.md +297 -0
  139. package/app/skills/debug/SKILL.md +154 -0
  140. package/app/skills/debug/scripts/error-parser.py +187 -0
  141. package/app/skills/debugging-tactics/SKILL.md +136 -0
  142. package/app/skills/deploy/SKILL.md +130 -0
  143. package/app/skills/deploy/scripts/pre_deploy_check.py +171 -0
  144. package/app/skills/deploy/templates/deployment-checklist.md +31 -0
  145. package/app/skills/design-an-interface/SKILL.md +105 -0
  146. package/app/skills/design-engineering/SKILL.md +260 -0
  147. package/app/skills/docker-devops/SKILL.md +303 -0
  148. package/app/skills/docs/SKILL.md +145 -0
  149. package/app/skills/docs/scripts/doc-inventory.py +176 -0
  150. package/app/skills/docs/templates/adr-template.md +36 -0
  151. package/app/skills/docs/templates/readme-template.md +67 -0
  152. package/app/skills/documentation-standards/SKILL.md +191 -0
  153. package/app/skills/ecommerce-patterns/SKILL.md +209 -0
  154. package/app/skills/evaluate/SKILL.md +132 -0
  155. package/app/skills/evolve/SKILL.md +27 -0
  156. package/app/skills/explain/SKILL.md +54 -0
  157. package/app/skills/explain/scripts/dependency-graph.py +215 -0
  158. package/app/skills/explore/SKILL.md +112 -0
  159. package/app/skills/explore/scripts/visualize.py +117 -0
  160. package/app/skills/fix/SKILL.md +78 -0
  161. package/app/skills/fix/scripts/error-classifier.py +191 -0
  162. package/app/skills/flutter-patterns/SKILL.md +254 -0
  163. package/app/skills/git-mastery/SKILL.md +70 -0
  164. package/app/skills/grill-me/SKILL.md +38 -0
  165. package/app/skills/health/SKILL.md +91 -0
  166. package/app/skills/health/scripts/health_check.py +162 -0
  167. package/app/skills/hive-mind/SKILL.md +56 -0
  168. package/app/skills/hook-creator/SKILL.md +107 -0
  169. package/app/skills/index/SKILL.md +74 -0
  170. package/app/skills/instinct-review/SKILL.md +77 -0
  171. package/app/skills/java-patterns/SKILL.md +442 -0
  172. package/app/skills/kotlin-patterns/SKILL.md +446 -0
  173. package/app/skills/lint/SKILL.md +103 -0
  174. package/app/skills/lint/scripts/detect-linters.py +112 -0
  175. package/app/skills/mcp-patterns/SKILL.md +270 -0
  176. package/app/skills/mem-search/SKILL.md +70 -0
  177. package/app/skills/migrate/SKILL.md +90 -0
  178. package/app/skills/migrate/scripts/migration-status.py +195 -0
  179. package/app/skills/migration-patterns/SKILL.md +260 -0
  180. package/app/skills/night-watch/SKILL.md +28 -0
  181. package/app/skills/observability-patterns/SKILL.md +203 -0
  182. package/app/skills/onboard/SKILL.md +76 -0
  183. package/app/skills/orchestrate/SKILL.md +86 -0
  184. package/app/skills/panic/SKILL.md +30 -0
  185. package/app/skills/performance-profiling/SKILL.md +59 -0
  186. package/app/skills/plan/SKILL.md +110 -0
  187. package/app/skills/plan/templates/plan-template.md +40 -0
  188. package/app/skills/plan-writing/SKILL.md +201 -0
  189. package/app/skills/plugin-creator/SKILL.md +78 -0
  190. package/app/skills/pr/SKILL.md +129 -0
  191. package/app/skills/pr/scripts/pr-summary.py +175 -0
  192. package/app/skills/prd-to-issues/SKILL.md +108 -0
  193. package/app/skills/prd-to-plan/SKILL.md +120 -0
  194. package/app/skills/predict/SKILL.md +30 -0
  195. package/app/skills/qa-session/SKILL.md +110 -0
  196. package/app/skills/rag-patterns/SKILL.md +203 -0
  197. package/app/skills/refactor/SKILL.md +124 -0
  198. package/app/skills/refactor/scripts/refactor-scan.py +210 -0
  199. package/app/skills/refactor-plan/SKILL.md +112 -0
  200. package/app/skills/repeat/SKILL.md +149 -0
  201. package/app/skills/research-mastery/SKILL.md +56 -0
  202. package/app/skills/review/SKILL.md +141 -0
  203. package/app/skills/review/scripts/diff-analyzer.py +170 -0
  204. package/app/skills/rollback/SKILL.md +87 -0
  205. package/app/skills/rollback/scripts/rollback_info.py +149 -0
  206. package/app/skills/ruby-patterns/SKILL.md +454 -0
  207. package/app/skills/rust-patterns/SKILL.md +446 -0
  208. package/app/skills/search/SKILL.md +64 -0
  209. package/app/skills/security-patterns/SKILL.md +91 -0
  210. package/app/skills/security-patterns/reference/authentication.md +37 -0
  211. package/app/skills/security-patterns/reference/authorization.md +22 -0
  212. package/app/skills/security-patterns/reference/input-validation.md +30 -0
  213. package/app/skills/security-patterns/reference/oauth-csrf-audit.md +131 -0
  214. package/app/skills/skill-creator/SKILL.md +154 -0
  215. package/app/skills/skill-creator/templates/dashboard/index.html +130 -0
  216. package/app/skills/skill-creator/templates/reasoning-engine/assets/example.json +12 -0
  217. package/app/skills/skill-creator/templates/reasoning-engine/search.py +110 -0
  218. package/app/skills/subagent-development/SKILL.md +225 -0
  219. package/app/skills/subagent-development/reference/code-quality-reviewer-prompt.md +145 -0
  220. package/app/skills/subagent-development/reference/implementer-prompt.md +118 -0
  221. package/app/skills/subagent-development/reference/spec-reviewer-prompt.md +100 -0
  222. package/app/skills/swarm/SKILL.md +81 -0
  223. package/app/skills/swift-patterns/SKILL.md +500 -0
  224. package/app/skills/tdd/SKILL.md +174 -0
  225. package/app/skills/tdd/reference/deep-modules.md +32 -0
  226. package/app/skills/tdd/reference/interface-design.md +32 -0
  227. package/app/skills/tdd/reference/mocking.md +52 -0
  228. package/app/skills/tdd/reference/refactoring.md +10 -0
  229. package/app/skills/tdd/reference/tests.md +59 -0
  230. package/app/skills/teams/SKILL.md +101 -0
  231. package/app/skills/test/SKILL.md +107 -0
  232. package/app/skills/test/scripts/detect-runner.py +113 -0
  233. package/app/skills/testing-patterns/SKILL.md +73 -0
  234. package/app/skills/testing-patterns/reference/flutter-testing.md +33 -0
  235. package/app/skills/testing-patterns/reference/go-testing.md +52 -0
  236. package/app/skills/testing-patterns/reference/php-phpunit.md +39 -0
  237. package/app/skills/testing-patterns/reference/python-pytest.md +228 -0
  238. package/app/skills/testing-patterns/reference/typescript-vitest.md +50 -0
  239. package/app/skills/triage-issue/SKILL.md +120 -0
  240. package/app/skills/typescript-patterns/SKILL.md +256 -0
  241. package/app/skills/ubiquitous-language/SKILL.md +74 -0
  242. package/app/skills/verification-before-completion/SKILL.md +108 -0
  243. package/app/skills/workflow/SKILL.md +250 -0
  244. package/app/skills/write-a-prd/SKILL.md +129 -0
  245. package/app/skills/write-a-prd/reference/visual-companion.md +78 -0
  246. package/app/skills/write-a-prd/scripts/frame-template.html +111 -0
  247. package/app/skills/write-a-prd/scripts/visual-server.cjs +79 -0
  248. package/app/templates/skill/generator/SKILL.md.template +40 -0
  249. package/app/templates/skill/knowledge/SKILL.md.template +52 -0
  250. package/app/templates/skill/linter/SKILL.md.template +34 -0
  251. package/app/templates/skill/reviewer/SKILL.md.template +51 -0
  252. package/app/templates/skill/workflow/SKILL.md.template +49 -0
  253. package/benchmarks/README.md +111 -0
  254. package/benchmarks/ecosystem-dashboard.json +148 -0
  255. package/benchmarks/ecosystem-harvest.json +148 -0
  256. package/benchmarks/results.json +38 -0
  257. package/benchmarks/run.py +351 -0
  258. package/bin/ai-toolkit.js +345 -0
  259. package/kb/best-practices/README.md +11 -0
  260. package/kb/howto/README.md +11 -0
  261. package/kb/procedures/maintenance-sop.md +306 -0
  262. package/kb/reference/agents-catalog.md +124 -0
  263. package/kb/reference/anti-pattern-registry-format.md +221 -0
  264. package/kb/reference/architecture-overview.md +232 -0
  265. package/kb/reference/benchmark-config.md +62 -0
  266. package/kb/reference/ci-integration.md +66 -0
  267. package/kb/reference/claude-ecosystem-benchmark-snapshot.md +80 -0
  268. package/kb/reference/claude-ecosystem-expansion-foundations.md +102 -0
  269. package/kb/reference/commands-catalog.md +21 -0
  270. package/kb/reference/distribution-model.md +63 -0
  271. package/kb/reference/global-install-model.md +56 -0
  272. package/kb/reference/hierarchical-override-pattern.md +200 -0
  273. package/kb/reference/hooks-catalog.md +306 -0
  274. package/kb/reference/integrations.md +88 -0
  275. package/kb/reference/language-packs.md +52 -0
  276. package/kb/reference/merge-friendly-install-model.md +58 -0
  277. package/kb/reference/plugin-pack-conventions.md +151 -0
  278. package/kb/reference/quick-wins-implementation-summary.md +70 -0
  279. package/kb/reference/skill-templates.md +50 -0
  280. package/kb/reference/skills-catalog.md +215 -0
  281. package/kb/reference/skills-unification.md +57 -0
  282. package/kb/reference/stats.md +69 -0
  283. package/kb/reference/sync.md +76 -0
  284. package/kb/troubleshooting/README.md +11 -0
  285. package/llms-full.txt +3068 -0
  286. package/llms.txt +39 -0
  287. package/package.json +75 -0
  288. package/scripts/_common.py +160 -0
  289. package/scripts/add_rule.py +50 -0
  290. package/scripts/benchmark_config.py +127 -0
  291. package/scripts/benchmark_ecosystem.py +288 -0
  292. package/scripts/check_deps.py +260 -0
  293. package/scripts/create_skill.py +118 -0
  294. package/scripts/doctor.py +504 -0
  295. package/scripts/eject.py +113 -0
  296. package/scripts/emission.py +256 -0
  297. package/scripts/evaluate_skills.py +260 -0
  298. package/scripts/frontmatter.py +58 -0
  299. package/scripts/generate_agents_md.py +91 -0
  300. package/scripts/generate_aider_conf.py +51 -0
  301. package/scripts/generate_cline.py +35 -0
  302. package/scripts/generate_copilot.py +30 -0
  303. package/scripts/generate_cursor_rules.py +35 -0
  304. package/scripts/generate_gemini.py +28 -0
  305. package/scripts/generate_llms_txt.py +164 -0
  306. package/scripts/generate_roo_modes.py +80 -0
  307. package/scripts/generate_windsurf.py +35 -0
  308. package/scripts/generator_base.py +140 -0
  309. package/scripts/harvest_ecosystem.py +50 -0
  310. package/scripts/inject_rule_cli.py +101 -0
  311. package/scripts/inject_section_cli.py +47 -0
  312. package/scripts/injection.py +180 -0
  313. package/scripts/install.py +236 -0
  314. package/scripts/install_git_hooks.py +71 -0
  315. package/scripts/install_steps/__init__.py +5 -0
  316. package/scripts/install_steps/ai_tools.py +261 -0
  317. package/scripts/install_steps/hooks.py +90 -0
  318. package/scripts/install_steps/markers.py +79 -0
  319. package/scripts/install_steps/symlinks.py +87 -0
  320. package/scripts/merge-hooks.py +192 -0
  321. package/scripts/plugin.py +642 -0
  322. package/scripts/plugin_schema.py +138 -0
  323. package/scripts/remove_rule.py +58 -0
  324. package/scripts/stats.py +81 -0
  325. package/scripts/sync.py +215 -0
  326. package/scripts/uninstall.py +292 -0
  327. package/scripts/validate.py +700 -0
@@ -0,0 +1,288 @@
1
+ #!/usr/bin/env python3
2
+ """benchmark-ecosystem — Generate ecosystem benchmark snapshot.
3
+
4
+ Usage:
5
+ benchmark_ecosystem.py [--offline] [--json|--dashboard-json|--markdown] [--out FILE]
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import os
11
+ import sys
12
+ import urllib.request
13
+ from datetime import date, datetime, timezone
14
+ from pathlib import Path
15
+
16
+ SNAPSHOT_DATE = "2026-03-28"
17
+ STALE_THRESHOLD_DAYS = 30
18
+
19
+ SNAPSHOT_DATA = [
20
+ {
21
+ "repo": "anthropics/claude-code",
22
+ "category": "official",
23
+ "stars": 83535,
24
+ "updated_at": "2026-03-27T16:50:16Z",
25
+ "commands_md": 18,
26
+ "agents_md": 15,
27
+ "skills": 10,
28
+ "hook_settings_files": 5,
29
+ "notes": "Official Claude Code repo with plugin layout, development kits, and modular commands/agents/hooks.",
30
+ },
31
+ {
32
+ "repo": "affaan-m/everything-claude-code",
33
+ "category": "ecosystem-scale",
34
+ "stars": 111863,
35
+ "updated_at": "2026-03-27T16:55:18Z",
36
+ "commands_md": 271,
37
+ "agents_md": 152,
38
+ "skills": 397,
39
+ "hook_settings_files": 2,
40
+ "notes": "Large ecosystem catalog. High inspiration value, high discoverability-debt risk.",
41
+ },
42
+ {
43
+ "repo": "ChrisWiles/claude-code-showcase",
44
+ "category": "practical-showcase",
45
+ "stars": 5593,
46
+ "updated_at": "2026-03-27T13:13:35Z",
47
+ "commands_md": 6,
48
+ "agents_md": 2,
49
+ "skills": 6,
50
+ "hook_settings_files": 1,
51
+ "notes": "Practical edit-time hooks, branch safety, formatting, and testing patterns.",
52
+ },
53
+ {
54
+ "repo": "disler/claude-code-hooks-mastery",
55
+ "category": "hooks-reference",
56
+ "stars": 3421,
57
+ "updated_at": "2026-03-27T15:49:11Z",
58
+ "commands_md": 21,
59
+ "agents_md": 19,
60
+ "skills": 0,
61
+ "hook_settings_files": 1,
62
+ "notes": "Strong reference for lifecycle breadth, status lines, and operational hook patterns.",
63
+ },
64
+ {
65
+ "repo": "codeaholicguy/ai-devkit",
66
+ "category": "cross-tool",
67
+ "stars": 985,
68
+ "updated_at": "2026-03-27T00:00:00Z",
69
+ "commands_md": 0,
70
+ "agents_md": 0,
71
+ "skills": 0,
72
+ "hook_settings_files": 0,
73
+ "notes": "Cross-tool toolkit positioning benchmark.",
74
+ },
75
+ {
76
+ "repo": "alirezarezvani/claude-code-skill-factory",
77
+ "category": "meta-tooling",
78
+ "stars": 638,
79
+ "updated_at": "2026-03-27T00:00:00Z",
80
+ "commands_md": 0,
81
+ "agents_md": 0,
82
+ "skills": 0,
83
+ "hook_settings_files": 0,
84
+ "notes": "Skill/agent/prompt factory inspiration for creator workflows.",
85
+ },
86
+ ]
87
+
88
+ COMPARISON_MATRIX = [
89
+ {
90
+ "pattern": "plugin-manifest-support",
91
+ "current_state": "implemented",
92
+ "benchmark_signal": "official Claude Code plugin layout",
93
+ "priority": "high",
94
+ "evidence": ["anthropics/claude-code"],
95
+ },
96
+ {
97
+ "pattern": "creator-workflows",
98
+ "current_state": "implemented",
99
+ "benchmark_signal": "meta-tooling for commands, hooks, agents, plugins",
100
+ "priority": "high",
101
+ "evidence": ["anthropics/claude-code", "alirezarezvani/claude-code-skill-factory"],
102
+ },
103
+ {
104
+ "pattern": "lifecycle-breadth",
105
+ "current_state": "implemented",
106
+ "benchmark_signal": "prompt governance, post-tool feedback, subagent hooks, session end",
107
+ "priority": "high",
108
+ "evidence": ["disler/claude-code-hooks-mastery", "ChrisWiles/claude-code-showcase"],
109
+ },
110
+ {
111
+ "pattern": "plugin-packs",
112
+ "current_state": "implemented-experimental",
113
+ "benchmark_signal": "modular domain packaging",
114
+ "priority": "medium",
115
+ "evidence": ["anthropics/claude-code", "affaan-m/everything-claude-code"],
116
+ },
117
+ {
118
+ "pattern": "benchmark-harvesting",
119
+ "current_state": "implemented",
120
+ "benchmark_signal": "repeatable evidence for docs and roadmap decisions",
121
+ "priority": "medium",
122
+ "evidence": ["anthropics/claude-code", "codeaholicguy/ai-devkit"],
123
+ },
124
+ ]
125
+
126
+
127
+ def refresh_online(snapshot: list[dict]) -> list[dict]:
128
+ """Try to refresh star counts from GitHub API."""
129
+ import copy
130
+ rows = copy.deepcopy(snapshot)
131
+ headers = {
132
+ "Accept": "application/vnd.github+json",
133
+ "User-Agent": "ai-toolkit-benchmark-script",
134
+ }
135
+ for item in rows:
136
+ repo = item["repo"]
137
+ url = f"https://api.github.com/repos/{repo}"
138
+ try:
139
+ req = urllib.request.Request(url, headers=headers)
140
+ with urllib.request.urlopen(req, timeout=10) as response:
141
+ data = json.load(response)
142
+ item["stars"] = data.get("stargazers_count", item["stars"])
143
+ item["updated_at"] = data.get("updated_at", item["updated_at"])
144
+ item["source"] = "github-api"
145
+ if data.get("description"):
146
+ item["description"] = data["description"]
147
+ except Exception:
148
+ item["source"] = "snapshot"
149
+ return rows
150
+
151
+
152
+ def annotate_snapshot(snapshot: list[dict]) -> list[dict]:
153
+ """Add source annotation to snapshot data."""
154
+ import copy
155
+ rows = copy.deepcopy(snapshot)
156
+ for row in rows:
157
+ row.setdefault("source", "snapshot")
158
+ return rows
159
+
160
+
161
+ def render_dashboard(rows: list[dict], mode: str) -> dict:
162
+ """Build dashboard JSON."""
163
+ snapshot_date = date.fromisoformat(SNAPSHOT_DATE)
164
+ today = datetime.now(timezone.utc).date()
165
+ age_days = (today - snapshot_date).days
166
+
167
+ def status_for_age(days: int, stale_days: int) -> str:
168
+ if days <= max(7, stale_days // 3):
169
+ return "fresh"
170
+ if days <= stale_days:
171
+ return "aging"
172
+ return "stale"
173
+
174
+ return {
175
+ "generated_at": datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z"),
176
+ "mode": mode,
177
+ "snapshot_date": str(snapshot_date),
178
+ "freshness": {
179
+ "stale_threshold_days": STALE_THRESHOLD_DAYS,
180
+ "age_days": age_days,
181
+ "status": status_for_age(age_days, STALE_THRESHOLD_DAYS),
182
+ },
183
+ "summary": {
184
+ "repo_count": len(rows),
185
+ "stars_total": sum(int(r.get("stars", 0)) for r in rows),
186
+ "categories": sorted({r.get("category", "unknown") for r in rows}),
187
+ "official_repo": "anthropics/claude-code",
188
+ },
189
+ "comparison_matrix": COMPARISON_MATRIX,
190
+ "repos": rows,
191
+ }
192
+
193
+
194
+ def render_markdown(dashboard: dict) -> str:
195
+ """Render dashboard as Markdown."""
196
+ lines: list[str] = []
197
+ data = dashboard
198
+ rows = data["repos"]
199
+
200
+ lines.append("# Claude Ecosystem Benchmark Snapshot")
201
+ lines.append("")
202
+ lines.append("Generated by `scripts/benchmark-ecosystem.sh`.")
203
+ lines.append("")
204
+ lines.append(f"- Snapshot date: `{data['snapshot_date']}`")
205
+ f = data["freshness"]
206
+ lines.append(f"- Freshness: `{f['status']}` ({f['age_days']} day(s) old, threshold {f['stale_threshold_days']} days)")
207
+ lines.append(f"- Mode: `{data['mode']}`")
208
+ lines.append("")
209
+ lines.append("| Repository | Category | Stars | Commands | Agents | Skills | Hook/Settings Files |")
210
+ lines.append("|------------|----------|-------|----------|--------|--------|---------------------|")
211
+ for row in rows:
212
+ lines.append(f"| `{row['repo']}` | {row['category']} | {row['stars']} | {row['commands_md']} | {row['agents_md']} | {row['skills']} | {row['hook_settings_files']} |")
213
+ lines.append("")
214
+ lines.append("## Comparison Matrix")
215
+ lines.append("")
216
+ lines.append("| Pattern | Current State | Benchmark Signal | Priority |")
217
+ lines.append("|---------|---------------|------------------|----------|")
218
+ for row in data["comparison_matrix"]:
219
+ lines.append(f"| `{row['pattern']}` | {row['current_state']} | {row['benchmark_signal']} | {row['priority']} |")
220
+ lines.append("")
221
+ lines.append("## Notes")
222
+ lines.append("")
223
+ for row in rows:
224
+ lines.append(f"- **`{row['repo']}`** — {row['notes']}")
225
+
226
+ return "\n".join(lines)
227
+
228
+
229
+ def main() -> None:
230
+ fmt = "markdown"
231
+ outfile = ""
232
+ offline = False
233
+
234
+ args = sys.argv[1:]
235
+ i = 0
236
+ while i < len(args):
237
+ a = args[i]
238
+ if a == "--offline":
239
+ offline = True
240
+ elif a == "--json":
241
+ fmt = "json"
242
+ elif a == "--dashboard-json":
243
+ fmt = "dashboard-json"
244
+ elif a == "--markdown":
245
+ fmt = "markdown"
246
+ elif a == "--format":
247
+ i += 1
248
+ fmt = args[i] if i < len(args) else "markdown"
249
+ elif a == "--out":
250
+ i += 1
251
+ outfile = args[i] if i < len(args) else ""
252
+ elif a in ("-h", "--help"):
253
+ print(__doc__)
254
+ sys.exit(0)
255
+ else:
256
+ print(f"Unknown option: {a}", file=sys.stderr)
257
+ sys.exit(1)
258
+ i += 1
259
+
260
+ mode = "offline"
261
+ if offline:
262
+ data = annotate_snapshot(SNAPSHOT_DATA)
263
+ else:
264
+ mode = "online"
265
+ try:
266
+ data = refresh_online(SNAPSHOT_DATA)
267
+ except Exception:
268
+ data = annotate_snapshot(SNAPSHOT_DATA)
269
+ mode = "offline"
270
+
271
+ dashboard = render_dashboard(data, mode)
272
+
273
+ if fmt == "json":
274
+ output = json.dumps(data, indent=2)
275
+ elif fmt == "dashboard-json":
276
+ output = json.dumps(dashboard, indent=2)
277
+ else:
278
+ output = render_markdown(dashboard)
279
+
280
+ if outfile:
281
+ Path(outfile).parent.mkdir(parents=True, exist_ok=True)
282
+ Path(outfile).write_text(output + "\n", encoding="utf-8")
283
+ else:
284
+ print(output)
285
+
286
+
287
+ if __name__ == "__main__":
288
+ main()
@@ -0,0 +1,260 @@
1
+ #!/usr/bin/env python3
2
+ """Check required dependencies and tell the user what to install.
3
+
4
+ Detects OS/distro and provides ready-to-copy install commands.
5
+ Called automatically by install.py and doctor.py.
6
+
7
+ Exit codes:
8
+ 0 all required deps present
9
+ 1 missing required deps (printed to stderr)
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import json
14
+ import shutil
15
+ import subprocess
16
+ import sys
17
+ from pathlib import Path
18
+
19
+ # Add scripts/ to path for _common import
20
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
21
+ from _common import detect_os
22
+
23
+
24
+ # ---------------------------------------------------------------------------
25
+ # Dependency definitions
26
+ # ---------------------------------------------------------------------------
27
+
28
+ REQUIRED = [
29
+ {
30
+ "name": "python3",
31
+ "check": "python3",
32
+ "min_version": "3.8",
33
+ "packages": {
34
+ "brew": "python3",
35
+ "apt": "python3",
36
+ "dnf": "python3",
37
+ "pacman": "python3",
38
+ "apk": "python3",
39
+ "zypper": "python3",
40
+ },
41
+ "reason": "All toolkit scripts run on Python 3 (stdlib only, no pip needed)",
42
+ },
43
+ {
44
+ "name": "git",
45
+ "check": "git",
46
+ "packages": {
47
+ "brew": "git",
48
+ "apt": "git",
49
+ "dnf": "git",
50
+ "pacman": "git",
51
+ "apk": "git",
52
+ "zypper": "git",
53
+ },
54
+ "reason": "Version control — hooks, commits, PR workflows",
55
+ },
56
+ {
57
+ "name": "node",
58
+ "check": "node",
59
+ "min_version": "18",
60
+ "packages": {
61
+ "brew": "node",
62
+ "apt": "nodejs",
63
+ "dnf": "nodejs",
64
+ "pacman": "nodejs",
65
+ "apk": "nodejs",
66
+ "zypper": "nodejs18",
67
+ },
68
+ "reason": "CLI entry point (bin/ai-toolkit.js)",
69
+ },
70
+ ]
71
+
72
+ OPTIONAL = [
73
+ {
74
+ "name": "sqlite3",
75
+ "check": "sqlite3",
76
+ "packages": {
77
+ "brew": "sqlite",
78
+ "apt": "sqlite3",
79
+ "dnf": "sqlite",
80
+ "pacman": "sqlite",
81
+ "apk": "sqlite",
82
+ "zypper": "sqlite3",
83
+ },
84
+ "reason": "Memory plugin pack (session persistence via SQLite + FTS5)",
85
+ },
86
+ {
87
+ "name": "bats",
88
+ "check": "bats",
89
+ "packages": {
90
+ "brew": "bats-core",
91
+ "apt": "bats",
92
+ "dnf": "bats",
93
+ "pacman": "bash-bats",
94
+ "apk": "bats",
95
+ "zypper": "bats",
96
+ },
97
+ "reason": "Running toolkit test suite (npm test)",
98
+ },
99
+ ]
100
+
101
+
102
+ # ---------------------------------------------------------------------------
103
+ # Version check helpers
104
+ # ---------------------------------------------------------------------------
105
+
106
+ def get_version(binary: str) -> str:
107
+ """Get version string from a binary."""
108
+ try:
109
+ result = subprocess.run(
110
+ [binary, "--version"],
111
+ capture_output=True,
112
+ text=True,
113
+ timeout=5,
114
+ )
115
+ output = result.stdout.strip() or result.stderr.strip()
116
+ # Extract version number pattern
117
+ import re
118
+ match = re.search(r"(\d+\.\d+(?:\.\d+)?)", output)
119
+ return match.group(1) if match else "unknown"
120
+ except (FileNotFoundError, subprocess.TimeoutExpired):
121
+ return ""
122
+
123
+
124
+ def version_ge(actual: str, minimum: str) -> bool:
125
+ """Check if actual version >= minimum version."""
126
+ try:
127
+ actual_parts = [int(x) for x in actual.split(".")[:3]]
128
+ min_parts = [int(x) for x in minimum.split(".")[:3]]
129
+ # Pad to same length
130
+ while len(actual_parts) < len(min_parts):
131
+ actual_parts.append(0)
132
+ while len(min_parts) < len(actual_parts):
133
+ min_parts.append(0)
134
+ return actual_parts >= min_parts
135
+ except (ValueError, IndexError):
136
+ return True # Can't parse, assume OK
137
+
138
+
139
+ # ---------------------------------------------------------------------------
140
+ # Main check
141
+ # ---------------------------------------------------------------------------
142
+
143
+ def check_deps(verbose: bool = True) -> dict:
144
+ """Check all dependencies and return status report.
145
+
146
+ Returns:
147
+ dict with keys: os_info, required, optional, all_ok, missing_cmds
148
+ """
149
+ os_info = detect_os()
150
+ pkg_mgr = os_info["pkg_manager"]
151
+ install_cmd = os_info["install_cmd"]
152
+
153
+ results: dict = {
154
+ "os_info": os_info,
155
+ "required": [],
156
+ "optional": [],
157
+ "all_ok": True,
158
+ "missing_cmds": [],
159
+ }
160
+
161
+ def check_one(dep: dict, required: bool) -> dict:
162
+ binary = dep["check"]
163
+ found = shutil.which(binary) is not None
164
+ version = get_version(binary) if found else ""
165
+ min_ver = dep.get("min_version", "")
166
+
167
+ ok = found
168
+ version_ok = True
169
+ if found and min_ver and version and version != "unknown":
170
+ version_ok = version_ge(version, min_ver)
171
+ ok = version_ok
172
+
173
+ install_hint = ""
174
+ if not ok and install_cmd and pkg_mgr in dep.get("packages", {}):
175
+ pkg = dep["packages"][pkg_mgr]
176
+ install_hint = f"{install_cmd} {pkg}"
177
+
178
+ return {
179
+ "name": dep["name"],
180
+ "found": found,
181
+ "version": version,
182
+ "version_ok": version_ok,
183
+ "min_version": min_ver,
184
+ "required": required,
185
+ "reason": dep["reason"],
186
+ "install_hint": install_hint,
187
+ }
188
+
189
+ for dep in REQUIRED:
190
+ result = check_one(dep, required=True)
191
+ results["required"].append(result)
192
+ if not result["found"] or not result["version_ok"]:
193
+ results["all_ok"] = False
194
+ if result["install_hint"]:
195
+ results["missing_cmds"].append(result["install_hint"])
196
+
197
+ for dep in OPTIONAL:
198
+ result = check_one(dep, required=False)
199
+ results["optional"].append(result)
200
+
201
+ return results
202
+
203
+
204
+ def print_report(results: dict) -> None:
205
+ """Print human-readable dependency report."""
206
+ os_info = results["os_info"]
207
+ print(f"System: {os_info['os']} ({os_info.get('distro', 'unknown')})")
208
+ print(f"Package manager: {os_info['pkg_manager']}")
209
+ print()
210
+
211
+ print("Required:")
212
+ for dep in results["required"]:
213
+ if dep["found"] and dep["version_ok"]:
214
+ ver = f" ({dep['version']})" if dep["version"] else ""
215
+ print(f" OK {dep['name']}{ver}")
216
+ elif dep["found"] and not dep["version_ok"]:
217
+ print(f" !! {dep['name']} ({dep['version']}) — need >= {dep['min_version']}")
218
+ if dep["install_hint"]:
219
+ print(f" Fix: {dep['install_hint']}")
220
+ else:
221
+ print(f" !! {dep['name']} — NOT FOUND")
222
+ print(f" Why: {dep['reason']}")
223
+ if dep["install_hint"]:
224
+ print(f" Fix: {dep['install_hint']}")
225
+
226
+ print()
227
+ print("Optional:")
228
+ for dep in results["optional"]:
229
+ if dep["found"]:
230
+ ver = f" ({dep['version']})" if dep["version"] else ""
231
+ print(f" OK {dep['name']}{ver}")
232
+ else:
233
+ print(f" -- {dep['name']} — not installed")
234
+ print(f" Why: {dep['reason']}")
235
+ if dep["install_hint"]:
236
+ print(f" Fix: {dep['install_hint']}")
237
+
238
+ if not results["all_ok"]:
239
+ print()
240
+ print("Missing required dependencies! Install with:")
241
+ for cmd in results["missing_cmds"]:
242
+ print(f" {cmd}")
243
+ print()
244
+
245
+
246
+ def main() -> None:
247
+ """CLI entry point."""
248
+ json_mode = "--json" in sys.argv
249
+ results = check_deps()
250
+
251
+ if json_mode:
252
+ print(json.dumps(results, indent=2))
253
+ else:
254
+ print_report(results)
255
+
256
+ sys.exit(0 if results["all_ok"] else 1)
257
+
258
+
259
+ if __name__ == "__main__":
260
+ main()
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env python3
2
+ """ai-toolkit create skill -- Scaffold a new skill from a template.
3
+
4
+ Usage:
5
+ create_skill.py <name> --template=<type> [--description="..."] [--output-dir=<path>]
6
+
7
+ Templates: linter, reviewer, generator, workflow, knowledge
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import re
12
+ import sys
13
+ from pathlib import Path
14
+
15
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
16
+ from _common import toolkit_dir
17
+
18
+
19
+ def _parse_args(argv: list[str]) -> dict[str, str]:
20
+ """Parse CLI arguments into a dict."""
21
+ result: dict[str, str] = {
22
+ "name": "",
23
+ "template": "",
24
+ "description": "",
25
+ "output_dir": str(toolkit_dir / "app" / "skills"),
26
+ }
27
+
28
+ i = 0
29
+ while i < len(argv):
30
+ arg = argv[i]
31
+ if arg.startswith("--template="):
32
+ result["template"] = arg.split("=", 1)[1]
33
+ elif arg == "--template":
34
+ i += 1
35
+ result["template"] = argv[i] if i < len(argv) else ""
36
+ elif arg.startswith("--description="):
37
+ result["description"] = arg.split("=", 1)[1]
38
+ elif arg == "--description":
39
+ i += 1
40
+ result["description"] = argv[i] if i < len(argv) else ""
41
+ elif arg.startswith("--output-dir="):
42
+ result["output_dir"] = arg.split("=", 1)[1]
43
+ elif arg == "--output-dir":
44
+ i += 1
45
+ result["output_dir"] = argv[i] if i < len(argv) else ""
46
+ elif arg.startswith("-"):
47
+ print(f"Unknown option: {arg}", file=sys.stderr)
48
+ sys.exit(1)
49
+ else:
50
+ result["name"] = arg
51
+ i += 1
52
+
53
+ return result
54
+
55
+
56
+ def main() -> None:
57
+ """Scaffold a new skill from a template."""
58
+ args = _parse_args(sys.argv[1:])
59
+ name = args["name"]
60
+ template = args["template"]
61
+ description = args["description"]
62
+ output_dir = Path(args["output_dir"])
63
+ templates_dir = toolkit_dir / "app" / "templates" / "skill"
64
+
65
+ # Validate name
66
+ if not name:
67
+ print("Error: skill name is required", file=sys.stderr)
68
+ print("Usage: ai-toolkit create skill <name> --template=<type>", file=sys.stderr)
69
+ sys.exit(1)
70
+
71
+ if re.search(r"[^a-z0-9-]", name):
72
+ print(f"Error: skill name must be lowercase with hyphens only (got: {name})", file=sys.stderr)
73
+ sys.exit(1)
74
+
75
+ if len(name) > 64:
76
+ print(f"Error: skill name must be at most 64 characters (got: {len(name)})", file=sys.stderr)
77
+ sys.exit(1)
78
+
79
+ # Validate template
80
+ if not template:
81
+ print("Error: --template is required", file=sys.stderr)
82
+ print("Available templates: linter, reviewer, generator, workflow, knowledge", file=sys.stderr)
83
+ sys.exit(1)
84
+
85
+ template_file = templates_dir / template / "SKILL.md.template"
86
+ if not template_file.is_file():
87
+ available = " ".join(
88
+ d.name for d in sorted(templates_dir.iterdir()) if d.is_dir()
89
+ ) if templates_dir.is_dir() else "(none)"
90
+ print(f"Error: unknown template '{template}'", file=sys.stderr)
91
+ print(f"Available templates: {available}", file=sys.stderr)
92
+ sys.exit(1)
93
+
94
+ # Check target does not exist
95
+ target_dir = output_dir / name
96
+ if target_dir.is_dir():
97
+ print(f"Error: skill '{name}' already exists at {target_dir}", file=sys.stderr)
98
+ sys.exit(1)
99
+
100
+ # Default description
101
+ if not description:
102
+ description = f"Provides {name} functionality"
103
+
104
+ # Create skill from template
105
+ target_dir.mkdir(parents=True, exist_ok=True)
106
+ content = template_file.read_text(encoding="utf-8")
107
+ content = content.replace("{{NAME}}", name).replace("{{DESCRIPTION}}", description)
108
+ (target_dir / "SKILL.md").write_text(content, encoding="utf-8")
109
+
110
+ print(f"Created: {target_dir}/SKILL.md (from {template} template)")
111
+ print()
112
+ print("Next steps:")
113
+ print(f" 1. Edit {target_dir}/SKILL.md")
114
+ print(" 2. Run: ai-toolkit validate")
115
+
116
+
117
+ if __name__ == "__main__":
118
+ main()