@kenkaiiii/gg-editor 0.7.0 → 0.7.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 (446) hide show
  1. package/dist/cli.js +64 -1
  2. package/dist/cli.js.map +1 -1
  3. package/dist/core/audio-mix.d.ts.map +1 -1
  4. package/dist/core/audio-mix.js +8 -1
  5. package/dist/core/audio-mix.js.map +1 -1
  6. package/dist/core/audio-mix.test.js +1 -1
  7. package/dist/core/audio-mix.test.js.map +1 -1
  8. package/dist/core/auth/api-keys.d.ts +1 -1
  9. package/dist/core/auth/api-keys.d.ts.map +1 -1
  10. package/dist/core/auth/api-keys.js +2 -1
  11. package/dist/core/auth/api-keys.js.map +1 -1
  12. package/dist/core/auth/login.d.ts.map +1 -1
  13. package/dist/core/auth/login.js.map +1 -1
  14. package/dist/core/beats.d.ts +59 -0
  15. package/dist/core/beats.d.ts.map +1 -0
  16. package/dist/core/beats.js +122 -0
  17. package/dist/core/beats.js.map +1 -0
  18. package/dist/core/beats.test.d.ts +2 -0
  19. package/dist/core/beats.test.d.ts.map +1 -0
  20. package/dist/core/beats.test.js +86 -0
  21. package/dist/core/beats.test.js.map +1 -0
  22. package/dist/core/brand-kit.d.ts +80 -0
  23. package/dist/core/brand-kit.d.ts.map +1 -0
  24. package/dist/core/brand-kit.js +96 -0
  25. package/dist/core/brand-kit.js.map +1 -0
  26. package/dist/core/brand-kit.test.d.ts +2 -0
  27. package/dist/core/brand-kit.test.d.ts.map +1 -0
  28. package/dist/core/brand-kit.test.js +76 -0
  29. package/dist/core/brand-kit.test.js.map +1 -0
  30. package/dist/core/bundled-sfx.d.ts +64 -0
  31. package/dist/core/bundled-sfx.d.ts.map +1 -0
  32. package/dist/core/bundled-sfx.js +218 -0
  33. package/dist/core/bundled-sfx.js.map +1 -0
  34. package/dist/core/bundled-sfx.test.d.ts +2 -0
  35. package/dist/core/bundled-sfx.test.d.ts.map +1 -0
  36. package/dist/core/bundled-sfx.test.js +81 -0
  37. package/dist/core/bundled-sfx.test.js.map +1 -0
  38. package/dist/core/child-abort.d.ts +57 -0
  39. package/dist/core/child-abort.d.ts.map +1 -0
  40. package/dist/core/child-abort.js +95 -0
  41. package/dist/core/child-abort.js.map +1 -0
  42. package/dist/core/child-abort.test.d.ts +2 -0
  43. package/dist/core/child-abort.test.d.ts.map +1 -0
  44. package/dist/core/child-abort.test.js +88 -0
  45. package/dist/core/child-abort.test.js.map +1 -0
  46. package/dist/core/clip-scoring.d.ts +44 -0
  47. package/dist/core/clip-scoring.d.ts.map +1 -0
  48. package/dist/core/clip-scoring.js +165 -0
  49. package/dist/core/clip-scoring.js.map +1 -0
  50. package/dist/core/clip-scoring.test.d.ts +2 -0
  51. package/dist/core/clip-scoring.test.d.ts.map +1 -0
  52. package/dist/core/clip-scoring.test.js +113 -0
  53. package/dist/core/clip-scoring.test.js.map +1 -0
  54. package/dist/core/emoji-captions.d.ts +45 -0
  55. package/dist/core/emoji-captions.d.ts.map +1 -0
  56. package/dist/core/emoji-captions.js +121 -0
  57. package/dist/core/emoji-captions.js.map +1 -0
  58. package/dist/core/face-reframe.d.ts +91 -0
  59. package/dist/core/face-reframe.d.ts.map +1 -0
  60. package/dist/core/face-reframe.js +141 -0
  61. package/dist/core/face-reframe.js.map +1 -0
  62. package/dist/core/face-reframe.test.d.ts +2 -0
  63. package/dist/core/face-reframe.test.d.ts.map +1 -0
  64. package/dist/core/face-reframe.test.js +171 -0
  65. package/dist/core/face-reframe.test.js.map +1 -0
  66. package/dist/core/filler-words.d.ts +57 -9
  67. package/dist/core/filler-words.d.ts.map +1 -1
  68. package/dist/core/filler-words.js +61 -9
  69. package/dist/core/filler-words.js.map +1 -1
  70. package/dist/core/filler-words.test.js +91 -17
  71. package/dist/core/filler-words.test.js.map +1 -1
  72. package/dist/core/hook-rewrite.d.ts +48 -0
  73. package/dist/core/hook-rewrite.d.ts.map +1 -0
  74. package/dist/core/hook-rewrite.js +151 -0
  75. package/dist/core/hook-rewrite.js.map +1 -0
  76. package/dist/core/hook-rewrite.test.d.ts +2 -0
  77. package/dist/core/hook-rewrite.test.d.ts.map +1 -0
  78. package/dist/core/hook-rewrite.test.js +58 -0
  79. package/dist/core/hook-rewrite.test.js.map +1 -0
  80. package/dist/core/hosts/lazy.d.ts.map +1 -1
  81. package/dist/core/hosts/lazy.js +2 -0
  82. package/dist/core/hosts/lazy.js.map +1 -1
  83. package/dist/core/hosts/premiere/adapter.d.ts +1 -0
  84. package/dist/core/hosts/premiere/adapter.d.ts.map +1 -1
  85. package/dist/core/hosts/premiere/adapter.js.map +1 -1
  86. package/dist/core/hosts/premiere/bridge-source.d.ts.map +1 -1
  87. package/dist/core/hosts/premiere/bridge-source.js +6 -3
  88. package/dist/core/hosts/premiere/bridge-source.js.map +1 -1
  89. package/dist/core/hosts/resolve/adapter.d.ts +1 -0
  90. package/dist/core/hosts/resolve/adapter.d.ts.map +1 -1
  91. package/dist/core/hosts/resolve/adapter.js.map +1 -1
  92. package/dist/core/hosts/resolve/bridge-source.d.ts.map +1 -1
  93. package/dist/core/hosts/resolve/bridge-source.js +31 -4
  94. package/dist/core/hosts/resolve/bridge-source.js.map +1 -1
  95. package/dist/core/hosts/resolve/bridge.d.ts +2 -19
  96. package/dist/core/hosts/resolve/bridge.d.ts.map +1 -1
  97. package/dist/core/hosts/resolve/bridge.js +70 -41
  98. package/dist/core/hosts/resolve/bridge.js.map +1 -1
  99. package/dist/core/hosts/resolve/bridge.test.js +130 -0
  100. package/dist/core/hosts/resolve/bridge.test.js.map +1 -1
  101. package/dist/core/hosts/types.d.ts +6 -0
  102. package/dist/core/hosts/types.d.ts.map +1 -1
  103. package/dist/core/hosts/types.js.map +1 -1
  104. package/dist/core/logger.d.ts +32 -0
  105. package/dist/core/logger.d.ts.map +1 -0
  106. package/dist/core/logger.js +188 -0
  107. package/dist/core/logger.js.map +1 -0
  108. package/dist/core/loop-match.d.ts +57 -0
  109. package/dist/core/loop-match.d.ts.map +1 -0
  110. package/dist/core/loop-match.js +91 -0
  111. package/dist/core/loop-match.js.map +1 -0
  112. package/dist/core/media/ffmpeg.d.ts.map +1 -1
  113. package/dist/core/media/ffmpeg.js +14 -3
  114. package/dist/core/media/ffmpeg.js.map +1 -1
  115. package/dist/core/multi-format.d.ts +67 -0
  116. package/dist/core/multi-format.d.ts.map +1 -0
  117. package/dist/core/multi-format.js +127 -0
  118. package/dist/core/multi-format.js.map +1 -0
  119. package/dist/core/multi-format.test.d.ts +2 -0
  120. package/dist/core/multi-format.test.d.ts.map +1 -0
  121. package/dist/core/multi-format.test.js +151 -0
  122. package/dist/core/multi-format.test.js.map +1 -0
  123. package/dist/core/python/beats.py +61 -0
  124. package/dist/core/python/face_reframe.py +163 -0
  125. package/dist/core/python/sidecar-path.d.ts +13 -0
  126. package/dist/core/python/sidecar-path.d.ts.map +1 -0
  127. package/dist/core/python/sidecar-path.js +24 -0
  128. package/dist/core/python/sidecar-path.js.map +1 -0
  129. package/dist/core/python.d.ts +57 -0
  130. package/dist/core/python.d.ts.map +1 -0
  131. package/dist/core/python.js +107 -0
  132. package/dist/core/python.js.map +1 -0
  133. package/dist/core/python.test.d.ts +2 -0
  134. package/dist/core/python.test.d.ts.map +1 -0
  135. package/dist/core/python.test.js +129 -0
  136. package/dist/core/python.test.js.map +1 -0
  137. package/dist/core/retention-structure.d.ts +81 -0
  138. package/dist/core/retention-structure.d.ts.map +1 -0
  139. package/dist/core/retention-structure.js +206 -0
  140. package/dist/core/retention-structure.js.map +1 -0
  141. package/dist/core/retention-structure.test.d.ts +2 -0
  142. package/dist/core/retention-structure.test.d.ts.map +1 -0
  143. package/dist/core/retention-structure.test.js +88 -0
  144. package/dist/core/retention-structure.test.js.map +1 -0
  145. package/dist/core/review.d.ts +17 -0
  146. package/dist/core/review.d.ts.map +1 -1
  147. package/dist/core/review.js +20 -24
  148. package/dist/core/review.js.map +1 -1
  149. package/dist/core/safe-paths.d.ts +11 -0
  150. package/dist/core/safe-paths.d.ts.map +1 -1
  151. package/dist/core/safe-paths.js +26 -10
  152. package/dist/core/safe-paths.js.map +1 -1
  153. package/dist/core/safe-paths.test.js +16 -0
  154. package/dist/core/safe-paths.test.js.map +1 -1
  155. package/dist/core/skills-loader.d.ts +48 -2
  156. package/dist/core/skills-loader.d.ts.map +1 -1
  157. package/dist/core/skills-loader.js +97 -19
  158. package/dist/core/skills-loader.js.map +1 -1
  159. package/dist/core/skills-loader.test.js +63 -1
  160. package/dist/core/skills-loader.test.js.map +1 -1
  161. package/dist/core/srt.d.ts +42 -7
  162. package/dist/core/srt.d.ts.map +1 -1
  163. package/dist/core/srt.js +101 -32
  164. package/dist/core/srt.js.map +1 -1
  165. package/dist/core/srt.test.js +54 -1
  166. package/dist/core/srt.test.js.map +1 -1
  167. package/dist/core/thumbnail-compose.d.ts +58 -0
  168. package/dist/core/thumbnail-compose.d.ts.map +1 -0
  169. package/dist/core/thumbnail-compose.js +101 -0
  170. package/dist/core/thumbnail-compose.js.map +1 -0
  171. package/dist/core/thumbnail-promise.d.ts +46 -0
  172. package/dist/core/thumbnail-promise.d.ts.map +1 -0
  173. package/dist/core/thumbnail-promise.js +133 -0
  174. package/dist/core/thumbnail-promise.js.map +1 -0
  175. package/dist/core/thumbnail-promise.test.d.ts +2 -0
  176. package/dist/core/thumbnail-promise.test.d.ts.map +1 -0
  177. package/dist/core/thumbnail-promise.test.js +52 -0
  178. package/dist/core/thumbnail-promise.test.js.map +1 -0
  179. package/dist/core/viral-moments.d.ts +70 -0
  180. package/dist/core/viral-moments.d.ts.map +1 -0
  181. package/dist/core/viral-moments.js +192 -0
  182. package/dist/core/viral-moments.js.map +1 -0
  183. package/dist/core/viral-moments.test.d.ts +2 -0
  184. package/dist/core/viral-moments.test.d.ts.map +1 -0
  185. package/dist/core/viral-moments.test.js +153 -0
  186. package/dist/core/viral-moments.test.js.map +1 -0
  187. package/dist/core/whisper.d.ts +16 -0
  188. package/dist/core/whisper.d.ts.map +1 -1
  189. package/dist/core/whisper.js +72 -5
  190. package/dist/core/whisper.js.map +1 -1
  191. package/dist/core/whisper.test.js +111 -1
  192. package/dist/core/whisper.test.js.map +1 -1
  193. package/dist/core/youtube-metadata.d.ts +44 -0
  194. package/dist/core/youtube-metadata.d.ts.map +1 -0
  195. package/dist/core/youtube-metadata.js +168 -0
  196. package/dist/core/youtube-metadata.js.map +1 -0
  197. package/dist/core/youtube-metadata.test.d.ts +2 -0
  198. package/dist/core/youtube-metadata.test.d.ts.map +1 -0
  199. package/dist/core/youtube-metadata.test.js +132 -0
  200. package/dist/core/youtube-metadata.test.js.map +1 -0
  201. package/dist/prompt-commands.d.ts +24 -0
  202. package/dist/prompt-commands.d.ts.map +1 -0
  203. package/dist/prompt-commands.js +243 -0
  204. package/dist/prompt-commands.js.map +1 -0
  205. package/dist/prompt-commands.test.d.ts +2 -0
  206. package/dist/prompt-commands.test.d.ts.map +1 -0
  207. package/dist/prompt-commands.test.js +46 -0
  208. package/dist/prompt-commands.test.js.map +1 -0
  209. package/dist/skills.d.ts +6 -6
  210. package/dist/skills.d.ts.map +1 -1
  211. package/dist/skills.js +1426 -445
  212. package/dist/skills.js.map +1 -1
  213. package/dist/system-prompt.d.ts.map +1 -1
  214. package/dist/system-prompt.js +108 -0
  215. package/dist/system-prompt.js.map +1 -1
  216. package/dist/tools/add-fades.d.ts.map +1 -1
  217. package/dist/tools/add-fades.js +2 -1
  218. package/dist/tools/add-fades.js.map +1 -1
  219. package/dist/tools/add-sfx-at-cuts.d.ts.map +1 -1
  220. package/dist/tools/add-sfx-at-cuts.js +36 -11
  221. package/dist/tools/add-sfx-at-cuts.js.map +1 -1
  222. package/dist/tools/add-sfx-to-timeline.d.ts +34 -0
  223. package/dist/tools/add-sfx-to-timeline.d.ts.map +1 -0
  224. package/dist/tools/add-sfx-to-timeline.js +169 -0
  225. package/dist/tools/add-sfx-to-timeline.js.map +1 -0
  226. package/dist/tools/add-sfx-to-timeline.test.d.ts +2 -0
  227. package/dist/tools/add-sfx-to-timeline.test.d.ts.map +1 -0
  228. package/dist/tools/add-sfx-to-timeline.test.js +181 -0
  229. package/dist/tools/add-sfx-to-timeline.test.js.map +1 -0
  230. package/dist/tools/audit-first-frame.d.ts +36 -0
  231. package/dist/tools/audit-first-frame.d.ts.map +1 -0
  232. package/dist/tools/audit-first-frame.js +181 -0
  233. package/dist/tools/audit-first-frame.js.map +1 -0
  234. package/dist/tools/audit-retention-structure.d.ts +20 -0
  235. package/dist/tools/audit-retention-structure.d.ts.map +1 -0
  236. package/dist/tools/audit-retention-structure.js +95 -0
  237. package/dist/tools/audit-retention-structure.js.map +1 -0
  238. package/dist/tools/audit-retention-structure.test.d.ts +2 -0
  239. package/dist/tools/audit-retention-structure.test.d.ts.map +1 -0
  240. package/dist/tools/audit-retention-structure.test.js +93 -0
  241. package/dist/tools/audit-retention-structure.test.js.map +1 -0
  242. package/dist/tools/bleep-words.d.ts +59 -0
  243. package/dist/tools/bleep-words.d.ts.map +1 -0
  244. package/dist/tools/bleep-words.js +211 -0
  245. package/dist/tools/bleep-words.js.map +1 -0
  246. package/dist/tools/bleep-words.test.d.ts +2 -0
  247. package/dist/tools/bleep-words.test.d.ts.map +1 -0
  248. package/dist/tools/bleep-words.test.js +96 -0
  249. package/dist/tools/bleep-words.test.js.map +1 -0
  250. package/dist/tools/burn-subtitles.d.ts.map +1 -1
  251. package/dist/tools/burn-subtitles.js +10 -5
  252. package/dist/tools/burn-subtitles.js.map +1 -1
  253. package/dist/tools/clean-audio.d.ts.map +1 -1
  254. package/dist/tools/clean-audio.js +2 -1
  255. package/dist/tools/clean-audio.js.map +1 -1
  256. package/dist/tools/cluster-takes.js +2 -1
  257. package/dist/tools/cluster-takes.js.map +1 -1
  258. package/dist/tools/compose-thumbnail-variants.d.ts +70 -0
  259. package/dist/tools/compose-thumbnail-variants.d.ts.map +1 -0
  260. package/dist/tools/compose-thumbnail-variants.js +274 -0
  261. package/dist/tools/compose-thumbnail-variants.js.map +1 -0
  262. package/dist/tools/compose-thumbnail.d.ts +6 -13
  263. package/dist/tools/compose-thumbnail.d.ts.map +1 -1
  264. package/dist/tools/compose-thumbnail.js +44 -81
  265. package/dist/tools/compose-thumbnail.js.map +1 -1
  266. package/dist/tools/concat-videos.d.ts.map +1 -1
  267. package/dist/tools/concat-videos.js +12 -5
  268. package/dist/tools/concat-videos.js.map +1 -1
  269. package/dist/tools/concat-videos.test.d.ts +2 -0
  270. package/dist/tools/concat-videos.test.d.ts.map +1 -0
  271. package/dist/tools/concat-videos.test.js +103 -0
  272. package/dist/tools/concat-videos.test.js.map +1 -0
  273. package/dist/tools/crossfade-videos.d.ts.map +1 -1
  274. package/dist/tools/crossfade-videos.js +2 -1
  275. package/dist/tools/crossfade-videos.js.map +1 -1
  276. package/dist/tools/cut-filler-words.d.ts.map +1 -1
  277. package/dist/tools/cut-filler-words.js +24 -8
  278. package/dist/tools/cut-filler-words.js.map +1 -1
  279. package/dist/tools/detect-speaker-changes.js +2 -1
  280. package/dist/tools/detect-speaker-changes.js.map +1 -1
  281. package/dist/tools/extract-audio.d.ts.map +1 -1
  282. package/dist/tools/extract-audio.js +13 -7
  283. package/dist/tools/extract-audio.js.map +1 -1
  284. package/dist/tools/face-reframe.d.ts +30 -0
  285. package/dist/tools/face-reframe.d.ts.map +1 -0
  286. package/dist/tools/face-reframe.js +143 -0
  287. package/dist/tools/face-reframe.js.map +1 -0
  288. package/dist/tools/face-reframe.test.d.ts +2 -0
  289. package/dist/tools/face-reframe.test.d.ts.map +1 -0
  290. package/dist/tools/face-reframe.test.js +139 -0
  291. package/dist/tools/face-reframe.test.js.map +1 -0
  292. package/dist/tools/find-viral-moments.d.ts +23 -0
  293. package/dist/tools/find-viral-moments.d.ts.map +1 -0
  294. package/dist/tools/find-viral-moments.js +176 -0
  295. package/dist/tools/find-viral-moments.js.map +1 -0
  296. package/dist/tools/find-viral-moments.test.d.ts +2 -0
  297. package/dist/tools/find-viral-moments.test.d.ts.map +1 -0
  298. package/dist/tools/find-viral-moments.test.js +144 -0
  299. package/dist/tools/find-viral-moments.test.js.map +1 -0
  300. package/dist/tools/generate-gif.d.ts.map +1 -1
  301. package/dist/tools/generate-gif.js +47 -40
  302. package/dist/tools/generate-gif.js.map +1 -1
  303. package/dist/tools/generate-gif.test.d.ts +2 -0
  304. package/dist/tools/generate-gif.test.d.ts.map +1 -0
  305. package/dist/tools/generate-gif.test.js +115 -0
  306. package/dist/tools/generate-gif.test.js.map +1 -0
  307. package/dist/tools/generate-outro.d.ts +18 -0
  308. package/dist/tools/generate-outro.d.ts.map +1 -0
  309. package/dist/tools/generate-outro.js +175 -0
  310. package/dist/tools/generate-outro.js.map +1 -0
  311. package/dist/tools/generate-youtube-metadata.d.ts +23 -0
  312. package/dist/tools/generate-youtube-metadata.d.ts.map +1 -0
  313. package/dist/tools/generate-youtube-metadata.js +103 -0
  314. package/dist/tools/generate-youtube-metadata.js.map +1 -0
  315. package/dist/tools/generate-youtube-metadata.test.d.ts +2 -0
  316. package/dist/tools/generate-youtube-metadata.test.d.ts.map +1 -0
  317. package/dist/tools/generate-youtube-metadata.test.js +118 -0
  318. package/dist/tools/generate-youtube-metadata.test.js.map +1 -0
  319. package/dist/tools/index.d.ts +14 -0
  320. package/dist/tools/index.d.ts.map +1 -1
  321. package/dist/tools/index.js +130 -1
  322. package/dist/tools/index.js.map +1 -1
  323. package/dist/tools/index.test.js +27 -1
  324. package/dist/tools/index.test.js.map +1 -1
  325. package/dist/tools/ken-burns.d.ts.map +1 -1
  326. package/dist/tools/ken-burns.js +2 -1
  327. package/dist/tools/ken-burns.js.map +1 -1
  328. package/dist/tools/loop-match-short.d.ts +22 -0
  329. package/dist/tools/loop-match-short.d.ts.map +1 -0
  330. package/dist/tools/loop-match-short.js +107 -0
  331. package/dist/tools/loop-match-short.js.map +1 -0
  332. package/dist/tools/mix-audio.d.ts.map +1 -1
  333. package/dist/tools/mix-audio.js +2 -1
  334. package/dist/tools/mix-audio.js.map +1 -1
  335. package/dist/tools/normalize-loudness.d.ts.map +1 -1
  336. package/dist/tools/normalize-loudness.js +2 -1
  337. package/dist/tools/normalize-loudness.js.map +1 -1
  338. package/dist/tools/path-traversal.test.d.ts +15 -0
  339. package/dist/tools/path-traversal.test.d.ts.map +1 -0
  340. package/dist/tools/path-traversal.test.js +223 -0
  341. package/dist/tools/path-traversal.test.js.map +1 -0
  342. package/dist/tools/pick-best-takes.js +2 -1
  343. package/dist/tools/pick-best-takes.js.map +1 -1
  344. package/dist/tools/punch-in.d.ts.map +1 -1
  345. package/dist/tools/punch-in.js +2 -1
  346. package/dist/tools/punch-in.js.map +1 -1
  347. package/dist/tools/read-transcript.js +2 -1
  348. package/dist/tools/read-transcript.js.map +1 -1
  349. package/dist/tools/render-multi-format.d.ts +35 -0
  350. package/dist/tools/render-multi-format.d.ts.map +1 -0
  351. package/dist/tools/render-multi-format.js +206 -0
  352. package/dist/tools/render-multi-format.js.map +1 -0
  353. package/dist/tools/render-multi-format.test.d.ts +2 -0
  354. package/dist/tools/render-multi-format.test.d.ts.map +1 -0
  355. package/dist/tools/render-multi-format.test.js +312 -0
  356. package/dist/tools/render-multi-format.test.js.map +1 -0
  357. package/dist/tools/render.d.ts.map +1 -1
  358. package/dist/tools/render.js +2 -2
  359. package/dist/tools/render.js.map +1 -1
  360. package/dist/tools/rewrite-hook.d.ts +32 -0
  361. package/dist/tools/rewrite-hook.d.ts.map +1 -0
  362. package/dist/tools/rewrite-hook.js +65 -0
  363. package/dist/tools/rewrite-hook.js.map +1 -0
  364. package/dist/tools/score-clip.d.ts +30 -0
  365. package/dist/tools/score-clip.d.ts.map +1 -0
  366. package/dist/tools/score-clip.js +109 -0
  367. package/dist/tools/score-clip.js.map +1 -0
  368. package/dist/tools/score-clip.test.d.ts +2 -0
  369. package/dist/tools/score-clip.test.d.ts.map +1 -0
  370. package/dist/tools/score-clip.test.js +110 -0
  371. package/dist/tools/score-clip.test.js.map +1 -0
  372. package/dist/tools/search-tools.d.ts +34 -0
  373. package/dist/tools/search-tools.d.ts.map +1 -0
  374. package/dist/tools/search-tools.js +86 -0
  375. package/dist/tools/search-tools.js.map +1 -0
  376. package/dist/tools/search-tools.test.d.ts +2 -0
  377. package/dist/tools/search-tools.test.d.ts.map +1 -0
  378. package/dist/tools/search-tools.test.js +60 -0
  379. package/dist/tools/search-tools.test.js.map +1 -0
  380. package/dist/tools/snap-cuts-to-beats.d.ts +18 -0
  381. package/dist/tools/snap-cuts-to-beats.d.ts.map +1 -0
  382. package/dist/tools/snap-cuts-to-beats.js +110 -0
  383. package/dist/tools/snap-cuts-to-beats.js.map +1 -0
  384. package/dist/tools/snap-cuts-to-beats.test.d.ts +2 -0
  385. package/dist/tools/snap-cuts-to-beats.test.d.ts.map +1 -0
  386. package/dist/tools/snap-cuts-to-beats.test.js +99 -0
  387. package/dist/tools/snap-cuts-to-beats.test.js.map +1 -0
  388. package/dist/tools/speed-ramp.d.ts.map +1 -1
  389. package/dist/tools/speed-ramp.js +2 -1
  390. package/dist/tools/speed-ramp.js.map +1 -1
  391. package/dist/tools/stabilize-video.d.ts.map +1 -1
  392. package/dist/tools/stabilize-video.js +2 -1
  393. package/dist/tools/stabilize-video.js.map +1 -1
  394. package/dist/tools/suggest-broll.d.ts +34 -0
  395. package/dist/tools/suggest-broll.d.ts.map +1 -0
  396. package/dist/tools/suggest-broll.js +367 -0
  397. package/dist/tools/suggest-broll.js.map +1 -0
  398. package/dist/tools/suggest-broll.test.d.ts +2 -0
  399. package/dist/tools/suggest-broll.test.d.ts.map +1 -0
  400. package/dist/tools/suggest-broll.test.js +217 -0
  401. package/dist/tools/suggest-broll.test.js.map +1 -0
  402. package/dist/tools/text-based-cut.d.ts +33 -0
  403. package/dist/tools/text-based-cut.d.ts.map +1 -0
  404. package/dist/tools/text-based-cut.js +172 -0
  405. package/dist/tools/text-based-cut.js.map +1 -0
  406. package/dist/tools/text-based-cut.test.d.ts +2 -0
  407. package/dist/tools/text-based-cut.test.d.ts.map +1 -0
  408. package/dist/tools/text-based-cut.test.js +32 -0
  409. package/dist/tools/text-based-cut.test.js.map +1 -0
  410. package/dist/tools/transcribe.d.ts +1 -1
  411. package/dist/tools/transition-videos.d.ts +1 -1
  412. package/dist/tools/transition-videos.d.ts.map +1 -1
  413. package/dist/tools/transition-videos.js +2 -1
  414. package/dist/tools/transition-videos.js.map +1 -1
  415. package/dist/tools/trim-dead-air.d.ts +59 -0
  416. package/dist/tools/trim-dead-air.d.ts.map +1 -0
  417. package/dist/tools/trim-dead-air.js +215 -0
  418. package/dist/tools/trim-dead-air.js.map +1 -0
  419. package/dist/tools/trim-dead-air.test.d.ts +2 -0
  420. package/dist/tools/trim-dead-air.test.d.ts.map +1 -0
  421. package/dist/tools/trim-dead-air.test.js +75 -0
  422. package/dist/tools/trim-dead-air.test.js.map +1 -0
  423. package/dist/tools/verify-thumbnail-promise.d.ts +33 -0
  424. package/dist/tools/verify-thumbnail-promise.d.ts.map +1 -0
  425. package/dist/tools/verify-thumbnail-promise.js +112 -0
  426. package/dist/tools/verify-thumbnail-promise.js.map +1 -0
  427. package/dist/tools/verify-thumbnail-promise.test.d.ts +2 -0
  428. package/dist/tools/verify-thumbnail-promise.test.d.ts.map +1 -0
  429. package/dist/tools/verify-thumbnail-promise.test.js +38 -0
  430. package/dist/tools/verify-thumbnail-promise.test.js.map +1 -0
  431. package/dist/tools/write-keyword-captions.d.ts +7 -0
  432. package/dist/tools/write-keyword-captions.d.ts.map +1 -1
  433. package/dist/tools/write-keyword-captions.js +35 -4
  434. package/dist/tools/write-keyword-captions.js.map +1 -1
  435. package/dist/ui/App.d.ts.map +1 -1
  436. package/dist/ui/App.js +75 -11
  437. package/dist/ui/App.js.map +1 -1
  438. package/dist/ui/tool-formatters.d.ts +30 -0
  439. package/dist/ui/tool-formatters.d.ts.map +1 -0
  440. package/dist/ui/tool-formatters.js +461 -0
  441. package/dist/ui/tool-formatters.js.map +1 -0
  442. package/dist/ui/tool-formatters.test.d.ts +2 -0
  443. package/dist/ui/tool-formatters.test.d.ts.map +1 -0
  444. package/dist/ui/tool-formatters.test.js +143 -0
  445. package/dist/ui/tool-formatters.test.js.map +1 -0
  446. package/package.json +10 -9
@@ -0,0 +1,367 @@
1
+ import { mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join, resolve as resolvePath } from "node:path";
4
+ import { z } from "zod";
5
+ import { resolveApiKey } from "../core/auth/api-keys.js";
6
+ import { compact, err } from "../core/format.js";
7
+ import { safeOutputPath } from "../core/safe-paths.js";
8
+ import { parseTranscript } from "../core/whisper.js";
9
+ /**
10
+ * suggest_broll — extract visually-searchable concepts from a transcript
11
+ * window via ONE LLM call, then query Pexels' free stock-video library
12
+ * and (optionally) download the top match per concept. The output shape
13
+ * is shaped to feed `insert_broll` directly:
14
+ *
15
+ * for (const it of items) {
16
+ * await insert_broll({
17
+ * mediaPath: it.mediaPath,
18
+ * recordFrame: Math.round(it.atSec * fps),
19
+ * });
20
+ * }
21
+ */
22
+ const SuggestBrollParams = z.object({
23
+ transcript: z
24
+ .string()
25
+ .describe("Path to a transcript JSON written by `transcribe`. Word-level timings not required — " +
26
+ "segment-level start/end is enough to place each B-roll suggestion."),
27
+ startSec: z
28
+ .number()
29
+ .min(0)
30
+ .optional()
31
+ .describe("Window start (seconds). Default 0. The LLM only sees text inside [startSec, endSec)."),
32
+ endSec: z
33
+ .number()
34
+ .min(0)
35
+ .optional()
36
+ .describe("Window end (seconds). Default = transcript.durationSec."),
37
+ topN: z
38
+ .number()
39
+ .int()
40
+ .min(1)
41
+ .max(20)
42
+ .optional()
43
+ .describe("Maximum B-roll suggestions to return. Default 5. Hard cap 20 — more than that bloats " +
44
+ "downloads and Pexels' free tier."),
45
+ orientation: z
46
+ .enum(["landscape", "portrait", "square"])
47
+ .optional()
48
+ .describe("Pexels orientation filter. Default 'landscape'. Use 'portrait' for Shorts/Reels/TikTok."),
49
+ minDurationSec: z
50
+ .number()
51
+ .min(1)
52
+ .optional()
53
+ .describe("Discard Pexels clips shorter than this (seconds). Default 5. Stops the tool from picking " +
54
+ "tiny stings that won't cover even one filler-cut."),
55
+ outDir: z
56
+ .string()
57
+ .optional()
58
+ .describe("Directory to download chosen videos into (relative resolves to cwd). Default '.gg/broll-cache'. " +
59
+ "Ignored when download=false."),
60
+ model: z
61
+ .string()
62
+ .optional()
63
+ .describe("OpenAI chat model used for the noun-phrase extraction step. Default 'gpt-4o-mini'."),
64
+ download: z
65
+ .boolean()
66
+ .optional()
67
+ .describe("When true (default), fetch each chosen video file to outDir and return its local path. " +
68
+ "When false, return only the Pexels CDN URL — useful for previewing before committing bandwidth."),
69
+ });
70
+ const LLM_SYSTEM = `You extract visually-searchable B-roll concepts from a video transcript.
71
+
72
+ Return JSON: {"queries":[{"atSec": number, "query": string, "why": string}, ...]}
73
+
74
+ Each query must be 2-4 words describing a CONCRETE visual that stock-footage libraries actually have:
75
+ GOOD: "coffee shop morning", "highway sunset driving", "woman typing laptop", "city skyline timelapse".
76
+ BAD : "the importance of focus", "feeling productive", "thinking about life".
77
+ Avoid abstract concepts, emotions, and named people/brands.
78
+
79
+ \`atSec\` is the timeline second nearest where the concept is mentioned in the transcript.
80
+ \`why\` is a ≤80-char rationale ("speaker mentions morning routine").
81
+
82
+ Return up to N queries, ordered by importance (most cover-worthy first).`;
83
+ export function createSuggestBrollTool(cwd) {
84
+ return {
85
+ name: "suggest_broll",
86
+ description: "Find B-roll for a transcript window: extracts visual concepts from the transcript via ONE " +
87
+ "LLM call, queries Pexels' free video library, downloads the top match per concept. REQUIRES " +
88
+ "PEXELS_API_KEY (free at pexels.com/api) and OPENAI_API_KEY (for the extraction step). " +
89
+ "Returns {count, items: [{atSec, mediaPath, query, durationSec, sourceUrl, photographer, ...}]} " +
90
+ "ready to feed `insert_broll(mediaPath, recordFrame=atSec*fps)`. The biggest creator multiplier — " +
91
+ "turns 'cover up these ums' into one tool call.",
92
+ parameters: SuggestBrollParams,
93
+ async execute(args, ctx) {
94
+ try {
95
+ const pexelsKey = resolveApiKey("PEXELS_API_KEY", "pexels");
96
+ if (!pexelsKey) {
97
+ return err("PEXELS_API_KEY not set", "free at https://www.pexels.com/api/ — set env or run ggeditor with the key in ~/.gg/api-keys.json");
98
+ }
99
+ const openaiKey = resolveApiKey("OPENAI_API_KEY", "openai");
100
+ if (!openaiKey) {
101
+ return err("OPENAI_API_KEY not set", "needed for the noun-phrase extraction step — set env or store via the onboarding flow");
102
+ }
103
+ const transcriptAbs = resolvePath(cwd, args.transcript);
104
+ let raw;
105
+ try {
106
+ raw = readFileSync(transcriptAbs, "utf8");
107
+ }
108
+ catch (e) {
109
+ return err(`cannot read transcript ${transcriptAbs}: ${e.message}`, "verify the transcript JSON exists");
110
+ }
111
+ let transcript;
112
+ try {
113
+ transcript = parseTranscript(raw);
114
+ }
115
+ catch (e) {
116
+ return err(e.message, "regenerate via transcribe()");
117
+ }
118
+ const startSec = args.startSec ?? 0;
119
+ const endSec = args.endSec ?? transcript.durationSec ?? Infinity;
120
+ if (endSec <= startSec) {
121
+ return err(`empty window: endSec (${endSec}) <= startSec (${startSec})`, "widen the [startSec, endSec) interval");
122
+ }
123
+ const topN = args.topN ?? 5;
124
+ const orientation = args.orientation ?? "landscape";
125
+ const minDurationSec = args.minDurationSec ?? 5;
126
+ const model = args.model ?? "gpt-4o-mini";
127
+ const download = args.download ?? true;
128
+ const windowText = buildWindowText(transcript.segments, startSec, endSec, 6000);
129
+ if (windowText.trim().length === 0) {
130
+ return err("no transcript text in window", "widen [startSec, endSec) or check the transcript");
131
+ }
132
+ // ── 1. LLM extraction ───────────────────────────────────
133
+ let queries;
134
+ try {
135
+ queries = await runQueryExtraction({
136
+ apiKey: openaiKey,
137
+ model,
138
+ text: windowText,
139
+ n: topN,
140
+ startSec,
141
+ endSec,
142
+ signal: ctx?.signal,
143
+ });
144
+ }
145
+ catch (e) {
146
+ return err(`LLM extraction failed: ${e.message}`);
147
+ }
148
+ if (queries.length === 0) {
149
+ return err("LLM returned zero queries", "the window may be too short or too abstract — widen it or try a different model");
150
+ }
151
+ // ── 2. Resolve outDir (only if downloading) ─────────────
152
+ let outDirAbs;
153
+ if (download) {
154
+ outDirAbs = args.outDir
155
+ ? safeOutputPath(cwd, args.outDir)
156
+ : safeOutputPath(cwd, join(".gg", "broll-cache"));
157
+ mkdirSync(outDirAbs, { recursive: true });
158
+ }
159
+ // ── 3. Pexels per query ─────────────────────────────────
160
+ const items = [];
161
+ const skipped = [];
162
+ for (const q of queries.slice(0, topN)) {
163
+ try {
164
+ const search = await searchPexels({
165
+ apiKey: pexelsKey,
166
+ query: q.query,
167
+ orientation,
168
+ perPage: 3,
169
+ signal: ctx?.signal,
170
+ });
171
+ const candidate = pickFirstAcceptable(search.videos, minDurationSec);
172
+ if (!candidate) {
173
+ skipped.push({ query: q.query, reason: "no Pexels match" });
174
+ continue;
175
+ }
176
+ const file = pickBestFile(candidate.video.video_files);
177
+ if (!file) {
178
+ skipped.push({ query: q.query, reason: "no playable video_file" });
179
+ continue;
180
+ }
181
+ let mediaPath;
182
+ if (download && outDirAbs) {
183
+ try {
184
+ mediaPath = await downloadVideo({
185
+ url: file.link,
186
+ fileType: file.file_type,
187
+ pexelsId: candidate.video.id,
188
+ outDir: outDirAbs,
189
+ signal: ctx?.signal,
190
+ });
191
+ }
192
+ catch (e) {
193
+ skipped.push({
194
+ query: q.query,
195
+ reason: `download failed: ${e.message}`,
196
+ });
197
+ continue;
198
+ }
199
+ }
200
+ items.push({
201
+ atSec: clampSec(q.atSec, startSec, endSec),
202
+ durationSec: candidate.video.duration,
203
+ mediaPath,
204
+ query: q.query,
205
+ why: q.why,
206
+ sourceUrl: candidate.video.url,
207
+ photographer: candidate.video.user?.name ?? "unknown",
208
+ pexelsId: candidate.video.id,
209
+ });
210
+ }
211
+ catch (e) {
212
+ // Per-query Pexels failures: surface 401 / 429 with actionable
213
+ // fixes; everything else lands in skipped[] so partial success
214
+ // is still useful.
215
+ const msg = e.message;
216
+ if (msg.startsWith("PEXELS_401")) {
217
+ return err("Pexels 401 unauthorized", "verify PEXELS_API_KEY");
218
+ }
219
+ if (msg.startsWith("PEXELS_429")) {
220
+ return err("Pexels rate-limited", "wait ~1h or upgrade plan");
221
+ }
222
+ skipped.push({ query: q.query, reason: msg.slice(0, 200) });
223
+ }
224
+ }
225
+ return compact({
226
+ count: items.length,
227
+ items,
228
+ skipped: skipped.length > 0 ? skipped : undefined,
229
+ });
230
+ }
231
+ catch (e) {
232
+ return err(e.message);
233
+ }
234
+ },
235
+ };
236
+ }
237
+ // ── Helpers ──────────────────────────────────────────────────
238
+ function buildWindowText(segments, startSec, endSec, maxChars) {
239
+ const parts = [];
240
+ let total = 0;
241
+ for (const s of segments) {
242
+ if (s.end <= startSec)
243
+ continue;
244
+ if (s.start >= endSec)
245
+ break;
246
+ const stamped = `[${s.start.toFixed(1)}s] ${s.text.trim()}`;
247
+ if (total + stamped.length + 1 > maxChars)
248
+ break;
249
+ parts.push(stamped);
250
+ total += stamped.length + 1;
251
+ }
252
+ return parts.join("\n");
253
+ }
254
+ function clampSec(v, lo, hi) {
255
+ if (!Number.isFinite(v))
256
+ return lo;
257
+ if (v < lo)
258
+ return lo;
259
+ if (v >= hi)
260
+ return Math.max(lo, hi - 0.001);
261
+ return +v.toFixed(2);
262
+ }
263
+ async function runQueryExtraction(opts) {
264
+ const userMsg = `Window: [${opts.startSec.toFixed(1)}s, ${opts.endSec.toFixed(1)}s). Return up to ${opts.n} queries.\n\n` +
265
+ `TRANSCRIPT:\n${opts.text}`;
266
+ const body = {
267
+ model: opts.model,
268
+ messages: [
269
+ { role: "system", content: LLM_SYSTEM },
270
+ { role: "user", content: userMsg },
271
+ ],
272
+ response_format: { type: "json_object" },
273
+ temperature: 0,
274
+ };
275
+ const res = await fetch("https://api.openai.com/v1/chat/completions", {
276
+ method: "POST",
277
+ headers: {
278
+ Authorization: `Bearer ${opts.apiKey}`,
279
+ "Content-Type": "application/json",
280
+ },
281
+ body: JSON.stringify(body),
282
+ signal: opts.signal,
283
+ });
284
+ if (!res.ok) {
285
+ const text = await res.text().catch(() => "");
286
+ throw new Error(`OpenAI HTTP ${res.status}: ${text.slice(0, 200)}`);
287
+ }
288
+ const data = (await res.json());
289
+ const content = data.choices?.[0]?.message?.content;
290
+ if (!content)
291
+ throw new Error("empty model response");
292
+ const start = content.indexOf("{");
293
+ const end = content.lastIndexOf("}");
294
+ if (start < 0 || end < start)
295
+ throw new Error("no JSON object in response");
296
+ const parsed = JSON.parse(content.slice(start, end + 1));
297
+ if (!Array.isArray(parsed.queries))
298
+ throw new Error("response missing queries[]");
299
+ const out = [];
300
+ for (const raw of parsed.queries) {
301
+ if (!raw || typeof raw !== "object")
302
+ continue;
303
+ const r = raw;
304
+ const query = String(r.query ?? "").trim();
305
+ if (!query)
306
+ continue;
307
+ const atSecRaw = Number(r.atSec);
308
+ const atSec = Number.isFinite(atSecRaw) ? atSecRaw : opts.startSec;
309
+ const why = String(r.why ?? "").slice(0, 200);
310
+ out.push({ atSec, query, why });
311
+ }
312
+ return out;
313
+ }
314
+ async function searchPexels(opts) {
315
+ const url = `https://api.pexels.com/videos/search` +
316
+ `?query=${encodeURIComponent(opts.query)}` +
317
+ `&per_page=${opts.perPage}` +
318
+ `&orientation=${opts.orientation}`;
319
+ const res = await fetch(url, {
320
+ headers: { Authorization: opts.apiKey },
321
+ signal: opts.signal,
322
+ });
323
+ if (res.status === 401)
324
+ throw new Error("PEXELS_401");
325
+ if (res.status === 429)
326
+ throw new Error("PEXELS_429");
327
+ if (!res.ok) {
328
+ const t = await res.text().catch(() => "");
329
+ throw new Error(`Pexels HTTP ${res.status}: ${t.slice(0, 200)}`);
330
+ }
331
+ return (await res.json());
332
+ }
333
+ function pickFirstAcceptable(videos, minDurationSec) {
334
+ if (!Array.isArray(videos))
335
+ return undefined;
336
+ for (const v of videos) {
337
+ if ((v.duration ?? 0) >= minDurationSec)
338
+ return { video: v };
339
+ }
340
+ return undefined;
341
+ }
342
+ /**
343
+ * Pick the best `video_files` entry: prefer mp4, prefer hd over sd, avoid
344
+ * uhd (multi-GB downloads on free tier are not creator-friendly).
345
+ */
346
+ function pickBestFile(files) {
347
+ if (!Array.isArray(files) || files.length === 0)
348
+ return undefined;
349
+ const mp4 = files.filter((f) => f.file_type === "video/mp4");
350
+ const pool = mp4.length > 0 ? mp4 : files;
351
+ return pool.find((f) => f.quality === "hd") ?? pool.find((f) => f.quality === "sd") ?? pool[0];
352
+ }
353
+ async function downloadVideo(opts) {
354
+ const res = await fetch(opts.url, { signal: opts.signal });
355
+ if (!res.ok)
356
+ throw new Error(`HTTP ${res.status}`);
357
+ const buf = Buffer.from(await res.arrayBuffer());
358
+ const ext = opts.fileType.endsWith("/webm") ? "webm" : "mp4";
359
+ const out = join(opts.outDir, `pexels-${opts.pexelsId}.${ext}`);
360
+ writeFileSync(out, buf);
361
+ return out;
362
+ }
363
+ // Re-export for tests that want to seed a tempdir without poking the cwd.
364
+ export function _tempBrollDir() {
365
+ return mkdtempSync(join(tmpdir(), "gg-broll-"));
366
+ }
367
+ //# sourceMappingURL=suggest-broll.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suggest-broll.js","sourceRoot":"","sources":["../../src/tools/suggest-broll.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=suggest-broll.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suggest-broll.test.d.ts","sourceRoot":"","sources":["../../src/tools/suggest-broll.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,217 @@
1
+ import { existsSync, mkdtempSync, readdirSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
5
+ import { createSuggestBrollTool } from "./suggest-broll.js";
6
+ /**
7
+ * suggest_broll mocks the network (OpenAI + Pexels) and the filesystem
8
+ * download path. It never actually hits the wire.
9
+ *
10
+ * Test ordering matters because we mutate process.env.PEXELS_API_KEY /
11
+ * OPENAI_API_KEY and stub global.fetch — every `it` cleans up.
12
+ */
13
+ const TX = {
14
+ language: "en",
15
+ durationSec: 60,
16
+ segments: [
17
+ { start: 0, end: 5, text: "Today I want to talk about my morning coffee routine." },
18
+ { start: 5, end: 10, text: "I drive down the highway as the sun rises." },
19
+ { start: 10, end: 15, text: "Then I open my laptop and start typing." },
20
+ ],
21
+ };
22
+ function makeTranscriptFile(t) {
23
+ const dir = mkdtempSync(join(tmpdir(), "gg-sbr-"));
24
+ const path = join(dir, "transcript.json");
25
+ writeFileSync(path, JSON.stringify(t), "utf8");
26
+ return { dir, path };
27
+ }
28
+ const ctx = {
29
+ signal: new AbortController().signal,
30
+ toolCallId: "t1",
31
+ };
32
+ // JSON helper for fetch mocks
33
+ function jsonResponse(body, status = 200) {
34
+ return new Response(JSON.stringify(body), {
35
+ status,
36
+ headers: { "Content-Type": "application/json" },
37
+ });
38
+ }
39
+ function llmResponse(queries) {
40
+ return jsonResponse({
41
+ choices: [{ message: { content: JSON.stringify({ queries }) } }],
42
+ });
43
+ }
44
+ function pexelsVideo(opts) {
45
+ return {
46
+ id: opts.id,
47
+ width: 1920,
48
+ height: 1080,
49
+ duration: opts.duration ?? 12,
50
+ url: opts.url ?? `https://www.pexels.com/video/${opts.id}/`,
51
+ user: { name: opts.user ?? "Jane Photographer" },
52
+ video_files: [
53
+ {
54
+ link: opts.link ?? `https://cdn.pexels.com/v/${opts.id}.mp4`,
55
+ quality: "hd",
56
+ width: 1920,
57
+ height: 1080,
58
+ file_type: "video/mp4",
59
+ },
60
+ ],
61
+ };
62
+ }
63
+ const ENV_BACKUP = {};
64
+ beforeEach(() => {
65
+ ENV_BACKUP.PEXELS_API_KEY = process.env.PEXELS_API_KEY;
66
+ ENV_BACKUP.OPENAI_API_KEY = process.env.OPENAI_API_KEY;
67
+ process.env.PEXELS_API_KEY = "test-pexels";
68
+ process.env.OPENAI_API_KEY = "test-openai";
69
+ });
70
+ afterEach(() => {
71
+ for (const [k, v] of Object.entries(ENV_BACKUP)) {
72
+ if (v === undefined)
73
+ delete process.env[k];
74
+ else
75
+ process.env[k] = v;
76
+ }
77
+ vi.restoreAllMocks();
78
+ vi.unstubAllGlobals();
79
+ });
80
+ describe("suggest_broll", () => {
81
+ it("errors when PEXELS_API_KEY is unset", async () => {
82
+ delete process.env.PEXELS_API_KEY;
83
+ // Make sure the stored-key fallback returns nothing either.
84
+ vi.doMock("../core/auth/api-keys.js", async (orig) => {
85
+ // eslint-disable-next-line @typescript-eslint/consistent-type-imports
86
+ const mod = await orig();
87
+ return {
88
+ ...mod,
89
+ getStoredApiKey: () => undefined,
90
+ resolveApiKey: (envVar) => envVar === "OPENAI_API_KEY" ? process.env.OPENAI_API_KEY : undefined,
91
+ };
92
+ });
93
+ // Re-import after the mock so the tool resolves the stubbed module.
94
+ const { createSuggestBrollTool: freshCreate } = await import("./suggest-broll.js");
95
+ const { dir } = makeTranscriptFile(TX);
96
+ const tool = freshCreate(dir);
97
+ const r = (await tool.execute({ transcript: "transcript.json" }, ctx));
98
+ expect(r).toMatch(/^error: PEXELS_API_KEY not set/);
99
+ vi.doUnmock("../core/auth/api-keys.js");
100
+ });
101
+ it("errors when transcript file is missing", async () => {
102
+ const dir = mkdtempSync(join(tmpdir(), "gg-sbr-"));
103
+ const tool = createSuggestBrollTool(dir);
104
+ const r = (await tool.execute({ transcript: "nope.json" }, ctx));
105
+ expect(r).toMatch(/^error: cannot read transcript/);
106
+ });
107
+ it("errors when transcript is malformed JSON", async () => {
108
+ const dir = mkdtempSync(join(tmpdir(), "gg-sbr-"));
109
+ writeFileSync(join(dir, "t.json"), "{not json", "utf8");
110
+ const tool = createSuggestBrollTool(dir);
111
+ const r = (await tool.execute({ transcript: "t.json" }, ctx));
112
+ expect(r).toMatch(/^error: Invalid transcript: not valid JSON/);
113
+ });
114
+ it("returns formatted items when LLM + Pexels both succeed (download=false)", async () => {
115
+ const fetchMock = vi
116
+ .fn()
117
+ .mockResolvedValueOnce(llmResponse([
118
+ { atSec: 2, query: "morning coffee shop", why: "speaker mentions coffee" },
119
+ { atSec: 7, query: "highway sunrise driving", why: "speaker drives at sunrise" },
120
+ ]))
121
+ .mockResolvedValueOnce(jsonResponse({ videos: [pexelsVideo({ id: 1001 })] }))
122
+ .mockResolvedValueOnce(jsonResponse({ videos: [pexelsVideo({ id: 1002 })] }));
123
+ vi.stubGlobal("fetch", fetchMock);
124
+ const { dir } = makeTranscriptFile(TX);
125
+ const tool = createSuggestBrollTool(dir);
126
+ const r = (await tool.execute({ transcript: "transcript.json", download: false }, ctx));
127
+ expect(r).not.toMatch(/^error/);
128
+ const parsed = JSON.parse(r);
129
+ expect(parsed.count).toBe(2);
130
+ expect(parsed.items).toHaveLength(2);
131
+ expect(parsed.items[0].query).toBe("morning coffee shop");
132
+ expect(parsed.items[0].sourceUrl).toContain("pexels.com");
133
+ expect(parsed.items[0].pexelsId).toBe(1001);
134
+ // download=false → no mediaPath
135
+ expect(parsed.items[0].mediaPath).toBeUndefined();
136
+ expect(parsed.items[1].pexelsId).toBe(1002);
137
+ // First call hits OpenAI, next two hit Pexels (no download fetches).
138
+ expect(fetchMock).toHaveBeenCalledTimes(3);
139
+ const urls = fetchMock.mock.calls.map((c) => c[0]);
140
+ expect(urls[0]).toContain("api.openai.com");
141
+ expect(urls[1]).toContain("api.pexels.com/videos/search");
142
+ expect(urls[2]).toContain("api.pexels.com/videos/search");
143
+ });
144
+ it("returns user-friendly error on Pexels 401", async () => {
145
+ const fetchMock = vi
146
+ .fn()
147
+ .mockResolvedValueOnce(llmResponse([{ atSec: 1, query: "morning coffee", why: "x" }]))
148
+ .mockResolvedValueOnce(new Response("unauthorized", { status: 401 }));
149
+ vi.stubGlobal("fetch", fetchMock);
150
+ const { dir } = makeTranscriptFile(TX);
151
+ const tool = createSuggestBrollTool(dir);
152
+ const r = (await tool.execute({ transcript: "transcript.json", download: false }, ctx));
153
+ expect(r).toMatch(/^error: Pexels 401 unauthorized/);
154
+ expect(r).toContain("verify PEXELS_API_KEY");
155
+ });
156
+ it("collects per-query failures into skipped[] and still returns successes", async () => {
157
+ const fetchMock = vi
158
+ .fn()
159
+ .mockResolvedValueOnce(llmResponse([
160
+ { atSec: 2, query: "coffee shop morning", why: "a" },
161
+ { atSec: 7, query: "obscure abstract concept", why: "b" },
162
+ ]))
163
+ .mockResolvedValueOnce(jsonResponse({ videos: [pexelsVideo({ id: 2001 })] }))
164
+ .mockResolvedValueOnce(jsonResponse({ videos: [] })); // empty → skipped
165
+ vi.stubGlobal("fetch", fetchMock);
166
+ const { dir } = makeTranscriptFile(TX);
167
+ const tool = createSuggestBrollTool(dir);
168
+ const r = (await tool.execute({ transcript: "transcript.json", download: false }, ctx));
169
+ expect(r).not.toMatch(/^error/);
170
+ const parsed = JSON.parse(r);
171
+ expect(parsed.count).toBe(1);
172
+ expect(parsed.items[0].pexelsId).toBe(2001);
173
+ expect(parsed.skipped).toHaveLength(1);
174
+ expect(parsed.skipped[0].query).toBe("obscure abstract concept");
175
+ expect(parsed.skipped[0].reason).toMatch(/no Pexels match/);
176
+ });
177
+ it("downloads to outDir when download=true and writes the file", async () => {
178
+ const downloadDir = mkdtempSync(join(tmpdir(), "gg-sbr-out-"));
179
+ const fakeBytes = Buffer.from("FAKE_VIDEO_BYTES");
180
+ const fetchMock = vi
181
+ .fn()
182
+ .mockResolvedValueOnce(llmResponse([{ atSec: 2, query: "coffee shop morning", why: "x" }]))
183
+ .mockResolvedValueOnce(jsonResponse({ videos: [pexelsVideo({ id: 3001 })] }))
184
+ .mockResolvedValueOnce(new Response(fakeBytes, { status: 200, headers: { "Content-Type": "video/mp4" } }));
185
+ vi.stubGlobal("fetch", fetchMock);
186
+ const { dir } = makeTranscriptFile(TX);
187
+ const tool = createSuggestBrollTool(dir);
188
+ const r = (await tool.execute({
189
+ transcript: "transcript.json",
190
+ download: true,
191
+ outDir: downloadDir,
192
+ }, ctx));
193
+ expect(r).not.toMatch(/^error/);
194
+ const parsed = JSON.parse(r);
195
+ expect(parsed.count).toBe(1);
196
+ expect(parsed.items[0].mediaPath).toBe(join(downloadDir, "pexels-3001.mp4"));
197
+ expect(existsSync(parsed.items[0].mediaPath)).toBe(true);
198
+ // Files in the dir = exactly one mp4.
199
+ const files = readdirSync(downloadDir);
200
+ expect(files).toContain("pexels-3001.mp4");
201
+ });
202
+ it("output is valid JSON with {count, items} shape", async () => {
203
+ const fetchMock = vi
204
+ .fn()
205
+ .mockResolvedValueOnce(llmResponse([{ atSec: 1, query: "city skyline", why: "x" }]))
206
+ .mockResolvedValueOnce(jsonResponse({ videos: [pexelsVideo({ id: 9 })] }));
207
+ vi.stubGlobal("fetch", fetchMock);
208
+ const { dir } = makeTranscriptFile(TX);
209
+ const tool = createSuggestBrollTool(dir);
210
+ const r = (await tool.execute({ transcript: "transcript.json", download: false }, ctx));
211
+ const parsed = JSON.parse(r);
212
+ expect(parsed).toHaveProperty("count");
213
+ expect(parsed).toHaveProperty("items");
214
+ expect(Array.isArray(parsed.items)).toBe(true);
215
+ });
216
+ });
217
+ //# sourceMappingURL=suggest-broll.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suggest-broll.test.js","sourceRoot":"","sources":["../../src/tools/suggest-broll.test.ts"],"names":[],"mappings":"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"}