@r1z4x/tezgah 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 (582) hide show
  1. package/CHANGELOG.md +738 -0
  2. package/LICENSE +21 -0
  3. package/MANIFEST +753 -0
  4. package/README.de.md +169 -0
  5. package/README.es.md +168 -0
  6. package/README.fr.md +166 -0
  7. package/README.md +161 -0
  8. package/README.tr.md +163 -0
  9. package/agents/tezgah-reviewer.md +70 -0
  10. package/bin/codegen +337 -0
  11. package/bin/consult +797 -0
  12. package/bin/tezgah-adhd +50 -0
  13. package/bin/tezgah-agents +45 -0
  14. package/bin/tezgah-capture +66 -0
  15. package/bin/tezgah-context +96 -0
  16. package/bin/tezgah-decisions +213 -0
  17. package/bin/tezgah-design +953 -0
  18. package/bin/tezgah-docs +1199 -0
  19. package/bin/tezgah-doctor +497 -0
  20. package/bin/tezgah-dsh +37 -0
  21. package/bin/tezgah-dsh.cmd +70 -0
  22. package/bin/tezgah-gate +75 -0
  23. package/bin/tezgah-import-ai-research +439 -0
  24. package/bin/tezgah-index +32 -0
  25. package/bin/tezgah-lessons +148 -0
  26. package/bin/tezgah-mcp +322 -0
  27. package/bin/tezgah-migrate +324 -0
  28. package/bin/tezgah-pony +50 -0
  29. package/bin/tezgah-research +772 -0
  30. package/bin/tezgah-rollback +93 -0
  31. package/bin/tezgah-route +124 -0
  32. package/bin/tezgah-setup +5798 -0
  33. package/bin/tezgah-status +383 -0
  34. package/bin/tezgah-task +607 -0
  35. package/bin/tezgah-taste +423 -0
  36. package/bin/tezgah-triage +485 -0
  37. package/bin/tezgah.js +36 -0
  38. package/commands/adhd.md +21 -0
  39. package/commands/ponytail.md +21 -0
  40. package/docs/README.md +112 -0
  41. package/docs/architecture.md +226 -0
  42. package/docs/citations-baseline.json +59 -0
  43. package/docs/clarity-baseline.json +116 -0
  44. package/docs/contract.md +416 -0
  45. package/docs/environment.md +141 -0
  46. package/docs/evidence.md +831 -0
  47. package/docs/feature-audit.md +139 -0
  48. package/docs/gate.md +407 -0
  49. package/docs/glossary.md +201 -0
  50. package/docs/hosts.md +400 -0
  51. package/docs/index.json +471 -0
  52. package/docs/judge.md +193 -0
  53. package/docs/layers.md +189 -0
  54. package/docs/models.md +160 -0
  55. package/docs/operations.md +666 -0
  56. package/docs/research.md +809 -0
  57. package/docs/results/paired-outcome-2026-10.jsonl +254 -0
  58. package/docs/results/paired-outcome-2026-10.md +204 -0
  59. package/docs/skills.md +236 -0
  60. package/docs/status-line.md +315 -0
  61. package/docs/testing.md +287 -0
  62. package/docs/vision.md +117 -0
  63. package/hooks/hooks.json +33 -0
  64. package/hooks/projects-auto-init.py +98 -0
  65. package/hooks/projects-posttooluse.py +149 -0
  66. package/hooks/projects-pretooluse.py +40 -0
  67. package/hooks/projects-stop.py +60 -0
  68. package/hooks/tezgah_agents.py +817 -0
  69. package/hooks/tezgah_apps.py +266 -0
  70. package/hooks/tezgah_attest.py +255 -0
  71. package/hooks/tezgah_clarity.py +171 -0
  72. package/hooks/tezgah_components.py +140 -0
  73. package/hooks/tezgah_context.py +2953 -0
  74. package/hooks/tezgah_embed.py +765 -0
  75. package/hooks/tezgah_gate.py +2736 -0
  76. package/hooks/tezgah_guard.py +177 -0
  77. package/hooks/tezgah_index.py +124 -0
  78. package/hooks/tezgah_integrity.py +5141 -0
  79. package/hooks/tezgah_judge.py +487 -0
  80. package/hooks/tezgah_lang.py +230 -0
  81. package/hooks/tezgah_lessons.py +210 -0
  82. package/hooks/tezgah_models.py +855 -0
  83. package/hooks/tezgah_paths.py +1132 -0
  84. package/hooks/tezgah_policy.py +1039 -0
  85. package/hooks/tezgah_rank.py +77 -0
  86. package/hooks/tezgah_replay.py +1109 -0
  87. package/hooks/tezgah_research.py +5176 -0
  88. package/hooks/tezgah_shapes.py +305 -0
  89. package/hooks/tezgah_skill_pick.py +227 -0
  90. package/hooks/tezgah_snapshot.py +490 -0
  91. package/hooks/tezgah_stopspec.py +320 -0
  92. package/hooks/tezgah_task.py +458 -0
  93. package/hooks/tezgah_taste.py +201 -0
  94. package/hooks/tezgah_untrusted.py +112 -0
  95. package/hooks/tezgah_update.py +430 -0
  96. package/hosts/codex/hook.py +268 -0
  97. package/hosts/codex/hooks.json +26 -0
  98. package/hosts/cursor/hook.py +461 -0
  99. package/hosts/cursor/hooks.json +44 -0
  100. package/hosts/dsh/hooks.json +21 -0
  101. package/hosts/dsh/statusline/lib/client.js +138 -0
  102. package/hosts/dsh/statusline/lib/index.js +104 -0
  103. package/hosts/dsh/statusline/package.json +28 -0
  104. package/hosts/omp/hook.py +277 -0
  105. package/hosts/omp/tezgah-hook.ts.in +701 -0
  106. package/hosts/opencode/plugins/tezgah.js +2742 -0
  107. package/hosts/opencode/tui/tezgah-tui.tsx +151 -0
  108. package/output-styles/tezgah.md +142 -0
  109. package/package.json +32 -0
  110. package/packaging/build.sh +342 -0
  111. package/packaging/install.ps1 +166 -0
  112. package/packaging/install.sh +56 -0
  113. package/packaging/upgrade.sh +142 -0
  114. package/skills/ai-research/0-autoresearch-skill/SKILL.md +411 -0
  115. package/skills/ai-research/0-autoresearch-skill/references/agent-continuity.md +95 -0
  116. package/skills/ai-research/0-autoresearch-skill/references/progress-reporting.md +166 -0
  117. package/skills/ai-research/0-autoresearch-skill/references/skill-routing.md +219 -0
  118. package/skills/ai-research/0-autoresearch-skill/templates/findings.md +44 -0
  119. package/skills/ai-research/0-autoresearch-skill/templates/research-log.md +41 -0
  120. package/skills/ai-research/01-model-architecture/litgpt/SKILL.md +469 -0
  121. package/skills/ai-research/01-model-architecture/litgpt/references/custom-models.md +569 -0
  122. package/skills/ai-research/01-model-architecture/litgpt/references/distributed-training.md +452 -0
  123. package/skills/ai-research/01-model-architecture/litgpt/references/supported-models.md +337 -0
  124. package/skills/ai-research/01-model-architecture/litgpt/references/training-recipes.md +620 -0
  125. package/skills/ai-research/01-model-architecture/mamba/SKILL.md +260 -0
  126. package/skills/ai-research/01-model-architecture/mamba/references/architecture-details.md +207 -0
  127. package/skills/ai-research/01-model-architecture/mamba/references/benchmarks.md +256 -0
  128. package/skills/ai-research/01-model-architecture/mamba/references/training-guide.md +389 -0
  129. package/skills/ai-research/01-model-architecture/nanogpt/SKILL.md +290 -0
  130. package/skills/ai-research/01-model-architecture/nanogpt/references/architecture.md +383 -0
  131. package/skills/ai-research/01-model-architecture/nanogpt/references/data.md +477 -0
  132. package/skills/ai-research/01-model-architecture/nanogpt/references/training.md +565 -0
  133. package/skills/ai-research/01-model-architecture/rwkv/SKILL.md +260 -0
  134. package/skills/ai-research/01-model-architecture/rwkv/references/architecture-details.md +345 -0
  135. package/skills/ai-research/01-model-architecture/rwkv/references/rwkv7.md +387 -0
  136. package/skills/ai-research/01-model-architecture/rwkv/references/state-management.md +370 -0
  137. package/skills/ai-research/01-model-architecture/torchtitan/SKILL.md +358 -0
  138. package/skills/ai-research/01-model-architecture/torchtitan/references/checkpoint.md +182 -0
  139. package/skills/ai-research/01-model-architecture/torchtitan/references/custom-models.md +259 -0
  140. package/skills/ai-research/01-model-architecture/torchtitan/references/float8.md +134 -0
  141. package/skills/ai-research/01-model-architecture/torchtitan/references/fsdp.md +127 -0
  142. package/skills/ai-research/02-tokenization/huggingface-tokenizers/SKILL.md +516 -0
  143. package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/algorithms.md +654 -0
  144. package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/integration.md +638 -0
  145. package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/pipeline.md +724 -0
  146. package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/training.md +566 -0
  147. package/skills/ai-research/02-tokenization/sentencepiece/SKILL.md +235 -0
  148. package/skills/ai-research/02-tokenization/sentencepiece/references/algorithms.md +201 -0
  149. package/skills/ai-research/02-tokenization/sentencepiece/references/training.md +305 -0
  150. package/skills/ai-research/03-fine-tuning/axolotl/SKILL.md +158 -0
  151. package/skills/ai-research/03-fine-tuning/axolotl/references/api.md +5549 -0
  152. package/skills/ai-research/03-fine-tuning/axolotl/references/dataset-formats.md +1030 -0
  153. package/skills/ai-research/03-fine-tuning/axolotl/references/index.md +16 -0
  154. package/skills/ai-research/03-fine-tuning/axolotl/references/other.md +3564 -0
  155. package/skills/ai-research/03-fine-tuning/llama-factory/SKILL.md +80 -0
  156. package/skills/ai-research/03-fine-tuning/llama-factory/references/_images.md +24 -0
  157. package/skills/ai-research/03-fine-tuning/llama-factory/references/advanced.md +1056 -0
  158. package/skills/ai-research/03-fine-tuning/llama-factory/references/getting_started.md +350 -0
  159. package/skills/ai-research/03-fine-tuning/llama-factory/references/index.md +20 -0
  160. package/skills/ai-research/03-fine-tuning/llama-factory/references/other.md +32 -0
  161. package/skills/ai-research/03-fine-tuning/peft/SKILL.md +431 -0
  162. package/skills/ai-research/03-fine-tuning/peft/references/advanced-usage.md +515 -0
  163. package/skills/ai-research/03-fine-tuning/peft/references/troubleshooting.md +481 -0
  164. package/skills/ai-research/03-fine-tuning/unsloth/SKILL.md +80 -0
  165. package/skills/ai-research/03-fine-tuning/unsloth/references/index.md +8 -0
  166. package/skills/ai-research/03-fine-tuning/unsloth/references/llms.md +83 -0
  167. package/skills/ai-research/04-mechanistic-interpretability/nnsight/SKILL.md +436 -0
  168. package/skills/ai-research/04-mechanistic-interpretability/nnsight/references/README.md +79 -0
  169. package/skills/ai-research/04-mechanistic-interpretability/nnsight/references/api.md +345 -0
  170. package/skills/ai-research/04-mechanistic-interpretability/nnsight/references/tutorials.md +301 -0
  171. package/skills/ai-research/04-mechanistic-interpretability/pyvene/SKILL.md +473 -0
  172. package/skills/ai-research/04-mechanistic-interpretability/pyvene/references/README.md +74 -0
  173. package/skills/ai-research/04-mechanistic-interpretability/pyvene/references/api.md +384 -0
  174. package/skills/ai-research/04-mechanistic-interpretability/pyvene/references/tutorials.md +377 -0
  175. package/skills/ai-research/04-mechanistic-interpretability/saelens/SKILL.md +386 -0
  176. package/skills/ai-research/04-mechanistic-interpretability/saelens/references/README.md +71 -0
  177. package/skills/ai-research/04-mechanistic-interpretability/saelens/references/api.md +334 -0
  178. package/skills/ai-research/04-mechanistic-interpretability/saelens/references/tutorials.md +319 -0
  179. package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/SKILL.md +346 -0
  180. package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/references/README.md +55 -0
  181. package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/references/api.md +363 -0
  182. package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/references/tutorials.md +340 -0
  183. package/skills/ai-research/05-data-processing/nemo-curator/SKILL.md +383 -0
  184. package/skills/ai-research/05-data-processing/nemo-curator/references/deduplication.md +88 -0
  185. package/skills/ai-research/05-data-processing/nemo-curator/references/filtering.md +103 -0
  186. package/skills/ai-research/05-data-processing/ray-data/SKILL.md +326 -0
  187. package/skills/ai-research/05-data-processing/ray-data/references/integration.md +83 -0
  188. package/skills/ai-research/05-data-processing/ray-data/references/transformations.md +84 -0
  189. package/skills/ai-research/06-post-training/grpo-rl-training/README.md +98 -0
  190. package/skills/ai-research/06-post-training/grpo-rl-training/SKILL.md +572 -0
  191. package/skills/ai-research/06-post-training/miles/SKILL.md +315 -0
  192. package/skills/ai-research/06-post-training/miles/references/api-reference.md +142 -0
  193. package/skills/ai-research/06-post-training/miles/references/troubleshooting.md +353 -0
  194. package/skills/ai-research/06-post-training/openrlhf/SKILL.md +249 -0
  195. package/skills/ai-research/06-post-training/openrlhf/references/algorithm-comparison.md +405 -0
  196. package/skills/ai-research/06-post-training/openrlhf/references/custom-rewards.md +531 -0
  197. package/skills/ai-research/06-post-training/openrlhf/references/hybrid-engine.md +288 -0
  198. package/skills/ai-research/06-post-training/openrlhf/references/multi-node-training.md +455 -0
  199. package/skills/ai-research/06-post-training/simpo/SKILL.md +219 -0
  200. package/skills/ai-research/06-post-training/simpo/references/datasets.md +479 -0
  201. package/skills/ai-research/06-post-training/simpo/references/hyperparameters.md +453 -0
  202. package/skills/ai-research/06-post-training/simpo/references/loss-functions.md +351 -0
  203. package/skills/ai-research/06-post-training/slime/SKILL.md +464 -0
  204. package/skills/ai-research/06-post-training/slime/references/api-reference.md +393 -0
  205. package/skills/ai-research/06-post-training/slime/references/troubleshooting.md +387 -0
  206. package/skills/ai-research/06-post-training/torchforge/SKILL.md +433 -0
  207. package/skills/ai-research/06-post-training/torchforge/references/api-reference.md +328 -0
  208. package/skills/ai-research/06-post-training/torchforge/references/troubleshooting.md +410 -0
  209. package/skills/ai-research/06-post-training/trl-fine-tuning/SKILL.md +455 -0
  210. package/skills/ai-research/06-post-training/trl-fine-tuning/references/dpo-variants.md +228 -0
  211. package/skills/ai-research/06-post-training/trl-fine-tuning/references/online-rl.md +83 -0
  212. package/skills/ai-research/06-post-training/trl-fine-tuning/references/reward-modeling.md +123 -0
  213. package/skills/ai-research/06-post-training/trl-fine-tuning/references/sft-training.md +169 -0
  214. package/skills/ai-research/06-post-training/verl/SKILL.md +391 -0
  215. package/skills/ai-research/06-post-training/verl/references/api-reference.md +302 -0
  216. package/skills/ai-research/06-post-training/verl/references/troubleshooting.md +392 -0
  217. package/skills/ai-research/07-safety-alignment/constitutional-ai/SKILL.md +290 -0
  218. package/skills/ai-research/07-safety-alignment/llamaguard/SKILL.md +337 -0
  219. package/skills/ai-research/07-safety-alignment/nemo-guardrails/SKILL.md +297 -0
  220. package/skills/ai-research/07-safety-alignment/prompt-guard/SKILL.md +312 -0
  221. package/skills/ai-research/08-distributed-training/accelerate/SKILL.md +332 -0
  222. package/skills/ai-research/08-distributed-training/accelerate/references/custom-plugins.md +454 -0
  223. package/skills/ai-research/08-distributed-training/accelerate/references/megatron-integration.md +490 -0
  224. package/skills/ai-research/08-distributed-training/accelerate/references/performance.md +526 -0
  225. package/skills/ai-research/08-distributed-training/deepspeed/SKILL.md +141 -0
  226. package/skills/ai-research/08-distributed-training/deepspeed/references/08.md +18 -0
  227. package/skills/ai-research/08-distributed-training/deepspeed/references/09.md +174 -0
  228. package/skills/ai-research/08-distributed-training/deepspeed/references/2020.md +379 -0
  229. package/skills/ai-research/08-distributed-training/deepspeed/references/2023.md +280 -0
  230. package/skills/ai-research/08-distributed-training/deepspeed/references/assets.md +180 -0
  231. package/skills/ai-research/08-distributed-training/deepspeed/references/index.md +36 -0
  232. package/skills/ai-research/08-distributed-training/deepspeed/references/mii.md +119 -0
  233. package/skills/ai-research/08-distributed-training/deepspeed/references/other.md +1192 -0
  234. package/skills/ai-research/08-distributed-training/megatron-core/SKILL.md +366 -0
  235. package/skills/ai-research/08-distributed-training/megatron-core/references/benchmarks.md +250 -0
  236. package/skills/ai-research/08-distributed-training/megatron-core/references/parallelism-guide.md +405 -0
  237. package/skills/ai-research/08-distributed-training/megatron-core/references/production-examples.md +474 -0
  238. package/skills/ai-research/08-distributed-training/megatron-core/references/training-recipes.md +548 -0
  239. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/SKILL.md +231 -0
  240. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_dcp_async_recipe.md +14 -0
  241. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_dcp_overview.md +19 -0
  242. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_dcp_recipe.md +18 -0
  243. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_ddp_notes.md +10 -0
  244. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_device_mesh_tutorial.md +22 -0
  245. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_examples_fsdp2.md +15 -0
  246. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_fsdp1_api.md +9 -0
  247. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_fsdp2_tutorial.md +45 -0
  248. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_fully_shard_api.md +49 -0
  249. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_tp_tutorial.md +22 -0
  250. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/ray_train_fsdp2_example.md +13 -0
  251. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/torchtitan_fsdp_notes.md +14 -0
  252. package/skills/ai-research/08-distributed-training/pytorch-lightning/SKILL.md +346 -0
  253. package/skills/ai-research/08-distributed-training/pytorch-lightning/references/callbacks.md +437 -0
  254. package/skills/ai-research/08-distributed-training/pytorch-lightning/references/distributed.md +491 -0
  255. package/skills/ai-research/08-distributed-training/pytorch-lightning/references/hyperparameter-tuning.md +557 -0
  256. package/skills/ai-research/08-distributed-training/ray-train/SKILL.md +406 -0
  257. package/skills/ai-research/08-distributed-training/ray-train/references/multi-node.md +629 -0
  258. package/skills/ai-research/09-infrastructure/lambda-labs/SKILL.md +545 -0
  259. package/skills/ai-research/09-infrastructure/lambda-labs/references/advanced-usage.md +612 -0
  260. package/skills/ai-research/09-infrastructure/lambda-labs/references/troubleshooting.md +531 -0
  261. package/skills/ai-research/09-infrastructure/modal/SKILL.md +341 -0
  262. package/skills/ai-research/09-infrastructure/modal/references/advanced-usage.md +504 -0
  263. package/skills/ai-research/09-infrastructure/modal/references/troubleshooting.md +495 -0
  264. package/skills/ai-research/09-infrastructure/skypilot/SKILL.md +509 -0
  265. package/skills/ai-research/09-infrastructure/skypilot/references/advanced-usage.md +492 -0
  266. package/skills/ai-research/09-infrastructure/skypilot/references/troubleshooting.md +571 -0
  267. package/skills/ai-research/10-optimization/awq/SKILL.md +310 -0
  268. package/skills/ai-research/10-optimization/awq/references/advanced-usage.md +325 -0
  269. package/skills/ai-research/10-optimization/awq/references/troubleshooting.md +345 -0
  270. package/skills/ai-research/10-optimization/bitsandbytes/SKILL.md +411 -0
  271. package/skills/ai-research/10-optimization/bitsandbytes/references/memory-optimization.md +522 -0
  272. package/skills/ai-research/10-optimization/bitsandbytes/references/qlora-training.md +522 -0
  273. package/skills/ai-research/10-optimization/bitsandbytes/references/quantization-formats.md +448 -0
  274. package/skills/ai-research/10-optimization/flash-attention/SKILL.md +367 -0
  275. package/skills/ai-research/10-optimization/flash-attention/references/benchmarks.md +216 -0
  276. package/skills/ai-research/10-optimization/flash-attention/references/transformers-integration.md +294 -0
  277. package/skills/ai-research/10-optimization/gguf/SKILL.md +427 -0
  278. package/skills/ai-research/10-optimization/gguf/references/advanced-usage.md +505 -0
  279. package/skills/ai-research/10-optimization/gguf/references/troubleshooting.md +443 -0
  280. package/skills/ai-research/10-optimization/gptq/SKILL.md +450 -0
  281. package/skills/ai-research/10-optimization/gptq/references/calibration.md +338 -0
  282. package/skills/ai-research/10-optimization/gptq/references/integration.md +130 -0
  283. package/skills/ai-research/10-optimization/gptq/references/troubleshooting.md +96 -0
  284. package/skills/ai-research/10-optimization/hqq/SKILL.md +445 -0
  285. package/skills/ai-research/10-optimization/hqq/references/advanced-usage.md +529 -0
  286. package/skills/ai-research/10-optimization/hqq/references/troubleshooting.md +504 -0
  287. package/skills/ai-research/10-optimization/ml-training-recipes/SKILL.md +319 -0
  288. package/skills/ai-research/10-optimization/ml-training-recipes/references/architecture.md +320 -0
  289. package/skills/ai-research/10-optimization/ml-training-recipes/references/biomedical.md +498 -0
  290. package/skills/ai-research/10-optimization/ml-training-recipes/references/domain-specific.md +626 -0
  291. package/skills/ai-research/10-optimization/ml-training-recipes/references/experiment-loop.md +129 -0
  292. package/skills/ai-research/10-optimization/ml-training-recipes/references/optimizers.md +330 -0
  293. package/skills/ai-research/10-optimization/ml-training-recipes/references/scaling-and-selection.md +428 -0
  294. package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/SKILL.md +405 -0
  295. package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/references/benchmarks.md +394 -0
  296. package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/references/custom-tasks.md +425 -0
  297. package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/references/issues.md +395 -0
  298. package/skills/ai-research/11-evaluation/lm-evaluation-harness/SKILL.md +490 -0
  299. package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/api-evaluation.md +491 -0
  300. package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/benchmark-guide.md +489 -0
  301. package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/custom-tasks.md +603 -0
  302. package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/distributed-eval.md +520 -0
  303. package/skills/ai-research/11-evaluation/nemo-evaluator/SKILL.md +494 -0
  304. package/skills/ai-research/11-evaluation/nemo-evaluator/references/adapter-system.md +341 -0
  305. package/skills/ai-research/11-evaluation/nemo-evaluator/references/configuration.md +448 -0
  306. package/skills/ai-research/11-evaluation/nemo-evaluator/references/custom-benchmarks.md +316 -0
  307. package/skills/ai-research/11-evaluation/nemo-evaluator/references/execution-backends.md +362 -0
  308. package/skills/ai-research/12-inference-serving/llama-cpp/SKILL.md +258 -0
  309. package/skills/ai-research/12-inference-serving/llama-cpp/references/optimization.md +90 -0
  310. package/skills/ai-research/12-inference-serving/llama-cpp/references/quantization.md +214 -0
  311. package/skills/ai-research/12-inference-serving/llama-cpp/references/server.md +126 -0
  312. package/skills/ai-research/12-inference-serving/sglang/SKILL.md +442 -0
  313. package/skills/ai-research/12-inference-serving/sglang/references/deployment.md +491 -0
  314. package/skills/ai-research/12-inference-serving/sglang/references/radix-attention.md +414 -0
  315. package/skills/ai-research/12-inference-serving/sglang/references/structured-generation.md +542 -0
  316. package/skills/ai-research/12-inference-serving/tensorrt-llm/SKILL.md +187 -0
  317. package/skills/ai-research/12-inference-serving/tensorrt-llm/references/multi-gpu.md +299 -0
  318. package/skills/ai-research/12-inference-serving/tensorrt-llm/references/optimization.md +243 -0
  319. package/skills/ai-research/12-inference-serving/tensorrt-llm/references/serving.md +471 -0
  320. package/skills/ai-research/12-inference-serving/vllm/SKILL.md +364 -0
  321. package/skills/ai-research/12-inference-serving/vllm/references/optimization.md +227 -0
  322. package/skills/ai-research/12-inference-serving/vllm/references/quantization.md +285 -0
  323. package/skills/ai-research/12-inference-serving/vllm/references/server-deployment.md +256 -0
  324. package/skills/ai-research/12-inference-serving/vllm/references/troubleshooting.md +448 -0
  325. package/skills/ai-research/13-mlops/mlflow/SKILL.md +704 -0
  326. package/skills/ai-research/13-mlops/mlflow/references/deployment.md +745 -0
  327. package/skills/ai-research/13-mlops/mlflow/references/model-registry.md +771 -0
  328. package/skills/ai-research/13-mlops/mlflow/references/tracking.md +681 -0
  329. package/skills/ai-research/13-mlops/swanlab/SKILL.md +406 -0
  330. package/skills/ai-research/13-mlops/swanlab/references/integrations.md +305 -0
  331. package/skills/ai-research/13-mlops/swanlab/references/visualization.md +234 -0
  332. package/skills/ai-research/13-mlops/tensorboard/SKILL.md +629 -0
  333. package/skills/ai-research/13-mlops/tensorboard/references/integrations.md +639 -0
  334. package/skills/ai-research/13-mlops/tensorboard/references/profiling.md +546 -0
  335. package/skills/ai-research/13-mlops/tensorboard/references/visualization.md +621 -0
  336. package/skills/ai-research/13-mlops/weights-and-biases/SKILL.md +590 -0
  337. package/skills/ai-research/13-mlops/weights-and-biases/references/artifacts.md +585 -0
  338. package/skills/ai-research/13-mlops/weights-and-biases/references/integrations.md +701 -0
  339. package/skills/ai-research/13-mlops/weights-and-biases/references/sweeps.md +848 -0
  340. package/skills/ai-research/14-agents/a-evolve/SKILL.md +383 -0
  341. package/skills/ai-research/14-agents/a-evolve/references/README.md +831 -0
  342. package/skills/ai-research/14-agents/a-evolve/references/api.md +594 -0
  343. package/skills/ai-research/14-agents/a-evolve/references/architecture.md +417 -0
  344. package/skills/ai-research/14-agents/a-evolve/references/design-patterns.md +462 -0
  345. package/skills/ai-research/14-agents/a-evolve/references/examples.md +352 -0
  346. package/skills/ai-research/14-agents/a-evolve/references/issues.md +591 -0
  347. package/skills/ai-research/14-agents/a-evolve/references/releases.md +112 -0
  348. package/skills/ai-research/14-agents/a-evolve/references/tutorials.md +819 -0
  349. package/skills/ai-research/14-agents/autogpt/SKILL.md +403 -0
  350. package/skills/ai-research/14-agents/autogpt/references/advanced-usage.md +536 -0
  351. package/skills/ai-research/14-agents/autogpt/references/troubleshooting.md +421 -0
  352. package/skills/ai-research/14-agents/crewai/SKILL.md +498 -0
  353. package/skills/ai-research/14-agents/crewai/references/flows.md +439 -0
  354. package/skills/ai-research/14-agents/crewai/references/tools.md +430 -0
  355. package/skills/ai-research/14-agents/crewai/references/troubleshooting.md +481 -0
  356. package/skills/ai-research/14-agents/langchain/SKILL.md +480 -0
  357. package/skills/ai-research/14-agents/langchain/references/agents.md +500 -0
  358. package/skills/ai-research/14-agents/langchain/references/integration.md +563 -0
  359. package/skills/ai-research/14-agents/langchain/references/rag.md +601 -0
  360. package/skills/ai-research/14-agents/llamaindex/SKILL.md +569 -0
  361. package/skills/ai-research/14-agents/llamaindex/references/agents.md +84 -0
  362. package/skills/ai-research/14-agents/llamaindex/references/data_connectors.md +109 -0
  363. package/skills/ai-research/14-agents/llamaindex/references/query_engines.md +407 -0
  364. package/skills/ai-research/15-rag/chroma/SKILL.md +406 -0
  365. package/skills/ai-research/15-rag/chroma/references/integration.md +39 -0
  366. package/skills/ai-research/15-rag/faiss/SKILL.md +221 -0
  367. package/skills/ai-research/15-rag/faiss/references/index_types.md +281 -0
  368. package/skills/ai-research/15-rag/pinecone/SKILL.md +358 -0
  369. package/skills/ai-research/15-rag/pinecone/references/deployment.md +182 -0
  370. package/skills/ai-research/15-rag/qdrant/SKILL.md +493 -0
  371. package/skills/ai-research/15-rag/qdrant/references/advanced-usage.md +649 -0
  372. package/skills/ai-research/15-rag/qdrant/references/troubleshooting.md +632 -0
  373. package/skills/ai-research/15-rag/sentence-transformers/SKILL.md +255 -0
  374. package/skills/ai-research/15-rag/sentence-transformers/references/models.md +124 -0
  375. package/skills/ai-research/16-prompt-engineering/dspy/SKILL.md +590 -0
  376. package/skills/ai-research/16-prompt-engineering/dspy/references/examples.md +664 -0
  377. package/skills/ai-research/16-prompt-engineering/dspy/references/modules.md +476 -0
  378. package/skills/ai-research/16-prompt-engineering/dspy/references/optimizers.md +567 -0
  379. package/skills/ai-research/16-prompt-engineering/guidance/SKILL.md +572 -0
  380. package/skills/ai-research/16-prompt-engineering/guidance/references/backends.md +555 -0
  381. package/skills/ai-research/16-prompt-engineering/guidance/references/constraints.md +675 -0
  382. package/skills/ai-research/16-prompt-engineering/guidance/references/examples.md +768 -0
  383. package/skills/ai-research/16-prompt-engineering/instructor/SKILL.md +740 -0
  384. package/skills/ai-research/16-prompt-engineering/instructor/references/examples.md +108 -0
  385. package/skills/ai-research/16-prompt-engineering/instructor/references/providers.md +71 -0
  386. package/skills/ai-research/16-prompt-engineering/instructor/references/validation.md +607 -0
  387. package/skills/ai-research/16-prompt-engineering/outlines/SKILL.md +652 -0
  388. package/skills/ai-research/16-prompt-engineering/outlines/references/backends.md +616 -0
  389. package/skills/ai-research/16-prompt-engineering/outlines/references/examples.md +774 -0
  390. package/skills/ai-research/16-prompt-engineering/outlines/references/json_generation.md +653 -0
  391. package/skills/ai-research/17-observability/langsmith/SKILL.md +422 -0
  392. package/skills/ai-research/17-observability/langsmith/references/advanced-usage.md +549 -0
  393. package/skills/ai-research/17-observability/langsmith/references/troubleshooting.md +538 -0
  394. package/skills/ai-research/17-observability/phoenix/SKILL.md +475 -0
  395. package/skills/ai-research/17-observability/phoenix/references/advanced-usage.md +620 -0
  396. package/skills/ai-research/17-observability/phoenix/references/troubleshooting.md +539 -0
  397. package/skills/ai-research/18-multimodal/audiocraft/SKILL.md +564 -0
  398. package/skills/ai-research/18-multimodal/audiocraft/references/advanced-usage.md +667 -0
  399. package/skills/ai-research/18-multimodal/audiocraft/references/troubleshooting.md +505 -0
  400. package/skills/ai-research/18-multimodal/blip-2/SKILL.md +564 -0
  401. package/skills/ai-research/18-multimodal/blip-2/references/advanced-usage.md +681 -0
  402. package/skills/ai-research/18-multimodal/blip-2/references/troubleshooting.md +527 -0
  403. package/skills/ai-research/18-multimodal/clip/SKILL.md +253 -0
  404. package/skills/ai-research/18-multimodal/clip/references/applications.md +208 -0
  405. package/skills/ai-research/18-multimodal/cosmos-policy/SKILL.md +402 -0
  406. package/skills/ai-research/18-multimodal/cosmos-policy/references/libero-commands.md +175 -0
  407. package/skills/ai-research/18-multimodal/cosmos-policy/references/robocasa-commands.md +147 -0
  408. package/skills/ai-research/18-multimodal/llava/SKILL.md +304 -0
  409. package/skills/ai-research/18-multimodal/llava/references/training.md +198 -0
  410. package/skills/ai-research/18-multimodal/openpi/SKILL.md +480 -0
  411. package/skills/ai-research/18-multimodal/openpi/references/checkpoints-and-env-map.md +86 -0
  412. package/skills/ai-research/18-multimodal/openpi/references/config-recipes.md +50 -0
  413. package/skills/ai-research/18-multimodal/openpi/references/pytorch-gotchas.md +49 -0
  414. package/skills/ai-research/18-multimodal/openpi/references/remote-client-pattern.md +48 -0
  415. package/skills/ai-research/18-multimodal/openpi/references/training-debugging.md +46 -0
  416. package/skills/ai-research/18-multimodal/openvla-oft/SKILL.md +441 -0
  417. package/skills/ai-research/18-multimodal/openvla-oft/references/aloha-workflow.md +141 -0
  418. package/skills/ai-research/18-multimodal/openvla-oft/references/config-troubleshooting.md +97 -0
  419. package/skills/ai-research/18-multimodal/openvla-oft/references/libero-workflow.md +115 -0
  420. package/skills/ai-research/18-multimodal/openvla-oft/references/paper-and-checkpoints.md +84 -0
  421. package/skills/ai-research/18-multimodal/segment-anything/SKILL.md +500 -0
  422. package/skills/ai-research/18-multimodal/segment-anything/references/advanced-usage.md +590 -0
  423. package/skills/ai-research/18-multimodal/segment-anything/references/troubleshooting.md +485 -0
  424. package/skills/ai-research/18-multimodal/stable-diffusion/SKILL.md +519 -0
  425. package/skills/ai-research/18-multimodal/stable-diffusion/references/advanced-usage.md +717 -0
  426. package/skills/ai-research/18-multimodal/stable-diffusion/references/troubleshooting.md +556 -0
  427. package/skills/ai-research/18-multimodal/whisper/SKILL.md +317 -0
  428. package/skills/ai-research/18-multimodal/whisper/references/languages.md +190 -0
  429. package/skills/ai-research/19-emerging-techniques/knowledge-distillation/SKILL.md +458 -0
  430. package/skills/ai-research/19-emerging-techniques/knowledge-distillation/references/minillm.md +335 -0
  431. package/skills/ai-research/19-emerging-techniques/long-context/SKILL.md +536 -0
  432. package/skills/ai-research/19-emerging-techniques/long-context/references/extension_methods.md +469 -0
  433. package/skills/ai-research/19-emerging-techniques/long-context/references/fine_tuning.md +612 -0
  434. package/skills/ai-research/19-emerging-techniques/long-context/references/rope.md +403 -0
  435. package/skills/ai-research/19-emerging-techniques/model-merging/SKILL.md +497 -0
  436. package/skills/ai-research/19-emerging-techniques/model-merging/references/coefficient-tuning.md +415 -0
  437. package/skills/ai-research/19-emerging-techniques/model-merging/references/evaluation.md +463 -0
  438. package/skills/ai-research/19-emerging-techniques/model-merging/references/examples.md +429 -0
  439. package/skills/ai-research/19-emerging-techniques/model-merging/references/methods.md +353 -0
  440. package/skills/ai-research/19-emerging-techniques/model-pruning/SKILL.md +495 -0
  441. package/skills/ai-research/19-emerging-techniques/model-pruning/references/wanda.md +348 -0
  442. package/skills/ai-research/19-emerging-techniques/moe-training/SKILL.md +526 -0
  443. package/skills/ai-research/19-emerging-techniques/moe-training/references/architectures.md +433 -0
  444. package/skills/ai-research/19-emerging-techniques/moe-training/references/inference.md +349 -0
  445. package/skills/ai-research/19-emerging-techniques/moe-training/references/training.md +426 -0
  446. package/skills/ai-research/19-emerging-techniques/speculative-decoding/SKILL.md +467 -0
  447. package/skills/ai-research/19-emerging-techniques/speculative-decoding/references/lookahead.md +310 -0
  448. package/skills/ai-research/19-emerging-techniques/speculative-decoding/references/medusa.md +351 -0
  449. package/skills/ai-research/20-ml-paper-writing/academic-plotting/SKILL.md +479 -0
  450. package/skills/ai-research/20-ml-paper-writing/academic-plotting/references/data-visualization.md +509 -0
  451. package/skills/ai-research/20-ml-paper-writing/academic-plotting/references/diagram-generation.md +395 -0
  452. package/skills/ai-research/20-ml-paper-writing/academic-plotting/references/style-guide.md +305 -0
  453. package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/SKILL.md +982 -0
  454. package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/checklists.md +348 -0
  455. package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/citation-workflow.md +563 -0
  456. package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/reviewer-guidelines.md +349 -0
  457. package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/sources.md +165 -0
  458. package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/writing-guide.md +477 -0
  459. package/skills/ai-research/20-ml-paper-writing/presenting-conference-talks/SKILL.md +298 -0
  460. package/skills/ai-research/20-ml-paper-writing/presenting-conference-talks/references/slide-templates.md +505 -0
  461. package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/SKILL.md +270 -0
  462. package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/checklist.md +279 -0
  463. package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/reviewer-guidelines.md +116 -0
  464. package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/section-blueprints.md +400 -0
  465. package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/systems-conferences.md +261 -0
  466. package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/writing-patterns.md +231 -0
  467. package/skills/ai-research/21-research-ideation/brainstorming-research-ideas/SKILL.md +384 -0
  468. package/skills/ai-research/21-research-ideation/creative-thinking-for-research/SKILL.md +366 -0
  469. package/skills/ai-research/22-agent-native-research-artifact/compiler/SKILL.md +245 -0
  470. package/skills/ai-research/22-agent-native-research-artifact/compiler/references/ara-schema.md +439 -0
  471. package/skills/ai-research/22-agent-native-research-artifact/compiler/references/exploration-tree-spec.md +125 -0
  472. package/skills/ai-research/22-agent-native-research-artifact/compiler/references/validation-checklist.md +149 -0
  473. package/skills/ai-research/22-agent-native-research-artifact/research-manager/SKILL.md +324 -0
  474. package/skills/ai-research/22-agent-native-research-artifact/research-manager/references/event-taxonomy.md +124 -0
  475. package/skills/ai-research/22-agent-native-research-artifact/research-manager/references/provenance-tags.md +190 -0
  476. package/skills/ai-research/22-agent-native-research-artifact/research-manager/references/session-protocol.md +162 -0
  477. package/skills/ai-research/22-agent-native-research-artifact/rigor-reviewer/SKILL.md +322 -0
  478. package/skills/ai-research/22-agent-native-research-artifact/rigor-reviewer/references/review-dimensions.md +182 -0
  479. package/skills/ai-research/SKILL.md +101 -0
  480. package/skills/ai-research/SOURCE +38 -0
  481. package/skills/ai-research/index/1-frame.md +18 -0
  482. package/skills/ai-research/index/2-data.md +21 -0
  483. package/skills/ai-research/index/3-train.md +48 -0
  484. package/skills/ai-research/index/4-measure.md +25 -0
  485. package/skills/ai-research/index/5-run.md +23 -0
  486. package/skills/ai-research/index/6-write.md +35 -0
  487. package/skills/ai-research/library.json +3456 -0
  488. package/skills/analyze-app/EVALS.md +82 -0
  489. package/skills/analyze-app/SKILL.md +188 -0
  490. package/skills/design-contract/EVALS.md +80 -0
  491. package/skills/design-contract/SKILL.md +171 -0
  492. package/skills/design-library/EVALS.md +85 -0
  493. package/skills/design-library/INDEX.md +59 -0
  494. package/skills/design-library/SKILL.md +58 -0
  495. package/skills/design-library/SOURCE +131 -0
  496. package/skills/design-library/adaptive-interfaces/skills/colour-independence/SKILL.md +90 -0
  497. package/skills/design-library/adaptive-interfaces/skills/flexible-typography/SKILL.md +83 -0
  498. package/skills/design-library/adaptive-interfaces/skills/information-density/SKILL.md +87 -0
  499. package/skills/design-library/adaptive-interfaces/skills/preference-audit/SKILL.md +70 -0
  500. package/skills/design-library/adaptive-interfaces/skills/responsive-accessibility/SKILL.md +86 -0
  501. package/skills/design-library/adaptive-interfaces/skills/responsive-review/SKILL.md +76 -0
  502. package/skills/design-library/adaptive-interfaces/skills/simplified-views/SKILL.md +97 -0
  503. package/skills/design-library/adaptive-interfaces/skills/specify/SKILL.md +63 -0
  504. package/skills/design-library/adaptive-interfaces/skills/user-preference-respect/SKILL.md +100 -0
  505. package/skills/design-library/cognitive-accessibility/skills/adaptive-personalisation/SKILL.md +61 -0
  506. package/skills/design-library/cognitive-accessibility/skills/assess-load/SKILL.md +48 -0
  507. package/skills/design-library/cognitive-accessibility/skills/cognitive-load-assessment/SKILL.md +60 -0
  508. package/skills/design-library/cognitive-accessibility/skills/contextual-help-design/SKILL.md +61 -0
  509. package/skills/design-library/cognitive-accessibility/skills/error-prevention-recovery/SKILL.md +71 -0
  510. package/skills/design-library/cognitive-accessibility/skills/focus-attention-design/SKILL.md +67 -0
  511. package/skills/design-library/cognitive-accessibility/skills/memory-load-reduction/SKILL.md +60 -0
  512. package/skills/design-library/cognitive-accessibility/skills/plain-language-design/SKILL.md +78 -0
  513. package/skills/design-library/cognitive-accessibility/skills/review/SKILL.md +56 -0
  514. package/skills/design-library/cognitive-accessibility/skills/simplify/SKILL.md +39 -0
  515. package/skills/design-library/cognitive-accessibility/skills/wayfinding-navigation/SKILL.md +64 -0
  516. package/skills/design-library/design-research/skills/behavioural-analytics/SKILL.md +33 -0
  517. package/skills/design-library/design-research/skills/qual-quant-triangulation/SKILL.md +33 -0
  518. package/skills/design-library/inclusive-interaction/skills/audit/SKILL.md +50 -0
  519. package/skills/design-library/inclusive-interaction/skills/design-flow/SKILL.md +58 -0
  520. package/skills/design-library/inclusive-interaction/skills/feedback-and-status/SKILL.md +76 -0
  521. package/skills/design-library/inclusive-interaction/skills/gesture-alternatives/SKILL.md +70 -0
  522. package/skills/design-library/inclusive-interaction/skills/keyboard-navigation/SKILL.md +99 -0
  523. package/skills/design-library/inclusive-interaction/skills/keyboard-review/SKILL.md +54 -0
  524. package/skills/design-library/inclusive-interaction/skills/motion-sensitivity/SKILL.md +79 -0
  525. package/skills/design-library/inclusive-interaction/skills/multi-modal-input/SKILL.md +70 -0
  526. package/skills/design-library/inclusive-interaction/skills/touch-target-design/SKILL.md +71 -0
  527. package/skills/design-library/inclusive-interaction/skills/voice-interaction/SKILL.md +68 -0
  528. package/skills/design-library/visual-critique/skills/critique-affordance/SKILL.md +45 -0
  529. package/skills/design-library/visual-critique/skills/critique-brand-consistency/SKILL.md +42 -0
  530. package/skills/design-library/visual-critique/skills/critique-color/SKILL.md +44 -0
  531. package/skills/design-library/visual-critique/skills/critique-composition/SKILL.md +46 -0
  532. package/skills/design-library/visual-critique/skills/critique-information-density/SKILL.md +45 -0
  533. package/skills/design-library/visual-critique/skills/critique-typography/SKILL.md +45 -0
  534. package/skills/design-library/visual-critique/skills/critique-visual-hierarchy/SKILL.md +40 -0
  535. package/skills/feature-audit/EVALS.md +83 -0
  536. package/skills/feature-audit/SKILL.md +326 -0
  537. package/skills/harness/EVALS.md +81 -0
  538. package/skills/harness/SKILL.md +88 -0
  539. package/skills/i-have-adhd/EVALS.md +80 -0
  540. package/skills/i-have-adhd/SKILL.md +183 -0
  541. package/skills/no-ai-slop/EVALS.md +89 -0
  542. package/skills/no-ai-slop/SKILL.md +209 -0
  543. package/skills/no-ai-slop/eval.md +52 -0
  544. package/skills/plan-add/EVALS.md +79 -0
  545. package/skills/plan-add/SKILL.md +179 -0
  546. package/skills/plan-add/render_table.py +72 -0
  547. package/skills/plan-status/EVALS.md +78 -0
  548. package/skills/plan-status/SKILL.md +52 -0
  549. package/skills/plan-sync/EVALS.md +80 -0
  550. package/skills/plan-sync/SKILL.md +69 -0
  551. package/skills/pm-frameworks/SKILL.md +33 -0
  552. package/skills/pm-frameworks/SOURCE +39 -0
  553. package/skills/pm-frameworks/intended-vs-implemented/SKILL.md +42 -0
  554. package/skills/pm-frameworks/opportunity-solution-tree/SKILL.md +64 -0
  555. package/skills/ponytail/EVALS.md +80 -0
  556. package/skills/ponytail/SKILL.md +124 -0
  557. package/skills/product-analysis/EVALS.md +103 -0
  558. package/skills/product-analysis/SKILL.md +361 -0
  559. package/skills/research/EVALS.md +104 -0
  560. package/skills/research/SKILL.md +570 -0
  561. package/skills/rl-env/SKILL.md +53 -0
  562. package/skills/rl-env/SOURCE +41 -0
  563. package/skills/rl-env/generate-nemo-gym-env/SKILL.md +169 -0
  564. package/skills/rl-env/generate-nemo-gym-env/references/architecture.md +114 -0
  565. package/skills/rl-env/generate-openenv-env/SKILL.md +183 -0
  566. package/skills/rl-env/generate-openenv-env/references/architecture.md +82 -0
  567. package/skills/rl-env/generate-ors-env/SKILL.md +209 -0
  568. package/skills/rl-env/generate-ors-env/references/architecture.md +113 -0
  569. package/skills/rl-env/generate-verifiers-env/SKILL.md +188 -0
  570. package/skills/rl-env/generate-verifiers-env/references/architecture.md +119 -0
  571. package/skills/rl-env/rl-env-from-description/SKILL.md +124 -0
  572. package/skills/rl-env/rl-env-from-description/references/interview.md +75 -0
  573. package/skills/rl-env/rl-env-from-description/references/nemo_gym.md +41 -0
  574. package/skills/rl-env/rl-env-from-description/references/openenv.md +35 -0
  575. package/skills/rl-env/rl-env-from-description/references/ors.md +50 -0
  576. package/skills/rl-env/rl-env-from-description/references/verifiers.md +39 -0
  577. package/skills/tezgah-contract/EVALS.md +78 -0
  578. package/skills/tezgah-contract/SKILL.md +792 -0
  579. package/statusline.py +129 -0
  580. package/workflows/graph-impact.js +153 -0
  581. package/workflows/graph-map.js +158 -0
  582. package/workflows/graph-review.js +170 -0
@@ -0,0 +1,953 @@
1
+ #!/usr/bin/env python3
2
+ """tezgah-design derive|check - the per-repo design contract, and the check that
3
+ can fail.
4
+
5
+ tezgah-design derive --repo DIR [--out FILE] [--json]
6
+ tezgah-design check --contract FILE --measured FILE|- [--json]
7
+
8
+ The contract is the floor a UI turn is judged against: the colour roles, the
9
+ type scale, the spacing unit and the state set a repository already uses, plus
10
+ the component inventory it owns. `derive` writes a first `.tezgah/design-contract.md`
11
+ from the repository's own token source (CSS custom properties, a Tailwind config,
12
+ a tokens/theme JSON) and exits 2 rather than invent a palette it did not find.
13
+ `check` compares a measurement - the per-component computed styles and observed
14
+ states the analyze-app loop produces - against that file, prints every violation
15
+ with its component and its rule, and exits non-zero when there is at least one.
16
+ It names how many components it judged, and exits 2 when that is zero: `0
17
+ violations` over a measurement that carries no component would say the app is
18
+ clean when nothing was looked at.
19
+
20
+ Stdlib only, deterministic, no network and no credential: the same tree and the
21
+ same measurement print the same bytes, with no clock and no path outside the
22
+ repository in the artifact.
23
+
24
+ derive exit 0 the contract was written; 2 no token source; 1 usage or IO
25
+ check exit 0 `0 violations` over at least one component judged; 1 one or
26
+ more violations; 2 usage, IO, a bad contract or nothing judged
27
+ """
28
+ import json
29
+ import os
30
+ import re
31
+ import sys
32
+
33
+ # The state set every interactive control and every data view owes: seven per
34
+ # control, eight per data view, thirteen distinct states - `loading` and `error`
35
+ # are the two the halves share, and the shipped lists name them twice rather than
36
+ # once. Pinned equal to the three lists the repository already ships
37
+ # (tests/test_design_cli.py:StateSetPin) rather than left to drift as a fourth
38
+ # copy.
39
+ STATES_INTERACTIVE = ("default", "hover", "focus", "active", "disabled",
40
+ "loading", "error")
41
+ STATES_DATA = ("empty", "loading", "skeleton", "error", "offline", "partial",
42
+ "long-text", "permission-denied")
43
+ STATES = STATES_INTERACTIVE + tuple(s for s in STATES_DATA
44
+ if s not in STATES_INTERACTIVE)
45
+ KINDS = ("interactive", "data")
46
+
47
+ # The floors that are not this repository's to choose: WCAG 2.2 SC 2.5.8 (the
48
+ # 24x24 CSS px target size) and SC 1.4.3 (4.5:1, or 3:1 for large text, which is
49
+ # 24px and up, or 18.66px bold).
50
+ TAP_TARGET = 24
51
+ CONTRAST_NORMAL = 4.5
52
+ CONTRAST_LARGE = 3.0
53
+ LARGE_TEXT = 24
54
+
55
+ # The two floors the vendored design library names and a measurement can decide:
56
+ # a focus indication that survives the outline being switched off (SC 2.4.7 Focus
57
+ # Visible, Level AA - skills/design-library's `keyboard-navigation` and
58
+ # `focus-attention-design`), and motion that has a declared way out (SC 2.3.3
59
+ # Animation from Interactions, Level AAA - `motion-sensitivity`). Their shape is
60
+ # habitat's component schema, where `focus` is a required part of a component's
61
+ # `accessibility` block: the measurement says what is there, the contract says
62
+ # what is allowed. Both read only declarations the measurement makes, so a
63
+ # measurement that says nothing about focus or motion is not judged at all.
64
+ # What counts as a focus indication beside a dead outline: a treatment that
65
+ # paints without it. `outline-color` is NOT one - a colour with `outline-style:
66
+ # none` and `outline-width: 0` paints nothing, and every resolved computed-style
67
+ # dump carries one, so accepting it would make the rule silent on the shape a
68
+ # real measurement has.
69
+ FOCUS_PROPS = ("outline", "outline-style", "outline-width", "outline-color")
70
+ # The props that can paint: a value among these is what the rule concludes from.
71
+ FOCUS_PAINTS = ("outline", "outline-style", "outline-width")
72
+ # A box-shadow paints on its own, so it settles the rule by itself. A border
73
+ # does not: `border-style`'s initial value is `none`, whose colour and width are
74
+ # ignored, and a computed width is 0 whenever the style is none or hidden - so a
75
+ # resolved computed-style dump of a border-less element carries
76
+ # `border-width: 0px` and a colour. `border_paints()` reads those.
77
+ FOCUS_ALTERNATIVES = ("box-shadow",)
78
+ FOCUS_BORDER_PAINTS = ("border", "border-style", "border-width")
79
+ # The style words that draw nothing at all, and the shape of a length token.
80
+ STYLE_OFF = frozenset(("none", "hidden"))
81
+ LENGTH_TOKEN = re.compile(r"^[-+]?\d*\.?\d+[a-z%]*$")
82
+ # A length that is zero in every entry, in any unit and any number of leading
83
+ # zeroes: a drawn border or outline needs one that is not.
84
+ ZERO = re.compile(r"^[-+]?0+\.?0*[a-z%]*$")
85
+ MOTION_PROPS = ("transition-duration", "animation-duration")
86
+
87
+ SKIP_DIRS = frozenset((".git", "node_modules", "dist", "build", ".venv", "venv",
88
+ "vendor", "__pycache__", ".next", ".cache", "coverage",
89
+ ".tezgah", ".codegraph"))
90
+ CSS_SUFFIXES = (".css", ".scss", ".sass", ".less")
91
+ TAILWIND_NAMES = ("tailwind.config.js", "tailwind.config.cjs",
92
+ "tailwind.config.mjs", "tailwind.config.ts",
93
+ "tailwind.config.json")
94
+ THEME_NAMES = ("theme.json", "tokens.json", "design-tokens.json")
95
+ FILE_CAP = 4000
96
+ CSS_CAP = 200
97
+
98
+ DECL = re.compile(r"(--[A-Za-z0-9_-]+)\s*:\s*([^;{}]+)")
99
+ BLOCK = re.compile(r"\b%s\s*:\s*\{")
100
+ PAIR = re.compile(r"^\s*['\"]?([A-Za-z0-9_-]+)['\"]?\s*:\s*(.+?)\s*$")
101
+ HEX3 = re.compile(r"^#([0-9a-f])([0-9a-f])([0-9a-f])$", re.I)
102
+ HEX6 = re.compile(r"^#([0-9a-f]{6})$", re.I)
103
+ RGB = re.compile(r"^rgba?\(\s*(\d+)[\s,]+(\d+)[\s,]+(\d+)"
104
+ r"(?:[\s,/]+([0-9.]+%?))?\s*\)$", re.I)
105
+ LENGTH = re.compile(r"^(-?\d*\.?\d+)(px|rem|pt|em|%)?$")
106
+ # Values that make no claim about a token: an absent value said out loud.
107
+ NOTHING = frozenset(("none", "transparent", "currentcolor", "inherit",
108
+ "initial", "unset", "auto", "normal"))
109
+ COLOUR_PROPS = ("color", "background-color", "border-color", "outline-color")
110
+ SPACING_PROPS = ("padding", "padding-top", "padding-right", "padding-bottom",
111
+ "padding-left", "margin", "margin-top", "margin-right",
112
+ "margin-bottom", "margin-left", "gap", "row-gap", "column-gap")
113
+ SPACE_NAMES = ("space-unit", "spacing-unit", "space-base", "grid-unit",
114
+ "base-unit", "space", "spacing", "unit", "rhythm")
115
+ TYPE_NAME = re.compile(r"^(?:font|text|type)[-_]?size|^fs(?:[-_]|$)"
116
+ r"|^(?:font|text)[-_]?scale", re.I)
117
+
118
+
119
+ # --- values -----------------------------------------------------------------
120
+ def normalise_colour(value):
121
+ """`#rrggbb` for a colour literal, or None. `transparent` and its family are
122
+ None without being a claim: they say there is no colour to judge."""
123
+ text = str(value or "").strip().lower()
124
+ if not text or text in NOTHING or text.startswith("var("):
125
+ return None
126
+ m = HEX3.match(text)
127
+ if m:
128
+ return "#" + "".join(c * 2 for c in m.groups())
129
+ if HEX6.match(text):
130
+ return text
131
+ m = RGB.match(text)
132
+ if m:
133
+ if m.group(4) and m.group(4).endswith("%"):
134
+ try:
135
+ if float(m.group(4)[:-1]) == 0:
136
+ return None
137
+ except ValueError:
138
+ return None
139
+ elif m.group(4) and float(m.group(4)) == 0:
140
+ return None
141
+ try:
142
+ return "#%02x%02x%02x" % tuple(min(255, int(m.group(i)))
143
+ for i in (1, 2, 3))
144
+ except ValueError:
145
+ return None
146
+ return None
147
+
148
+
149
+ def length_px(value):
150
+ """The value in CSS px, or None when it is not an absolute length. `rem` is
151
+ read at the root size (16px), `pt` at 4/3 px; a unitless value is a length
152
+ only at zero, and `em`/`%` depend on a context this file does not have."""
153
+ m = LENGTH.match(str(value or "").strip().lower())
154
+ if not m:
155
+ return None
156
+ n, unit = float(m.group(1)), m.group(2)
157
+ if unit == "px":
158
+ return n
159
+ if unit is None:
160
+ return 0.0 if n == 0 else None
161
+ if unit == "rem":
162
+ return n * 16
163
+ if unit == "pt":
164
+ return n * 4 / 3
165
+ return None
166
+
167
+
168
+ def _luminance(hex_colour):
169
+ parts = [int(hex_colour[i:i + 2], 16) / 255 for i in (1, 3, 5)]
170
+ parts = [p / 12.92 if p <= 0.03928 else ((p + 0.055) / 1.055) ** 2.4
171
+ for p in parts]
172
+ return 0.2126 * parts[0] + 0.7152 * parts[1] + 0.0722 * parts[2]
173
+
174
+
175
+ def contrast_ratio(fore, back):
176
+ """The WCAG 2.2 contrast ratio between two `#rrggbb` colours."""
177
+ a, b = _luminance(fore), _luminance(back)
178
+ hi, lo = max(a, b), min(a, b)
179
+ return (hi + 0.05) / (lo + 0.05)
180
+
181
+
182
+ def durations_ms(value):
183
+ """(the longest readable time in ms, the count of entries that were not a
184
+ time) for a CSS time or a comma list.
185
+
186
+ A list takes its longest entry - that is the one a person sits through and
187
+ the one a guard has to cover - and it is read entry by entry, so one entry
188
+ nobody can parse neither hides a readable one nor lets the value read as
189
+ settled."""
190
+ worst, unreadable = None, 0
191
+ for part in str(value or "").split(","):
192
+ m = re.fullmatch(r"\s*(-?\d*\.?\d+)\s*(ms|s)\s*", part)
193
+ if not m:
194
+ unreadable += 1
195
+ continue
196
+ ms = float(m.group(1)) * (1 if m.group(2) == "ms" else 1000)
197
+ worst = ms if worst is None else max(worst, ms)
198
+ return worst, unreadable
199
+
200
+
201
+ def paints_nothing(value):
202
+ """True when a declaration draws nothing: every entry is a zero length, or a
203
+ word that claims nothing (`none`, `hidden`, `transparent` and its family).
204
+
205
+ A resolved computed-style dump carries these where nothing is drawn -
206
+ `outline-width: 0px`, `border-width: 0px`, `box-shadow: none` - so reading
207
+ one as evidence of a treatment is how a rule goes silent on the measurement
208
+ shape it was written for."""
209
+ parts = str(value or "").lower().replace(",", " ").split()
210
+ return bool(parts) and all(p in NOTHING or p == "hidden" or ZERO.match(p)
211
+ for p in parts)
212
+
213
+
214
+ def declaration_draws(value):
215
+ """True when one measured declaration draws something.
216
+
217
+ A lone longhand is judged by its own value (`2px` draws, `0px` does not).
218
+ The `border` and `outline` shorthands carry width, style and colour in one
219
+ string, so they draw only when no component of them says otherwise: a
220
+ `none`/`hidden` style word, or a width that is zero - `border: 0 solid #111`
221
+ draws nothing whatever the style says, which is a border-less element's
222
+ computed shape on a Tailwind page, and `outline: 0 solid #111` is focus with
223
+ nothing to see."""
224
+ parts = str(value or "").lower().replace(",", " ").split()
225
+ if not parts:
226
+ return False
227
+ if any(part == "auto" for part in parts):
228
+ # `outline-style: auto` is the focus ring the UA draws, so it belongs on
229
+ # the drawing side even though `auto` claims nothing for most props.
230
+ return True
231
+ if any(part in STYLE_OFF for part in parts):
232
+ return False
233
+ if all(paints_nothing(part) for part in parts):
234
+ return False
235
+ widths = [part for part in parts if LENGTH_TOKEN.match(part)]
236
+ return not (widths and all(ZERO.match(width) for width in widths))
237
+
238
+
239
+ def border_paints(styles):
240
+ """True when the measurement names a border that draws something.
241
+
242
+ Every declared part of it has to draw: a live `border-style` beside
243
+ `border-width: 0px` draws nothing, and that pair is the computed shape of a
244
+ border-less element on a Tailwind page, so either half read alone would let
245
+ the rule settle on a border nobody sees."""
246
+ values = [styles[prop] for prop in FOCUS_BORDER_PAINTS if prop in styles]
247
+ return bool(values) and all(declaration_draws(value) for value in values)
248
+
249
+
250
+ def focus_outline_off(styles):
251
+ """The declarations that switch focus off with nothing beside them to show
252
+ it, or [].
253
+
254
+ `outline: none` is a violation only when the same measurement names no other
255
+ indication: a `box-shadow` that draws, or a border that can paint, is a focus
256
+ treatment by another route. An `outline-color`, a bare `border-color` and a
257
+ zero-width border are not: a resolved computed-style dump carries all three
258
+ while nothing is drawn."""
259
+ off = ["%s: %s" % (prop, styles[prop])
260
+ for prop in FOCUS_PAINTS
261
+ if prop in styles and not declaration_draws(styles[prop])]
262
+ if not off:
263
+ return []
264
+ if any(prop in styles and not paints_nothing(styles[prop])
265
+ for prop in FOCUS_ALTERNATIVES):
266
+ return []
267
+ if border_paints(styles):
268
+ return []
269
+ return off
270
+
271
+
272
+ # --- reading the repository's own tokens ------------------------------------
273
+ def walk(root):
274
+ """Every file under `root`, repo-relative and sorted, with the directories a
275
+ token source is never in skipped and the count bounded."""
276
+ out = []
277
+ for base, dirs, names in os.walk(root):
278
+ dirs[:] = sorted(d for d in dirs if d not in SKIP_DIRS)
279
+ for name in sorted(names):
280
+ rel = os.path.relpath(os.path.join(base, name), root)
281
+ out.append(rel.replace(os.sep, "/"))
282
+ if len(out) >= FILE_CAP:
283
+ return out
284
+ return out
285
+
286
+
287
+ def read_text(root, rel):
288
+ try:
289
+ with open(os.path.join(root, rel), encoding="utf-8",
290
+ errors="replace") as fh:
291
+ return fh.read()
292
+ except OSError:
293
+ return ""
294
+
295
+
296
+ def css_declarations(root, files):
297
+ """{name: value} from the custom properties of this repository's stylesheets,
298
+ later declarations winning, files in sorted order."""
299
+ out, sources = {}, []
300
+ seen = 0
301
+ for rel in files:
302
+ if not rel.lower().endswith(CSS_SUFFIXES):
303
+ continue
304
+ seen += 1
305
+ if seen > CSS_CAP:
306
+ break
307
+ text = read_text(root, rel)
308
+ found = False
309
+ for name, value in DECL.findall(text):
310
+ out[name.lstrip("-")] = value.strip()
311
+ found = True
312
+ if found:
313
+ sources.append(rel)
314
+ return out, sources
315
+
316
+
317
+ def _block_body(text, key):
318
+ """Every `key: { ... }` body in `text`, brace-balanced, in file order."""
319
+ out = []
320
+ for m in re.finditer(BLOCK.pattern % re.escape(key), text):
321
+ i, depth = m.end(), 1
322
+ while i < len(text) and depth:
323
+ if text[i] == "{":
324
+ depth += 1
325
+ elif text[i] == "}":
326
+ depth -= 1
327
+ i += 1
328
+ out.append(text[m.end():i - 1])
329
+ return out
330
+
331
+
332
+ def _pairs(body):
333
+ """The `key: value` pairs at the top level of a config block. A nested
334
+ object is skipped, not flattened: its leaves are a scale of their own and
335
+ this reader does not claim to know its shape."""
336
+ items, depth, buf = [], 0, []
337
+ for ch in body:
338
+ if ch in "{[":
339
+ depth += 1
340
+ elif ch in "}]":
341
+ depth -= 1
342
+ if ch == "," and depth == 0:
343
+ items.append("".join(buf))
344
+ buf = []
345
+ else:
346
+ buf.append(ch)
347
+ items.append("".join(buf))
348
+ out = []
349
+ for item in items:
350
+ if "{" in item:
351
+ continue
352
+ m = PAIR.match(item)
353
+ if m:
354
+ out.append((m.group(1), m.group(2).strip().strip("'\"")))
355
+ return out
356
+
357
+
358
+ def tailwind_tokens(root, files):
359
+ """The tokens a Tailwind config declares, read from its `colors`, `spacing`
360
+ and `fontSize` blocks."""
361
+ rel = next((f for f in files if os.path.basename(f) in TAILWIND_NAMES), None)
362
+ if rel is None:
363
+ return {}, []
364
+ text = read_text(root, rel)
365
+ colours, space, scale = {}, [], []
366
+ for body in _block_body(text, "colors"):
367
+ for key, value in _pairs(body):
368
+ hexed = normalise_colour(value)
369
+ if hexed:
370
+ colours[key] = hexed
371
+ for body in _block_body(text, "spacing"):
372
+ for key, value in _pairs(body):
373
+ px = length_px(value)
374
+ if px:
375
+ space.append((key in ("unit", "base"), px))
376
+ for body in _block_body(text, "fontSize"):
377
+ for _, value in _pairs(body):
378
+ for token in re.findall(r"['\"]?([\d.]+(?:px|rem|pt))", value):
379
+ px = length_px(token)
380
+ if px:
381
+ scale.append(int(round(px)))
382
+ out = {}
383
+ # A key named `unit`/`base` states the unit; otherwise the greatest common
384
+ # divisor of the scale the config declares is the unit it is built on.
385
+ named = sorted((px for explicit, px in space if explicit))
386
+ if named:
387
+ out["space_unit"] = int(named[0])
388
+ elif space:
389
+ out["space_unit"] = int(_gcd([px for _, px in space]))
390
+ if scale:
391
+ out["type_scale"] = sorted(set(scale))
392
+ if colours:
393
+ out["colors"] = colours
394
+ return out, [rel]
395
+
396
+
397
+ def theme_tokens(root, files):
398
+ """The tokens a tokens/theme JSON declares, found by key anywhere in it."""
399
+ rel = next((f for f in files if os.path.basename(f) in THEME_NAMES), None)
400
+ if rel is None:
401
+ return {}, []
402
+ try:
403
+ data = json.loads(read_text(root, rel))
404
+ except ValueError:
405
+ return {}, []
406
+ colours, space, scale = {}, {}, []
407
+
408
+ def visit(node):
409
+ if isinstance(node, dict):
410
+ for key, value in node.items():
411
+ low = str(key).lower()
412
+ if isinstance(value, dict):
413
+ if low in ("colors", "color", "palette", "colour"):
414
+ for name, item in value.items():
415
+ if isinstance(item, str) and normalise_colour(item):
416
+ colours[str(name)] = normalise_colour(item)
417
+ if low in ("spacing", "space"):
418
+ for name, item in value.items():
419
+ px = length_px(item) if isinstance(item, str) else None
420
+ if px:
421
+ space[str(name)] = px
422
+ if low in ("fontsize", "font-size", "font_sizes",
423
+ "font-sizes"):
424
+ for _, item in value.items():
425
+ token = item[0] if isinstance(item, list) and item \
426
+ else item
427
+ px = length_px(token) if isinstance(token, str) else None
428
+ if px:
429
+ scale.append(int(round(px)))
430
+ visit(value)
431
+ elif isinstance(node, list):
432
+ for item in node:
433
+ visit(item)
434
+
435
+ visit(data)
436
+ out = {}
437
+ if space:
438
+ out["space_unit"] = int(_gcd(list(space.values())))
439
+ if scale:
440
+ out["type_scale"] = sorted(set(scale))
441
+ if colours:
442
+ out["colors"] = colours
443
+ return out, [rel]
444
+
445
+
446
+ def _gcd(values):
447
+ values = [int(round(v)) for v in values if v]
448
+ if not values:
449
+ return 0
450
+ out = values[0]
451
+ for v in values[1:]:
452
+ while v:
453
+ out, v = v, out % v
454
+ return out
455
+
456
+
457
+ def _roles(declarations):
458
+ """{role: hex} for the custom properties that carry a colour literal."""
459
+ out = {}
460
+ for name, value in declarations.items():
461
+ hexed = normalise_colour(value)
462
+ if not hexed:
463
+ continue
464
+ role = re.sub(r"^(?:colou?r|clr|c)[-_]", "", name, flags=re.I)
465
+ role = re.sub(r"[-_]?colou?r$", "", role, flags=re.I)
466
+ out[(role or "color").replace("_", "-").strip("-")] = hexed
467
+ return out
468
+
469
+
470
+ def css_tokens(root, files):
471
+ """The tokens a repository's CSS custom properties carry."""
472
+ decls, sources = css_declarations(root, files)
473
+ if not decls:
474
+ return {}, []
475
+ out = {}
476
+ colours = _roles(decls)
477
+ if colours:
478
+ out["colors"] = colours
479
+ # A property named for the unit states it; otherwise the greatest common
480
+ # divisor of the spacing scale the file declares is the unit it is built on.
481
+ for key, value in decls.items():
482
+ bare = re.sub(r"[-_]unit$", "", key).strip("-")
483
+ if key in SPACE_NAMES or bare in SPACE_NAMES:
484
+ px = length_px(value)
485
+ if px:
486
+ out["space_unit"] = int(round(px))
487
+ break
488
+ if "space_unit" not in out:
489
+ scale = [length_px(v) for k, v in decls.items()
490
+ if re.match(r"^(?:space|spacing|gap)[-_]", k)]
491
+ scale = [px for px in scale if px]
492
+ if scale:
493
+ out["space_unit"] = int(_gcd(scale))
494
+ scale = []
495
+ for key, value in decls.items():
496
+ if TYPE_NAME.search(key):
497
+ px = length_px(value)
498
+ if px:
499
+ scale.append(int(round(px)))
500
+ if scale:
501
+ out["type_scale"] = sorted(set(scale))
502
+ return out, sources
503
+
504
+
505
+ def derive(root):
506
+ """(tokens, source, read from) from the repository's own token source, or
507
+ (None, reason, []) when it carries none."""
508
+ files = walk(root)
509
+ for name, reader in (("css-custom-properties", css_tokens),
510
+ ("tailwind-config", tailwind_tokens),
511
+ ("theme-json", theme_tokens)):
512
+ tokens, sources = reader(root, files)
513
+ if tokens.get("colors"):
514
+ return tokens, name, sources
515
+ return None, ("no token source: looked for CSS custom properties, a "
516
+ "Tailwind config and a tokens/theme JSON"), []
517
+
518
+
519
+ def contract_data(tokens, source):
520
+ """The machine half of the contract: the derived tokens, the shipped state
521
+ set, and the component inventory the repository owns."""
522
+ return {
523
+ "version": 1,
524
+ "source": source,
525
+ "tokens": {
526
+ "space_unit": tokens.get("space_unit"),
527
+ "type_scale": tokens.get("type_scale") or [],
528
+ "colors": tokens.get("colors") or {},
529
+ "tap_target": TAP_TARGET,
530
+ "contrast": {"normal": CONTRAST_NORMAL, "large": CONTRAST_LARGE},
531
+ },
532
+ "states": {"interactive": list(STATES_INTERACTIVE),
533
+ "data": list(STATES_DATA)},
534
+ "components": [],
535
+ }
536
+
537
+
538
+ def contract_text(data, sources, derived_note):
539
+ """The artifact: what a reader opens, and the block `check` reads. Field
540
+ names and prose stay English; nothing here carries a clock or a machine
541
+ path.
542
+
543
+ The inventory line is always written, and says plainly when it is empty:
544
+ `derive` reads tokens, never components - the measurement names a component,
545
+ the repository names files - so a derived contract's `component-inventory`
546
+ rule is inert until someone fills the list in. A reader who assumed the
547
+ floor judged the inventory would read every derived contract as stricter
548
+ than it is."""
549
+ read = ", ".join(sources[:3]) if sources else "(none)"
550
+ names = [str(c.get("name")) for c in (data.get("components") or [])
551
+ if isinstance(c, dict)]
552
+ inventory = ", ".join(names) if names else "(empty)"
553
+ rule = ("""- `components` is the inventory this contract owns, and it is EMPTY:
554
+ `derive` reads tokens and never components, so the `component-inventory` rule
555
+ is inert on this contract - nothing below judges a component that is not
556
+ listed. Add one `{name, kind}` per component the repository owns."""
557
+ if not names else
558
+ """- `components` is the inventory this contract owns. A component the
559
+ measurement shows that is not listed here is a violation, so a new component
560
+ is added here before the turn closes.""")
561
+ return """# Design contract
562
+
563
+ source: %s
564
+ read from: %s
565
+ component inventory: %s
566
+
567
+ The floor this repository's screens are judged against. `bin/tezgah-design check`
568
+ compares a measurement - the per-component computed styles and observed states
569
+ the analyze-app loop produces - against the block below and exits non-zero on
570
+ every disagreement. The shape, the state set and the derivation rule live in the
571
+ `design-contract` skill.
572
+
573
+ - Colour roles are this repository's own token names; nothing here was invented.
574
+ - `tap_target` and `contrast` are WCAG 2.2 floors (SC 2.5.8, SC 1.4.3), not this
575
+ repository's choices.
576
+ - `space_unit` is the unit the repository's own spacing tokens are built on; a
577
+ measured spacing that is not a multiple of it is a violation.
578
+ %s
579
+ - %s
580
+
581
+ ```json
582
+ %s
583
+ ```
584
+ """ % (data["source"], read, inventory, rule, derived_note,
585
+ json.dumps(data, indent=2, sort_keys=True))
586
+
587
+
588
+ # --- the check ---------------------------------------------------------------
589
+ def read_contract(path):
590
+ """(data, reason): the fenced JSON block of a contract file, or why not."""
591
+ try:
592
+ with open(path, encoding="utf-8") as fh:
593
+ text = fh.read()
594
+ except OSError as exc:
595
+ return None, "cannot read the contract: %s" % exc
596
+ m = re.search(r"```json\s*\n(.*?)\n```", text, re.S)
597
+ if not m:
598
+ return None, ("the contract carries no ```json block: the machine half "
599
+ "of the artifact is missing")
600
+ try:
601
+ data = json.loads(m.group(1))
602
+ except ValueError as exc:
603
+ return None, "the contract's json block does not parse: %s" % exc
604
+ if not isinstance(data, dict):
605
+ return None, "the contract's json block is not an object"
606
+ return data, None
607
+
608
+
609
+ def _violation(component, rule, detail):
610
+ return {"component": component, "rule": rule, "detail": detail}
611
+
612
+
613
+ def check(data, measured):
614
+ """(violations, unjudged, judged): every disagreement between a measurement
615
+ and the contract, each naming its component and its rule, the count of
616
+ measured values the contract could not judge at all, and how many components
617
+ it judged at all.
618
+
619
+ `judged` is what keeps "judged everything, found nothing" apart from "judged
620
+ nothing": a measurement that carries no component the contract can judge is
621
+ not a clean app, and the caller refuses to report it as one. A component
622
+ counts only when a rule actually judged it - the presence of a dict is not a
623
+ judgement, so `{"components": [{}]}` judges nothing, and neither is a name the
624
+ contract's inventory lists: `component-inventory` is a finding about the name
625
+ and nothing more, so a component that arrived with only a name is not counted
626
+ as judged. The contract-level rules above run either way - an unusable
627
+ contract is a finding whether or not anything was measured against it."""
628
+ out, unjudged, judged = [], 0, 0
629
+
630
+ def bad(component, rule, detail):
631
+ out.append(_violation(component, rule, detail))
632
+
633
+ if not str(data.get("source") or "").strip():
634
+ bad("contract", "contract-source",
635
+ "the contract carries no `source:` line, so nobody can say whether "
636
+ "it was read from this repository or invented")
637
+ tokens = data.get("tokens") if isinstance(data.get("tokens"), dict) else {}
638
+ colours = {str(k): normalise_colour(v)
639
+ for k, v in (tokens.get("colors") or {}).items()}
640
+ palette = sorted({v for v in colours.values() if v})
641
+ if not palette:
642
+ bad("contract", "contract-palette",
643
+ "the contract names no colour role, so no colour can be judged "
644
+ "against it")
645
+ space = tokens.get("space_unit")
646
+ scale = [int(v) for v in (tokens.get("type_scale") or []) if v is not None]
647
+ tap = tokens.get("tap_target") or TAP_TARGET
648
+ reduced = bool(tokens.get("reduced_motion"))
649
+ floors = tokens.get("contrast") or {}
650
+ normal = float(floors.get("normal") or CONTRAST_NORMAL)
651
+ large = float(floors.get("large") or CONTRAST_LARGE)
652
+ states = data.get("states") if isinstance(data.get("states"), dict) else {}
653
+ for kind, shipped in (("interactive", STATES_INTERACTIVE),
654
+ ("data", STATES_DATA)):
655
+ got = states.get(kind)
656
+ if not isinstance(got, list) or len(got) != len(shipped) \
657
+ or any(str(a) != b for a, b in zip(got, shipped)):
658
+ bad("contract", "state-set",
659
+ "the contract's `%s` states are not the shipped set (%s): a "
660
+ "floor that drops a state is not the floor" % (kind, ", ".join(shipped)))
661
+ inventory = [str(c.get("name")) for c in (data.get("components") or [])
662
+ if isinstance(c, dict)]
663
+
664
+ for comp in (measured.get("components") or []):
665
+ if not isinstance(comp, dict):
666
+ unjudged += 1
667
+ continue
668
+ # A rule that read a value of this component sets this; a dict no rule
669
+ # could read anything out of is not a judged component, however many
670
+ # keys it arrived with.
671
+ hit = False
672
+ name = str(comp.get("name") or "?")
673
+ styles = {str(k).lower(): v for k, v in (comp.get("styles") or {}).items()}
674
+ for prop in COLOUR_PROPS:
675
+ if prop not in styles:
676
+ continue
677
+ hexed = normalise_colour(styles[prop])
678
+ if not hexed:
679
+ if str(styles[prop]).strip().lower() not in NOTHING:
680
+ unjudged += 1
681
+ continue
682
+ hit = True
683
+ if palette and hexed not in palette:
684
+ bad(name, "palette",
685
+ "%s %s is not a colour role in the contract (%s)"
686
+ % (prop, styles[prop], ", ".join(palette)))
687
+ for prop in ("font-size",):
688
+ if prop not in styles:
689
+ continue
690
+ px = length_px(styles[prop])
691
+ if px is None or not scale:
692
+ unjudged += 1
693
+ else:
694
+ hit = True
695
+ if int(round(px)) not in scale:
696
+ bad(name, "type-scale",
697
+ "%s %s is off the contract's type scale (%s)"
698
+ % (prop, styles[prop],
699
+ ", ".join("%dpx" % s for s in scale)))
700
+ for prop, value in sorted(styles.items()):
701
+ if prop not in SPACING_PROPS:
702
+ continue
703
+ for part in str(value).split():
704
+ px = length_px(part)
705
+ if px is None or not space:
706
+ unjudged += 1
707
+ else:
708
+ hit = True
709
+ if px % space:
710
+ bad(name, "spacing-rhythm",
711
+ "%s %s is not a multiple of the %spx spacing unit"
712
+ % (prop, value, space))
713
+ kind = comp.get("kind")
714
+ if kind == "interactive":
715
+ for prop in ("width", "height"):
716
+ px = length_px(styles.get(prop))
717
+ if px is None:
718
+ unjudged += 1
719
+ else:
720
+ hit = True
721
+ if px < tap:
722
+ bad(name, "tap-target",
723
+ "%s %s is below the %dpx target floor (WCAG 2.2 "
724
+ "SC 2.5.8)" % (prop, styles[prop], tap))
725
+ claims = [prop for prop in FOCUS_PROPS if prop in styles]
726
+ if claims:
727
+ off = focus_outline_off(styles)
728
+ if off:
729
+ hit = True
730
+ bad(name, "focus-visible",
731
+ "%s, with no other focus indication measured beside it "
732
+ "(a box-shadow, a border that draws): a keyboard user "
733
+ "cannot see where they are (WCAG 2.2 SC 2.4.7 Focus "
734
+ "Visible, Level AA)" % ", ".join(off))
735
+ elif (any(prop in styles and declaration_draws(styles[prop])
736
+ for prop in FOCUS_PAINTS) or border_paints(styles)):
737
+ hit = True
738
+ else:
739
+ # an outline-colour with no outline to paint says nothing a
740
+ # rule can conclude from: a value, not a judgement
741
+ unjudged += 1
742
+ moving, judged_motion = [], False
743
+ for prop in MOTION_PROPS:
744
+ if prop not in styles:
745
+ continue
746
+ ms, unreadable = durations_ms(styles[prop])
747
+ unjudged += unreadable
748
+ if ms is None:
749
+ continue
750
+ judged_motion = True
751
+ if ms > 0:
752
+ moving.append("%s: %s" % (prop, styles[prop]))
753
+ if judged_motion:
754
+ hit = True
755
+ if moving and not reduced:
756
+ bad(name, "reduced-motion",
757
+ "%s is measured and the contract declares no reduced-motion "
758
+ "guard (`tokens.reduced_motion`): motion with no way out "
759
+ "(WCAG 2.2 SC 2.3.3 Animation from Interactions, Level AAA)"
760
+ % ", ".join(moving))
761
+ fore = normalise_colour(styles.get("color"))
762
+ back = normalise_colour(styles.get("background-color"))
763
+ if fore and back:
764
+ hit = True
765
+ size = length_px(styles.get("font-size"))
766
+ floor = large if size is not None and size >= LARGE_TEXT else normal
767
+ ratio = contrast_ratio(fore, back)
768
+ if ratio + 1e-9 < floor:
769
+ bad(name, "contrast",
770
+ "%.2f:1 for %s on %s is below the %.1f:1 floor (WCAG 2.2 "
771
+ "SC 1.4.3)" % (ratio, styles.get("color"),
772
+ styles.get("background-color"), floor))
773
+ if kind in KINDS:
774
+ hit = True
775
+ required = states.get(kind) or []
776
+ shown = [str(s) for s in (comp.get("states") or [])]
777
+ missing = [s for s in required if s not in shown]
778
+ if missing:
779
+ bad(name, "state-coverage",
780
+ "states not observed: %s" % ", ".join(missing))
781
+ elif kind is None:
782
+ unjudged += 1
783
+ if inventory and name not in inventory:
784
+ bad(name, "component-inventory",
785
+ "not in the contract's component inventory")
786
+ if hit:
787
+ judged += 1
788
+ out.sort(key=lambda v: (v["component"], v["rule"], v["detail"]))
789
+ return out, unjudged, judged
790
+
791
+
792
+ # --- the command line --------------------------------------------------------
793
+ class Usage(Exception):
794
+ pass
795
+
796
+
797
+ def parse(argv, names):
798
+ """`--flag value` pairs for the flags this verb takes; an unknown flag or a
799
+ missing value is a usage error, never a silently ignored argument."""
800
+ out, i = {}, 0
801
+ while i < len(argv):
802
+ arg = argv[i]
803
+ if arg == "--json":
804
+ out["json"] = True
805
+ elif arg in names:
806
+ if i + 1 >= len(argv):
807
+ raise Usage("%s wants a value" % arg)
808
+ out[arg.lstrip("-")] = argv[i + 1]
809
+ i += 1
810
+ else:
811
+ raise Usage("unknown argument: %s" % arg)
812
+ i += 1
813
+ return out
814
+
815
+
816
+ def _print_json(payload):
817
+ sys.stdout.write(json.dumps(payload, indent=2, sort_keys=True) + "\n")
818
+
819
+
820
+ def derive_cli(opts):
821
+ root = os.path.abspath(opts.get("repo") or "")
822
+ if not os.path.isdir(root):
823
+ raise Usage("--repo must name a directory")
824
+ out = opts.get("out") or os.path.join(root, ".tezgah", "design-contract.md")
825
+ if os.path.exists(out):
826
+ # A contract that exists is the repository's own decision: it carries
827
+ # the component inventory someone filled in, so overwriting it would
828
+ # throw that away. Re-deriving over a token change is a hand edit, or a
829
+ # deliberate `rm` first.
830
+ raise Usage("the contract already exists at %s: a contract is edited, "
831
+ "not overwritten - remove it first or pass --out elsewhere"
832
+ % os.path.relpath(out, root))
833
+ tokens, source, sources = derive(root)
834
+ if tokens is None:
835
+ if opts.get("json"):
836
+ _print_json({"ok": False, "error": source})
837
+ sys.stderr.write("tezgah-design: %s\nWrite the contract by hand with "
838
+ "`source: derived` naming where the floor came from "
839
+ "(the design-contract skill says how), or point "
840
+ "`--repo` at a repository that has one.\n" % source)
841
+ return 2
842
+ data = contract_data(tokens, source)
843
+ note = ("Derived from the repository's own token source; refresh it by "
844
+ "removing this file and re-running `tezgah-design derive`." if sources else
845
+ "Derived, not read: name here what the floor came from.")
846
+ text = contract_text(data, sources, note)
847
+ try:
848
+ os.makedirs(os.path.dirname(os.path.abspath(out)), exist_ok=True)
849
+ with open(out, "w", encoding="utf-8") as fh:
850
+ fh.write(text)
851
+ except OSError as exc:
852
+ raise Usage("cannot write %s: %s" % (out, exc))
853
+ shown = os.path.relpath(out, root)
854
+ if opts.get("json"):
855
+ _print_json({"ok": True, "out": shown, "source": source,
856
+ "colors": len(data["tokens"]["colors"]),
857
+ "space_unit": data["tokens"]["space_unit"],
858
+ "type_scale": data["tokens"]["type_scale"],
859
+ "components": len(data["components"])})
860
+ else:
861
+ sys.stdout.write(
862
+ "wrote %s (source: %s, %d colour roles, %s, %d type steps)\n"
863
+ % (shown, source, len(data["tokens"]["colors"]),
864
+ "%spx unit" % data["tokens"]["space_unit"]
865
+ if data["tokens"]["space_unit"] else "no spacing unit found",
866
+ len(data["tokens"]["type_scale"])))
867
+ sys.stdout.write(
868
+ "component inventory: empty - `derive` reads tokens and never "
869
+ "components, so the `component-inventory` rule is inert on this "
870
+ "contract until the list is filled in\n")
871
+ return 0
872
+
873
+
874
+ def check_cli(opts):
875
+ contract = opts.get("contract")
876
+ measured = opts.get("measured")
877
+ if not contract or not measured:
878
+ raise Usage("check wants --contract FILE and --measured FILE|-")
879
+ data, reason = read_contract(contract)
880
+ if data is None:
881
+ raise Usage(reason)
882
+ if measured == "-":
883
+ raw = sys.stdin.read()
884
+ else:
885
+ try:
886
+ with open(measured, encoding="utf-8") as fh:
887
+ raw = fh.read()
888
+ except OSError as exc:
889
+ raise Usage("cannot read the measurement: %s" % exc)
890
+ if not raw.strip():
891
+ raise Usage("the measurement at %s is empty" % measured)
892
+ try:
893
+ got = json.loads(raw)
894
+ except ValueError as exc:
895
+ raise Usage("the measurement does not parse: %s" % exc)
896
+ if isinstance(got, list):
897
+ got = {"components": got}
898
+ if not isinstance(got, dict):
899
+ raise Usage("the measurement is not an object with a `components` list")
900
+ violations, unjudged, judged = check(data, got)
901
+ if not judged:
902
+ # `0 violations` over a measurement with nothing in it says the app is
903
+ # clean when nothing was looked at, and the Stop rule reads that output
904
+ # as the floor having been applied. It is a usage error, not a pass.
905
+ message = (
906
+ "nothing was judged: %s, so `0 violations` would report a clean app "
907
+ "when nothing was looked at. Pass the per-component styles and "
908
+ "states the analyze-app read produces."
909
+ % ("the measurement carries no `components` list"
910
+ if not got.get("components") else
911
+ "no entry in `components` is one the contract could judge"))
912
+ if opts.get("json"):
913
+ _print_json({"ok": False, "count": len(violations),
914
+ "violations": violations, "unjudged": unjudged,
915
+ "judged": 0, "error": message})
916
+ else:
917
+ sys.stderr.write("tezgah-design: %s\n" % message)
918
+ return 2
919
+ if opts.get("json"):
920
+ _print_json({"ok": not violations, "count": len(violations),
921
+ "violations": violations, "unjudged": unjudged,
922
+ "judged": judged})
923
+ else:
924
+ sys.stdout.write("%d violations\n" % len(violations))
925
+ for v in violations:
926
+ sys.stdout.write("%s: %s - %s\n"
927
+ % (v["component"], v["rule"], v["detail"]))
928
+ if unjudged:
929
+ sys.stdout.write("%d measured values the contract could not judge\n"
930
+ % unjudged)
931
+ sys.stdout.write("%d component%s judged\n"
932
+ % (judged, "" if judged == 1 else "s"))
933
+ return 1 if violations else 0
934
+
935
+
936
+ def main(argv):
937
+ if not argv or argv[0] in ("-h", "--help"):
938
+ sys.stdout.write(__doc__)
939
+ return 0 if argv else 2
940
+ verb, rest = argv[0], argv[1:]
941
+ try:
942
+ if verb == "derive":
943
+ return derive_cli(parse(rest, ("--repo", "--out")))
944
+ if verb == "check":
945
+ return check_cli(parse(rest, ("--contract", "--measured")))
946
+ raise Usage("unknown verb: %s (derive|check)" % verb)
947
+ except Usage as exc:
948
+ sys.stderr.write("tezgah-design: %s\n" % exc)
949
+ return 2
950
+
951
+
952
+ if __name__ == "__main__":
953
+ sys.exit(main(sys.argv[1:]))