dsh-hyperframes 0.3.2 → 0.4.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 (375) hide show
  1. package/README.en.md +5 -4
  2. package/README.md +6 -5
  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
@@ -0,0 +1,85 @@
1
+ // Media downloads use public HTTP(S) URLs. Validate every redirect target;
2
+ // a provider result must meet the same host policy as a direct ingest URL.
3
+ // Public HTTPS-to-HTTP redirects are allowed, matching direct HTTP support.
4
+ // This is a literal-host policy, not DNS pinning: DNS resolution remains trusted.
5
+
6
+ import { BlockList, isIP } from "node:net";
7
+
8
+ const blocked = new BlockList();
9
+ for (const [network, prefix] of [
10
+ ["0.0.0.0", 8],
11
+ ["10.0.0.0", 8],
12
+ ["100.64.0.0", 10],
13
+ ["127.0.0.0", 8],
14
+ ["169.254.0.0", 16],
15
+ ["172.16.0.0", 12],
16
+ ["192.0.0.0", 24],
17
+ ["192.0.2.0", 24],
18
+ ["192.88.99.0", 24],
19
+ ["192.168.0.0", 16],
20
+ ["198.18.0.0", 15],
21
+ ["198.51.100.0", 24],
22
+ ["203.0.113.0", 24],
23
+ ["224.0.0.0", 4],
24
+ ["240.0.0.0", 4],
25
+ ])
26
+ blocked.addSubnet(network, prefix, "ipv4");
27
+ for (const [network, prefix] of [
28
+ ["::", 128],
29
+ ["::1", 128],
30
+ ["fc00::", 7],
31
+ ["fe80::", 10],
32
+ ["fec0::", 10],
33
+ ["ff00::", 8],
34
+ ["2001:db8::", 32],
35
+ ])
36
+ blocked.addSubnet(network, prefix, "ipv6");
37
+
38
+ export function isPublicMediaUrl(value) {
39
+ try {
40
+ const url = new URL(value);
41
+ if (url.protocol !== "http:" && url.protocol !== "https:") return false;
42
+ const host = url.hostname.replace(/\.$/, "");
43
+ if (
44
+ host === "localhost" ||
45
+ host.endsWith(".localhost") ||
46
+ host.endsWith(".local") ||
47
+ host.endsWith(".internal")
48
+ )
49
+ return false;
50
+ const address = host.replace(/^\[|\]$/g, "");
51
+ const family = isIP(address);
52
+ return family === 0 || !blocked.check(address, family === 4 ? "ipv4" : "ipv6");
53
+ } catch {
54
+ return false;
55
+ }
56
+ }
57
+
58
+ export async function fetchMedia(url, { method = "GET", signal, fetchImpl = fetch } = {}) {
59
+ let current = String(url);
60
+ for (let hop = 0; hop <= 5; hop++) {
61
+ if (!isPublicMediaUrl(current))
62
+ throw new Error("Media download blocked: URL is not public HTTP(S)");
63
+ const response = await fetchImpl(current, { method, signal, redirect: "manual" });
64
+ if (!(response.status >= 300 && response.status < 400)) return response;
65
+ const location = response.headers.get("location");
66
+ if (!location) return response;
67
+ await response.body?.cancel();
68
+ current = new URL(location, current).href;
69
+ }
70
+ throw new Error("Media download exceeded redirect limit");
71
+ }
72
+
73
+ // Stream and abort once the cap is crossed, so a lying or chunked body can't buffer past it.
74
+ export async function readCappedBody(res, maxBytes, label) {
75
+ const declared = Number(res.headers.get("content-length"));
76
+ if (declared > maxBytes) throw new Error(`${label}: ${declared} bytes exceeds ${maxBytes} cap`);
77
+ const chunks = [];
78
+ let total = 0;
79
+ for await (const chunk of res.body) {
80
+ total += chunk.length;
81
+ if (total > maxBytes) throw new Error(`${label}: stream exceeds ${maxBytes} cap`);
82
+ chunks.push(chunk);
83
+ }
84
+ return Buffer.concat(chunks, total);
85
+ }
@@ -0,0 +1,20 @@
1
+ import { homedir } from "node:os";
2
+ import { join } from "node:path";
3
+
4
+ // The one owner of where the person's media library lives. This repo's test runs set
5
+ // HYPERFRAMES_MEDIA_HOME_REQUIRED, so a test that forgot HYPERFRAMES_MEDIA_HOME fails instead
6
+ // of writing fixtures into the media library apps list as the person's own files.
7
+ export function mediaHome() {
8
+ const override = process.env.HYPERFRAMES_MEDIA_HOME;
9
+ if (override) return override;
10
+ if (process.env.HYPERFRAMES_MEDIA_HOME_REQUIRED) {
11
+ throw new Error(
12
+ "media-use: a test reached the real ~/.media; set HYPERFRAMES_MEDIA_HOME to a temp dir",
13
+ );
14
+ }
15
+ return homedir();
16
+ }
17
+
18
+ export function globalMediaDir() {
19
+ return join(mediaHome(), ".media");
20
+ }
@@ -1,5 +1,18 @@
1
1
  import { existsSync } from "node:fs";
2
- import { resolveSpawnCommand } from "../../audio/scripts/lib/tts.mjs";
2
+ import { dirname, join } from "node:path";
3
+
4
+ function resolveNpxCliPath(env, pathExists) {
5
+ const npmExecPath = env.npm_execpath;
6
+ const nodeExecPath = env.npm_node_execpath || process.execPath;
7
+ if (npmExecPath) {
8
+ const fileName = npmExecPath.replace(/\\/g, "/").split("/").pop()?.toLowerCase();
9
+ const candidate =
10
+ fileName === "npx-cli.js" ? npmExecPath : join(dirname(npmExecPath), "npx-cli.js");
11
+ if (pathExists(candidate)) return candidate;
12
+ }
13
+ const besideNode = join(dirname(nodeExecPath), "node_modules", "npm", "bin", "npx-cli.js");
14
+ return pathExists(besideNode) ? besideNode : null;
15
+ }
3
16
 
4
17
  // Sync-spawn analog of the audio engine's spawnP, for execFileSync call sites
5
18
  // that must hard-fail (rather than fall through to another provider) when npx
@@ -18,7 +31,20 @@ export function resolveNpxInvocation(
18
31
  env = process.env,
19
32
  pathExists = existsSync,
20
33
  ) {
21
- const resolved = resolveSpawnCommand("npx", argv, opts, platform, env, pathExists);
34
+ const resolved =
35
+ platform !== "win32"
36
+ ? { cmd: "npx", args: argv, opts: { stdio: "ignore", ...opts } }
37
+ : (() => {
38
+ const nodeExecPath = env.npm_node_execpath || process.execPath;
39
+ const npxCliPath = resolveNpxCliPath(env, pathExists);
40
+ return npxCliPath
41
+ ? {
42
+ cmd: nodeExecPath,
43
+ args: [npxCliPath, ...argv.map((arg) => String(arg))],
44
+ opts: { stdio: "ignore", windowsHide: true, ...opts },
45
+ }
46
+ : null;
47
+ })();
22
48
  if (!resolved) {
23
49
  // npx-on-win32 with no resolvable npx-cli.js — same terminal condition
24
50
  // spawnP warns about, surfaced as a throw for callers with no fallback.
@@ -1,6 +1,6 @@
1
1
  import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
2
- import { homedir } from "node:os";
3
2
  import { basename, dirname, join, resolve } from "node:path";
3
+ import { globalMediaDir } from "./media-home.mjs";
4
4
 
5
5
  /**
6
6
  * Remembered defaults — the lightweight tier of HyperFrames user memory.
@@ -41,7 +41,7 @@ export function projectPrefsPath(projectDir) {
41
41
  }
42
42
 
43
43
  export function userPrefsPath() {
44
- return join(homedir(), ".media", PREFS_FILE);
44
+ return join(globalMediaDir(), PREFS_FILE);
45
45
  }
46
46
 
47
47
  function emptyFile() {
@@ -8,8 +8,8 @@ import {
8
8
  rmSync,
9
9
  writeFileSync,
10
10
  } from "node:fs";
11
- import { homedir } from "node:os";
12
11
  import { basename, join, resolve } from "node:path";
12
+ import { globalMediaDir } from "./media-home.mjs";
13
13
  import { appendRecord, mediaDir, nextId } from "./manifest.mjs";
14
14
  import { regenerateIndex } from "./index-gen.mjs";
15
15
  import { mergedPreferences } from "./prefs-store.mjs";
@@ -58,7 +58,7 @@ export function projectRecipesDir(projectDir) {
58
58
  }
59
59
 
60
60
  export function userRecipesDir() {
61
- return join(homedir(), ".media", "recipes");
61
+ return join(globalMediaDir(), "recipes");
62
62
  }
63
63
 
64
64
  export function slugifyRecipeName(name) {
@@ -1,20 +1,13 @@
1
- // Opt-out usage tracking for media-use, sharing the hyperframes CLI/studio
2
- // identity (packages/cli/src/telemetry): the same install id from
3
- // ~/.hyperframes/config.json, plus a $identify to the HeyGen account on sign-in,
4
- // so a person is one PostHog profile across surfaces — not a fresh id per tool.
5
- // Not fully anonymous by design (it must dedupe): pseudonymous before sign-in,
6
- // account-linked after. Event PROPERTIES stay coarse — media TYPE, resolution
7
- // SOURCE, winning PROVIDER — never the intent text, file names, or paths.
8
- //
9
- // Same public PostHog project key as the CLI (a write-only ingestion key, safe
10
- // to ship), same opt-outs (DO_NOT_TRACK / HYPERFRAMES_NO_TELEMETRY / CI / dev),
11
- // and $ip:null so no IP is recorded. Fire-and-forget: telemetry never blocks a
12
- // resolve and never throws into it.
1
+ // Usage tracking shares the CLI and Studio identity. Properties stay coarse and
2
+ // never carry intent text, file names, or paths.
13
3
 
14
4
  import { randomUUID } from "node:crypto";
15
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
5
+ import * as fs from "node:fs";
6
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
16
7
  import { homedir } from "node:os";
17
- import { join } from "node:path";
8
+ import { dirname, join } from "node:path";
9
+ import { withFileLock } from "./config-lock.mjs";
10
+ import { globalMediaDir } from "./media-home.mjs";
18
11
 
19
12
  const POSTHOG_API_KEY = "phc_zjjbX0PnWxERXrMHhkEJWj9A9BhGVLRReICgsfTMmpx";
20
13
  const POSTHOG_HOST = "https://us.i.posthog.com";
@@ -22,10 +15,6 @@ const TIMEOUT_MS = 1500;
22
15
  let identifiedAccount = false;
23
16
  let warnedNonDefaultHost = false;
24
17
 
25
- // Same CI/test signals the test suite itself sets (resolve.test.mjs's U7 test
26
- // sets NODE_ENV=test and clears CI to prove the interception seam works) —
27
- // reused here, not a new heuristic, so that deliberate test usage never
28
- // triggers the warning below.
29
18
  function isTestOrCiContext() {
30
19
  return (
31
20
  process.env.CI === "true" ||
@@ -35,16 +24,6 @@ function isTestOrCiContext() {
35
24
  );
36
25
  }
37
26
 
38
- // Test-only interception seam: a real HTTP destination a test can point at,
39
- // so a spawned-child test (resolve.test.mjs) can prove track() never reaches
40
- // production rather than trusting DO_NOT_TRACK alone (a future call site or
41
- // test could forget to set that env var). Falls back to the real production
42
- // host whenever unset — production behavior is unchanged.
43
- //
44
- // Safety net: if this ever leaks into a real user's shell, track() would
45
- // silently redirect to a likely-dead host and postBatch()'s catch{} would
46
- // swallow the failure with zero signal. Surface one stderr warning outside
47
- // test/CI contexts so a real user gets some indication instead of silence.
48
27
  function posthogHost() {
49
28
  const override = process.env.MEDIA_USE_TELEMETRY_HOST;
50
29
  if (override && !warnedNonDefaultHost && !isTestOrCiContext()) {
@@ -67,12 +46,7 @@ export function optedOut() {
67
46
  );
68
47
  }
69
48
 
70
- // CLI + studio share one install identity in ~/.hyperframes/config.json
71
- // (packages/cli/src/telemetry/config.ts — same path, same `anonymousId` /
72
- // `telemetryNoticeShown` fields). Read and write that same file so media-use is
73
- // the same PostHog person and shows the notice once per person, not per tool.
74
- // Computed per call (not a module const) so it honors HOME at runtime — tests
75
- // sandbox HOME, and os.homedir() re-reads it each call.
49
+ // Read and write the shared config so media-use keeps one identity per install.
76
50
  function sharedConfigPath() {
77
51
  return join(homedir(), ".hyperframes", "config.json");
78
52
  }
@@ -90,10 +64,24 @@ function readSharedConfig() {
90
64
  return {};
91
65
  }
92
66
 
93
- function writeSharedConfig(config) {
94
- const dir = join(homedir(), ".hyperframes");
95
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
96
- writeFileSync(join(dir, "config.json"), JSON.stringify(config, null, 2) + "\n");
67
+ // Best effort: skipped when the lock cannot be taken or the file cannot be read, never written unlocked.
68
+ function updateSharedConfig(patch) {
69
+ const file = sharedConfigPath();
70
+ mkdirSync(dirname(file), { recursive: true });
71
+ try {
72
+ withFileLock(`${file}.lock`, fs, () => {
73
+ let config = {};
74
+ try {
75
+ config = JSON.parse(readFileSync(file, "utf8"));
76
+ } catch (error) {
77
+ if (error.code !== "ENOENT") return;
78
+ }
79
+ if (!config || typeof config !== "object" || Array.isArray(config)) return;
80
+ const tmp = `${file}.${process.pid}.tmp`;
81
+ writeFileSync(tmp, JSON.stringify({ ...config, ...patch }, null, 2) + "\n", { mode: 0o600 });
82
+ renameSync(tmp, file);
83
+ });
84
+ } catch {}
97
85
  }
98
86
 
99
87
  // Adopt a pre-existing media-use-only id (~/.media/anon-id from before this
@@ -101,7 +89,7 @@ function writeSharedConfig(config) {
101
89
  // one — otherwise cross-surface continuity would start over on upgrade.
102
90
  function legacyMediaAnonId() {
103
91
  try {
104
- const file = join(homedir(), ".media", "anon-id");
92
+ const file = join(globalMediaDir(), "anon-id");
105
93
  if (existsSync(file)) {
106
94
  const id = readFileSync(file, "utf8").trim();
107
95
  if (id) return id;
@@ -121,7 +109,7 @@ function anonymousId() {
121
109
  return config.anonymousId.trim();
122
110
  }
123
111
  const id = legacyMediaAnonId() || randomUUID();
124
- writeSharedConfig({ ...config, anonymousId: id });
112
+ updateSharedConfig({ anonymousId: id });
125
113
  return id;
126
114
  } catch {
127
115
  return "anon"; // best-effort; a shared bucket is fine if the fs is read-only
@@ -161,7 +149,7 @@ function showTelemetryNotice() {
161
149
  "If you sign in to HeyGen, usage links to your account email or username. Opt out with HYPERFRAMES_NO_TELEMETRY=1 or DO_NOT_TRACK=1.",
162
150
  ].join("\n"),
163
151
  );
164
- writeSharedConfig({ ...config, telemetryNoticeShown: true });
152
+ updateSharedConfig({ telemetryNoticeShown: true });
165
153
  } catch {
166
154
  // notice is best-effort; never surface into the command
167
155
  }
@@ -0,0 +1,21 @@
1
+ function round3(n) {
2
+ return Math.round(Number(n) * 1000) / 1000;
3
+ }
4
+
5
+ // 30ms in/out ramps kill the click at every concat boundary. A segment shorter
6
+ // than 4x the ramp would spend its whole length fading, so scale down there and
7
+ // skip entirely on a degenerate one. fadeIn/fadeOut are false at the export's
8
+ // own true start/end, where there is no splice to smooth.
9
+ export function fadeFilterFor(durationSeconds, { fadeIn, fadeOut }) {
10
+ if (!fadeIn && !fadeOut) return null;
11
+ const FADE_SECONDS = 0.03;
12
+ if (!Number.isFinite(durationSeconds) || durationSeconds <= 0.01) return null;
13
+ const d = Math.min(FADE_SECONDS, durationSeconds / 4);
14
+ const parts = [];
15
+ if (fadeIn) parts.push(`afade=t=in:st=0:d=${round3(d)}`);
16
+ if (fadeOut) {
17
+ const out = round3(durationSeconds - d);
18
+ if (out > 0) parts.push(`afade=t=out:st=${out}:d=${round3(d)}`);
19
+ }
20
+ return parts.length ? parts.join(",") : null;
21
+ }
@@ -11,7 +11,7 @@
11
11
  * Record one confirmed brief answer into the project tier; the same value
12
12
  * confirmed in two different projects promotes the key to the user tier.
13
13
  *
14
- * Consumption rules live in hyperframes-core/references/brief-contract.md § 2
14
+ * Consumption rules live in hyperframes/references/brief-contract.md § 2
15
15
  * (Remembered defaults): a remembered value becomes the recommended option
16
16
  * with a receipt — it never skips a question.
17
17
  */
@@ -19,7 +19,7 @@
19
19
  * frame.md over the project's, and print the brief values + skeleton path.
20
20
  *
21
21
  * When recipes are offered/consumed is the review loop's and the intent
22
- * layer's business — see hyperframes-core/references/review-loop.md § 4 and
22
+ * layer's business — see hyperframes/references/review-loop.md § 4 and
23
23
  * the intent layer's recipe check (hyperframes SKILL.md § 4).
24
24
  */
25
25
  import { parseArgs } from "node:util";
@@ -0,0 +1,62 @@
1
+ import assert from "node:assert/strict";
2
+ import { spawnSync } from "node:child_process";
3
+ import { copyFileSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
4
+ import { delimiter, join } from "node:path";
5
+ import { tmpdir } from "node:os";
6
+ import { fileURLToPath } from "node:url";
7
+ import { test } from "node:test";
8
+
9
+ test(
10
+ "plugin resolver uses the release CLI without a repository checkout",
11
+ { skip: process.platform === "win32" },
12
+ (t) => {
13
+ const dir = mkdtempSync(join(tmpdir(), "hf-resolve-plugin-"));
14
+ t.after(() => rmSync(dir, { recursive: true, force: true }));
15
+ mkdirSync(join(dir, "lib"));
16
+ for (const file of ["resolve.mjs", "lib/npx-sync.mjs"]) {
17
+ copyFileSync(fileURLToPath(new URL(file, import.meta.url)), join(dir, file));
18
+ }
19
+ writeFileSync(
20
+ join(dir, "npx"),
21
+ `#!${process.execPath}\nconsole.log(JSON.stringify({args:process.argv.slice(2),skip:process.env.HYPERFRAMES_SKIP_SKILLS}));process.exit(7);`,
22
+ { mode: 0o755 },
23
+ );
24
+ const result = spawnSync(process.execPath, [join(dir, "resolve.mjs"), "--intent", "a & b"], {
25
+ cwd: dir,
26
+ encoding: "utf8",
27
+ env: {
28
+ ...process.env,
29
+ PATH: `${dir}${delimiter}${process.env.PATH}`,
30
+ HYPERFRAMES_PLUGIN_VERSION: "1.2.3",
31
+ HYPERFRAMES_SKIP_SKILLS: "1",
32
+ },
33
+ });
34
+ assert.equal(result.status, 7, result.stderr);
35
+ assert.deepEqual(JSON.parse(result.stdout), {
36
+ args: ["--yes", "hyperframes@1.2.3", "media-use", "resolve", "--intent", "a & b"],
37
+ skip: "1",
38
+ });
39
+ },
40
+ );
41
+
42
+ test("helper package override keeps a contributor's local CLI", (t) => {
43
+ const root = mkdtempSync(join(tmpdir(), "hf-resolve-local-"));
44
+ t.after(() => rmSync(root, { recursive: true, force: true }));
45
+ const scripts = join(root, "skills/media-use/scripts");
46
+ mkdirSync(join(scripts, "lib"), { recursive: true });
47
+ mkdirSync(join(root, "packages/cli/dist"), { recursive: true });
48
+ for (const file of ["resolve.mjs", "lib/npx-sync.mjs"]) {
49
+ copyFileSync(fileURLToPath(new URL(file, import.meta.url)), join(scripts, file));
50
+ }
51
+ writeFileSync(join(root, "packages/cli/dist/cli.js"), 'console.log("local-cli");');
52
+ const result = spawnSync(process.execPath, [join(scripts, "resolve.mjs")], {
53
+ encoding: "utf8",
54
+ env: {
55
+ ...process.env,
56
+ HYPERFRAMES_PLUGIN_VERSION: "",
57
+ HYPERFRAMES_SKILL_PKG_VERSION: "0.8.79",
58
+ },
59
+ });
60
+ assert.equal(result.status, 0, result.stderr);
61
+ assert.equal(result.stdout.trim(), "local-cli");
62
+ });