zilmate 1.9.3 → 1.10.1

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 (306) hide show
  1. package/.agents/skills/ad-creative/SKILL.md +362 -0
  2. package/.agents/skills/ad-creative/evals/evals.json +90 -0
  3. package/.agents/skills/ad-creative/references/generative-tools.md +637 -0
  4. package/.agents/skills/ad-creative/references/platform-specs.md +213 -0
  5. package/.agents/skills/ai-seo/SKILL.md +489 -0
  6. package/.agents/skills/ai-seo/evals/evals.json +90 -0
  7. package/.agents/skills/ai-seo/references/content-patterns.md +285 -0
  8. package/.agents/skills/ai-seo/references/content-types.md +71 -0
  9. package/.agents/skills/ai-seo/references/okf.md +104 -0
  10. package/.agents/skills/ai-seo/references/platform-ranking-factors.md +154 -0
  11. package/.agents/skills/clerk-backend-api/SKILL.md +426 -0
  12. package/.agents/skills/clerk-backend-api/evals/evals.json +87 -0
  13. package/.agents/skills/clerk-backend-api/scripts/api-specs-context.sh +30 -0
  14. package/.agents/skills/clerk-backend-api/scripts/execute-request.sh +88 -0
  15. package/.agents/skills/clerk-backend-api/scripts/extract-endpoint-detail.sh +165 -0
  16. package/.agents/skills/clerk-backend-api/scripts/extract-tag-endpoints.sh +208 -0
  17. package/.agents/skills/clerk-backend-api/scripts/extract-tags.js +14 -0
  18. package/.agents/skills/copy-editing/SKILL.md +457 -0
  19. package/.agents/skills/copy-editing/evals/evals.json +89 -0
  20. package/.agents/skills/copy-editing/references/checklist.md +66 -0
  21. package/.agents/skills/copy-editing/references/content-refresh.md +38 -0
  22. package/.agents/skills/copy-editing/references/plain-english-alternatives.md +394 -0
  23. package/.agents/skills/hyperframes/SKILL.md +163 -0
  24. package/.agents/skills/hyperframes-cli/SKILL.md +109 -0
  25. package/.agents/skills/hyperframes-cli/references/doctor-browser.md +45 -0
  26. package/.agents/skills/hyperframes-cli/references/init-and-scaffold.md +51 -0
  27. package/.agents/skills/hyperframes-cli/references/lambda.md +132 -0
  28. package/.agents/skills/hyperframes-cli/references/lint-validate-inspect.md +121 -0
  29. package/.agents/skills/hyperframes-cli/references/preview-render.md +109 -0
  30. package/.agents/skills/hyperframes-cli/references/upgrade-info-misc.md +75 -0
  31. package/.agents/skills/hyperframes-media/SKILL.md +97 -0
  32. package/.agents/skills/hyperframes-media/assets/sfx/CREDITS.md +35 -0
  33. package/.agents/skills/hyperframes-media/assets/sfx/manifest.json +97 -0
  34. package/.agents/skills/hyperframes-media/references/bgm.md +72 -0
  35. package/.agents/skills/hyperframes-media/references/captions/authoring.md +159 -0
  36. package/.agents/skills/hyperframes-media/references/captions/motion.md +87 -0
  37. package/.agents/skills/hyperframes-media/references/captions/transcript-handling.md +97 -0
  38. package/.agents/skills/hyperframes-media/references/remove-background.md +143 -0
  39. package/.agents/skills/hyperframes-media/references/requirements.md +29 -0
  40. package/.agents/skills/hyperframes-media/references/sfx.md +42 -0
  41. package/.agents/skills/hyperframes-media/references/transcribe.md +52 -0
  42. package/.agents/skills/hyperframes-media/references/tts-to-captions.md +24 -0
  43. package/.agents/skills/hyperframes-media/references/tts.md +135 -0
  44. package/.agents/skills/hyperframes-media/scripts/audio.mjs +282 -0
  45. package/.agents/skills/hyperframes-media/scripts/heygen-tts.mjs +121 -0
  46. package/.agents/skills/hyperframes-media/scripts/lib/bgm.mjs +235 -0
  47. package/.agents/skills/hyperframes-media/scripts/lib/heygen.mjs +131 -0
  48. package/.agents/skills/hyperframes-media/scripts/lib/sfx.mjs +128 -0
  49. package/.agents/skills/hyperframes-media/scripts/lib/tts.mjs +220 -0
  50. package/.agents/skills/hyperframes-media/scripts/lyria-recipe.py +128 -0
  51. package/.agents/skills/hyperframes-media/scripts/wait-bgm.mjs +167 -0
  52. package/.agents/skills/hyperframes-registry/SKILL.md +101 -0
  53. package/.agents/skills/hyperframes-registry/examples/add-block.md +51 -0
  54. package/.agents/skills/hyperframes-registry/examples/add-component.md +73 -0
  55. package/.agents/skills/hyperframes-registry/references/contributing.md +166 -0
  56. package/.agents/skills/hyperframes-registry/references/demo-html-pattern.md +54 -0
  57. package/.agents/skills/hyperframes-registry/references/discovery.md +215 -0
  58. package/.agents/skills/hyperframes-registry/references/install-locations.md +45 -0
  59. package/.agents/skills/hyperframes-registry/references/templates.md +417 -0
  60. package/.agents/skills/hyperframes-registry/references/wiring-blocks.md +61 -0
  61. package/.agents/skills/hyperframes-registry/references/wiring-components.md +39 -0
  62. package/.agents/skills/marketing-psychology/SKILL.md +455 -0
  63. package/.agents/skills/marketing-psychology/evals/evals.json +88 -0
  64. package/.agents/skills/mintlify/SKILL.md +328 -0
  65. package/.agents/skills/product-launch-video/SKILL.md +206 -0
  66. package/.agents/skills/product-launch-video/references/cut-catalog.md +220 -0
  67. package/.agents/skills/product-launch-video/references/motion-language.md +156 -0
  68. package/.agents/skills/product-launch-video/references/story-design.md +373 -0
  69. package/.agents/skills/product-launch-video/references/visual-design.md +126 -0
  70. package/.agents/skills/product-launch-video/scripts/assemble-index.mjs +570 -0
  71. package/.agents/skills/product-launch-video/scripts/audio.mjs +253 -0
  72. package/.agents/skills/product-launch-video/scripts/build-frame.mjs +536 -0
  73. package/.agents/skills/product-launch-video/scripts/captions.mjs +508 -0
  74. package/.agents/skills/product-launch-video/scripts/lib/assets.mjs +55 -0
  75. package/.agents/skills/product-launch-video/scripts/lib/dimensions.mjs +45 -0
  76. package/.agents/skills/product-launch-video/scripts/lib/storyboard.mjs +249 -0
  77. package/.agents/skills/product-launch-video/scripts/lib/tokens.mjs +204 -0
  78. package/.agents/skills/product-launch-video/scripts/lib/transition-registry.mjs +38 -0
  79. package/.agents/skills/product-launch-video/scripts/lib/transitions.json +71 -0
  80. package/.agents/skills/product-launch-video/scripts/stage-assets.mjs +39 -0
  81. package/.agents/skills/product-launch-video/scripts/transitions.mjs +320 -0
  82. package/.agents/skills/product-launch-video/sub-agents/frame-worker.md +74 -0
  83. package/.agents/skills/prompt-engineering-patterns/SKILL.md +144 -0
  84. package/.agents/skills/prompt-engineering-patterns/assets/few-shot-examples.json +106 -0
  85. package/.agents/skills/prompt-engineering-patterns/assets/prompt-template-library.md +264 -0
  86. package/.agents/skills/prompt-engineering-patterns/references/chain-of-thought.md +412 -0
  87. package/.agents/skills/prompt-engineering-patterns/references/details.md +338 -0
  88. package/.agents/skills/prompt-engineering-patterns/references/few-shot-learning.md +386 -0
  89. package/.agents/skills/prompt-engineering-patterns/references/prompt-optimization.md +428 -0
  90. package/.agents/skills/prompt-engineering-patterns/references/prompt-templates.md +484 -0
  91. package/.agents/skills/prompt-engineering-patterns/references/system-prompts.md +195 -0
  92. package/.agents/skills/prompt-engineering-patterns/scripts/optimize-prompt.py +279 -0
  93. package/.agents/skills/remotion-to-hyperframes/SKILL.md +127 -0
  94. package/.agents/skills/remotion-to-hyperframes/assets/.gitkeep +0 -0
  95. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/run.sh +249 -0
  96. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/README.md +41 -0
  97. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/expected.json +26 -0
  98. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/hf-src/index.html +61 -0
  99. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/remotion-src/package.json +14 -0
  100. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/remotion-src/remotion.config.ts +13 -0
  101. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/remotion-src/src/Root.tsx +13 -0
  102. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/remotion-src/src/TitleCard.tsx +34 -0
  103. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/remotion-src/src/index.ts +4 -0
  104. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/remotion-src/tsconfig.json +15 -0
  105. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/README.md +54 -0
  106. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/expected.json +29 -0
  107. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/hf-src/index.html +118 -0
  108. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/remotion-src/package.json +14 -0
  109. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/remotion-src/remotion.config.ts +13 -0
  110. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/remotion-src/src/MultiScene.tsx +105 -0
  111. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/remotion-src/src/Root.tsx +13 -0
  112. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/remotion-src/src/index.ts +4 -0
  113. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/remotion-src/tsconfig.json +15 -0
  114. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/setup.sh +34 -0
  115. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/README.md +85 -0
  116. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/expected.json +41 -0
  117. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/hf-src/index.html +269 -0
  118. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/package.json +15 -0
  119. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/remotion.config.ts +13 -0
  120. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/src/Root.tsx +27 -0
  121. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/src/Stargazed.tsx +37 -0
  122. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/src/components/AnimatedNumber.tsx +23 -0
  123. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/src/components/StatCard.tsx +59 -0
  124. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/src/components/UnderlinedText.tsx +47 -0
  125. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/src/index.ts +4 -0
  126. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/src/scenes/OutroScene.tsx +18 -0
  127. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/src/scenes/StatsScene.tsx +34 -0
  128. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/src/scenes/TitleScene.tsx +55 -0
  129. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/tsconfig.json +15 -0
  130. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/README.md +51 -0
  131. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/cases/01-use-state.tsx +29 -0
  132. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/cases/02-use-effect-deps.tsx +29 -0
  133. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/cases/03-async-metadata.tsx +39 -0
  134. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/cases/04-third-party-react.tsx +30 -0
  135. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/cases/05-lambda-config.tsx +38 -0
  136. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/cases/06-warnings-only.tsx +36 -0
  137. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/cases/07-custom-hook.tsx +28 -0
  138. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/cases/08-mixed.tsx +41 -0
  139. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/expected.json +85 -0
  140. package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/validate.sh +110 -0
  141. package/.agents/skills/remotion-to-hyperframes/references/api-map.md +142 -0
  142. package/.agents/skills/remotion-to-hyperframes/references/escape-hatch.md +115 -0
  143. package/.agents/skills/remotion-to-hyperframes/references/eval.md +140 -0
  144. package/.agents/skills/remotion-to-hyperframes/references/fonts.md +112 -0
  145. package/.agents/skills/remotion-to-hyperframes/references/limitations.md +136 -0
  146. package/.agents/skills/remotion-to-hyperframes/references/lottie.md +121 -0
  147. package/.agents/skills/remotion-to-hyperframes/references/media.md +149 -0
  148. package/.agents/skills/remotion-to-hyperframes/references/parameters.md +167 -0
  149. package/.agents/skills/remotion-to-hyperframes/references/sequencing.md +195 -0
  150. package/.agents/skills/remotion-to-hyperframes/references/timing.md +165 -0
  151. package/.agents/skills/remotion-to-hyperframes/references/transitions.md +114 -0
  152. package/.agents/skills/remotion-to-hyperframes/scripts/.gitkeep +0 -0
  153. package/.agents/skills/remotion-to-hyperframes/scripts/frame_strip.sh +107 -0
  154. package/.agents/skills/remotion-to-hyperframes/scripts/lint_source.py +358 -0
  155. package/.agents/skills/remotion-to-hyperframes/scripts/render_diff.sh +103 -0
  156. package/.agents/skills/remotion-to-hyperframes/scripts/tests/fixtures/blocker.tsx +50 -0
  157. package/.agents/skills/remotion-to-hyperframes/scripts/tests/fixtures/clean.tsx +46 -0
  158. package/.agents/skills/remotion-to-hyperframes/scripts/tests/smoke.sh +90 -0
  159. package/.agents/skills/seo-audit/SKILL.md +497 -0
  160. package/.agents/skills/seo-audit/evals/evals.json +136 -0
  161. package/.agents/skills/seo-audit/references/ai-writing-detection.md +200 -0
  162. package/.agents/skills/seo-audit/references/international-seo.md +230 -0
  163. package/README.md +4 -2
  164. package/SDK.md +64 -1
  165. package/dist/agents/coding.agent.d.ts +632 -0
  166. package/dist/agents/coding.agent.d.ts.map +1 -1
  167. package/dist/agents/coding.agent.js +11 -3
  168. package/dist/agents/coding.agent.js.map +1 -1
  169. package/dist/agents/developer-helper.agent.d.ts +704 -0
  170. package/dist/agents/developer-helper.agent.d.ts.map +1 -1
  171. package/dist/agents/developer-helper.agent.js +6 -0
  172. package/dist/agents/developer-helper.agent.js.map +1 -1
  173. package/dist/agents/manager.d.ts +1009 -4
  174. package/dist/agents/manager.d.ts.map +1 -1
  175. package/dist/agents/manager.js +16 -5
  176. package/dist/agents/manager.js.map +1 -1
  177. package/dist/agents/security.agent.d.ts +157 -3
  178. package/dist/agents/security.agent.d.ts.map +1 -1
  179. package/dist/agents/security.agent.js +3 -0
  180. package/dist/agents/security.agent.js.map +1 -1
  181. package/dist/agents/swarm/main.js +1 -1
  182. package/dist/agents/swarm/main.js.map +1 -1
  183. package/dist/agents/swarm/registry.d.ts.map +1 -1
  184. package/dist/agents/swarm/registry.js +232 -26
  185. package/dist/agents/swarm/registry.js.map +1 -1
  186. package/dist/cli/chat.d.ts +1 -1
  187. package/dist/cli/chat.d.ts.map +1 -1
  188. package/dist/cli/chat.js +32 -10
  189. package/dist/cli/chat.js.map +1 -1
  190. package/dist/cli/doctor.d.ts +14 -0
  191. package/dist/cli/doctor.d.ts.map +1 -1
  192. package/dist/cli/doctor.js +91 -0
  193. package/dist/cli/doctor.js.map +1 -1
  194. package/dist/cli/format.d.ts +1 -0
  195. package/dist/cli/format.d.ts.map +1 -1
  196. package/dist/cli/format.js +68 -14
  197. package/dist/cli/format.js.map +1 -1
  198. package/dist/cli/menu.d.ts.map +1 -1
  199. package/dist/cli/menu.js +102 -0
  200. package/dist/cli/menu.js.map +1 -1
  201. package/dist/cli/setup.d.ts +10 -0
  202. package/dist/cli/setup.d.ts.map +1 -1
  203. package/dist/cli/setup.js +187 -3
  204. package/dist/cli/setup.js.map +1 -1
  205. package/dist/cli/update.d.ts +2 -0
  206. package/dist/cli/update.d.ts.map +1 -1
  207. package/dist/cli/update.js +89 -1
  208. package/dist/cli/update.js.map +1 -1
  209. package/dist/config/env.d.ts +12 -0
  210. package/dist/config/env.d.ts.map +1 -1
  211. package/dist/config/env.js +19 -5
  212. package/dist/config/env.js.map +1 -1
  213. package/dist/index.d.ts +1 -1
  214. package/dist/index.d.ts.map +1 -1
  215. package/dist/index.js +61 -5
  216. package/dist/index.js.map +1 -1
  217. package/dist/jobs/trigger-orchestrator.d.ts +5 -1
  218. package/dist/jobs/trigger-orchestrator.d.ts.map +1 -1
  219. package/dist/jobs/trigger-orchestrator.js +29 -9
  220. package/dist/jobs/trigger-orchestrator.js.map +1 -1
  221. package/dist/jobs/trigger-router.d.ts.map +1 -1
  222. package/dist/jobs/trigger-router.js +3 -2
  223. package/dist/jobs/trigger-router.js.map +1 -1
  224. package/dist/memory/corporate-wiki.d.ts +15 -0
  225. package/dist/memory/corporate-wiki.d.ts.map +1 -0
  226. package/dist/memory/corporate-wiki.js +152 -0
  227. package/dist/memory/corporate-wiki.js.map +1 -0
  228. package/dist/observability/doctor.d.ts.map +1 -1
  229. package/dist/observability/doctor.js +12 -4
  230. package/dist/observability/doctor.js.map +1 -1
  231. package/dist/pre-init.d.ts +2 -0
  232. package/dist/pre-init.d.ts.map +1 -0
  233. package/dist/pre-init.js +3 -0
  234. package/dist/pre-init.js.map +1 -0
  235. package/dist/runtime/chat-bridge.d.ts.map +1 -1
  236. package/dist/runtime/chat-bridge.js +33 -2
  237. package/dist/runtime/chat-bridge.js.map +1 -1
  238. package/dist/runtime/swarm.d.ts +0 -1
  239. package/dist/runtime/swarm.d.ts.map +1 -1
  240. package/dist/runtime/swarm.js +26 -15
  241. package/dist/runtime/swarm.js.map +1 -1
  242. package/dist/safety/approvals.d.ts +2 -2
  243. package/dist/safety/approvals.d.ts.map +1 -1
  244. package/dist/safety/approvals.js +47 -1
  245. package/dist/safety/approvals.js.map +1 -1
  246. package/dist/safety/redaction.d.ts.map +1 -1
  247. package/dist/safety/redaction.js +10 -0
  248. package/dist/safety/redaction.js.map +1 -1
  249. package/dist/server.d.ts +1 -0
  250. package/dist/server.d.ts.map +1 -1
  251. package/dist/server.js +1 -0
  252. package/dist/server.js.map +1 -1
  253. package/dist/tools/cloud.tool.d.ts +394 -0
  254. package/dist/tools/cloud.tool.d.ts.map +1 -0
  255. package/dist/tools/cloud.tool.js +784 -0
  256. package/dist/tools/cloud.tool.js.map +1 -0
  257. package/dist/tools/computer-use.tool.d.ts +6 -6
  258. package/dist/tools/corporate-wiki.tool.d.ts +22 -0
  259. package/dist/tools/corporate-wiki.tool.d.ts.map +1 -0
  260. package/dist/tools/corporate-wiki.tool.js +39 -0
  261. package/dist/tools/corporate-wiki.tool.js.map +1 -0
  262. package/dist/tools/desktop.tool.d.ts +96 -0
  263. package/dist/tools/desktop.tool.d.ts.map +1 -1
  264. package/dist/tools/desktop.tool.js +439 -0
  265. package/dist/tools/desktop.tool.js.map +1 -1
  266. package/dist/tools/devops.tool.d.ts +162 -0
  267. package/dist/tools/devops.tool.d.ts.map +1 -0
  268. package/dist/tools/devops.tool.js +377 -0
  269. package/dist/tools/devops.tool.js.map +1 -0
  270. package/dist/tools/multimedia.tool.d.ts +126 -0
  271. package/dist/tools/multimedia.tool.d.ts.map +1 -0
  272. package/dist/tools/multimedia.tool.js +533 -0
  273. package/dist/tools/multimedia.tool.js.map +1 -0
  274. package/dist/tools/osint.tool.d.ts +6 -6
  275. package/dist/tools/sandbox-dev.tool.d.ts +15 -0
  276. package/dist/tools/sandbox-dev.tool.d.ts.map +1 -0
  277. package/dist/tools/sandbox-dev.tool.js +139 -0
  278. package/dist/tools/sandbox-dev.tool.js.map +1 -0
  279. package/dist/tools/setup-assistant.tool.d.ts +1 -1
  280. package/dist/tools/shell.tool.d.ts +82 -0
  281. package/dist/tools/shell.tool.d.ts.map +1 -1
  282. package/dist/tools/shell.tool.js +192 -1
  283. package/dist/tools/shell.tool.js.map +1 -1
  284. package/dist/tools/swarm-ops.tool.d.ts +14 -0
  285. package/dist/tools/swarm-ops.tool.d.ts.map +1 -1
  286. package/dist/tools/swarm-ops.tool.js +44 -0
  287. package/dist/tools/swarm-ops.tool.js.map +1 -1
  288. package/dist/tools/sysops.tool.d.ts +157 -0
  289. package/dist/tools/sysops.tool.d.ts.map +1 -0
  290. package/dist/tools/sysops.tool.js +643 -0
  291. package/dist/tools/sysops.tool.js.map +1 -0
  292. package/dist/voice/cascade.d.ts +1 -0
  293. package/dist/voice/cascade.d.ts.map +1 -1
  294. package/dist/voice/cascade.js +16 -1
  295. package/dist/voice/cascade.js.map +1 -1
  296. package/dist/voice/deepgram.d.ts.map +1 -1
  297. package/dist/voice/deepgram.js +34 -2
  298. package/dist/voice/deepgram.js.map +1 -1
  299. package/dist/voice/terminal.d.ts +1 -0
  300. package/dist/voice/terminal.d.ts.map +1 -1
  301. package/dist/voice/terminal.js +28 -0
  302. package/dist/voice/terminal.js.map +1 -1
  303. package/dist/voice/types.d.ts +2 -0
  304. package/dist/voice/types.d.ts.map +1 -1
  305. package/package.json +9 -1
  306. package/scripts/release-github.mjs +23 -18
@@ -0,0 +1,279 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Prompt Optimization Script
4
+
5
+ Automatically test and optimize prompts using A/B testing and metrics tracking.
6
+ """
7
+
8
+ import json
9
+ import time
10
+ from typing import List, Dict, Any
11
+ from dataclasses import dataclass
12
+ from concurrent.futures import ThreadPoolExecutor
13
+ import numpy as np
14
+
15
+
16
+ @dataclass
17
+ class TestCase:
18
+ input: Dict[str, Any]
19
+ expected_output: str
20
+ metadata: Dict[str, Any] = None
21
+
22
+
23
+ class PromptOptimizer:
24
+ def __init__(self, llm_client, test_suite: List[TestCase]):
25
+ self.client = llm_client
26
+ self.test_suite = test_suite
27
+ self.results_history = []
28
+ self.executor = ThreadPoolExecutor()
29
+
30
+ def shutdown(self):
31
+ """Shutdown the thread pool executor."""
32
+ self.executor.shutdown(wait=True)
33
+
34
+ def evaluate_prompt(self, prompt_template: str, test_cases: List[TestCase] = None) -> Dict[str, float]:
35
+ """Evaluate a prompt template against test cases in parallel."""
36
+ if test_cases is None:
37
+ test_cases = self.test_suite
38
+
39
+ metrics = {
40
+ 'accuracy': [],
41
+ 'latency': [],
42
+ 'token_count': [],
43
+ 'success_rate': []
44
+ }
45
+
46
+ def process_test_case(test_case):
47
+ start_time = time.time()
48
+
49
+ # Render prompt with test case inputs
50
+ prompt = prompt_template.format(**test_case.input)
51
+
52
+ # Get LLM response
53
+ response = self.client.complete(prompt)
54
+
55
+ # Measure latency
56
+ latency = time.time() - start_time
57
+
58
+ # Calculate individual metrics
59
+ token_count = len(prompt.split()) + len(response.split())
60
+ success = 1 if response else 0
61
+ accuracy = self.calculate_accuracy(response, test_case.expected_output)
62
+
63
+ return {
64
+ 'latency': latency,
65
+ 'token_count': token_count,
66
+ 'success_rate': success,
67
+ 'accuracy': accuracy
68
+ }
69
+
70
+ # Run test cases in parallel
71
+ results = list(self.executor.map(process_test_case, test_cases))
72
+
73
+ # Aggregate metrics
74
+ for result in results:
75
+ metrics['latency'].append(result['latency'])
76
+ metrics['token_count'].append(result['token_count'])
77
+ metrics['success_rate'].append(result['success_rate'])
78
+ metrics['accuracy'].append(result['accuracy'])
79
+
80
+ return {
81
+ 'avg_accuracy': np.mean(metrics['accuracy']),
82
+ 'avg_latency': np.mean(metrics['latency']),
83
+ 'p95_latency': np.percentile(metrics['latency'], 95),
84
+ 'avg_tokens': np.mean(metrics['token_count']),
85
+ 'success_rate': np.mean(metrics['success_rate'])
86
+ }
87
+
88
+ def calculate_accuracy(self, response: str, expected: str) -> float:
89
+ """Calculate accuracy score between response and expected output."""
90
+ # Simple exact match
91
+ if response.strip().lower() == expected.strip().lower():
92
+ return 1.0
93
+
94
+ # Partial match using word overlap
95
+ response_words = set(response.lower().split())
96
+ expected_words = set(expected.lower().split())
97
+
98
+ if not expected_words:
99
+ return 0.0
100
+
101
+ overlap = len(response_words & expected_words)
102
+ return overlap / len(expected_words)
103
+
104
+ def optimize(self, base_prompt: str, max_iterations: int = 5) -> Dict[str, Any]:
105
+ """Iteratively optimize a prompt."""
106
+ current_prompt = base_prompt
107
+ best_prompt = base_prompt
108
+ best_score = 0
109
+ current_metrics = None
110
+
111
+ for iteration in range(max_iterations):
112
+ print(f"\nIteration {iteration + 1}/{max_iterations}")
113
+
114
+ # Evaluate current prompt
115
+ # Bolt Optimization: Avoid re-evaluating if we already have metrics from previous iteration
116
+ if current_metrics:
117
+ metrics = current_metrics
118
+ else:
119
+ metrics = self.evaluate_prompt(current_prompt)
120
+
121
+ print(f"Accuracy: {metrics['avg_accuracy']:.2f}, Latency: {metrics['avg_latency']:.2f}s")
122
+
123
+ # Track results
124
+ self.results_history.append({
125
+ 'iteration': iteration,
126
+ 'prompt': current_prompt,
127
+ 'metrics': metrics
128
+ })
129
+
130
+ # Update best if improved
131
+ if metrics['avg_accuracy'] > best_score:
132
+ best_score = metrics['avg_accuracy']
133
+ best_prompt = current_prompt
134
+
135
+ # Stop if good enough
136
+ if metrics['avg_accuracy'] > 0.95:
137
+ print("Achieved target accuracy!")
138
+ break
139
+
140
+ # Generate variations for next iteration
141
+ variations = self.generate_variations(current_prompt, metrics)
142
+
143
+ # Test variations and pick best
144
+ best_variation = current_prompt
145
+ best_variation_score = metrics['avg_accuracy']
146
+ best_variation_metrics = metrics
147
+
148
+ for variation in variations:
149
+ var_metrics = self.evaluate_prompt(variation)
150
+ if var_metrics['avg_accuracy'] > best_variation_score:
151
+ best_variation_score = var_metrics['avg_accuracy']
152
+ best_variation = variation
153
+ best_variation_metrics = var_metrics
154
+
155
+ current_prompt = best_variation
156
+ current_metrics = best_variation_metrics
157
+
158
+ return {
159
+ 'best_prompt': best_prompt,
160
+ 'best_score': best_score,
161
+ 'history': self.results_history
162
+ }
163
+
164
+ def generate_variations(self, prompt: str, current_metrics: Dict) -> List[str]:
165
+ """Generate prompt variations to test."""
166
+ variations = []
167
+
168
+ # Variation 1: Add explicit format instruction
169
+ variations.append(prompt + "\n\nProvide your answer in a clear, concise format.")
170
+
171
+ # Variation 2: Add step-by-step instruction
172
+ variations.append("Let's solve this step by step.\n\n" + prompt)
173
+
174
+ # Variation 3: Add verification step
175
+ variations.append(prompt + "\n\nVerify your answer before responding.")
176
+
177
+ # Variation 4: Make more concise
178
+ concise = self.make_concise(prompt)
179
+ if concise != prompt:
180
+ variations.append(concise)
181
+
182
+ # Variation 5: Add examples (if none present)
183
+ if "example" not in prompt.lower():
184
+ variations.append(self.add_examples(prompt))
185
+
186
+ return variations[:3] # Return top 3 variations
187
+
188
+ def make_concise(self, prompt: str) -> str:
189
+ """Remove redundant words to make prompt more concise."""
190
+ replacements = [
191
+ ("in order to", "to"),
192
+ ("due to the fact that", "because"),
193
+ ("at this point in time", "now"),
194
+ ("in the event that", "if"),
195
+ ]
196
+
197
+ result = prompt
198
+ for old, new in replacements:
199
+ result = result.replace(old, new)
200
+
201
+ return result
202
+
203
+ def add_examples(self, prompt: str) -> str:
204
+ """Add example section to prompt."""
205
+ return f"""{prompt}
206
+
207
+ Example:
208
+ Input: Sample input
209
+ Output: Sample output
210
+ """
211
+
212
+ def compare_prompts(self, prompt_a: str, prompt_b: str) -> Dict[str, Any]:
213
+ """A/B test two prompts."""
214
+ print("Testing Prompt A...")
215
+ metrics_a = self.evaluate_prompt(prompt_a)
216
+
217
+ print("Testing Prompt B...")
218
+ metrics_b = self.evaluate_prompt(prompt_b)
219
+
220
+ return {
221
+ 'prompt_a_metrics': metrics_a,
222
+ 'prompt_b_metrics': metrics_b,
223
+ 'winner': 'A' if metrics_a['avg_accuracy'] > metrics_b['avg_accuracy'] else 'B',
224
+ 'improvement': abs(metrics_a['avg_accuracy'] - metrics_b['avg_accuracy'])
225
+ }
226
+
227
+ def export_results(self, filename: str):
228
+ """Export optimization results to JSON."""
229
+ with open(filename, 'w') as f:
230
+ json.dump(self.results_history, f, indent=2)
231
+
232
+
233
+ def main():
234
+ # Example usage
235
+ test_suite = [
236
+ TestCase(
237
+ input={'text': 'This movie was amazing!'},
238
+ expected_output='Positive'
239
+ ),
240
+ TestCase(
241
+ input={'text': 'Worst purchase ever.'},
242
+ expected_output='Negative'
243
+ ),
244
+ TestCase(
245
+ input={'text': 'It was okay, nothing special.'},
246
+ expected_output='Neutral'
247
+ )
248
+ ]
249
+
250
+ # Mock LLM client for demonstration
251
+ class MockLLMClient:
252
+ def complete(self, prompt):
253
+ # Simulate LLM response
254
+ if 'amazing' in prompt:
255
+ return 'Positive'
256
+ elif 'worst' in prompt.lower():
257
+ return 'Negative'
258
+ else:
259
+ return 'Neutral'
260
+
261
+ optimizer = PromptOptimizer(MockLLMClient(), test_suite)
262
+
263
+ try:
264
+ base_prompt = "Classify the sentiment of: {text}\nSentiment:"
265
+
266
+ results = optimizer.optimize(base_prompt)
267
+
268
+ print("\n" + "="*50)
269
+ print("Optimization Complete!")
270
+ print(f"Best Accuracy: {results['best_score']:.2f}")
271
+ print(f"Best Prompt:\n{results['best_prompt']}")
272
+
273
+ optimizer.export_results('optimization_results.json')
274
+ finally:
275
+ optimizer.shutdown()
276
+
277
+
278
+ if __name__ == '__main__':
279
+ main()
@@ -0,0 +1,127 @@
1
+ ---
2
+ name: remotion-to-hyperframes
3
+ description: 'Port an existing Remotion (React) composition to HyperFrames HTML. Use ONLY when the user explicitly asks to port/convert/migrate/translate a Remotion source. Do NOT use: (a) authoring a new HyperFrames composition; (b) Remotion mentioned in passing; (c) Remotion code shared as reference only; (d) "same video as my Remotion one" without explicit migrate request — treat as fresh build. Doubt → `/general-video`. One-way, Remotion-only: no reverse export (HyperFrames→Remotion or any framework), no non-Remotion source (After Effects, Framer Motion, plain React/CSS) → out of scope, re-create via `/general-video`. Flags unsupported patterns (useState, useEffect, async calculateMetadata, third-party React libs, `@remotion/lambda`) and recommends runtime interop over lossy translation. Unsure whether to port vs. build fresh, or only a passing Remotion mention? → /hyperframes.'
4
+ ---
5
+
6
+ # Remotion to HyperFrames
7
+
8
+ > **Confirm the route before you build.** Use this **only** to port an existing **Remotion** (React) composition's source into HyperFrames. Authoring a **new** composition (even one inspired by a Remotion video) → the creation workflows / `/general-video`. **Out of scope** (one-way, Remotion-only): no reverse export (HyperFrames → Remotion or any framework), and a **non-Remotion** source (After Effects, Framer Motion, plain React / CSS) has no Remotion source to translate → re-create via `/general-video`. Unsure, or only a passing Remotion mention? **Read `/hyperframes` first.**
9
+
10
+ ## Overview
11
+
12
+ Translate Remotion (React-based) video compositions into HyperFrames (HTML + GSAP) compositions. Most Remotion idioms have direct HyperFrames equivalents — the translation is mechanical for ~80% of typical compositions. This skill encodes the mapping and guards against the lossy 20% by refusing to translate patterns that don't fit HF's seek-driven model and recommending the runtime interop pattern from [PR #214](https://github.com/heygen-com/hyperframes/pull/214) instead.
13
+
14
+ The skill ships with a **tiered test corpus** (T1–T4, 4 fixtures total) that grades translations against measured SSIM thresholds. Don't translate without running the eval — a translation that "looks right" but renders 0.05 SSIM lower than the validated baseline is silently wrong.
15
+
16
+ ## When to use
17
+
18
+ **Use this skill ONLY when the user explicitly asks to migrate from Remotion.** Example trigger phrases:
19
+
20
+ - "port my Remotion project to HyperFrames"
21
+ - "convert this Remotion code to HyperFrames"
22
+ - "migrate from Remotion"
23
+ - "translate this Remotion comp"
24
+ - "rewrite this as HyperFrames HTML"
25
+
26
+ **Do NOT use this skill when:**
27
+
28
+ - (a) The user is authoring a **new** HyperFrames composition, even if they have or are A/B-testing a similar Remotion video.
29
+ - (b) The user mentions Remotion in passing without asking for migration.
30
+ - (c) The user shares Remotion code as reference material rather than asking for a translation.
31
+ - (d) The user asks for "the same video as my Remotion one" without explicitly asking to migrate the source — treat that as a fresh HyperFrames build.
32
+
33
+ **NOT SUPPORTED (decline — this is not what this skill does):**
34
+
35
+ - **The reverse direction.** Exporting a HyperFrames composition back out _to_ Remotion (or to any other framework) is not a workflow — the translation is Remotion → HyperFrames only. Say so plainly.
36
+ - **Non-Remotion sources.** An After Effects project (`.aep`), a Framer Motion / plain-React / CSS animation, or any other tool's source is not a Remotion composition — there is no Remotion source to translate. Re-create it natively via `/general-video`, or decline if HyperFrames can't represent it.
37
+
38
+ When in doubt, default to authoring a native HyperFrames composition with `/general-video` (the general HyperFrames authoring flow) instead.
39
+
40
+ ## Workflow
41
+
42
+ ### Step 1: Lint the source
43
+
44
+ Run [`scripts/lint_source.py`](scripts/lint_source.py) over the Remotion source directory. The lint detects patterns that can't translate cleanly:
45
+
46
+ - **Blockers** (refuse + recommend interop): `useState`, `useReducer`, `useEffect`/`useLayoutEffect` with non-empty deps, async `calculateMetadata`, third-party React UI libraries (MUI, Chakra, Mantine, antd, shadcn, Radix, NextUI).
47
+ - **Warnings** (translate after dropping the construct): `@remotion/lambda` config, `delayRender`, `useCallback`, `useMemo`, custom hooks.
48
+ - **Info** (translate with note): `staticFile`, `interpolateColors`.
49
+
50
+ If any blocker fires, **stop**. Read [`references/escape-hatch.md`](references/escape-hatch.md) and surface the recommendation message. Warnings don't stop translation — drop the offending construct in step 3 and note the gap in `TRANSLATION_NOTES.md`. `@remotion/lambda` config is the canonical warning case: the skill drops the import + `renderMediaOnLambda(...)` calls but translates the rest of the composition.
51
+
52
+ ### Step 2: Plan the translation
53
+
54
+ Read [`references/api-map.md`](references/api-map.md) — the index of every Remotion API and its HF equivalent or per-topic reference. Identify which topic references you'll need based on what the source uses:
55
+
56
+ | Source contains | Load reference |
57
+ | ------------------------------------------------------------------------- | --------------------------------------------- |
58
+ | `Composition`, `defaultProps`, `schema`, `calculateMetadata` | [`parameters.md`](references/parameters.md) |
59
+ | `Sequence`, `Series`, `Loop`, `AbsoluteFill`, `Freeze` | [`sequencing.md`](references/sequencing.md) |
60
+ | `useCurrentFrame`, `interpolate`, `spring`, `Easing`, `interpolateColors` | [`timing.md`](references/timing.md) |
61
+ | `Audio`, `Video`, `Img`, `IFrame`, `staticFile`, `delayRender` | [`media.md`](references/media.md) |
62
+ | `TransitionSeries`, `@remotion/transitions` | [`transitions.md`](references/transitions.md) |
63
+ | `@remotion/lottie` | [`lottie.md`](references/lottie.md) |
64
+ | `@remotion/google-fonts/<Family>`, `Font.loadFont`, `@font-face` | [`fonts.md`](references/fonts.md) |
65
+
66
+ Don't load all of them — load only what the specific source needs.
67
+
68
+ ### Step 3: Generate the HF composition
69
+
70
+ Emit `index.html` with:
71
+
72
+ - Root `<div id="stage">` carrying the composition's `data-composition-id`, `data-start="0"`, `data-duration` (in seconds), `data-fps`, `data-width`, `data-height`, plus one `data-*` per scalar prop.
73
+ - A flat list of scene divs with `data-start` / `data-duration` / `data-track-index`.
74
+ - Inline `<style>` for layout; CSS sets the `from` state of every animated property.
75
+ - A single `<script>` tag at the bottom containing one paused `gsap.timeline({paused: true})`. Every Remotion `useCurrentFrame()` derivation becomes a tween on this timeline at the right offset.
76
+ - `window.__timelines["<composition-id>"] = tl;` registers the timeline with HF's runtime.
77
+
78
+ Custom React subcomponents inline as repeated HTML using the prop interface as the template (see [`parameters.md`](references/parameters.md) for the per-instance `data-*` pattern).
79
+
80
+ ### Step 4: Validate
81
+
82
+ Run the eval harness — [`references/eval.md`](references/eval.md) for the full guide. Quick path:
83
+
84
+ ```bash
85
+ # Render Remotion baseline (after npm install in the fixture)
86
+ cd remotion-src && npx remotion render <CompositionId> out/baseline.mp4
87
+
88
+ # Render HF translation
89
+ cd ../hf-src && npx hyperframes render --skill=remotion-to-hyperframes --output ../hf.mp4
90
+
91
+ # SSIM diff
92
+ ../../scripts/render_diff.sh ./remotion-src/out/baseline.mp4 ./hf.mp4 ./diff
93
+ ```
94
+
95
+ Threshold: ~0.02 below `p05` of the source's complexity tier (see `eval.md`'s validated thresholds table). If the diff fails, run [`scripts/frame_strip.sh`](scripts/frame_strip.sh) to see _which_ frames diverged, then re-read the relevant timing/sequencing/media reference.
96
+
97
+ **Critical**: both renders must use matching pixel format. Set `Config.setVideoImageFormat("png")` + `Config.setColorSpace("bt709")` in the Remotion source's `remotion.config.ts` — otherwise the diff measures encoder differences (~0.05 SSIM hit), not translation fidelity.
98
+
99
+ ### Step 5: Document gaps
100
+
101
+ Anything that didn't translate cleanly (volume ramps dropped, custom presentations approximated, fonts substituted) gets a `TRANSLATION_NOTES.md` written next to the HF output. See [`references/limitations.md`](references/limitations.md) for the format.
102
+
103
+ ## What this skill explicitly does NOT do
104
+
105
+ - **Translate React state machines.** Compositions that drive animation via `useState` + `useEffect` are not deterministic frame-capture targets in HyperFrames' seek-driven model. Recommend the runtime interop pattern.
106
+ - **Run Remotion's render pipeline alongside HyperFrames.** That's the runtime interop pattern from [PR #214](https://github.com/heygen-com/hyperframes/pull/214) — a separate solution for compositions that fail this skill's lint.
107
+
108
+ (`@remotion/lambda` is _not_ a blocker — Lambda config is deployment, not animation. The skill drops it as a warning and translates the rest. See [`references/escape-hatch.md`](references/escape-hatch.md).)
109
+
110
+ ## How to grade your own translation
111
+
112
+ Run the test corpus orchestrator:
113
+
114
+ ```bash
115
+ ./assets/test-corpus/run.sh
116
+ ```
117
+
118
+ It runs T1, T2, T3 (render + diff) and T4 (lint validation), prints a per-tier pass/fail table, and emits an aggregate JSON report. Use this to verify the skill is working end-to-end on a clean checkout — and as a regression check after editing any reference.
119
+
120
+ Validated baseline (as of 2026-04-27):
121
+
122
+ | Tier | Composition shape | Mean SSIM | Threshold |
123
+ | ---- | ------------------------------------------- | --------- | --------- |
124
+ | T1 | single-element fade-in | 0.974 | 0.95 |
125
+ | T2 | multi-scene + spring + audio + image | 0.985 | 0.95 |
126
+ | T3 | data-driven, custom subcomponents, count-up | 0.953 | 0.90 |
127
+ | T4 | escape-hatch (8 lint cases) | 8/8 pass | n/a |
@@ -0,0 +1,249 @@
1
+ #!/usr/bin/env bash
2
+ # run.sh — corpus orchestrator. Runs every tier and prints a pass/fail summary.
3
+ #
4
+ # Tiers 1-3: render Remotion baseline + HF translation, run SSIM diff,
5
+ # assert mean >= ssim_threshold from each fixture's expected.json.
6
+ # Tier 4: runs cases/validate.sh which lints each case and asserts against
7
+ # expected.json.
8
+ #
9
+ # Usage:
10
+ # ./run.sh run all tiers
11
+ # ./run.sh tier-1-title-card run a single tier
12
+ #
13
+ # Requirements:
14
+ # - ffmpeg, ffprobe, python3 on PATH
15
+ # - node 22 (for the HF CLI)
16
+ # - npm (for Remotion installs)
17
+ # - HF CLI built at packages/cli/dist/cli.js (run `bun run --filter @hyperframes/cli build`
18
+ # in the repo root if missing)
19
+ #
20
+ # Output:
21
+ # <fixture>/diff/summary.json per-fixture SSIM summary
22
+ # <fixture>/strip/strip.png per-fixture comparison strip (only on fail)
23
+ # ./run-report.json aggregate report
24
+
25
+ set -euo pipefail
26
+
27
+ THIS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
28
+ SKILL_DIR="$(cd "$THIS_DIR/../.." && pwd)"
29
+ REPO_ROOT="$(cd "$SKILL_DIR/../.." && pwd)"
30
+
31
+ LINT="$SKILL_DIR/scripts/lint_source.py"
32
+ DIFF="$SKILL_DIR/scripts/render_diff.sh"
33
+ STRIP="$SKILL_DIR/scripts/frame_strip.sh"
34
+ HF_CLI="$REPO_ROOT/packages/cli/dist/cli.js"
35
+ REPORT="$THIS_DIR/run-report.json"
36
+
37
+ # Per-fixture results land here as one JSON file each, then the aggregator
38
+ # globs them. This is safer than building JSON via bash string concatenation
39
+ # (a fixture name containing a quote would break the previous approach).
40
+ RESULTS_DIR="$(mktemp -d)"
41
+ trap 'rm -rf "$RESULTS_DIR"' EXIT
42
+
43
+ # T4 is lint-only — no ffmpeg or HF CLI needed. Defer the render-tier
44
+ # toolchain checks until run_render_tier() actually runs, so
45
+ # `./run.sh tier-4-escape-hatch` works on a clean checkout.
46
+ require_render_tier_tools() {
47
+ if [[ ! -f "$HF_CLI" ]]; then
48
+ echo "error: HF CLI not built at $HF_CLI" >&2
49
+ echo " Run 'bun run --filter @hyperframes/cli build' in $REPO_ROOT" >&2
50
+ return 2
51
+ fi
52
+ if ! command -v ffmpeg >/dev/null 2>&1; then
53
+ echo "error: ffmpeg not on PATH" >&2
54
+ return 2
55
+ fi
56
+ return 0
57
+ }
58
+
59
+ # Write one fixture's result as a JSON file. Values are passed via argv so
60
+ # bash string interpolation can't corrupt the JSON or inject Python source.
61
+ write_result() {
62
+ local fixture_name="$1"
63
+ local status="$2"
64
+ shift 2
65
+ python3 - "$RESULTS_DIR/$fixture_name.json" "$fixture_name" "$status" "$@" <<'PY'
66
+ import json
67
+ import sys
68
+
69
+ out_path, fixture_name, status, *kvs = sys.argv[1:]
70
+ result = {"fixture": fixture_name, "status": status}
71
+ for i in range(0, len(kvs), 2):
72
+ k, v = kvs[i], kvs[i + 1]
73
+ try:
74
+ result[k] = float(v) if "." in v or v.lstrip("-").isdigit() else v
75
+ except ValueError:
76
+ result[k] = v
77
+ with open(out_path, "w") as f:
78
+ json.dump(result, f)
79
+ PY
80
+ }
81
+
82
+ # Read a top-level scalar value from a JSON file. Falls back to $3 if the
83
+ # key is missing (used to default composition_id for older fixtures).
84
+ read_json_value() {
85
+ local file="$1"
86
+ local key="$2"
87
+ local default="${3:-}"
88
+ python3 - "$file" "$key" "$default" <<'PY'
89
+ import json
90
+ import sys
91
+
92
+ path, key, default = sys.argv[1], sys.argv[2], sys.argv[3]
93
+ with open(path) as f:
94
+ data = json.load(f)
95
+ val = data.get(key, default)
96
+ print(val if val is not None else "")
97
+ PY
98
+ }
99
+
100
+ run_render_tier() {
101
+ local fixture_dir="$1"
102
+ local fixture_name
103
+ fixture_name=$(basename "$fixture_dir")
104
+ local expected="$fixture_dir/expected.json"
105
+
106
+ if ! require_render_tier_tools; then
107
+ echo " ⚠ $fixture_name: render toolchain unavailable, skipping"
108
+ write_result "$fixture_name" "skipped" reason "render toolchain unavailable"
109
+ return 0
110
+ fi
111
+
112
+ local threshold composition_id
113
+ threshold=$(read_json_value "$expected" "ssim_threshold")
114
+ composition_id=$(read_json_value "$expected" "composition_id" "Composition")
115
+
116
+ echo " ▶ $fixture_name (threshold $threshold, composition $composition_id)"
117
+
118
+ if [[ -x "$fixture_dir/setup.sh" ]]; then
119
+ "$fixture_dir/setup.sh" >/dev/null
120
+ fi
121
+
122
+ if ! python3 "$LINT" "$fixture_dir/remotion-src/src/" >/dev/null; then
123
+ echo " ✗ lint failed (blockers in Remotion source)"
124
+ write_result "$fixture_name" "fail" stage "lint"
125
+ return 0
126
+ fi
127
+
128
+ if [[ ! -d "$fixture_dir/remotion-src/node_modules" ]]; then
129
+ echo " ⏳ npm install (first run)"
130
+ (cd "$fixture_dir/remotion-src" && npm install --silent --no-progress >/dev/null 2>&1)
131
+ fi
132
+
133
+ echo " ⏳ render Remotion baseline"
134
+ if ! (cd "$fixture_dir/remotion-src" && \
135
+ npx --no-install remotion render "$composition_id" out/baseline.mp4 >/dev/null 2>&1); then
136
+ echo " ✗ Remotion render failed"
137
+ write_result "$fixture_name" "fail" stage "remotion-render"
138
+ return 0
139
+ fi
140
+
141
+ echo " ⏳ render HF translation"
142
+ if ! (cd "$fixture_dir" && \
143
+ node "$HF_CLI" render hf-src/ --output hf.mp4 --quiet >/dev/null 2>&1); then
144
+ echo " ✗ HF render failed"
145
+ write_result "$fixture_name" "fail" stage "hf-render"
146
+ return 0
147
+ fi
148
+
149
+ if R2HF_SSIM_THRESHOLD="$threshold" "$DIFF" \
150
+ "$fixture_dir/remotion-src/out/baseline.mp4" \
151
+ "$fixture_dir/hf.mp4" \
152
+ "$fixture_dir/diff" >/dev/null; then
153
+ local mean
154
+ mean=$(read_json_value "$fixture_dir/diff/summary.json" "mean")
155
+ echo " ✓ pass (mean SSIM $mean, threshold $threshold)"
156
+ write_result "$fixture_name" "pass" mean_ssim "$mean" threshold "$threshold"
157
+ else
158
+ local mean
159
+ mean=$(read_json_value "$fixture_dir/diff/summary.json" "mean")
160
+ echo " ✗ fail (mean SSIM $mean, threshold $threshold)"
161
+ "$STRIP" \
162
+ "$fixture_dir/remotion-src/out/baseline.mp4" \
163
+ "$fixture_dir/hf.mp4" \
164
+ "$fixture_dir/strip" 8 >/dev/null
165
+ write_result "$fixture_name" "fail" stage "ssim" mean_ssim "$mean" threshold "$threshold"
166
+ fi
167
+ }
168
+
169
+ run_lint_tier() {
170
+ local fixture_dir="$1"
171
+ local fixture_name
172
+ fixture_name=$(basename "$fixture_dir")
173
+
174
+ echo " ▶ $fixture_name (lint-only)"
175
+ if "$fixture_dir/validate.sh" >/dev/null 2>&1; then
176
+ echo " ✓ pass (8/8 cases)"
177
+ write_result "$fixture_name" "pass" mode "lint"
178
+ else
179
+ echo " ✗ fail (some cases mismatched expected.json)"
180
+ write_result "$fixture_name" "fail" mode "lint"
181
+ fi
182
+ }
183
+
184
+ echo "remotion-to-hyperframes corpus run"
185
+ echo "=================================="
186
+
187
+ for tier in tier-1-title-card tier-2-multi-scene tier-3-data-driven; do
188
+ if [[ -n "${1:-}" && "$1" != "$tier" ]]; then
189
+ continue
190
+ fi
191
+ if [[ -d "$THIS_DIR/$tier" ]]; then
192
+ run_render_tier "$THIS_DIR/$tier"
193
+ fi
194
+ done
195
+
196
+ if [[ -z "${1:-}" || "$1" == "tier-4-escape-hatch" ]]; then
197
+ if [[ -d "$THIS_DIR/tier-4-escape-hatch" ]]; then
198
+ run_lint_tier "$THIS_DIR/tier-4-escape-hatch"
199
+ fi
200
+ fi
201
+
202
+ # Aggregate the per-fixture JSON files into one report.
203
+ #
204
+ # Skipped fixtures are *not* a pass — they mean a tier didn't run because
205
+ # tooling or fixtures were unavailable. The orchestrator exits non-zero on
206
+ # any skip so a clean checkout that lacks the HF CLI doesn't accidentally
207
+ # report "passed 1/4" (T4 alone) and look like the corpus is healthy.
208
+ #
209
+ # Single-tier mode (`./run.sh tier-N`) only writes a result file for the
210
+ # selected tier; tiers that weren't run aren't counted as skips.
211
+ python3 - "$RESULTS_DIR" "$REPORT" <<'PY'
212
+ import json
213
+ import sys
214
+ from pathlib import Path
215
+
216
+ results_dir, out_path = Path(sys.argv[1]), Path(sys.argv[2])
217
+ results = sorted(
218
+ (json.loads(p.read_text()) for p in results_dir.glob("*.json")),
219
+ key=lambda r: r["fixture"],
220
+ )
221
+
222
+ total = len(results)
223
+ passed = sum(1 for r in results if r["status"] == "pass")
224
+ failed = sum(1 for r in results if r["status"] == "fail")
225
+ skipped = sum(1 for r in results if r["status"] == "skipped")
226
+ report = {
227
+ "total": total,
228
+ "passed": passed,
229
+ "failed": failed,
230
+ "skipped": skipped,
231
+ "results": results,
232
+ }
233
+ out_path.write_text(json.dumps(report, indent=2))
234
+
235
+ print()
236
+ print("=" * 50)
237
+ print(f" passed {passed}/{total}, failed {failed}, skipped {skipped}")
238
+ print(f" report → {out_path}")
239
+ if skipped > 0:
240
+ skipped_fixtures = [r["fixture"] for r in results if r["status"] == "skipped"]
241
+ skipped_reasons = sorted({r.get("reason", "unknown") for r in results if r["status"] == "skipped"})
242
+ print()
243
+ print(f" ⚠ {skipped} skipped: {', '.join(skipped_fixtures)}")
244
+ for reason in skipped_reasons:
245
+ print(f" reason: {reason}")
246
+ print(" Skipped fixtures count as failures for the aggregate.")
247
+ print("=" * 50)
248
+ sys.exit(0 if failed == 0 and skipped == 0 else 1)
249
+ PY