@prestyj/cli 5.28.0 → 5.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (398) hide show
  1. package/README.md +2 -2
  2. package/assets/motion/THIRD-PARTY.md +14 -19
  3. package/assets/motion/bin/contact-sheet.mjs +9 -3
  4. package/assets/motion/bin/cues.mjs +337 -0
  5. package/assets/motion/bin/flash-check.mjs +314 -0
  6. package/assets/motion/bin/fonts.mjs +17 -13
  7. package/assets/motion/bin/library.mjs +61 -18
  8. package/assets/motion/bin/motion-blur.mjs +943 -0
  9. package/assets/motion/bin/motion-check.mjs +366 -9
  10. package/assets/motion/bin/music-fit.mjs +436 -0
  11. package/assets/motion/bin/pdf-extract.mjs +22 -10
  12. package/assets/motion/bin/reference-study.mjs +346 -0
  13. package/assets/motion/bin/score-synth.mjs +1052 -93
  14. package/assets/motion/fonts/finger-paint/OFL.txt +93 -0
  15. package/assets/motion/fonts/finger-paint/finger-paint-normal.woff2 +0 -0
  16. package/assets/motion/fonts/fonts.json +56 -0
  17. package/assets/motion/fonts/short-stack/OFL.txt +94 -0
  18. package/assets/motion/fonts/short-stack/short-stack-normal.woff2 +0 -0
  19. package/assets/motion/fonts/sora/OFL.txt +93 -0
  20. package/assets/motion/fonts/sora/sora-normal.woff2 +0 -0
  21. package/assets/motion/fonts/specimen.jpg +0 -0
  22. package/assets/motion/fonts/unbounded/OFL.txt +93 -0
  23. package/assets/motion/fonts/unbounded/unbounded-normal.woff2 +0 -0
  24. package/assets/motion/library/README.md +52 -14
  25. package/assets/motion/library/kit/moves.js +1981 -0
  26. package/assets/motion/library/library.json +232 -0
  27. package/assets/motion/library/pieces/camera-rig/meta.json +13 -0
  28. package/assets/motion/library/pieces/camera-rig/piece.html +153 -0
  29. package/assets/motion/library/pieces/camera-rig/preview.jpg +0 -0
  30. package/assets/motion/library/pieces/chain-knock/meta.json +13 -0
  31. package/assets/motion/library/pieces/chain-knock/piece.html +195 -0
  32. package/assets/motion/library/pieces/chain-knock/preview.jpg +0 -0
  33. package/assets/motion/library/pieces/gather-to-logo/meta.json +13 -0
  34. package/assets/motion/library/pieces/gather-to-logo/piece.html +159 -0
  35. package/assets/motion/library/pieces/gather-to-logo/preview.jpg +0 -0
  36. package/assets/motion/library/pieces/morph-carry/meta.json +13 -0
  37. package/assets/motion/library/pieces/morph-carry/piece.html +173 -0
  38. package/assets/motion/library/pieces/morph-carry/preview.jpg +0 -0
  39. package/assets/motion/library/pieces/one-shape-journey/meta.json +13 -0
  40. package/assets/motion/library/pieces/one-shape-journey/piece.html +195 -0
  41. package/assets/motion/library/pieces/one-shape-journey/preview.jpg +0 -0
  42. package/assets/motion/library/pieces/open-from-subject/meta.json +13 -0
  43. package/assets/motion/library/pieces/open-from-subject/piece.html +168 -0
  44. package/assets/motion/library/pieces/open-from-subject/preview.jpg +0 -0
  45. package/assets/motion/library/pieces/request-to-result/meta.json +13 -0
  46. package/assets/motion/library/pieces/request-to-result/piece.html +212 -0
  47. package/assets/motion/library/pieces/request-to-result/preview.jpg +0 -0
  48. package/assets/motion/library/pieces/scale-dive/meta.json +13 -0
  49. package/assets/motion/library/pieces/scale-dive/piece.html +321 -0
  50. package/assets/motion/library/pieces/scale-dive/preview.jpg +0 -0
  51. package/assets/motion/library/pieces/screen-replica-steps/meta.json +13 -0
  52. package/assets/motion/library/pieces/screen-replica-steps/piece.html +366 -0
  53. package/assets/motion/library/pieces/screen-replica-steps/preview.jpg +0 -0
  54. package/assets/motion/library/pieces/zoom-into-card/meta.json +13 -0
  55. package/assets/motion/library/pieces/zoom-into-card/piece.html +179 -0
  56. package/assets/motion/library/pieces/zoom-into-card/preview.jpg +0 -0
  57. package/assets/motion/library/sheets/diagram.jpg +0 -0
  58. package/assets/motion/library/sheets/frame.jpg +0 -0
  59. package/assets/motion/library/sheets/transition.jpg +0 -0
  60. package/assets/motion/library/sheets/ui.jpg +0 -0
  61. package/assets/motion/plugin.json +1 -1
  62. package/assets/motion/references/build-sheet.md +206 -0
  63. package/assets/motion/references/runtime/determinism-rules.md +3 -3
  64. package/assets/motion/references/runtime/gsap-easing-and-stagger.md +28 -28
  65. package/assets/motion/references/runtime/gsap.md +3 -3
  66. package/assets/motion/references/runtime/inputs-and-assets.md +21 -16
  67. package/assets/motion/references/runtime/lint-validate-inspect.md +3 -3
  68. package/assets/motion/references/runtime/minimal-composition.md +6 -0
  69. package/assets/motion/references/runtime/preview-render.md +3 -3
  70. package/assets/motion/skills/app-walkthrough/SKILL.md +66 -0
  71. package/assets/motion/skills/before-after/SKILL.md +53 -0
  72. package/assets/motion/skills/brand-kit/SKILL.md +17 -16
  73. package/assets/motion/skills/dev-tool-video/SKILL.md +57 -0
  74. package/assets/motion/skills/launch-video/SKILL.md +62 -0
  75. package/assets/motion/skills/match-reference/SKILL.md +58 -0
  76. package/assets/motion/skills/motion/SKILL.md +167 -98
  77. package/assets/motion/skills/source-ingest/SKILL.md +23 -15
  78. package/assets/motion/skills/website-video/SKILL.md +59 -0
  79. package/assets/skills/bulletproof/SKILL.md +36 -11
  80. package/assets/skills/bulletproof/references/agent-surface.md +19 -9
  81. package/assets/skills/bulletproof/references/audit-protocol.md +20 -5
  82. package/assets/skills/bulletproof/references/platform-playbooks.md +5 -4
  83. package/assets/skills/bulletproof/references/provenance.md +26 -1
  84. package/assets/skills/bulletproof/references/secure-defaults.md +6 -5
  85. package/assets/skills/bulletproof/references/supply-chain.md +21 -17
  86. package/assets/skills/bulletproof/references/threat-landscape.md +28 -26
  87. package/assets/skills/bulletproof/references/verification.md +2 -0
  88. package/assets/skills/clarify/SKILL.md +25 -16
  89. package/assets/skills/code-review/SKILL.md +71 -13
  90. package/assets/skills/code-review/references/agent-diffs.md +27 -0
  91. package/assets/skills/code-review/references/tests.md +19 -0
  92. package/assets/skills/compliance-guard/SKILL.md +20 -5
  93. package/assets/skills/compliance-guard/references/artifacts.md +1 -1
  94. package/assets/skills/compliance-guard/references/eu-uk.md +16 -16
  95. package/assets/skills/compliance-guard/references/lawsuit-vectors.md +5 -5
  96. package/assets/skills/compliance-guard/references/provenance.md +41 -2
  97. package/assets/skills/compliance-guard/references/sector-gates.md +3 -3
  98. package/assets/skills/compliance-guard/references/security-baseline.md +2 -2
  99. package/assets/skills/compliance-guard/references/trigger-map.md +5 -5
  100. package/assets/skills/compliance-guard/references/us.md +27 -21
  101. package/assets/skills/durable/SKILL.md +87 -79
  102. package/assets/skills/durable/references/agent-db-safety.md +69 -0
  103. package/assets/skills/durable/references/backups-and-runtime.md +19 -12
  104. package/assets/skills/durable/references/migrations-and-schema.md +13 -6
  105. package/assets/skills/evidence-led-ui/SKILL.md +69 -127
  106. package/assets/skills/evidence-led-ui/references/anti-defaults.md +107 -208
  107. package/assets/skills/evidence-led-ui/references/direction.md +124 -0
  108. package/assets/skills/evidence-led-ui/references/production-contract.md +8 -0
  109. package/assets/skills/evidence-led-ui/references/provenance.md +24 -1
  110. package/assets/skills/lean/SKILL.md +90 -71
  111. package/assets/skills/lean/references/memory-and-processes.md +3 -2
  112. package/assets/skills/lean/references/playbooks.md +37 -12
  113. package/assets/skills/refactoring/SKILL.md +24 -3
  114. package/assets/skills/refactoring/references/agent-pitfalls.md +4 -1
  115. package/assets/skills/refactoring/references/legacy.md +21 -0
  116. package/assets/skills/root-cause/SKILL.md +20 -10
  117. package/assets/skills/shared-language/SKILL.md +16 -14
  118. package/assets/skills/tdd/SKILL.md +27 -15
  119. package/dist/app-sidecar.js +203 -47
  120. package/dist/app-sidecar.js.map +1 -1
  121. package/dist/cli.js +20 -28
  122. package/dist/cli.js.map +1 -1
  123. package/dist/core/acceptance-checks.d.ts +48 -0
  124. package/dist/core/acceptance-checks.js +144 -0
  125. package/dist/core/acceptance-checks.js.map +1 -0
  126. package/dist/core/agent-session.d.ts +119 -75
  127. package/dist/core/agent-session.js +561 -395
  128. package/dist/core/agent-session.js.map +1 -1
  129. package/dist/core/agents.d.ts +6 -5
  130. package/dist/core/agents.js +12 -3
  131. package/dist/core/agents.js.map +1 -1
  132. package/dist/core/ask-user.d.ts +90 -8
  133. package/dist/core/ask-user.js +124 -13
  134. package/dist/core/ask-user.js.map +1 -1
  135. package/dist/core/auth-providers.js +1 -1
  136. package/dist/core/auth-providers.js.map +1 -1
  137. package/dist/core/autopilot-verdict.d.ts +5 -1
  138. package/dist/core/autopilot-verdict.js +30 -13
  139. package/dist/core/autopilot-verdict.js.map +1 -1
  140. package/dist/core/bundled-agents.js +1 -3
  141. package/dist/core/bundled-agents.js.map +1 -1
  142. package/dist/core/cache-diagnostics.d.ts +68 -0
  143. package/dist/core/cache-diagnostics.js +196 -0
  144. package/dist/core/cache-diagnostics.js.map +1 -0
  145. package/dist/core/cache-expiry.d.ts +87 -0
  146. package/dist/core/cache-expiry.js +111 -0
  147. package/dist/core/cache-expiry.js.map +1 -0
  148. package/dist/core/compaction/compactor.js +78 -48
  149. package/dist/core/compaction/compactor.js.map +1 -1
  150. package/dist/core/compaction/plan-step-policy.d.ts +46 -0
  151. package/dist/core/compaction/plan-step-policy.js +57 -0
  152. package/dist/core/compaction/plan-step-policy.js.map +1 -0
  153. package/dist/core/destructive-git-guard.d.ts +90 -0
  154. package/dist/core/destructive-git-guard.js +871 -0
  155. package/dist/core/destructive-git-guard.js.map +1 -0
  156. package/dist/core/event-bus.d.ts +3 -0
  157. package/dist/core/event-bus.js +5 -0
  158. package/dist/core/event-bus.js.map +1 -1
  159. package/dist/core/fast-apply-benchmark.d.ts +1 -1
  160. package/dist/core/fast-apply-benchmark.js +2 -2
  161. package/dist/core/fast-apply-benchmark.js.map +1 -1
  162. package/dist/core/injection-detect.d.ts +38 -0
  163. package/dist/core/injection-detect.js +232 -0
  164. package/dist/core/injection-detect.js.map +1 -0
  165. package/dist/core/keep-awake.d.ts +88 -0
  166. package/dist/core/keep-awake.js +251 -0
  167. package/dist/core/keep-awake.js.map +1 -0
  168. package/dist/core/mcp/client.d.ts +72 -0
  169. package/dist/core/mcp/client.js +264 -41
  170. package/dist/core/mcp/client.js.map +1 -1
  171. package/dist/core/mcp/content.js +6 -2
  172. package/dist/core/mcp/content.js.map +1 -1
  173. package/dist/core/mcp/store.d.ts +6 -1
  174. package/dist/core/mcp/store.js +12 -1
  175. package/dist/core/mcp/store.js.map +1 -1
  176. package/dist/core/mcp/types.d.ts +18 -0
  177. package/dist/core/model-unavailable.d.ts +14 -0
  178. package/dist/core/model-unavailable.js +23 -0
  179. package/dist/core/model-unavailable.js.map +1 -0
  180. package/dist/core/node-debugger.d.ts +148 -0
  181. package/dist/core/node-debugger.js +642 -0
  182. package/dist/core/node-debugger.js.map +1 -0
  183. package/dist/core/nolan-context.d.ts +7 -5
  184. package/dist/core/nolan-context.js +106 -16
  185. package/dist/core/nolan-context.js.map +1 -1
  186. package/dist/core/nolan-prompt.js +24 -21
  187. package/dist/core/nolan-prompt.js.map +1 -1
  188. package/dist/core/package-threats.d.ts +18 -0
  189. package/dist/core/package-threats.js +168 -0
  190. package/dist/core/package-threats.js.map +1 -0
  191. package/dist/core/persistent-shell.d.ts +58 -6
  192. package/dist/core/persistent-shell.js +331 -49
  193. package/dist/core/persistent-shell.js.map +1 -1
  194. package/dist/core/process-manager.d.ts +14 -0
  195. package/dist/core/process-manager.js +61 -0
  196. package/dist/core/process-manager.js.map +1 -1
  197. package/dist/core/progress/git-xp.js +8 -14
  198. package/dist/core/progress/git-xp.js.map +1 -1
  199. package/dist/core/project-discovery.js +77 -26
  200. package/dist/core/project-discovery.js.map +1 -1
  201. package/dist/core/semantic-search-benchmark.d.ts +1 -1
  202. package/dist/core/semantic-search-benchmark.js +2 -2
  203. package/dist/core/semantic-search-benchmark.js.map +1 -1
  204. package/dist/core/session-history.d.ts +12 -0
  205. package/dist/core/session-history.js +27 -0
  206. package/dist/core/session-history.js.map +1 -1
  207. package/dist/core/session-manager.d.ts +13 -1
  208. package/dist/core/session-manager.js +38 -18
  209. package/dist/core/session-manager.js.map +1 -1
  210. package/dist/core/session-summary-index.d.ts +37 -0
  211. package/dist/core/session-summary-index.js +172 -0
  212. package/dist/core/session-summary-index.js.map +1 -0
  213. package/dist/core/settings-manager.d.ts +2 -0
  214. package/dist/core/settings-manager.js +10 -0
  215. package/dist/core/settings-manager.js.map +1 -1
  216. package/dist/core/shell-threats-popular-packages.d.ts +11 -0
  217. package/dist/core/shell-threats-popular-packages.js +675 -0
  218. package/dist/core/shell-threats-popular-packages.js.map +1 -0
  219. package/dist/core/shell-threats.d.ts +8 -0
  220. package/dist/core/shell-threats.js +186 -0
  221. package/dist/core/shell-threats.js.map +1 -0
  222. package/dist/core/skills.js +16 -4
  223. package/dist/core/skills.js.map +1 -1
  224. package/dist/core/stream-rules.d.ts +30 -0
  225. package/dist/core/stream-rules.js +151 -0
  226. package/dist/core/stream-rules.js.map +1 -0
  227. package/dist/core/subagent-manager.d.ts +23 -6
  228. package/dist/core/subagent-manager.js +25 -9
  229. package/dist/core/subagent-manager.js.map +1 -1
  230. package/dist/core/subagent-policy.js +1 -1
  231. package/dist/core/subagent-policy.js.map +1 -1
  232. package/dist/core/subagent-receipt.d.ts +54 -0
  233. package/dist/core/subagent-receipt.js +276 -0
  234. package/dist/core/subagent-receipt.js.map +1 -0
  235. package/dist/core/subagent-turn-record.d.ts +2 -0
  236. package/dist/core/subagent-turn-record.js.map +1 -1
  237. package/dist/core/test-impact.d.ts +73 -0
  238. package/dist/core/test-impact.js +467 -0
  239. package/dist/core/test-impact.js.map +1 -0
  240. package/dist/core/thinking-level.d.ts +1 -1
  241. package/dist/core/thinking-level.js +1 -1
  242. package/dist/core/thinking-level.js.map +1 -1
  243. package/dist/core/verification-gate.d.ts +2 -0
  244. package/dist/core/verification-gate.js +4 -0
  245. package/dist/core/verification-gate.js.map +1 -1
  246. package/dist/core/verification-snapshot.js +3 -5
  247. package/dist/core/verification-snapshot.js.map +1 -1
  248. package/dist/core/workspace-guard.d.ts +18 -7
  249. package/dist/core/workspace-guard.js +227 -60
  250. package/dist/core/workspace-guard.js.map +1 -1
  251. package/dist/core/worktree-setup.d.ts +23 -0
  252. package/dist/core/worktree-setup.js +128 -9
  253. package/dist/core/worktree-setup.js.map +1 -1
  254. package/dist/core/worktree.d.ts +20 -2
  255. package/dist/core/worktree.js +74 -31
  256. package/dist/core/worktree.js.map +1 -1
  257. package/dist/interactive.js +2 -1
  258. package/dist/interactive.js.map +1 -1
  259. package/dist/modes/json-mode.js +11 -2
  260. package/dist/modes/json-mode.js.map +1 -1
  261. package/dist/modes/subagent-worker-mode.d.ts +36 -1
  262. package/dist/modes/subagent-worker-mode.js +100 -42
  263. package/dist/modes/subagent-worker-mode.js.map +1 -1
  264. package/dist/motion-agent/motion-agent.d.ts +7 -3
  265. package/dist/motion-agent/motion-agent.js +6 -8
  266. package/dist/motion-agent/motion-agent.js.map +1 -1
  267. package/dist/motion-agent/motion-prompt.d.ts +1 -1
  268. package/dist/motion-agent/motion-prompt.js +16 -25
  269. package/dist/motion-agent/motion-prompt.js.map +1 -1
  270. package/dist/motion-agent/motion-review-session.js +1 -1
  271. package/dist/motion-agent/motion-review-session.js.map +1 -1
  272. package/dist/motion-agent/motion-review.d.ts +10 -3
  273. package/dist/motion-agent/motion-review.js +15 -7
  274. package/dist/motion-agent/motion-review.js.map +1 -1
  275. package/dist/motion-agent/motion-studio-context.js +1 -1
  276. package/dist/motion-agent/motion-studio-context.js.map +1 -1
  277. package/dist/system-prompt.d.ts +2 -1
  278. package/dist/system-prompt.js +15 -4
  279. package/dist/system-prompt.js.map +1 -1
  280. package/dist/test-support/keep-alive.d.ts +14 -0
  281. package/dist/test-support/keep-alive.js +17 -0
  282. package/dist/test-support/keep-alive.js.map +1 -0
  283. package/dist/tools/ask-user.js +3 -3
  284. package/dist/tools/ask-user.js.map +1 -1
  285. package/dist/tools/bash-read-evidence.d.ts +10 -0
  286. package/dist/tools/bash-read-evidence.js +133 -0
  287. package/dist/tools/bash-read-evidence.js.map +1 -0
  288. package/dist/tools/bash.d.ts +10 -1
  289. package/dist/tools/bash.js +179 -7
  290. package/dist/tools/bash.js.map +1 -1
  291. package/dist/tools/debug.d.ts +54 -0
  292. package/dist/tools/debug.js +233 -0
  293. package/dist/tools/debug.js.map +1 -0
  294. package/dist/tools/edit.js +13 -5
  295. package/dist/tools/edit.js.map +1 -1
  296. package/dist/tools/goals.d.ts +1 -1
  297. package/dist/tools/index.d.ts +25 -2
  298. package/dist/tools/index.js +48 -7
  299. package/dist/tools/index.js.map +1 -1
  300. package/dist/tools/prompt-hints.js +2 -0
  301. package/dist/tools/prompt-hints.js.map +1 -1
  302. package/dist/tools/read-tracker.d.ts +35 -2
  303. package/dist/tools/read-tracker.js +108 -11
  304. package/dist/tools/read-tracker.js.map +1 -1
  305. package/dist/tools/read.js +39 -7
  306. package/dist/tools/read.js.map +1 -1
  307. package/dist/tools/skill.js +5 -0
  308. package/dist/tools/skill.js.map +1 -1
  309. package/dist/tools/subagent-control.js +44 -8
  310. package/dist/tools/subagent-control.js.map +1 -1
  311. package/dist/tools/subagent-shared.d.ts +48 -8
  312. package/dist/tools/subagent-shared.js +75 -14
  313. package/dist/tools/subagent-shared.js.map +1 -1
  314. package/dist/tools/subagent.d.ts +8 -2
  315. package/dist/tools/subagent.js +28 -10
  316. package/dist/tools/subagent.js.map +1 -1
  317. package/dist/tools/task-output.js +3 -2
  318. package/dist/tools/task-output.js.map +1 -1
  319. package/dist/tools/task-send.d.ts +1 -1
  320. package/dist/tools/task-send.js +15 -1
  321. package/dist/tools/task-send.js.map +1 -1
  322. package/dist/tools/tool-tiers.d.ts +2 -2
  323. package/dist/tools/tool-tiers.js +3 -2
  324. package/dist/tools/tool-tiers.js.map +1 -1
  325. package/dist/tools/truncate.d.ts +21 -0
  326. package/dist/tools/truncate.js +187 -0
  327. package/dist/tools/truncate.js.map +1 -1
  328. package/dist/tools/ui-adopt.js +2 -0
  329. package/dist/tools/ui-adopt.js.map +1 -1
  330. package/dist/tools/write.js +4 -3
  331. package/dist/tools/write.js.map +1 -1
  332. package/dist/ui/App.d.ts +0 -4
  333. package/dist/ui/App.js +5 -28
  334. package/dist/ui/App.js.map +1 -1
  335. package/dist/ui/components/ActivityIndicator.js +1 -0
  336. package/dist/ui/components/ActivityIndicator.js.map +1 -1
  337. package/dist/ui/components/Footer.js +1 -1
  338. package/dist/ui/components/Footer.js.map +1 -1
  339. package/dist/ui/hooks/useAgentLoop.d.ts +1 -8
  340. package/dist/ui/hooks/useAgentLoop.js +1 -119
  341. package/dist/ui/hooks/useAgentLoop.js.map +1 -1
  342. package/dist/ui/render.d.ts +2 -4
  343. package/dist/ui/render.js +3 -2
  344. package/dist/ui/render.js.map +1 -1
  345. package/dist/utils/git.d.ts +77 -0
  346. package/dist/utils/git.js +285 -21
  347. package/dist/utils/git.js.map +1 -1
  348. package/dist/utils/github-ci.js +2 -1
  349. package/dist/utils/github-ci.js.map +1 -1
  350. package/dist/utils/github.js +11 -9
  351. package/dist/utils/github.js.map +1 -1
  352. package/dist/utils/image.d.ts +14 -0
  353. package/dist/utils/image.js +16 -0
  354. package/dist/utils/image.js.map +1 -1
  355. package/dist/utils/process.d.ts +20 -0
  356. package/dist/utils/process.js +98 -0
  357. package/dist/utils/process.js.map +1 -1
  358. package/dist/utils/text.d.ts +12 -0
  359. package/dist/utils/text.js +11 -0
  360. package/dist/utils/text.js.map +1 -1
  361. package/package.json +6 -6
  362. package/assets/motion/skills/mixkit-split-text-617/SKILL.md +0 -115
  363. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-480.json +0 -1
  364. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-494.json +0 -1
  365. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-5.json +0 -1
  366. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-508.json +0 -1
  367. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6525.json +0 -1
  368. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6539.json +0 -1
  369. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6647.json +0 -1
  370. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6663.json +0 -1
  371. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6677.json +0 -1
  372. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6691.json +0 -1
  373. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6706.json +0 -1
  374. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6722.json +0 -1
  375. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6736.json +0 -1
  376. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6750.json +0 -1
  377. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6764.json +0 -1
  378. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6780.json +0 -1
  379. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6794.json +0 -1
  380. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6810.json +0 -1
  381. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6823.json +0 -1
  382. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6872.json +0 -1
  383. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6936.json +0 -1
  384. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-76.json +0 -1
  385. package/assets/motion/skills/mixkit-split-text-617/data/manifest.json +0 -495
  386. package/assets/motion/skills/mixkit-split-text-617/references/RECONSTRUCTION.md +0 -201
  387. package/assets/motion/skills/mixkit-split-text-617/references/VERIFICATION.md +0 -107
  388. package/assets/motion/skills/mixkit-split-text-617/tools/inspect_motion.py +0 -130
  389. package/assets/motion/skills/video-qa/SKILL.md +0 -66
  390. package/dist/core/ideal-review-subagent.d.ts +0 -42
  391. package/dist/core/ideal-review-subagent.js +0 -95
  392. package/dist/core/ideal-review-subagent.js.map +0 -1
  393. package/dist/core/ideal-review.d.ts +0 -82
  394. package/dist/core/ideal-review.js +0 -242
  395. package/dist/core/ideal-review.js.map +0 -1
  396. package/dist/motion-agent/motion-check-tool.d.ts +0 -21
  397. package/dist/motion-agent/motion-check-tool.js +0 -206
  398. package/dist/motion-agent/motion-check-tool.js.map +0 -1
@@ -0,0 +1,436 @@
1
+ #!/usr/bin/env node
2
+ // EZ Motion music fit: cut a supplied music track to the picture's length out
3
+ // of whole bars of the original, so it starts, lands and ends on the beat.
4
+ //
5
+ // Usage: node music-fit.mjs <track.(mp3|wav|m4a)> --duration <s>
6
+ // [--land <trackTime>@<filmTime>] [--out <dir>]
7
+ // Writes: <out>/music.wav (48 kHz stereo, exactly --duration long) and
8
+ // <out>/music-fit.json (bpm, the fitted track's downbeats in film
9
+ // time and the edit list: which source range plays where).
10
+ // Prints a one-line JSON summary; errors print { ok: false, error } and exit 1.
11
+ //
12
+ // Method (deterministic, constant tempo assumed — produced music):
13
+ // 1. Decode to 48 kHz stereo with ffmpeg; analyse a mono mix at 24 kHz.
14
+ // 2. Onset strength: log-magnitude spectral flux (1024-sample Hann frames,
15
+ // hop 256 ≈ 10.7 ms), minus its 0.5 s moving average, half-wave
16
+ // rectified. A second envelope uses only bins below 200 Hz (the kick).
17
+ // 3. Tempo: autocorrelation of the envelope over lags for 60–200 bpm, with a
18
+ // log-normal preference around 120 bpm against octave errors; then a fine
19
+ // search (±2 % in 0.01 bpm steps, quarter-frame phases) for the period and
20
+ // phase whose beat comb collects the most onset strength over the whole
21
+ // track, so the grid does not drift over minutes.
22
+ // 4. Downbeats: of the four beat phases, the one whose beats carry the most
23
+ // onset strength (low band weighted double, since the kick marks "one").
24
+ // 5. Plan: film downbeats sit at land + k·bar. Before the land the track
25
+ // plays into it (a pickup from the source before a downbeat, repeating
26
+ // bars only when the intro is too short); after it whole bars play on,
27
+ // jumping (by whole phrases of 4 bars when possible) to the track's own
28
+ // ending so the last downbeat lands 0.25 s–1 bar before the end and its
29
+ // ring-out fades. Every cut sits on a downbeat of both source and film,
30
+ // joined by a 40 ms equal-power crossfade centred on it.
31
+ import { spawn } from "node:child_process";
32
+ import { mkdir, writeFile } from "node:fs/promises";
33
+ import { join, resolve } from "node:path";
34
+ import { ffmpegBinary } from "./media-binaries.mjs";
35
+
36
+ const SR = 48000;
37
+ const ASR = 24000;
38
+ const FRAME = 1024;
39
+ const HOP = 256;
40
+ const LAG = (FRAME * 3) / 4;
41
+ const XFADE = 0.04;
42
+ const MIN_TAIL = 0.25;
43
+ const END_FADE = 0.6;
44
+
45
+ class FitError extends Error {}
46
+
47
+ /** @param {string[]} argv */
48
+ function parseArgs(argv) {
49
+ const opts = { track: "", duration: NaN, land: null, out: "." };
50
+ for (let i = 0; i < argv.length; i++) {
51
+ const a = argv[i];
52
+ if (a === "--duration") opts.duration = Number(argv[++i]);
53
+ else if (a === "--out") opts.out = argv[++i] ?? "";
54
+ else if (a === "--land") {
55
+ const m = /^(\d+(?:\.\d+)?)@(\d+(?:\.\d+)?)$/.exec(argv[++i] ?? "");
56
+ if (!m) throw new FitError("--land must be <trackTime>@<filmTime> in seconds, e.g. 12.5@4");
57
+ opts.land = { track: Number(m[1]), film: Number(m[2]) };
58
+ } else if (a.startsWith("--")) throw new FitError(`unknown option ${a}`);
59
+ else if (!opts.track) opts.track = a;
60
+ else throw new FitError(`unexpected argument ${a}`);
61
+ }
62
+ if (!opts.track)
63
+ throw new FitError(
64
+ "usage: music-fit.mjs <track.(mp3|wav|m4a)> --duration <s> [--land <trackTime>@<filmTime>] [--out <dir>]",
65
+ );
66
+ if (!/\.(mp3|wav|m4a)$/i.test(opts.track)) throw new FitError("track must be .mp3, .wav or .m4a");
67
+ if (!(opts.duration > 0 && opts.duration <= 900))
68
+ throw new FitError("--duration must be between 0 and 900 seconds");
69
+ if (!opts.out) throw new FitError("--out needs a directory");
70
+ if (opts.land && !(opts.land.film < opts.duration))
71
+ throw new FitError("--land film time must be inside --duration");
72
+ return opts;
73
+ }
74
+
75
+ /** Decode any track to 48 kHz interleaved stereo float PCM. */
76
+ async function decode(path) {
77
+ const ffmpeg = await ffmpegBinary();
78
+ const args = ["-v", "error", "-i", path, "-ac", "2", "-ar", String(SR), "-f", "f32le", "pipe:1"];
79
+ const bytes = await new Promise((done, failed) => {
80
+ const child = spawn(ffmpeg, args, { stdio: ["ignore", "pipe", "pipe"] });
81
+ const chunks = [];
82
+ let err = "";
83
+ child.stdout.on("data", (c) => chunks.push(c));
84
+ child.stderr.on("data", (c) => (err += c));
85
+ child.on("error", failed);
86
+ child.on("close", (code) =>
87
+ code === 0
88
+ ? done(Buffer.concat(chunks))
89
+ : failed(new FitError(`could not decode ${path}: ${err.trim() || `ffmpeg exit ${code}`}`)),
90
+ );
91
+ });
92
+ const n = Math.floor(bytes.length / 8);
93
+ if (n < SR) throw new FitError("track is shorter than one second or not audio");
94
+ const l = new Float32Array(n);
95
+ const r = new Float32Array(n);
96
+ for (let i = 0; i < n; i++) {
97
+ l[i] = bytes.readFloatLE(i * 8);
98
+ r[i] = bytes.readFloatLE(i * 8 + 4);
99
+ }
100
+ return { l, r, n };
101
+ }
102
+
103
+ /** In-place radix-2 FFT. */
104
+ function fft(re, im) {
105
+ const n = re.length;
106
+ for (let i = 1, j = 0; i < n; i++) {
107
+ let bit = n >> 1;
108
+ for (; j & bit; bit >>= 1) j ^= bit;
109
+ j ^= bit;
110
+ if (i < j) {
111
+ [re[i], re[j]] = [re[j], re[i]];
112
+ [im[i], im[j]] = [im[j], im[i]];
113
+ }
114
+ }
115
+ for (let len = 2; len <= n; len <<= 1) {
116
+ const ang = (-2 * Math.PI) / len;
117
+ for (let i = 0; i < n; i += len)
118
+ for (let k = 0; k < len / 2; k++) {
119
+ const wr = Math.cos(ang * k);
120
+ const wi = Math.sin(ang * k);
121
+ const a = i + k;
122
+ const b = a + len / 2;
123
+ const xr = re[b] * wr - im[b] * wi;
124
+ const xi = re[b] * wi + im[b] * wr;
125
+ re[b] = re[a] - xr;
126
+ im[b] = im[a] - xi;
127
+ re[a] += xr;
128
+ im[a] += xi;
129
+ }
130
+ }
131
+ }
132
+
133
+ /** Normalised onset-strength envelopes (full band and below 200 Hz), one value per hop. */
134
+ function onsetEnvelopes(audio) {
135
+ const m = Math.floor(audio.n / 2);
136
+ const mono = new Float32Array(m);
137
+ for (let i = 0; i < m; i++)
138
+ mono[i] = (audio.l[2 * i] + audio.r[2 * i] + audio.l[2 * i + 1] + audio.r[2 * i + 1]) / 4;
139
+ const frames = Math.max(1, Math.floor((m - FRAME) / HOP) + 1);
140
+ const win = Float32Array.from(
141
+ { length: FRAME },
142
+ (_, i) => 0.5 - 0.5 * Math.cos((2 * Math.PI * i) / FRAME),
143
+ );
144
+ const bins = FRAME / 2;
145
+ const lowBins = Math.round((200 * FRAME) / ASR);
146
+ let prev = new Float32Array(bins);
147
+ const full = new Float64Array(frames);
148
+ const low = new Float64Array(frames);
149
+ const re = new Float64Array(FRAME);
150
+ const im = new Float64Array(FRAME);
151
+ for (let f = 0; f < frames; f++) {
152
+ for (let i = 0; i < FRAME; i++) {
153
+ re[i] = (mono[f * HOP + i] ?? 0) * win[i];
154
+ im[i] = 0;
155
+ }
156
+ fft(re, im);
157
+ const mag = new Float32Array(bins);
158
+ for (let k = 0; k < bins; k++) {
159
+ mag[k] = Math.log1p(1000 * Math.hypot(re[k], im[k]));
160
+ const d = mag[k] - prev[k];
161
+ if (f > 0 && d > 0) {
162
+ full[f] += d;
163
+ if (k <= lowBins) low[f] += d;
164
+ }
165
+ }
166
+ prev = mag;
167
+ }
168
+ return { full: normalise(full), low: normalise(low), frames };
169
+ }
170
+
171
+ /** Subtract a 0.5 s moving average, half-wave rectify, scale to unit mean. */
172
+ function normalise(env) {
173
+ const half = Math.round((0.25 * ASR) / HOP);
174
+ const out = new Float64Array(env.length);
175
+ const pre = new Float64Array(env.length + 1);
176
+ for (let i = 0; i < env.length; i++) pre[i + 1] = pre[i] + env[i];
177
+ let sum = 0;
178
+ for (let i = 0; i < env.length; i++) {
179
+ const a = Math.max(0, i - half);
180
+ const b = Math.min(env.length, i + half + 1);
181
+ out[i] = Math.max(0, env[i] - (pre[b] - pre[a]) / (b - a));
182
+ sum += out[i];
183
+ }
184
+ const mean = sum / env.length || 1;
185
+ for (let i = 0; i < out.length; i++) out[i] /= mean;
186
+ return out;
187
+ }
188
+
189
+ const at = (env, x) => {
190
+ const i = Math.floor(x);
191
+ if (i < 0 || i + 1 >= env.length) return 0;
192
+ return env[i] + (env[i + 1] - env[i]) * (x - i);
193
+ };
194
+
195
+ /** Tempo, beat phase and downbeat phase from the onset envelopes. */
196
+ function beatGrid({ full, low, frames }) {
197
+ const fps = ASR / HOP;
198
+ // Coarse: autocorrelation with a log-normal tempo preference around 120 bpm.
199
+ let best = { score: -Infinity, lag: 0 };
200
+ const minLag = Math.floor((60 / 200) * fps);
201
+ const maxLag = Math.ceil((60 / 60) * fps);
202
+ // Smooth for the coarse search so a fractional-frame period still correlates.
203
+ const soft = full.map(
204
+ (_, i) =>
205
+ [-2, -1, 0, 1, 2].reduce((s, d, k) => s + (full[i + d] ?? 0) * [1, 2, 3, 2, 1][k], 0) / 9,
206
+ );
207
+ const ac = (lag) => {
208
+ let s = 0;
209
+ for (let i = 0; i + lag < frames; i++) s += soft[i] * soft[i + lag];
210
+ return s / (frames - lag);
211
+ };
212
+ for (let lag = minLag; lag <= maxLag; lag++) {
213
+ const s = ac(lag);
214
+ const bpm = (60 * fps) / lag;
215
+ const score = s * Math.exp(-0.5 * (Math.log2(bpm / 120) / 1) ** 2);
216
+ if (score > best.score) best = { score, lag };
217
+ }
218
+ // Between a tempo and its double, the prior alone cannot tell; when beats at
219
+ // half the lag correlate nearly as well, every half-beat is a beat.
220
+ const near = (lag) => Math.max(ac(lag - 1), ac(lag), ac(lag + 1));
221
+ const half = Math.round(best.lag / 2);
222
+ if (half >= minLag && near(half) >= 0.8 * near(best.lag)) best = { score: 0, lag: best.lag / 2 };
223
+ const coarse = (60 * fps) / best.lag;
224
+ // Fine: the period and phase whose comb collects the most onset strength.
225
+ let fine = { score: -Infinity, bpm: coarse, phase: 0 };
226
+ for (let bpm = coarse * 0.98; bpm <= coarse * 1.02; bpm += 0.01) {
227
+ const period = (60 * fps) / bpm;
228
+ for (let phase = 0; phase < period; phase += 0.25) {
229
+ let s = 0;
230
+ let k = 0;
231
+ for (let x = phase; x < frames - 1; x += period, k++) s += at(full, x);
232
+ s /= k || 1;
233
+ if (s > fine.score) fine = { score: s, bpm, phase };
234
+ }
235
+ }
236
+ const beatSec = 60 / fine.bpm;
237
+ // Log flux rises as soon as an onset enters frame f's window; calibrated on
238
+ // click tracks, frame f marks the onset three quarters into its window.
239
+ const offset = (fine.phase * HOP + LAG) / ASR;
240
+ const first = offset - Math.floor(offset / beatSec) * beatSec;
241
+ const beats = [];
242
+ for (let t = first; t < frames / fps; t += beatSec) beats.push(t);
243
+ const strength = [0, 0, 0, 0];
244
+ beats.forEach((t, i) => {
245
+ const x = (t * ASR - LAG) / HOP;
246
+ strength[i % 4] += at(full, x) + 2 * at(low, x);
247
+ });
248
+ const down = strength.indexOf(Math.max(...strength));
249
+ return { bpm: fine.bpm, beatSec, firstBeat: first, firstDownbeat: first + down * beatSec };
250
+ }
251
+
252
+ /**
253
+ * Plan the fitted track: a list of { src, film, len } segments (seconds),
254
+ * every boundary on a downbeat of both source and film.
255
+ */
256
+ function plan({ duration, trackDur, bar, d0, land }) {
257
+ const downs = [];
258
+ for (let t = d0; t <= trackDur + 1e-9; t += bar) downs.push(t);
259
+ if (downs.length < 2) throw new FitError("track is too short to hold one whole bar");
260
+ let j = 0;
261
+ if (land) {
262
+ let bestD = Infinity;
263
+ downs.forEach((d, i) => {
264
+ if (i < downs.length - 1 && Math.abs(d - land.track) < bestD)
265
+ [bestD, j] = [Math.abs(d - land.track), i];
266
+ });
267
+ }
268
+ const L = land ? land.film : Math.min(downs[0], duration);
269
+ const remaining = duration - L;
270
+ const M = remaining < MIN_TAIL ? 0 : Math.max(0, Math.floor((remaining - MIN_TAIL) / bar));
271
+ const tail = remaining - M * bar;
272
+ // Ending downbeat e: one the tail can ring from inside the track, a whole number
273
+ // of phrases away from the plain continuation when possible.
274
+ const fits = downs.map((_, i) => i).filter((i) => i > 0 && downs[i] + tail <= trackDur + 1e-9);
275
+ const late = (fits.length ? fits : [downs.length - 1]).slice(-4).reverse();
276
+ const e = M === 0 ? j : (late.find((i) => (((i - j - M) % 4) + 4) % 4 === 0) ?? late[0]);
277
+ /** @type {number[]} source bar index per film bar after the land */
278
+ const after = [];
279
+ let p = j;
280
+ const outro = Math.min(M, 8);
281
+ for (let t = 0; t < M; t++) {
282
+ const r = M - t;
283
+ if (t > 0 && p + r !== e) {
284
+ if (p + r < e && r <= outro)
285
+ p = e - r; // skip ahead into the ending
286
+ else if (p + r > e && p >= e) p = e - r >= 0 ? e - r : p % 4; // loop back
287
+ }
288
+ after.push(p++);
289
+ }
290
+ const segs = [];
291
+ const push = (src, film, len) => {
292
+ const last = segs.at(-1);
293
+ if (
294
+ last &&
295
+ Math.abs(last.src + last.len - src) < 1e-9 &&
296
+ Math.abs(last.film + last.len - film) < 1e-9
297
+ )
298
+ last.len += len;
299
+ else segs.push({ src, film, len });
300
+ };
301
+ // Before the land: play into it, contiguous when the intro is long enough.
302
+ if (L > 0) {
303
+ if (downs[j] - L >= 0) push(downs[j] - L, 0, L);
304
+ else {
305
+ const K = Math.floor(L / bar);
306
+ const x = L - K * bar;
307
+ const pre = [];
308
+ for (let i = 1; i <= K; i++) {
309
+ let q = j - i;
310
+ while (q < 0) q += 4;
311
+ if (q >= downs.length - 1) q = Math.max(0, downs.length - 2);
312
+ pre.unshift(q);
313
+ }
314
+ if (x > 1e-9) {
315
+ let q = pre[0] ?? j;
316
+ while (downs[q] - x < 0 && q + 4 < downs.length - 1) q += 4;
317
+ if (downs[q] - x < 0) q = 1;
318
+ push(Math.max(0, downs[q] - x), 0, x);
319
+ }
320
+ pre.forEach((q, i) => push(downs[q], x + i * bar, bar));
321
+ }
322
+ }
323
+ after.forEach((q, i) => push(downs[q], L + i * bar, bar));
324
+ push(downs[e], L + M * bar, tail);
325
+ const filmDowns = [];
326
+ for (let k = -Math.floor(L / bar); L + k * bar <= duration - MIN_TAIL + 1e-9; k++)
327
+ filmDowns.push(L + k * bar);
328
+ return { segs, landIndex: j, filmDowns, landDown: downs[j] };
329
+ }
330
+
331
+ /** Render the segments with equal-power crossfades at each cut and a fade at the end. */
332
+ function renderFit(audio, segs, duration) {
333
+ const n = Math.round(duration * SR);
334
+ const l = new Float32Array(n);
335
+ const r = new Float32Array(n);
336
+ const h = XFADE / 2;
337
+ segs.forEach((s, idx) => {
338
+ const first = idx === 0;
339
+ const last = idx === segs.length - 1;
340
+ const from = first ? s.film : s.film - h;
341
+ const to = last ? s.film + s.len : s.film + s.len + h;
342
+ const i0 = Math.max(0, Math.ceil(from * SR - 1e-6));
343
+ const i1 = Math.min(n, Math.ceil(to * SR - 1e-6));
344
+ for (let i = i0; i < i1; i++) {
345
+ const tf = i / SR;
346
+ let g = 1;
347
+ if (!first && tf < s.film + h) g *= Math.sin(((tf - (s.film - h)) / XFADE) * (Math.PI / 2));
348
+ if (!last && tf > s.film + s.len - h)
349
+ g *= Math.cos(((tf - (s.film + s.len - h)) / XFADE) * (Math.PI / 2));
350
+ if (last) {
351
+ const fade = Math.min(END_FADE, s.len);
352
+ const left = duration - tf;
353
+ if (left < fade) g *= Math.sin((Math.max(0, left) / fade) * (Math.PI / 2));
354
+ }
355
+ const x = (s.src + (tf - s.film)) * SR;
356
+ const k = Math.floor(x);
357
+ if (k < 0 || k + 1 >= audio.n) continue;
358
+ const fr = x - k;
359
+ l[i] += (audio.l[k] + (audio.l[k + 1] - audio.l[k]) * fr) * g;
360
+ r[i] += (audio.r[k] + (audio.r[k + 1] - audio.r[k]) * fr) * g;
361
+ }
362
+ });
363
+ const out = Buffer.alloc(44 + n * 4);
364
+ out.write("RIFF", 0);
365
+ out.writeUInt32LE(36 + n * 4, 4);
366
+ out.write("WAVE", 8);
367
+ out.write("fmt ", 12);
368
+ out.writeUInt32LE(16, 16);
369
+ out.writeUInt16LE(1, 20);
370
+ out.writeUInt16LE(2, 22);
371
+ out.writeUInt32LE(SR, 24);
372
+ out.writeUInt32LE(SR * 4, 28);
373
+ out.writeUInt16LE(4, 32);
374
+ out.writeUInt16LE(16, 34);
375
+ out.write("data", 36);
376
+ out.writeUInt32LE(n * 4, 40);
377
+ const q = (v) => Math.round(Math.max(-1, Math.min(1, v)) * 32767);
378
+ for (let i = 0; i < n; i++) {
379
+ out.writeInt16LE(q(l[i]), 44 + i * 4);
380
+ out.writeInt16LE(q(r[i]), 46 + i * 4);
381
+ }
382
+ return out;
383
+ }
384
+
385
+ const r4 = (v) => Math.round(v * 10000) / 10000;
386
+
387
+ async function main() {
388
+ const opts = parseArgs(process.argv.slice(2));
389
+ const audio = await decode(resolve(opts.track));
390
+ const trackDur = audio.n / SR;
391
+ const grid = beatGrid(onsetEnvelopes(audio));
392
+ const bar = grid.beatSec * 4;
393
+ const d0 = grid.firstDownbeat - Math.floor(grid.firstDownbeat / bar) * bar;
394
+ if (opts.land && !(opts.land.track >= 0 && opts.land.track < trackDur))
395
+ throw new FitError(`--land track time must be inside the track (0-${trackDur.toFixed(2)} s)`);
396
+ const fit = plan({ duration: opts.duration, trackDur, bar, d0, land: opts.land });
397
+ const outDir = resolve(opts.out);
398
+ await mkdir(outDir, { recursive: true });
399
+ await writeFile(join(outDir, "music.wav"), renderFit(audio, fit.segs, opts.duration));
400
+ const report = {
401
+ source: resolve(opts.track),
402
+ duration: opts.duration,
403
+ sourceDuration: r4(trackDur),
404
+ bpm: Math.round(grid.bpm * 100) / 100,
405
+ beatSec: r4(grid.beatSec),
406
+ barSec: r4(bar),
407
+ sourceFirstBeat: r4(grid.firstBeat),
408
+ sourceFirstDownbeat: r4(d0),
409
+ ...(opts.land
410
+ ? {
411
+ land: {
412
+ requested: opts.land.track,
413
+ sourceDownbeat: r4(fit.landDown),
414
+ film: opts.land.film,
415
+ },
416
+ }
417
+ : {}),
418
+ downbeats: fit.filmDowns.map(r4),
419
+ edits: fit.segs.map((s) => ({
420
+ source: [r4(s.src), r4(s.src + s.len)],
421
+ film: [r4(s.film), r4(s.film + s.len)],
422
+ })),
423
+ crossfade: XFADE,
424
+ };
425
+ await writeFile(join(outDir, "music-fit.json"), `${JSON.stringify(report, null, 2)}\n`);
426
+ process.stdout.write(
427
+ `${JSON.stringify({ ok: true, outDir, files: ["music.wav", "music-fit.json"], bpm: report.bpm, duration: opts.duration, edits: report.edits.length, cuts: report.edits.length - 1 })}\n`,
428
+ );
429
+ }
430
+
431
+ main().catch((error) => {
432
+ process.stdout.write(
433
+ `${JSON.stringify({ ok: false, error: error instanceof Error ? error.message : String(error) })}\n`,
434
+ );
435
+ process.exit(1);
436
+ });
@@ -30,7 +30,10 @@ function encodePng(width, height, channels, pixels) {
30
30
  const raw = Buffer.alloc((stride + 1) * height);
31
31
  for (let y = 0; y < height; y++) {
32
32
  raw[y * (stride + 1)] = 0;
33
- Buffer.from(pixels.buffer, pixels.byteOffset + y * stride, stride).copy(raw, y * (stride + 1) + 1);
33
+ Buffer.from(pixels.buffer, pixels.byteOffset + y * stride, stride).copy(
34
+ raw,
35
+ y * (stride + 1) + 1,
36
+ );
34
37
  }
35
38
  const crcTable = new Int32Array(256).map((_, n) => {
36
39
  let c = n;
@@ -76,9 +79,10 @@ try {
76
79
  ({ totalPages, text } = await unpdf.extractText(pdf, { mergePages: false }));
77
80
  } catch (error) {
78
81
  // pdf.js errors carry the whole minified bundle in their stack; keep only the message.
79
- const message = error instanceof Error || (error && typeof error.message === "string")
80
- ? error.message
81
- : String(error);
82
+ const message =
83
+ error instanceof Error || (error && typeof error.message === "string")
84
+ ? error.message
85
+ : String(error);
82
86
  process.stderr.write(`Could not read PDF ${input}: ${message}\n`);
83
87
  process.exit(1);
84
88
  }
@@ -93,7 +97,12 @@ try {
93
97
  const pages = Array.isArray(text) ? text : [String(text)];
94
98
  const md = [`# ${basename(input)}`, ""];
95
99
  pages.forEach((pageText, i) => {
96
- md.push(`## Page ${i + 1}`, "", pageText.trim() || "_(no extractable text — likely scanned or image-only)_", "");
100
+ md.push(
101
+ `## Page ${i + 1}`,
102
+ "",
103
+ pageText.trim() || "_(no extractable text — likely scanned or image-only)_",
104
+ "",
105
+ );
97
106
  });
98
107
  await writeFile(join(outDir, "text.md"), md.join("\n"));
99
108
 
@@ -113,14 +122,15 @@ for (let page = 1; page <= totalPages; page++) {
113
122
  if (![1, 3, 4].includes(channels)) continue;
114
123
  n += 1;
115
124
  const file = `p${page}-${n}.png`;
116
- await writeFile(join(outDir, "images", file), encodePng(img.width, img.height, channels, img.data));
125
+ await writeFile(
126
+ join(outDir, "images", file),
127
+ encodePng(img.width, img.height, channels, img.data),
128
+ );
117
129
  images.push({ page, file: `images/${file}`, width: img.width, height: img.height });
118
130
  }
119
131
  }
120
132
 
121
- const emptyPages = pages
122
- .map((t, i) => (t.trim() ? null : i + 1))
123
- .filter((p) => p !== null);
133
+ const emptyPages = pages.map((t, i) => (t.trim() ? null : i + 1)).filter((p) => p !== null);
124
134
  const meta = {
125
135
  source: input,
126
136
  pages: totalPages,
@@ -130,4 +140,6 @@ const meta = {
130
140
  images,
131
141
  };
132
142
  await writeFile(join(outDir, "meta.json"), `${JSON.stringify(meta, null, 2)}\n`);
133
- process.stdout.write(`${JSON.stringify({ ok: true, pages: totalPages, images: images.length, pagesWithoutText: emptyPages.length, outDir })}\n`);
143
+ process.stdout.write(
144
+ `${JSON.stringify({ ok: true, pages: totalPages, images: images.length, pagesWithoutText: emptyPages.length, outDir })}\n`,
145
+ );