dsh-hyperframes 0.3.2 → 0.4.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 (375) hide show
  1. package/README.en.md +4 -3
  2. package/README.md +5 -4
  3. package/lib/index.d.ts +1 -1
  4. package/lib/index.js +1 -0
  5. package/package.json +2 -2
  6. package/skills/embedded-captions/SKILL.md +28 -3
  7. package/skills/embedded-captions/references/aesthetic-principles.md +2 -3
  8. package/skills/embedded-captions/references/rail.md +1 -1
  9. package/skills/embedded-captions/scripts/check-occlusion.cjs +4 -1
  10. package/skills/embedded-captions/scripts/check-overflow.cjs +1 -0
  11. package/skills/embedded-captions/scripts/check-rail-climax.cjs +5 -1
  12. package/skills/embedded-captions/scripts/fixtures/heroless/theme.json +11 -0
  13. package/skills/embedded-captions/scripts/hf-cli.cjs +33 -0
  14. package/skills/embedded-captions/scripts/make-theme.cjs +95 -57
  15. package/skills/embedded-captions/scripts/make-theme.test.mjs +131 -0
  16. package/skills/embedded-captions/scripts/matte.cjs +1 -13
  17. package/skills/embedded-captions/scripts/measure-layout.cjs +2 -1
  18. package/skills/embedded-captions/scripts/preview-frames.cjs +39 -11
  19. package/skills/embedded-captions/scripts/preview-frames.test.mjs +24 -0
  20. package/skills/embedded-captions/scripts/render-and-composite.sh +8 -52
  21. package/skills/embedded-captions/scripts/safe-zones.cjs +4 -1
  22. package/skills/embedded-captions/scripts/transcribe.cjs +5 -14
  23. package/skills/embedded-captions/scripts/transcribe.test.mjs +41 -0
  24. package/skills/faceless-explainer/SKILL.md +20 -16
  25. package/skills/faceless-explainer/references/story-design.md +1 -1
  26. package/skills/faceless-explainer/scripts/assemble-index.mjs +6 -4
  27. package/skills/faceless-explainer/scripts/assemble-index.test.mjs +57 -2
  28. package/skills/faceless-explainer/scripts/audio.mjs +2 -0
  29. package/skills/faceless-explainer/scripts/build-frame.mjs +6 -3
  30. package/skills/faceless-explainer/scripts/captions.mjs +7 -4
  31. package/skills/faceless-explainer/scripts/frame-packets.mjs +4 -4
  32. package/skills/faceless-explainer/scripts/lib/bgm-volume.mjs +4 -0
  33. package/skills/faceless-explainer/scripts/lib/captured-fonts.mjs +58 -0
  34. package/skills/{hyperframes-core → faceless-explainer}/scripts/lib/frame-packets-core.mjs +5 -23
  35. package/skills/faceless-explainer/scripts/lib/storyboard.mjs +1 -1
  36. package/skills/faceless-explainer/scripts/lib/transitions.json +3 -3
  37. package/skills/faceless-explainer/scripts/transitions.mjs +1 -0
  38. package/skills/faceless-explainer/scripts/transitions.test.mjs +2 -0
  39. package/skills/faceless-explainer/sub-agents/frame-worker.md +1 -1
  40. package/skills/figma/SKILL.md +2 -0
  41. package/skills/general-video/SKILL.md +13 -11
  42. package/skills/general-video/scripts/frame-packets.mjs +4 -4
  43. package/skills/general-video/scripts/lib/frame-packets-core.mjs +194 -0
  44. package/skills/general-video/sub-agents/frame-worker.md +1 -1
  45. package/skills/hyperframes/SKILL.md +40 -30
  46. package/skills/{hyperframes-core → hyperframes}/references/brief-contract.md +15 -15
  47. package/skills/{hyperframes-core → hyperframes}/references/brief-format.md +8 -8
  48. package/skills/hyperframes/references/capability-menu.md +2 -2
  49. package/skills/{hyperframes-core → hyperframes}/references/frame-worker-core.md +1 -1
  50. package/skills/hyperframes/references/intent-interview.md +16 -16
  51. package/skills/hyperframes/references/plugin-installation.md +43 -0
  52. package/skills/{hyperframes-core → hyperframes}/references/production-loop.md +11 -11
  53. package/skills/hyperframes/references/review-loop.md +37 -0
  54. package/skills/hyperframes/references/route-briefs.md +1 -1
  55. package/skills/hyperframes/references/routes/motion-graphics.md +1 -1
  56. package/skills/{hyperframes-core → hyperframes}/references/script-format.md +3 -3
  57. package/skills/hyperframes/references/skill-lifecycle.md +2 -0
  58. package/skills/{hyperframes-core → hyperframes}/references/storyboard-format.md +3 -34
  59. package/skills/hyperframes/scripts/lib/frame-packets-core.mjs +194 -0
  60. package/skills/hyperframes/scripts/plugin-cli.mjs +88 -0
  61. package/skills/hyperframes/scripts/plugin-cli.test.mjs +117 -0
  62. package/skills/hyperframes-animation/SKILL.md +5 -1
  63. package/skills/hyperframes-animation/adapters/gsap.md +1 -1
  64. package/skills/hyperframes-animation/adapters/lottie.md +15 -2
  65. package/skills/hyperframes-animation/adapters/three.md +14 -0
  66. package/skills/hyperframes-animation/blueprints/titlecard-reveal.md +1 -1
  67. package/skills/hyperframes-animation/references/motion-blur.md +133 -0
  68. package/skills/hyperframes-animation/rules/cursor-click-ripple.md +1 -1
  69. package/skills/hyperframes-animation/rules/dynamic-content-sequencing.md +1 -1
  70. package/skills/hyperframes-animation/rules/hacker-flip-3d.md +1 -1
  71. package/skills/hyperframes-animation/rules/kinetic-beat-slam.md +2 -2
  72. package/skills/hyperframes-animation/rules/motion-blur-streak.md +1 -1
  73. package/skills/hyperframes-animation/rules/vertical-spring-ticker.md +1 -1
  74. package/skills/hyperframes-animation/scripts/package-loader.mjs +47 -16
  75. package/skills/hyperframes-animation/scripts/package-loader.test.mjs +52 -0
  76. package/skills/hyperframes-animation/techniques.md +1 -1
  77. package/skills/hyperframes-animation/transitions/TRANSITION-REGISTRY.md +3 -3
  78. package/skills/hyperframes-animation/transitions/css-push.md +4 -4
  79. package/skills/hyperframes-audio/SKILL.md +30 -22
  80. package/skills/hyperframes-audio/scripts/carve.mjs +6 -3
  81. package/skills/hyperframes-audio/scripts/carve.test.mjs +16 -1
  82. package/skills/hyperframes-cli/SKILL.md +44 -35
  83. package/skills/hyperframes-cli/references/init-and-scaffold.md +8 -6
  84. package/skills/hyperframes-cli/references/lint-validate-inspect.md +3 -3
  85. package/skills/hyperframes-cli/references/preview-render.md +35 -32
  86. package/skills/hyperframes-cli/references/upgrade-info-misc.md +50 -1
  87. package/skills/hyperframes-core/SKILL.md +30 -24
  88. package/skills/hyperframes-core/references/composition-patterns.md +3 -42
  89. package/skills/hyperframes-core/references/creator-editing-recipes.md +131 -7
  90. package/skills/hyperframes-core/references/data-attributes.md +11 -11
  91. package/skills/hyperframes-core/references/determinism-rules.md +2 -19
  92. package/skills/hyperframes-core/references/full-screen-motion.md +0 -9
  93. package/skills/hyperframes-core/references/minimal-composition.md +2 -2
  94. package/skills/hyperframes-core/references/sub-compositions.md +3 -66
  95. package/skills/hyperframes-core/references/tailwind.md +1 -20
  96. package/skills/hyperframes-core/references/tracks-and-clips.md +2 -6
  97. package/skills/hyperframes-core/references/variables-and-media.md +3 -3
  98. package/skills/hyperframes-creative/SKILL.md +2 -0
  99. package/skills/hyperframes-creative/references/house-style.md +15 -15
  100. package/skills/hyperframes-creative/references/story-spine.md +3 -1
  101. package/skills/hyperframes-creative/references/storyboard-recipe.md +57 -0
  102. package/skills/hyperframes-creative/references/typography.md +1 -1
  103. package/skills/hyperframes-creative/scripts/package-loader.mjs +47 -16
  104. package/skills/hyperframes-creative/scripts/package-loader.test.mjs +52 -0
  105. package/skills/hyperframes-keyframes/SKILL.md +4 -2
  106. package/skills/hyperframes-registry/SKILL.md +3 -1
  107. package/skills/hyperframes-registry/references/contributing.md +8 -2
  108. package/skills/hyperframes-registry/references/discovery.md +20 -34
  109. package/skills/hyperframes-studio/SKILL.md +77 -0
  110. package/skills/media-use/SKILL.md +14 -12
  111. package/skills/media-use/audio/references/captions/authoring.md +4 -0
  112. package/skills/media-use/audio/references/remove-background.md +1 -1
  113. package/skills/media-use/audio/references/tts-to-captions.md +11 -2
  114. package/skills/media-use/audio/references/tts.md +84 -6
  115. package/skills/media-use/audio/scripts/audio.mjs +15 -6
  116. package/skills/media-use/audio/scripts/gemini-pipeline.test.mjs +113 -0
  117. package/skills/media-use/audio/scripts/lib/audio-meta.mjs +39 -0
  118. package/skills/media-use/audio/scripts/lib/audio-meta.test.mjs +136 -0
  119. package/skills/media-use/audio/scripts/lib/bgm-volume.mjs +4 -0
  120. package/skills/media-use/audio/scripts/lib/bgm.mjs +2 -6
  121. package/skills/media-use/audio/scripts/lib/gemini-auth.mjs +43 -0
  122. package/skills/media-use/audio/scripts/lib/gemini-auth.py +52 -0
  123. package/skills/media-use/audio/scripts/lib/gemini-auth.test.mjs +86 -0
  124. package/skills/media-use/audio/scripts/lib/gemini-auth_test.py +90 -0
  125. package/skills/media-use/audio/scripts/lib/gemini-tts.mjs +122 -0
  126. package/skills/media-use/audio/scripts/lib/gemini-tts.test.mjs +243 -0
  127. package/skills/media-use/audio/scripts/lib/heygen.mjs +2 -1
  128. package/skills/media-use/audio/scripts/lib/tts.mjs +15 -3
  129. package/skills/media-use/audio/scripts/wait-bgm.mjs +8 -4
  130. package/skills/media-use/audio/scripts/wait-bgm.test.mjs +65 -0
  131. package/skills/media-use/references/audio.md +3 -2
  132. package/skills/media-use/references/grading.md +7 -7
  133. package/skills/media-use/references/media-treatment-recipes.md +1 -1
  134. package/skills/media-use/references/memory.md +2 -2
  135. package/skills/media-use/references/meta.md +2 -2
  136. package/skills/media-use/references/operations.md +15 -13
  137. package/skills/media-use/references/resolve.md +22 -11
  138. package/skills/media-use/references/setup-providers.md +11 -11
  139. package/skills/media-use/scripts/audio-duck.mjs +19 -27
  140. package/skills/media-use/scripts/compatibility.test.mjs +96 -0
  141. package/skills/media-use/scripts/lib/config-lock.mjs +45 -0
  142. package/skills/media-use/scripts/lib/duck.mjs +16 -10
  143. package/skills/media-use/scripts/lib/media-fetch.mjs +85 -0
  144. package/skills/media-use/scripts/lib/media-home.mjs +20 -0
  145. package/skills/media-use/scripts/lib/npx-sync.mjs +28 -2
  146. package/skills/media-use/scripts/lib/prefs-store.mjs +2 -2
  147. package/skills/media-use/scripts/lib/recipe-store.mjs +2 -2
  148. package/skills/media-use/scripts/lib/telemetry.mjs +29 -41
  149. package/skills/media-use/scripts/lib/transcriptCutFade.mjs +21 -0
  150. package/skills/media-use/scripts/prefs.mjs +1 -1
  151. package/skills/media-use/scripts/recipe.mjs +1 -1
  152. package/skills/media-use/scripts/resolve-plugin.test.mjs +62 -0
  153. package/skills/media-use/scripts/resolve.mjs +27 -1267
  154. package/skills/media-use/scripts/transcribe.mjs +39 -25
  155. package/skills/media-use/scripts/transcribe.test.mjs +112 -0
  156. package/skills/media-use/scripts/transcript-cut.mjs +39 -8
  157. package/skills/media-use/scripts/transcript-cut.test.mjs +117 -0
  158. package/skills/motion-graphics/SKILL.md +3 -1
  159. package/skills/motion-graphics/agents/builder.md +1 -0
  160. package/skills/motion-graphics/agents/director.md +2 -1
  161. package/skills/motion-graphics/catalog-map.md +25 -13
  162. package/skills/motion-graphics/categories/charts/module.md +2 -1
  163. package/skills/motion-graphics/categories/lower-thirds/module.md +4 -0
  164. package/skills/motion-graphics/categories/news/module.md +1 -1
  165. package/skills/motion-graphics/references/motion-vocabulary.md +4 -0
  166. package/skills/music-to-video/SKILL.md +8 -6
  167. package/skills/music-to-video/references/montage.md +3 -6
  168. package/skills/music-to-video/references/motion-primitives/3d-card-flip/index.html +10 -111
  169. package/skills/music-to-video/references/motion-primitives/3d-card-flip/scene.html +119 -0
  170. package/skills/music-to-video/references/motion-primitives/bg-flow-field/index.html +11 -284
  171. package/skills/music-to-video/references/motion-primitives/bg-flow-field/scene.html +294 -0
  172. package/skills/music-to-video/references/motion-primitives/binary-decrypt/index.html +10 -76
  173. package/skills/music-to-video/references/motion-primitives/binary-decrypt/scene.html +85 -0
  174. package/skills/music-to-video/references/motion-primitives/blur-resolve/index.html +10 -52
  175. package/skills/music-to-video/references/motion-primitives/blur-resolve/scene.html +60 -0
  176. package/skills/music-to-video/references/motion-primitives/braam-punch/index.html +10 -92
  177. package/skills/music-to-video/references/motion-primitives/braam-punch/scene.html +100 -0
  178. package/skills/music-to-video/references/motion-primitives/chromatic-split/index.html +10 -103
  179. package/skills/music-to-video/references/motion-primitives/chromatic-split/scene.html +111 -0
  180. package/skills/music-to-video/references/motion-primitives/chrome-sweep/index.html +10 -60
  181. package/skills/music-to-video/references/motion-primitives/chrome-sweep/scene.html +68 -0
  182. package/skills/music-to-video/references/motion-primitives/counting-punch/index.html +10 -110
  183. package/skills/music-to-video/references/motion-primitives/counting-punch/scene.html +119 -0
  184. package/skills/music-to-video/references/motion-primitives/crash-zoom-in/index.html +10 -112
  185. package/skills/music-to-video/references/motion-primitives/crash-zoom-in/scene.html +120 -0
  186. package/skills/music-to-video/references/motion-primitives/datamosh-smear/index.html +10 -121
  187. package/skills/music-to-video/references/motion-primitives/datamosh-smear/scene.html +131 -0
  188. package/skills/music-to-video/references/motion-primitives/directional-fill/index.html +10 -90
  189. package/skills/music-to-video/references/motion-primitives/directional-fill/scene.html +103 -0
  190. package/skills/music-to-video/references/motion-primitives/dolly-zoom/index.html +10 -94
  191. package/skills/music-to-video/references/motion-primitives/dolly-zoom/scene.html +102 -0
  192. package/skills/music-to-video/references/motion-primitives/electric-arc/index.html +10 -100
  193. package/skills/music-to-video/references/motion-primitives/electric-arc/scene.html +105 -0
  194. package/skills/music-to-video/references/motion-primitives/flash-cut/index.html +10 -89
  195. package/skills/music-to-video/references/motion-primitives/flash-cut/scene.html +97 -0
  196. package/skills/music-to-video/references/motion-primitives/gooey-metaball/index.html +10 -197
  197. package/skills/music-to-video/references/motion-primitives/gooey-metaball/scene.html +206 -0
  198. package/skills/music-to-video/references/motion-primitives/hard-cut/index.html +10 -74
  199. package/skills/music-to-video/references/motion-primitives/hard-cut/scene.html +82 -0
  200. package/skills/music-to-video/references/motion-primitives/hypercut-whip/index.html +10 -36
  201. package/skills/music-to-video/references/motion-primitives/hypercut-whip/scene.html +44 -0
  202. package/skills/music-to-video/references/motion-primitives/iris-open/index.html +10 -61
  203. package/skills/music-to-video/references/motion-primitives/iris-open/scene.html +69 -0
  204. package/skills/music-to-video/references/motion-primitives/kinetic-letter-in/index.html +10 -55
  205. package/skills/music-to-video/references/motion-primitives/kinetic-letter-in/scene.html +64 -0
  206. package/skills/music-to-video/references/motion-primitives/liquid-morph/index.html +10 -88
  207. package/skills/music-to-video/references/motion-primitives/liquid-morph/scene.html +96 -0
  208. package/skills/music-to-video/references/motion-primitives/mask-reveal/index.html +10 -66
  209. package/skills/music-to-video/references/motion-primitives/mask-reveal/scene.html +74 -0
  210. package/skills/music-to-video/references/motion-primitives/mosaic-pack/index.html +10 -81
  211. package/skills/music-to-video/references/motion-primitives/mosaic-pack/scene.html +89 -0
  212. package/skills/music-to-video/references/motion-primitives/neon-flicker/index.html +10 -65
  213. package/skills/music-to-video/references/motion-primitives/neon-flicker/scene.html +73 -0
  214. package/skills/music-to-video/references/motion-primitives/outline-to-fill/index.html +10 -74
  215. package/skills/music-to-video/references/motion-primitives/outline-to-fill/scene.html +82 -0
  216. package/skills/music-to-video/references/motion-primitives/palette-flip/index.html +10 -89
  217. package/skills/music-to-video/references/motion-primitives/palette-flip/scene.html +97 -0
  218. package/skills/music-to-video/references/motion-primitives/particle-burst/index.html +10 -98
  219. package/skills/music-to-video/references/motion-primitives/particle-burst/scene.html +106 -0
  220. package/skills/music-to-video/references/motion-primitives/pixel-dissolve/index.html +10 -78
  221. package/skills/music-to-video/references/motion-primitives/pixel-dissolve/scene.html +86 -0
  222. package/skills/music-to-video/references/motion-primitives/radial-burst-lines/index.html +10 -117
  223. package/skills/music-to-video/references/motion-primitives/radial-burst-lines/scene.html +130 -0
  224. package/skills/music-to-video/references/motion-primitives/screen-shake/index.html +10 -70
  225. package/skills/music-to-video/references/motion-primitives/screen-shake/scene.html +78 -0
  226. package/skills/music-to-video/references/motion-primitives/slot-machine-reveal/index.html +10 -87
  227. package/skills/music-to-video/references/motion-primitives/slot-machine-reveal/scene.html +100 -0
  228. package/skills/music-to-video/references/motion-primitives/spotlight-sweep/index.html +10 -94
  229. package/skills/music-to-video/references/motion-primitives/spotlight-sweep/scene.html +102 -0
  230. package/skills/music-to-video/references/motion-primitives/staggered-exit/index.html +10 -74
  231. package/skills/music-to-video/references/motion-primitives/staggered-exit/scene.html +82 -0
  232. package/skills/music-to-video/references/motion-primitives/text-spectral-rays/index.html +11 -271
  233. package/skills/music-to-video/references/motion-primitives/text-spectral-rays/scene.html +280 -0
  234. package/skills/music-to-video/references/motion-primitives/text-wave-distort/index.html +10 -92
  235. package/skills/music-to-video/references/motion-primitives/text-wave-distort/scene.html +106 -0
  236. package/skills/music-to-video/references/motion-primitives/tile-mosaic/index.html +10 -101
  237. package/skills/music-to-video/references/motion-primitives/tile-mosaic/scene.html +109 -0
  238. package/skills/music-to-video/references/motion-primitives/typewriter-reveal/index.html +10 -79
  239. package/skills/music-to-video/references/motion-primitives/typewriter-reveal/scene.html +91 -0
  240. package/skills/music-to-video/references/motion-primitives/word-grid-burst/index.html +10 -83
  241. package/skills/music-to-video/references/motion-primitives/word-grid-burst/scene.html +96 -0
  242. package/skills/music-to-video/references/planning.md +2 -2
  243. package/skills/music-to-video/scripts/lib/storyboard.mjs +1 -1
  244. package/skills/music-to-video/sub-agents/frame-worker.md +2 -2
  245. package/skills/pr-to-video/SKILL.md +20 -16
  246. package/skills/pr-to-video/references/code-vocabulary.md +14 -12
  247. package/skills/pr-to-video/references/story-design.md +1 -1
  248. package/skills/pr-to-video/scripts/assemble-index.mjs +6 -4
  249. package/skills/pr-to-video/scripts/assemble-index.test.mjs +57 -2
  250. package/skills/pr-to-video/scripts/audio.mjs +2 -0
  251. package/skills/pr-to-video/scripts/build-frame.mjs +6 -3
  252. package/skills/pr-to-video/scripts/captions.mjs +7 -4
  253. package/skills/pr-to-video/scripts/captions.test.mjs +41 -0
  254. package/skills/pr-to-video/scripts/frame-packets.mjs +4 -4
  255. package/skills/pr-to-video/scripts/lib/bgm-volume.mjs +4 -0
  256. package/skills/pr-to-video/scripts/lib/captured-fonts.mjs +58 -0
  257. package/skills/pr-to-video/scripts/lib/frame-packets-core.mjs +194 -0
  258. package/skills/pr-to-video/scripts/lib/storyboard.mjs +1 -1
  259. package/skills/pr-to-video/scripts/lib/transitions.json +3 -3
  260. package/skills/pr-to-video/scripts/transitions.mjs +7 -5
  261. package/skills/pr-to-video/sub-agents/frame-worker.md +1 -1
  262. package/skills/product-launch-video/SKILL.md +20 -16
  263. package/skills/product-launch-video/references/story-design.md +1 -1
  264. package/skills/product-launch-video/scripts/assemble-index.mjs +6 -4
  265. package/skills/product-launch-video/scripts/assemble-index.test.mjs +57 -2
  266. package/skills/product-launch-video/scripts/audio.mjs +2 -0
  267. package/skills/product-launch-video/scripts/audio.test.mjs +16 -0
  268. package/skills/product-launch-video/scripts/build-frame-subsets.test.mjs +152 -0
  269. package/skills/product-launch-video/scripts/build-frame.mjs +6 -3
  270. package/skills/product-launch-video/scripts/captions.mjs +7 -4
  271. package/skills/product-launch-video/scripts/frame-packets.mjs +4 -4
  272. package/skills/product-launch-video/scripts/lib/bgm-volume.mjs +4 -0
  273. package/skills/product-launch-video/scripts/lib/captured-fonts.mjs +58 -0
  274. package/skills/product-launch-video/scripts/lib/frame-packets-core.mjs +194 -0
  275. package/skills/product-launch-video/scripts/lib/storyboard.mjs +1 -1
  276. package/skills/product-launch-video/scripts/lib/transitions.json +3 -3
  277. package/skills/product-launch-video/scripts/transitions.mjs +7 -5
  278. package/skills/product-launch-video/scripts/transitions.test.mjs +68 -0
  279. package/skills/product-launch-video/sub-agents/frame-worker.md +1 -1
  280. package/skills/remotion-to-hyperframes/SKILL.md +7 -4
  281. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/expected.json +5 -5
  282. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/hf-src/compositions/title.html +31 -0
  283. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/hf-src/index.html +10 -25
  284. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/README.md +8 -8
  285. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/expected.json +9 -9
  286. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/hf-src/compositions/scene-1.html +35 -0
  287. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/hf-src/compositions/scene-2.html +35 -0
  288. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/hf-src/compositions/scene-3.html +36 -0
  289. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/hf-src/index.html +28 -71
  290. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/expected.json +3 -3
  291. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/hf-src/compositions/scene-1.html +52 -0
  292. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/hf-src/compositions/scene-2.html +99 -0
  293. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/hf-src/compositions/scene-3.html +55 -0
  294. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/hf-src/index.html +13 -212
  295. package/skills/remotion-to-hyperframes/references/api-map.md +16 -16
  296. package/skills/remotion-to-hyperframes/references/limitations.md +7 -7
  297. package/skills/remotion-to-hyperframes/references/lottie.md +5 -7
  298. package/skills/remotion-to-hyperframes/references/media.md +3 -3
  299. package/skills/remotion-to-hyperframes/references/parameters.md +5 -0
  300. package/skills/remotion-to-hyperframes/references/sequencing.md +71 -18
  301. package/skills/slideshow/SKILL.md +4 -1
  302. package/skills/slideshow/references/standalone-harness.md +0 -3
  303. package/skills/talking-head-recut/SKILL.md +10 -1
  304. package/skills/hyperframes-core/references/review-loop.md +0 -41
  305. package/skills/media-use/scripts/lib/adopt.mjs +0 -128
  306. package/skills/media-use/scripts/lib/adopt.test.mjs +0 -95
  307. package/skills/media-use/scripts/lib/bgm-provider.mjs +0 -20
  308. package/skills/media-use/scripts/lib/brand-provider.mjs +0 -59
  309. package/skills/media-use/scripts/lib/bundled-sfx-provider.mjs +0 -108
  310. package/skills/media-use/scripts/lib/bundled-sfx-provider.test.mjs +0 -85
  311. package/skills/media-use/scripts/lib/cache.mjs +0 -150
  312. package/skills/media-use/scripts/lib/candidates.mjs +0 -91
  313. package/skills/media-use/scripts/lib/candidates.test.mjs +0 -155
  314. package/skills/media-use/scripts/lib/codex-provider.mjs +0 -161
  315. package/skills/media-use/scripts/lib/codex-provider.test.mjs +0 -34
  316. package/skills/media-use/scripts/lib/coverage.test.mjs +0 -117
  317. package/skills/media-use/scripts/lib/cube-build.mjs +0 -181
  318. package/skills/media-use/scripts/lib/cube-build.test.mjs +0 -80
  319. package/skills/media-use/scripts/lib/cube-validate.mjs +0 -198
  320. package/skills/media-use/scripts/lib/cube-validate.test.mjs +0 -125
  321. package/skills/media-use/scripts/lib/cutlist.test.mjs +0 -148
  322. package/skills/media-use/scripts/lib/duck.test.mjs +0 -118
  323. package/skills/media-use/scripts/lib/error-diffusion.test.mjs +0 -102
  324. package/skills/media-use/scripts/lib/freeze.mjs +0 -70
  325. package/skills/media-use/scripts/lib/freeze.test.mjs +0 -46
  326. package/skills/media-use/scripts/lib/grade-analyzer.mjs +0 -264
  327. package/skills/media-use/scripts/lib/grade-analyzer.test.mjs +0 -285
  328. package/skills/media-use/scripts/lib/heygen-cli.mjs +0 -191
  329. package/skills/media-use/scripts/lib/heygen-cli.test.mjs +0 -301
  330. package/skills/media-use/scripts/lib/heygen-search.mjs +0 -45
  331. package/skills/media-use/scripts/lib/heygen-search.test.mjs +0 -49
  332. package/skills/media-use/scripts/lib/heygen-video-provider.mjs +0 -127
  333. package/skills/media-use/scripts/lib/heygen-video-provider.test.mjs +0 -344
  334. package/skills/media-use/scripts/lib/image-provider.mjs +0 -44
  335. package/skills/media-use/scripts/lib/local-models.mjs +0 -318
  336. package/skills/media-use/scripts/lib/local-models.test.mjs +0 -220
  337. package/skills/media-use/scripts/lib/local-run.mjs +0 -78
  338. package/skills/media-use/scripts/lib/local-run.test.mjs +0 -121
  339. package/skills/media-use/scripts/lib/logo-provider.mjs +0 -222
  340. package/skills/media-use/scripts/lib/logo-provider.test.mjs +0 -137
  341. package/skills/media-use/scripts/lib/ltx-video-provider.mjs +0 -94
  342. package/skills/media-use/scripts/lib/ltx-video-provider.test.mjs +0 -316
  343. package/skills/media-use/scripts/lib/lut-preset-provider.mjs +0 -266
  344. package/skills/media-use/scripts/lib/lut-preset-provider.test.mjs +0 -176
  345. package/skills/media-use/scripts/lib/manifest.test.mjs +0 -388
  346. package/skills/media-use/scripts/lib/match.mjs +0 -47
  347. package/skills/media-use/scripts/lib/mflux-provider.mjs +0 -128
  348. package/skills/media-use/scripts/lib/mflux-provider.test.mjs +0 -174
  349. package/skills/media-use/scripts/lib/misses.mjs +0 -49
  350. package/skills/media-use/scripts/lib/misses.test.mjs +0 -78
  351. package/skills/media-use/scripts/lib/npx-sync.test.mjs +0 -50
  352. package/skills/media-use/scripts/lib/parakeet-words.test.mjs +0 -44
  353. package/skills/media-use/scripts/lib/prefs-store.test.mjs +0 -189
  354. package/skills/media-use/scripts/lib/probe.mjs +0 -39
  355. package/skills/media-use/scripts/lib/probe.test.mjs +0 -31
  356. package/skills/media-use/scripts/lib/providers.mjs +0 -5
  357. package/skills/media-use/scripts/lib/recipe-store.test.mjs +0 -367
  358. package/skills/media-use/scripts/lib/registry.mjs +0 -218
  359. package/skills/media-use/scripts/lib/registry.test.mjs +0 -261
  360. package/skills/media-use/scripts/lib/search.mjs +0 -24
  361. package/skills/media-use/scripts/lib/search.test.mjs +0 -32
  362. package/skills/media-use/scripts/lib/sfx-provider.mjs +0 -23
  363. package/skills/media-use/scripts/lib/specs.mjs +0 -132
  364. package/skills/media-use/scripts/lib/specs.test.mjs +0 -157
  365. package/skills/media-use/scripts/lib/stats.mjs +0 -117
  366. package/skills/media-use/scripts/lib/stats.test.mjs +0 -165
  367. package/skills/media-use/scripts/lib/telemetry.test.mjs +0 -373
  368. package/skills/media-use/scripts/lib/tts-local-provider.mjs +0 -92
  369. package/skills/media-use/scripts/lib/tts-local-provider.test.mjs +0 -72
  370. package/skills/media-use/scripts/lib/usage.mjs +0 -57
  371. package/skills/media-use/scripts/lib/usage.test.mjs +0 -54
  372. package/skills/media-use/scripts/lib/voice-provider.mjs +0 -57
  373. package/skills/media-use/scripts/lib/voice-provider.test.mjs +0 -46
  374. package/skills/media-use/scripts/resolve.test.mjs +0 -1120
  375. /package/skills/{hyperframes-core → hyperframes}/references/subagent-dispatch.md +0 -0
@@ -1,218 +0,0 @@
1
- // Provider registry — the v2 contract.
2
- //
3
- // Each media type maps to an ORDERED list of provider entries. Providers are
4
- // tried in order; the first to return a non-null result wins, which keeps
5
- // resolution deterministic (same request -> same provider -> same file ->
6
- // reproducible renders). heygen-CLI is always first for the types it serves.
7
- //
8
- // An entry exposes any of three capability methods — search / generate /
9
- // process — plus { name }. media-use holds no keys; each external tool owns its
10
- // own auth. Providers, by type:
11
- // - heygen CLI: catalog + TTS, first for every type it serves (OAuth free
12
- // allowance first, then the user's HeyGen billing path)
13
- // - mflux: local FLUX-class image gen, spec-selected to the machine's RAM
14
- // (free, private, offline once cached)
15
- // - codex CLI: image gen on the user's ChatGPT sub — the better-quality upsell
16
- // and the fallback when no local model fits
17
- // - Kokoro (via the hyperframes CLI): local voiceover, free/private fallback
18
- // when HeyGen credentials are absent or --local-only is requested
19
- //
20
- // Generation is local-first, cloud-upsell. `ctx.provider` forces one provider
21
- // (e.g. "make an image with codex").
22
-
23
- import { bgmProvider } from "./bgm-provider.mjs";
24
- import { sfxProvider } from "./sfx-provider.mjs";
25
- import { bundledSfxProvider } from "./bundled-sfx-provider.mjs";
26
- import { imageProvider, iconProvider } from "./image-provider.mjs";
27
- import { brandProvider } from "./brand-provider.mjs";
28
- import {
29
- svglSearch,
30
- simpleIconsSearch,
31
- githubAvatarSearch,
32
- faviconSearch,
33
- } from "./logo-provider.mjs";
34
- import { heygenTtsGenerate } from "./voice-provider.mjs";
35
- import { heygenVideoGenerate } from "./heygen-video-provider.mjs";
36
- import { ltxVideoGenerate } from "./ltx-video-provider.mjs";
37
- import { localTtsGenerate } from "./tts-local-provider.mjs";
38
- import { codexImageGenerate } from "./codex-provider.mjs";
39
- import { mfluxImageGenerate } from "./mflux-provider.mjs";
40
-
41
- // Provider markers: `network` = hits a remote service (skipped by --local-only).
42
- // `paid` = may cost wallet credits after any OAuth/web-plan free allowance
43
- // (documentation for the agent's cost judgment, X4: agent-initiated paid should
44
- // confirm). HeyGen catalog SEARCH is free; HeyGen TTS is free for eligible
45
- // OAuth CLI users up to the monthly allowance, then follows the user's billing.
46
- const A = (name, caps) => ({ name, ...caps }); // local, free
47
- const N = (name, caps) => ({ name, network: true, ...caps }); // remote, free
48
- const P = (name, caps) => ({ name, network: true, paid: true, ...caps }); // remote, paid
49
-
50
- // heygen-CLI first. All remote providers are skipped by --local-only.
51
- const REGISTRY = {
52
- bgm: [N("heygen.audio.sounds", { search: bgmProvider.search })],
53
- sfx: [
54
- N("heygen.audio.sounds", { search: sfxProvider.search }),
55
- A("bundled.sfx", { search: bundledSfxProvider.search }),
56
- ],
57
- image: [
58
- N("heygen.asset.search", { search: imageProvider.search }),
59
- // Catalog miss -> generate. Local first (best FLUX-class model the machine's
60
- // RAM can run, spec-selected; free, private, kept under --local-only), then
61
- // the codex CLI on the user's ChatGPT sub as the better-quality upsell and
62
- // the fallback when no local model fits.
63
- A("mflux.local", { generate: mfluxImageGenerate }),
64
- N("codex.image_gen", { generate: codexImageGenerate }),
65
- ],
66
- icon: [N("heygen.asset.search", { search: iconProvider.search })],
67
- logo: [
68
- // Official brand marks. Tiers verified by a 54-brand stress test (100%
69
- // cascade hit); HeyGen asset search is deliberately absent — it returns
70
- // generic look-alike icons for brand queries. All free, all network →
71
- // --local-only leaves only the cache rungs.
72
- N("svgl", { search: svglSearch }),
73
- N("simple-icons", { search: simpleIconsSearch }),
74
- N("github.avatar", { search: githubAvatarSearch }),
75
- N("favicon.ddg", { search: faviconSearch }),
76
- ],
77
- voice: [
78
- // HeyGen TTS first when credentialed so CLI/OAuth users consume the free
79
- // web-plan allowance (10 min/month) before any paid path. --local-only skips
80
- // it and keeps Kokoro as the private/offline fallback.
81
- // Deliberately kept `paid` (X4 confirm-before-call) even though the first
82
- // 10 min/month are free: the client can't know the remaining allowance, so
83
- // confirming is safer than risking a silent charge once it's spent. (A
84
- // tri-state "quota-first, paid after" would need backend quota state.)
85
- P("heygen.tts", { generate: heygenTtsGenerate }),
86
- A("kokoro.local", { generate: localTtsGenerate }),
87
- ],
88
- video: [
89
- // HeyGen avatar video first when credentialed; --local-only skips it and
90
- // keeps LTX as the local fallback.
91
- P("heygen.video", { generate: heygenVideoGenerate }),
92
- A("ltx.local", { generate: ltxVideoGenerate }),
93
- ],
94
- brand: [
95
- // Local design spec, not heygen — reads frame.md / design.md tokens.
96
- A("design_spec", { search: brandProvider.search }),
97
- ],
98
- grade: [
99
- // Local deterministic cascade handled by resolve.mjs so grade records can
100
- // carry an inline block as well as an optional frozen .cube file.
101
- A("color_grade.local", { search: async () => null, generate: async () => null }),
102
- ],
103
- lut: [
104
- // Lower-level local LUT generation/freezing path handled by resolve.mjs.
105
- A("cube_lut.local", { search: async () => null, generate: async () => null }),
106
- ],
107
- };
108
-
109
- function listFor(type) {
110
- const list = REGISTRY[type];
111
- if (!list) throw new Error(`unknown media type: ${type}`);
112
- return list;
113
- }
114
-
115
- /** Ordered providers for a type. */
116
- export function getProviders(type) {
117
- return listFor(type);
118
- }
119
-
120
- /** All declared media types. */
121
- export function listTypes() {
122
- return Object.keys(REGISTRY);
123
- }
124
-
125
- /** Provider names available for a type, in cascade order (for --provider validation). */
126
- export function providerNamesFor(type) {
127
- return listFor(type).map((p) => p.name);
128
- }
129
-
130
- /**
131
- * name -> cost tier ("local" | "network_free" | "network_paid") over a collection
132
- * of ordered provider lists, i.e. the A / N / P distinction the constructors above
133
- * already declare. Exported so the conflict rule below is testable against a
134
- * fixture; production reads the REGISTRY-wide index built from it.
135
- *
136
- * A name declared under two media types must carry the same tier in both. If it
137
- * didn't, "did this resolve cost credit" would depend on which type happened to
138
- * serve it, and the telemetry property would mean nothing — so this throws at
139
- * import rather than silently picking one.
140
- */
141
- export function buildProviderTierIndex(providerLists) {
142
- const tiers = new Map();
143
- for (const list of providerLists) {
144
- for (const p of list) {
145
- const tier = p.paid ? "network_paid" : p.network ? "network_free" : "local";
146
- const prior = tiers.get(p.name);
147
- if (prior && prior !== tier)
148
- throw new Error(
149
- `provider "${p.name}" is declared ${prior} under one media type and ${tier} under another`,
150
- );
151
- tiers.set(p.name, tier);
152
- }
153
- }
154
- return tiers;
155
- }
156
-
157
- const PROVIDER_TIERS = buildProviderTierIndex(Object.values(REGISTRY));
158
-
159
- /**
160
- * Cost tier of a provider by name, or undefined for a name the registry doesn't
161
- * declare. The registry stays the single owner of "does this cost credit", so
162
- * dashboards and callers never re-derive it from provider-name string matching.
163
- */
164
- export function providerTierFor(name) {
165
- return PROVIDER_TIERS.get(name);
166
- }
167
-
168
- /**
169
- * Does an override token (full name like "codex.image_gen" or a prefix like
170
- * "codex") match any provider declared for the type? Same match rule as
171
- * runProviders, so validation and dispatch never disagree.
172
- */
173
- export function providerMatches(type, want) {
174
- return providerNamesFor(type).some((n) => n === want || n.startsWith(`${want}.`));
175
- }
176
-
177
- /**
178
- * Back-compat shim for the v1 single-provider API. Returns the first declared
179
- * provider for the type (tagged with `type`); throws for an unknown type.
180
- * Kept for v1 callers only — new code should use getProviders/runCapability.
181
- */
182
- export function getProvider(type) {
183
- const first = listFor(type)[0] || {};
184
- return { ...first, type };
185
- }
186
-
187
- /**
188
- * Run a capability across an explicit ordered provider list. Tries each in
189
- * order, returns the first non-null result, skips providers that don't expose
190
- * the capability. Pure over its input — the unit-testable core of the cascade.
191
- *
192
- * Offline guard: a `network` provider is skipped when `ctx.localOnly` is set —
193
- * unconditionally, even under a `ctx.provider` override. --local-only is a hard
194
- * safety flag: it must never make a network call. Forcing a network provider
195
- * while offline yields a clean miss (the caller explains the conflict), never a
196
- * silent network request.
197
- * Provider override: `ctx.provider` (a full name like "codex.image_gen" or a
198
- * prefix like "codex") pins resolution to matching providers only — this is how
199
- * a user "make an image WITH codex" forces the upsell instead of taking the
200
- * free-first default.
201
- */
202
- export async function runProviders(providers, capability, intent, ctx) {
203
- const want = ctx?.provider;
204
- for (const p of providers) {
205
- if (want && p.name !== want && !p.name.startsWith(`${want}.`)) continue;
206
- if (p.network && ctx?.localOnly) continue; // --local-only wins, even over --provider
207
- const fn = p[capability];
208
- if (typeof fn !== "function") continue;
209
- const res = await fn(intent, ctx);
210
- if (res) return res;
211
- }
212
- return null;
213
- }
214
-
215
- /** Run a capability over the providers for a type (deterministic, heygen-first). */
216
- export async function runCapability(type, capability, intent, ctx) {
217
- return runProviders(getProviders(type), capability, intent, ctx);
218
- }
@@ -1,261 +0,0 @@
1
- import { strict as assert } from "node:assert";
2
- import { test } from "node:test";
3
- import {
4
- getProviders,
5
- getProvider,
6
- listTypes,
7
- providerMatches,
8
- providerNamesFor,
9
- runProviders,
10
- runCapability,
11
- providerTierFor,
12
- buildProviderTierIndex,
13
- } from "./registry.mjs";
14
-
15
- // --- registry shape -------------------------------------------------------
16
-
17
- test("listTypes exposes the v2 media types", () => {
18
- const types = listTypes();
19
- for (const t of [
20
- "bgm",
21
- "sfx",
22
- "image",
23
- "icon",
24
- "logo",
25
- "voice",
26
- "video",
27
- "brand",
28
- "grade",
29
- "lut",
30
- ]) {
31
- assert.ok(types.includes(t), `missing type: ${t}`);
32
- }
33
- });
34
-
35
- test("heygen provider is first for every type it serves", () => {
36
- for (const t of ["bgm", "sfx", "image", "icon"]) {
37
- const first = getProviders(t)[0];
38
- assert.ok(first, `no enabled provider for ${t}`);
39
- assert.match(first.name, /^heygen/, `${t} first provider is ${first.name}`);
40
- }
41
- });
42
-
43
- test("sanctioned providers only: heygen, local mflux/kokoro/ltx, codex, design spec, logo tiers", () => {
44
- const allowed =
45
- /^heygen|^bundled\.sfx$|^mflux\.local$|^kokoro\.local$|^ltx\.local$|^codex\.image_gen$|^design_spec$|^svgl$|^simple-icons$|^github\.avatar$|^favicon\.ddg$|^color_grade\.local$|^cube_lut\.local$/;
46
- for (const t of listTypes()) {
47
- for (const p of getProviders(t)) {
48
- assert.ok(allowed.test(p.name), `${t} lists unsanctioned provider: ${p.name}`);
49
- }
50
- }
51
- });
52
-
53
- test("image cascade: heygen catalog, then local mflux, then the codex upsell", () => {
54
- const ps = getProviders("image");
55
- assert.match(ps[0].name, /^heygen/, "heygen catalog first");
56
- const names = ps.map((p) => p.name);
57
- const mflux = ps.find((p) => p.name === "mflux.local");
58
- const codex = ps.find((p) => p.name === "codex.image_gen");
59
- assert.ok(mflux && typeof mflux.generate === "function", "local mflux registered");
60
- assert.ok(codex && typeof codex.generate === "function", "codex upsell registered");
61
- assert.ok(names.indexOf("mflux.local") < names.indexOf("codex.image_gen"), "local before codex");
62
- assert.ok(!mflux.network, "local mflux is kept under --local-only");
63
- assert.ok(codex.network, "codex is network (skipped under --local-only)");
64
- });
65
-
66
- test("voice cascade: HeyGen TTS first, Kokoro remains the local fallback", () => {
67
- const ps = getProviders("voice");
68
- assert.equal(ps[0].name, "heygen.tts", "HeyGen TTS is first when credentials exist");
69
- assert.ok(ps[0].network, "HeyGen TTS is network (skipped under --local-only)");
70
- assert.ok(ps[0].paid, "HeyGen TTS may bill after the OAuth free allowance");
71
- assert.equal(ps[1].name, "kokoro.local", "local Kokoro is the offline fallback");
72
- assert.ok(!ps[1].network, "local Kokoro kept under --local-only");
73
- assert.ok(!ps[1].paid, "local Kokoro is free");
74
- });
75
-
76
- test("video cascade: HeyGen first, LTX local fallback, generate-only", async () => {
77
- assert.deepEqual(providerNamesFor("video"), ["heygen.video", "ltx.local"]);
78
- assert.equal(providerMatches("video", "ltx.local"), true);
79
-
80
- const ps = getProviders("video");
81
- assert.ok(ps[0].network, "HeyGen video is network (skipped under --local-only)");
82
- assert.ok(ps[0].paid, "HeyGen video may bill after the OAuth free allowance");
83
- assert.ok(!ps[1].network, "local LTX is kept under --local-only");
84
- assert.equal(await runCapability("video", "search", "x", {}), null);
85
- });
86
-
87
- test("sfx cascade: HeyGen catalog first, bundled library remains the local fallback", () => {
88
- const ps = getProviders("sfx");
89
- assert.equal(ps[0].name, "heygen.audio.sounds");
90
- assert.ok(ps[0].network, "HeyGen SFX catalog is network-only");
91
- assert.equal(ps[1].name, "bundled.sfx");
92
- assert.equal(typeof ps[1].search, "function");
93
- assert.ok(!ps[1].network, "bundled SFX remain available offline");
94
- });
95
-
96
- test("ctx.provider forces one generator (e.g. 'make an image WITH codex')", async () => {
97
- const providers = [
98
- { name: "heygen.asset.search", network: true, search: async () => null },
99
- { name: "mflux.local", generate: async () => ({ hit: "local" }) },
100
- { name: "codex.image_gen", network: true, generate: async () => ({ hit: "codex" }) },
101
- ];
102
- // no override: local wins (first generate to return non-null)
103
- assert.deepEqual(await runProviders(providers, "generate", "x", {}), { hit: "local" });
104
- // override to codex: skip local, use codex even though local would have worked
105
- assert.deepEqual(await runProviders(providers, "generate", "x", { provider: "codex" }), {
106
- hit: "codex",
107
- });
108
- // override matches the full name too
109
- assert.deepEqual(
110
- await runProviders(providers, "generate", "x", { provider: "codex.image_gen" }),
111
- { hit: "codex" },
112
- );
113
- // --local-only wins even over a forced network provider: no network call,
114
- // clean miss (the caller surfaces the conflict). A forced LOCAL provider under
115
- // --local-only still runs.
116
- assert.equal(
117
- await runProviders(providers, "generate", "x", { provider: "codex", localOnly: true }),
118
- null,
119
- );
120
- assert.deepEqual(
121
- await runProviders(providers, "generate", "x", { provider: "mflux", localOnly: true }),
122
- { hit: "local" },
123
- );
124
- });
125
-
126
- test("getProvider returns the first provider with its type, throws for unknown", () => {
127
- const p = getProvider("bgm");
128
- assert.equal(p.type, "bgm");
129
- assert.equal(typeof p.search, "function");
130
- assert.throws(() => getProvider("unknown_type"), /unknown media type/);
131
- });
132
-
133
- test("getProviders throws for unknown type", () => {
134
- assert.throws(() => getProviders("nope"), /unknown media type/);
135
- });
136
-
137
- // --- deterministic capability execution (runProviders core) ---------------
138
-
139
- test("runProviders calls providers in order and returns the first non-null", async () => {
140
- const calls = [];
141
- const providers = [
142
- {
143
- name: "a",
144
- enabled: true,
145
- search: async () => {
146
- calls.push("a");
147
- return null;
148
- },
149
- },
150
- {
151
- name: "b",
152
- enabled: true,
153
- search: async () => {
154
- calls.push("b");
155
- return { hit: "b" };
156
- },
157
- },
158
- {
159
- name: "c",
160
- enabled: true,
161
- search: async () => {
162
- calls.push("c");
163
- return { hit: "c" };
164
- },
165
- },
166
- ];
167
- const res = await runProviders(providers, "search", "x", {});
168
- assert.deepEqual(res, { hit: "b" });
169
- assert.deepEqual(calls, ["a", "b"], "must stop at first non-null, never call c");
170
- });
171
-
172
- test("runProviders skips providers missing the requested capability", async () => {
173
- const providers = [
174
- { name: "a", enabled: true /* no search */ },
175
- { name: "b", enabled: true, search: async () => ({ hit: "b" }) },
176
- ];
177
- const res = await runProviders(providers, "search", "x", {});
178
- assert.deepEqual(res, { hit: "b" });
179
- });
180
-
181
- test("runProviders returns null when no provider yields a result", async () => {
182
- const providers = [{ name: "a", enabled: true, search: async () => null }];
183
- assert.equal(await runProviders(providers, "search", "x", {}), null);
184
- });
185
-
186
- test("runCapability('bgm','process') is null — process slot is graceful when unfilled", async () => {
187
- assert.equal(await runCapability("bgm", "process", "x", {}), null);
188
- });
189
-
190
- // --- provider cost tier (telemetry) ---------------------------------------
191
-
192
- test("providerTierFor reports the registry's own A/N/P declaration", () => {
193
- assert.equal(providerTierFor("heygen.tts"), "network_paid");
194
- assert.equal(providerTierFor("heygen.video"), "network_paid");
195
- assert.equal(providerTierFor("heygen.audio.sounds"), "network_free");
196
- assert.equal(providerTierFor("heygen.asset.search"), "network_free");
197
- assert.equal(providerTierFor("codex.image_gen"), "network_free");
198
- assert.equal(providerTierFor("bundled.sfx"), "local");
199
- assert.equal(providerTierFor("kokoro.local"), "local");
200
- });
201
-
202
- test("providerTierFor agrees across every type that declares the same name", () => {
203
- // heygen.audio.sounds serves both bgm and sfx; heygen.asset.search serves both
204
- // image and icon. A name whose tier depended on the media type would make the
205
- // telemetry property meaningless.
206
- const byName = new Map();
207
- for (const type of listTypes()) {
208
- for (const name of providerNamesFor(type)) {
209
- const tier = providerTierFor(name);
210
- assert.ok(tier, `every declared provider has a tier (${type}/${name})`);
211
- const prior = byName.get(name);
212
- if (prior) assert.equal(tier, prior, `${name} must carry one tier across types`);
213
- byName.set(name, tier);
214
- }
215
- }
216
- });
217
-
218
- test("providerTierFor returns undefined for a name the registry does not declare", () => {
219
- assert.equal(providerTierFor("does.not.exist"), undefined);
220
- assert.equal(providerTierFor(undefined), undefined);
221
- assert.equal(providerTierFor(null), undefined);
222
- assert.equal(providerTierFor(""), undefined);
223
- });
224
-
225
- test("buildProviderTierIndex throws when one name carries two tiers", () => {
226
- assert.throws(
227
- () =>
228
- buildProviderTierIndex([
229
- [{ name: "dual", network: true }],
230
- [{ name: "dual", network: true, paid: true }],
231
- ]),
232
- /declared network_free under one media type and network_paid under another/,
233
- );
234
- });
235
-
236
- test("buildProviderTierIndex accepts the same name repeated at the same tier", () => {
237
- const index = buildProviderTierIndex([
238
- [{ name: "same", network: true }],
239
- [{ name: "same", network: true }],
240
- ]);
241
- assert.equal(index.get("same"), "network_free");
242
- });
243
-
244
- test("--local-only skips every network provider (even free remote ones)", async () => {
245
- let remoteRan = false;
246
- const providers = [
247
- {
248
- name: "heygen",
249
- network: true,
250
- search: async () => {
251
- remoteRan = true;
252
- return { hit: "net" };
253
- },
254
- },
255
- { name: "local", search: async () => ({ hit: "local" }) },
256
- ];
257
- assert.deepEqual(await runProviders(providers, "search", "x", { localOnly: true }), {
258
- hit: "local",
259
- });
260
- assert.equal(remoteRan, false, "the remote provider must not be called offline");
261
- });
@@ -1,24 +0,0 @@
1
- // Paginated text search over a manifest (project or global) by id / description
2
- // / entity. Plain substring match — no vector DB (B4): the agent's own file
3
- // search covers semantics; this just keeps result pages small enough to not
4
- // blow the context window.
5
-
6
- const PAGE = 10;
7
-
8
- export function searchRecords(records, query, { page = 1, pageSize = PAGE } = {}) {
9
- const q = String(query || "")
10
- .trim()
11
- .toLowerCase();
12
- const matched = q
13
- ? records.filter((r) =>
14
- [r.id, r.description, r.entity, r.type].some(
15
- (f) => f && String(f).toLowerCase().includes(q),
16
- ),
17
- )
18
- : records.slice();
19
- const total = matched.length;
20
- const pages = Math.max(1, Math.ceil(total / pageSize));
21
- const p = Math.min(Math.max(1, page), pages);
22
- const start = (p - 1) * pageSize;
23
- return { results: matched.slice(start, start + pageSize), total, page: p, pages, pageSize };
24
- }
@@ -1,32 +0,0 @@
1
- import { strict as assert } from "node:assert";
2
- import { test } from "node:test";
3
- import { searchRecords } from "./search.mjs";
4
-
5
- const recs = Array.from({ length: 23 }, (_, i) => ({
6
- id: `bgm_${i}`,
7
- type: i % 2 ? "bgm" : "sfx",
8
- description: i === 5 ? "energetic tech whoosh" : `track ${i}`,
9
- }));
10
-
11
- test("matches id / description / type, case-insensitively", () => {
12
- assert.equal(searchRecords(recs, "ENERGETIC").results.length, 1);
13
- assert.equal(searchRecords(recs, "energetic").results[0].id, "bgm_5");
14
- assert.ok(searchRecords(recs, "sfx").total > 0);
15
- });
16
-
17
- test("caps page size and reports pagination", () => {
18
- const r = searchRecords(recs, "", { pageSize: 10 });
19
- assert.equal(r.results.length, 10, "never returns more than a page");
20
- assert.equal(r.total, 23);
21
- assert.equal(r.pages, 3);
22
- assert.equal(r.page, 1);
23
- });
24
-
25
- test("page navigation returns the right slice, clamps out-of-range", () => {
26
- assert.equal(searchRecords(recs, "", { page: 3, pageSize: 10 }).results.length, 3);
27
- assert.equal(searchRecords(recs, "", { page: 99, pageSize: 10 }).page, 3, "clamped to last page");
28
- });
29
-
30
- test("empty query returns everything (paginated)", () => {
31
- assert.equal(searchRecords(recs, "").total, 23);
32
- });
@@ -1,23 +0,0 @@
1
- import { heygenSearch } from "./heygen-search.mjs";
2
-
3
- export const sfxProvider = {
4
- async search(intent) {
5
- const results = heygenSearch("audio sounds list", intent, {
6
- type: "sound_effects",
7
- minScore: 0.4,
8
- });
9
- if (!results) return null;
10
- const best = results[0];
11
- return {
12
- url: best.audio_url,
13
- source: "search",
14
- // ext derived from audio_url by resolve.mjs — catalog SFX are .mp3 or .wav
15
- metadata: {
16
- description: best.description || best.name || intent,
17
- duration: best.duration || null,
18
- provider: "heygen.audio.sounds",
19
- provenance: { track_id: best.id, score: best.score, query: intent },
20
- },
21
- };
22
- },
23
- };