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
@@ -1,132 +0,0 @@
1
- // Machine-capability probe for the spec-gated local-model fallback.
2
- //
3
- // Local models are USER-INSTALLED and local-use-only — media-use recommends,
4
- // spec-checks, and assists install, but never bundles or runs them as a service.
5
- // This probe answers "what tier can this machine actually run?" so selection can
6
- // offer a medium/large local model, or fall back to recommending the CLI path.
7
- //
8
- // `osMod` and `exec` are injectable for tests. `exec(cmd)` returns the command's
9
- // stdout as a string, or throws / returns null on failure.
10
-
11
- import os from "node:os";
12
- import { statfsSync } from "node:fs";
13
- import { dirname, join } from "node:path";
14
- import { execSync } from "node:child_process";
15
-
16
- function defaultExec(cmd) {
17
- return execSync(cmd, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 4000 });
18
- }
19
-
20
- // Available (not just total) RAM — the real budget for "will this model fit
21
- // alongside the OS + open apps". On unified-memory Macs the model shares system
22
- // RAM, so a big model on a busy machine OOMs/thrashes even if total RAM looks
23
- // ample. macOS: vm_stat free + inactive + speculative + purgeable pages (all
24
- // reclaimable). Linux: /proc/meminfo MemAvailable. Fallback: total (optimistic
25
- // but stable when the probe is unavailable, e.g. in tests).
26
- function availableRamMB(platform, exec, totalMB) {
27
- try {
28
- if (platform === "darwin") {
29
- const out = String(exec("vm_stat"));
30
- const pageSize = parseInt((out.match(/page size of (\d+)/) || [])[1] || "16384", 10);
31
- const pages = (name) => {
32
- const m = out.match(new RegExp(`${name}:\\s+(\\d+)`));
33
- return m ? parseInt(m[1], 10) : 0;
34
- };
35
- const reclaimable =
36
- pages("Pages free") +
37
- pages("Pages inactive") +
38
- pages("Pages speculative") +
39
- pages("Pages purgeable");
40
- const mb = Math.round((reclaimable * pageSize) / (1024 * 1024));
41
- if (mb > 0) return mb;
42
- } else if (platform === "linux") {
43
- const out = String(exec("cat /proc/meminfo"));
44
- const m = out.match(/MemAvailable:\s+(\d+)\s+kB/);
45
- if (m) return Math.round(parseInt(m[1], 10) / 1024);
46
- }
47
- } catch {
48
- // probe unavailable — fall through to the total-RAM estimate
49
- }
50
- return totalMB;
51
- }
52
-
53
- function detectGpu(platform, arch, ramMB, exec) {
54
- // Apple Silicon: Metal GPU with unified memory — VRAM tracks system RAM.
55
- if (platform === "darwin" && arch === "arm64") {
56
- return { present: true, kind: "apple", vramMB: ramMB };
57
- }
58
- // NVIDIA: query total VRAM. Any failure (no driver, no GPU) -> no GPU.
59
- try {
60
- const out = exec("nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits");
61
- const mb = parseInt(String(out).trim().split(/\r?\n/)[0], 10);
62
- if (Number.isFinite(mb) && mb > 0) return { present: true, kind: "nvidia", vramMB: mb };
63
- } catch {
64
- // fall through — no usable GPU
65
- }
66
- return { present: false, kind: null, vramMB: 0 };
67
- }
68
-
69
- export function probeSpecs({ osMod = os, exec = defaultExec } = {}) {
70
- const platform = osMod.platform();
71
- const arch = osMod.arch();
72
- const cpuCores = osMod.cpus().length;
73
- const ramMB = Math.round(osMod.totalmem() / (1024 * 1024));
74
- return {
75
- platform,
76
- arch,
77
- cpuCores,
78
- ramMB,
79
- availableRamMB: availableRamMB(platform, exec, ramMB),
80
- appleSilicon: platform === "darwin" && arch === "arm64",
81
- gpu: detectGpu(platform, arch, ramMB, exec),
82
- };
83
- }
84
-
85
- // Where Hugging Face actually puts downloaded weights. A free-space check
86
- // against cwd measures the wrong filesystem, so the disk question has to be
87
- // asked about this directory. Precedence follows huggingface_hub's own order.
88
- export function weightsCacheDir({ env = process.env, osMod = os } = {}) {
89
- if (env.HF_HUB_CACHE) return env.HF_HUB_CACHE;
90
- if (env.HUGGINGFACE_HUB_CACHE) return env.HUGGINGFACE_HUB_CACHE;
91
- if (env.HF_HOME) return join(env.HF_HOME, "hub");
92
- return join(osMod.homedir(), ".cache", "huggingface", "hub");
93
- }
94
-
95
- // Free space on the filesystem that will hold the weights. The cache dir
96
- // usually does not exist until the first download and statfs throws on a
97
- // missing path, so walk up to the deepest ancestor that does exist. Returns
98
- // null when even the root cannot be read, so callers can say "unknown" instead
99
- // of implying zero and scaring someone off a download that would have worked.
100
- export function freeSpaceMB(dir, statfsFn = statfsSync) {
101
- let path = dir;
102
- for (;;) {
103
- try {
104
- const { bavail, bsize } = statfsFn(path);
105
- return (bavail * bsize) / 1e6;
106
- } catch {
107
- const parent = dirname(path);
108
- if (parent === path) return null;
109
- path = parent;
110
- }
111
- }
112
- }
113
-
114
- // One line the user reads BEFORE agreeing to a pull that can be tens of GB.
115
- // Always names the size and where it lands. When it will not fit we say so
116
- // plainly rather than withholding the tier: a machine that could free up space
117
- // should still be told the tier exists. `statfsFn` / `env` / `osMod` are
118
- // injectable for tests.
119
- export function describeDownload(
120
- sizeMB,
121
- { statfsFn = statfsSync, env = process.env, osMod = os } = {},
122
- ) {
123
- const dir = weightsCacheDir({ env, osMod });
124
- const gb = (mb) => (mb / 1000).toFixed(1);
125
- const head = `downloads ~${gb(sizeMB)}GB of weights to ${dir}`;
126
- const free = freeSpaceMB(dir, statfsFn);
127
- if (free == null) return `${head} (free space unknown)`;
128
- if (free < sizeMB) {
129
- return `${head}, but only ${gb(free)}GB is free there, so it will NOT fit as-is`;
130
- }
131
- return `${head} (${gb(free)}GB free there)`;
132
- }
@@ -1,157 +0,0 @@
1
- import { strict as assert } from "node:assert";
2
- import { test } from "node:test";
3
- import { describeDownload, freeSpaceMB, probeSpecs, weightsCacheDir } from "./specs.mjs";
4
-
5
- // Fake os module + exec so the probe is deterministic across CI machines.
6
- const fakeOs = (over = {}) => ({
7
- platform: () => over.platform ?? "linux",
8
- arch: () => over.arch ?? "x64",
9
- cpus: () => Array.from({ length: over.cores ?? 8 }),
10
- totalmem: () => (over.ramMB ?? 16384) * 1024 * 1024,
11
- });
12
-
13
- test("probeSpecs reports structured caps", () => {
14
- const s = probeSpecs({ osMod: fakeOs({ cores: 12, ramMB: 32768 }), exec: () => null });
15
- assert.equal(s.cpuCores, 12);
16
- assert.equal(s.ramMB, 32768);
17
- assert.equal(s.platform, "linux");
18
- assert.equal(s.gpu.present, false);
19
- // probe unavailable (exec returns null) -> availableRamMB falls back to total
20
- assert.equal(s.availableRamMB, 32768);
21
- });
22
-
23
- test("availableRamMB is read from /proc/meminfo on Linux", () => {
24
- const exec = (cmd) =>
25
- cmd.includes("meminfo") ? "MemTotal: 33554432 kB\nMemAvailable: 8388608 kB\n" : null;
26
- const s = probeSpecs({ osMod: fakeOs({ platform: "linux", ramMB: 32768 }), exec });
27
- assert.equal(s.availableRamMB, 8192, "8388608 kB -> 8192 MB");
28
- });
29
-
30
- test("availableRamMB is summed from reclaimable vm_stat pages on macOS", () => {
31
- const vmStat =
32
- "Mach Virtual Memory Statistics: (page size of 16384 bytes)\n" +
33
- "Pages free: 100000.\n" +
34
- "Pages inactive: 200000.\n" +
35
- "Pages speculative: 50000.\n" +
36
- "Pages purgeable: 10000.\n";
37
- const exec = (cmd) => (cmd.includes("vm_stat") ? vmStat : null);
38
- const s = probeSpecs({
39
- osMod: fakeOs({ platform: "darwin", arch: "arm64", ramMB: 24576 }),
40
- exec,
41
- });
42
- // (100000+200000+50000+10000) pages * 16384 B / 1MiB = 5625 MB
43
- assert.equal(s.availableRamMB, 5625);
44
- });
45
-
46
- test("Apple Silicon is detected as a unified-memory GPU", () => {
47
- const s = probeSpecs({
48
- osMod: fakeOs({ platform: "darwin", arch: "arm64", ramMB: 24576 }),
49
- exec: () => null,
50
- });
51
- assert.equal(s.appleSilicon, true);
52
- assert.equal(s.gpu.present, true);
53
- assert.equal(s.gpu.kind, "apple");
54
- // unified memory: VRAM tracks system RAM
55
- assert.equal(s.gpu.vramMB, 24576);
56
- });
57
-
58
- test("NVIDIA GPU is detected via nvidia-smi VRAM query", () => {
59
- const exec = (cmd) => (cmd.includes("nvidia-smi") ? "24564" : null);
60
- const s = probeSpecs({ osMod: fakeOs({ platform: "linux" }), exec });
61
- assert.equal(s.gpu.present, true);
62
- assert.equal(s.gpu.kind, "nvidia");
63
- assert.equal(s.gpu.vramMB, 24564);
64
- });
65
-
66
- test("no GPU when nvidia-smi is absent / fails", () => {
67
- const s = probeSpecs({
68
- osMod: fakeOs({ platform: "linux" }),
69
- exec: () => {
70
- throw new Error("command not found");
71
- },
72
- });
73
- assert.equal(s.gpu.present, false);
74
- assert.equal(s.gpu.vramMB, 0);
75
- });
76
-
77
- // --- download disclosure: what the user is agreeing to before the pull ---
78
-
79
- const fakeHome = { homedir: () => "/home/tester" };
80
- // statfs reports blocks, not bytes: bavail * bsize. 1 MB blocks keep the sums
81
- // readable, and mirror the real struct's shape.
82
- const fakeStatfs = (freeMB, existsOnly) => (path) => {
83
- if (existsOnly && path !== existsOnly) throw new Error(`ENOENT: ${path}`);
84
- return { bavail: freeMB, bsize: 1e6 };
85
- };
86
-
87
- test("weightsCacheDir follows huggingface_hub's precedence", () => {
88
- assert.equal(
89
- weightsCacheDir({ env: {}, osMod: fakeHome }),
90
- "/home/tester/.cache/huggingface/hub",
91
- );
92
- assert.equal(weightsCacheDir({ env: { HF_HOME: "/data/hf" }, osMod: fakeHome }), "/data/hf/hub");
93
- assert.equal(
94
- weightsCacheDir({ env: { HF_HOME: "/data/hf", HUGGINGFACE_HUB_CACHE: "/c" }, osMod: fakeHome }),
95
- "/c",
96
- "HUGGINGFACE_HUB_CACHE outranks HF_HOME",
97
- );
98
- assert.equal(
99
- weightsCacheDir({ env: { HF_HUB_CACHE: "/a", HUGGINGFACE_HUB_CACHE: "/c" }, osMod: fakeHome }),
100
- "/a",
101
- "HF_HUB_CACHE wins outright",
102
- );
103
- });
104
-
105
- test("freeSpaceMB walks up to the deepest existing ancestor", () => {
106
- // the cache dir does not exist until the first download, and statfs throws
107
- // on a missing path - so the answer has to come from an ancestor
108
- const statfs = fakeStatfs(4096, "/home");
109
- assert.equal(freeSpaceMB("/home/tester/.cache/huggingface/hub", statfs), 4096);
110
- });
111
-
112
- test("freeSpaceMB reports null rather than zero when nothing can be read", () => {
113
- assert.equal(
114
- freeSpaceMB("/home/tester/.cache", () => {
115
- throw new Error("EACCES");
116
- }),
117
- null,
118
- "unknown must not be reported as no-space",
119
- );
120
- });
121
-
122
- test("describeDownload names the size and where it lands", () => {
123
- const msg = describeDownload(87500, {
124
- statfsFn: fakeStatfs(200000),
125
- env: {},
126
- osMod: fakeHome,
127
- });
128
- assert.match(msg, /~87\.5GB/);
129
- assert.match(msg, /\/home\/tester\/\.cache\/huggingface\/hub/);
130
- assert.match(msg, /200\.0GB free/);
131
- assert.equal(/NOT fit/.test(msg), false, "it fits, so no warning");
132
- });
133
-
134
- test("describeDownload says plainly when the weights will not fit", () => {
135
- const msg = describeDownload(87500, {
136
- statfsFn: fakeStatfs(14000),
137
- env: {},
138
- osMod: fakeHome,
139
- });
140
- assert.match(msg, /only 14\.0GB is free there/);
141
- assert.match(msg, /will NOT fit as-is/);
142
- // the tier is still described, not withheld: a machine that could free up
143
- // space should know the tier exists
144
- assert.match(msg, /~87\.5GB/);
145
- });
146
-
147
- test("describeDownload admits when free space is unknown", () => {
148
- const msg = describeDownload(87500, {
149
- statfsFn: () => {
150
- throw new Error("EACCES");
151
- },
152
- env: {},
153
- osMod: fakeHome,
154
- });
155
- assert.match(msg, /free space unknown/);
156
- assert.equal(/NOT fit/.test(msg), false, "unknown is not a refusal");
157
- });
@@ -1,117 +0,0 @@
1
- import { statSync } from "node:fs";
2
- import { readGlobalManifest } from "./cache.mjs";
3
- import { readManifest } from "./manifest.mjs";
4
- import { readMisses } from "./misses.mjs";
5
-
6
- const TOP_MISSES = 5;
7
-
8
- function emptyReport() {
9
- return {
10
- total_resolves: 0,
11
- by_type: {},
12
- by_source: {},
13
- by_provider: {},
14
- by_via: {},
15
- misses: 0,
16
- hit_rate: null,
17
- top_missed_intents: {},
18
- global_cache_assets: 0,
19
- global_cache_disk_bytes: 0,
20
- cross_project_reuse: 0,
21
- };
22
- }
23
-
24
- function increment(map, key) {
25
- if (!key) return;
26
- map[key] = (map[key] || 0) + 1;
27
- }
28
-
29
- function timestampOf(record) {
30
- return record?.ts || record?.timestamp || record?.created_at || record?.createdAt || null;
31
- }
32
-
33
- function inWindow(record, cutoff) {
34
- if (!cutoff) return true;
35
- const ts = timestampOf(record);
36
- // Older manifest records may not carry a timestamp; keep them in the report
37
- // because --days can only window records/misses that carry a ts/timestamp.
38
- if (!ts) return true;
39
- const time = Date.parse(ts);
40
- return Number.isNaN(time) ? true : time >= cutoff;
41
- }
42
-
43
- function sourceOf(record) {
44
- return record?._source || record?.source || record?.provenance?.source || "unknown";
45
- }
46
-
47
- function normalizeIntent(intent) {
48
- return String(intent ?? "")
49
- .trim()
50
- .toLowerCase()
51
- .replace(/\s+/g, " ");
52
- }
53
-
54
- function topMissedIntents(misses) {
55
- const grouped = {};
56
- for (const miss of misses) {
57
- const type = miss?.type || "unknown";
58
- const intent = normalizeIntent(miss?.intent);
59
- if (!intent) continue;
60
- grouped[type] ||= {};
61
- grouped[type][intent] = (grouped[type][intent] || 0) + 1;
62
- }
63
- const out = {};
64
- for (const [type, intents] of Object.entries(grouped)) {
65
- out[type] = Object.entries(intents)
66
- .map(([intent, count]) => ({ intent, count }))
67
- .sort((a, b) => b.count - a.count || a.intent.localeCompare(b.intent))
68
- .slice(0, TOP_MISSES);
69
- }
70
- return out;
71
- }
72
-
73
- function diskBytes(records) {
74
- let total = 0;
75
- for (const record of records) {
76
- const p = record?.cached_path || record?.path;
77
- if (!p) continue;
78
- try {
79
- total += statSync(p).size;
80
- } catch {
81
- // cache entries can outlive files; stats skips missing files
82
- }
83
- }
84
- return total;
85
- }
86
-
87
- export function buildStats({ projectDir, days, now = Date.now() } = {}) {
88
- // Only a positive finite --days windows the report; null / NaN / <= 0 mean
89
- // "all time" rather than silently excluding everything (a negative cutoff
90
- // would land in the future and drop every record). The reads below are each
91
- // best-effort (they return [] / skip on IO errors), so there is no top-level
92
- // catch masking a real logic bug as an all-zero "no usage" report.
93
- const n = Number(days);
94
- const cutoff = Number.isFinite(n) && n > 0 ? Number(now) - n * 24 * 60 * 60 * 1000 : null;
95
- const records = (projectDir ? readManifest(projectDir) : []).filter((r) => inWindow(r, cutoff));
96
- const misses = readMisses().filter((miss) => inWindow(miss, cutoff));
97
- const globalRecords = readGlobalManifest();
98
- const report = emptyReport();
99
-
100
- report.total_resolves = records.length;
101
- report.misses = misses.length;
102
- for (const record of records) {
103
- increment(report.by_type, record?.type || "unknown");
104
- increment(report.by_source, sourceOf(record));
105
- increment(report.by_provider, record?.provenance?.provider);
106
- increment(report.by_via, record?.provenance?.via);
107
- }
108
-
109
- const attempts = report.total_resolves + report.misses;
110
- report.hit_rate = attempts === 0 ? null : report.total_resolves / attempts;
111
- report.top_missed_intents = topMissedIntents(misses);
112
- report.global_cache_assets = globalRecords.length;
113
- report.global_cache_disk_bytes = diskBytes(globalRecords);
114
- report.cross_project_reuse = globalRecords.filter((r) => r?.provenance?.reused_by).length;
115
-
116
- return report;
117
- }
@@ -1,165 +0,0 @@
1
- import { strict as assert } from "node:assert";
2
- import { test } from "node:test";
3
- import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
4
- import { tmpdir } from "node:os";
5
- import { join } from "node:path";
6
- import { buildStats } from "./stats.mjs";
7
-
8
- function sandbox() {
9
- const root = mkdtempSync(join(tmpdir(), "mu-stats-"));
10
- const home = join(root, "home");
11
- const projectDir = join(root, "project");
12
- mkdirSync(home, { recursive: true });
13
- mkdirSync(projectDir, { recursive: true });
14
- process.env.HOME = home;
15
- return { root, home, projectDir };
16
- }
17
-
18
- function restoreEnv(saved) {
19
- for (const k of Object.keys(process.env)) if (!(k in saved)) delete process.env[k];
20
- Object.assign(process.env, saved);
21
- }
22
-
23
- function seedManifest(dir, records) {
24
- mkdirSync(join(dir, ".media"), { recursive: true });
25
- writeFileSync(
26
- join(dir, ".media/manifest.jsonl"),
27
- records.map((record) => JSON.stringify(record)).join("\n") + "\n",
28
- );
29
- }
30
-
31
- function isoDaysAgo(days) {
32
- return new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
33
- }
34
-
35
- test("buildStats aggregates resolves, misses, providers, sources, and reuse", () => {
36
- const savedEnv = { ...process.env };
37
- const { root, home, projectDir } = sandbox();
38
- try {
39
- seedManifest(projectDir, [
40
- {
41
- id: "bgm_001",
42
- type: "bgm",
43
- source: "search",
44
- ts: isoDaysAgo(0),
45
- provenance: { provider: "heygen.audio.sounds", prompt: "upbeat", via: "url" },
46
- },
47
- {
48
- id: "image_001",
49
- type: "image",
50
- _source: "reused-explicit",
51
- timestamp: isoDaysAgo(0),
52
- provenance: { provider: "local", reused_by: "agent" },
53
- },
54
- {
55
- id: "bgm_002",
56
- type: "bgm",
57
- source: "generated",
58
- provenance: { provider: "codex" },
59
- },
60
- ]);
61
- const cachedFile = join(home, ".media/mu-v1-cache/asset.wav");
62
- mkdirSync(join(cachedFile, ".."), { recursive: true });
63
- writeFileSync(cachedFile, "12345");
64
- seedManifest(home, [
65
- {
66
- id: "bgm_009",
67
- type: "bgm",
68
- reusable: true,
69
- cached_path: cachedFile,
70
- provenance: { provider: "heygen.audio.sounds", reused_by: "agent" },
71
- },
72
- ]);
73
- writeFileSync(
74
- join(home, ".media/misses.jsonl"),
75
- JSON.stringify({
76
- ts: isoDaysAgo(0),
77
- type: "bgm",
78
- intent: "dark cinematic riser",
79
- }) + "\n",
80
- { flag: "a" },
81
- );
82
-
83
- const stats = buildStats({ projectDir });
84
- assert.equal(stats.total_resolves, 3);
85
- assert.deepEqual(stats.by_type, { bgm: 2, image: 1 });
86
- assert.deepEqual(stats.by_source, { search: 1, "reused-explicit": 1, generated: 1 });
87
- assert.equal(stats.by_provider["heygen.audio.sounds"], 1);
88
- assert.equal(stats.by_via.url, 1);
89
- assert.equal(stats.misses, 1);
90
- assert.equal(stats.hit_rate, 0.75);
91
- assert.deepEqual(stats.top_missed_intents.bgm[0], {
92
- intent: "dark cinematic riser",
93
- count: 1,
94
- });
95
- assert.equal(stats.global_cache_assets, 1);
96
- assert.equal(stats.global_cache_disk_bytes, 5);
97
- assert.equal(stats.cross_project_reuse, 1);
98
- } finally {
99
- restoreEnv(savedEnv);
100
- rmSync(root, { recursive: true, force: true });
101
- }
102
- });
103
-
104
- test("buildStats returns a zeroed report when nothing exists", () => {
105
- const savedEnv = { ...process.env };
106
- const { root, projectDir } = sandbox();
107
- try {
108
- const stats = buildStats({ projectDir });
109
- assert.equal(stats.total_resolves, 0);
110
- assert.deepEqual(stats.by_type, {});
111
- assert.deepEqual(stats.by_source, {});
112
- assert.deepEqual(stats.by_provider, {});
113
- assert.deepEqual(stats.by_via, {});
114
- assert.equal(stats.misses, 0);
115
- assert.equal(stats.hit_rate, null);
116
- assert.deepEqual(stats.top_missed_intents, {});
117
- assert.equal(stats.global_cache_assets, 0);
118
- assert.equal(stats.global_cache_disk_bytes, 0);
119
- assert.equal(stats.cross_project_reuse, 0);
120
- } finally {
121
- restoreEnv(savedEnv);
122
- rmSync(root, { recursive: true, force: true });
123
- }
124
- });
125
-
126
- test("buildStats returns JSON-safe output", () => {
127
- const savedEnv = { ...process.env };
128
- const { root, projectDir } = sandbox();
129
- try {
130
- const stats = buildStats({ projectDir });
131
- assert.deepEqual(JSON.parse(JSON.stringify(stats)), stats);
132
- } finally {
133
- restoreEnv(savedEnv);
134
- rmSync(root, { recursive: true, force: true });
135
- }
136
- });
137
-
138
- test("buildStats applies days window to timestamped records and misses", () => {
139
- const savedEnv = { ...process.env };
140
- const { root, home, projectDir } = sandbox();
141
- try {
142
- seedManifest(projectDir, [
143
- { id: "bgm_old", type: "bgm", ts: isoDaysAgo(100), provenance: { provider: "old" } },
144
- { id: "bgm_new", type: "bgm", ts: isoDaysAgo(1), provenance: { provider: "new" } },
145
- { id: "image_untimed", type: "image", provenance: { provider: "none" } },
146
- ]);
147
- mkdirSync(join(home, ".media"), { recursive: true });
148
- writeFileSync(
149
- join(home, ".media/misses.jsonl"),
150
- [
151
- JSON.stringify({ ts: isoDaysAgo(100), type: "bgm", intent: "old miss" }),
152
- JSON.stringify({ ts: isoDaysAgo(1), type: "bgm", intent: "new miss" }),
153
- ].join("\n"),
154
- );
155
-
156
- const stats = buildStats({ projectDir, days: 7 });
157
- assert.equal(stats.total_resolves, 2);
158
- assert.deepEqual(stats.by_type, { bgm: 1, image: 1 });
159
- assert.equal(stats.misses, 1);
160
- assert.equal(stats.top_missed_intents.bgm[0].intent, "new miss");
161
- } finally {
162
- restoreEnv(savedEnv);
163
- rmSync(root, { recursive: true, force: true });
164
- }
165
- });