@1agh/maude 0.42.0 → 0.44.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 (332) hide show
  1. package/apps/studio/.ai/cache/_stats.json +7 -0
  2. package/apps/studio/acp/bootstrap-brief.ts +12 -2
  3. package/apps/studio/acp/bridge.ts +44 -10
  4. package/apps/studio/acp/env.ts +23 -0
  5. package/apps/studio/acp/login-state.ts +263 -0
  6. package/apps/studio/acp/plugin-bootstrap.ts +31 -25
  7. package/apps/studio/acp/probe.ts +152 -1
  8. package/apps/studio/annotations-layer.tsx +1451 -324
  9. package/apps/studio/annotations-model.ts +58 -0
  10. package/apps/studio/api.ts +568 -24
  11. package/apps/studio/bin/_audio-search.mjs +140 -0
  12. package/apps/studio/bin/_import-asset-pdf-worker.mjs +34 -0
  13. package/apps/studio/bin/_import-asset.mjs +815 -0
  14. package/apps/studio/bin/_import-brand.mjs +635 -0
  15. package/apps/studio/bin/_import-tokens-alias-resolver.mjs +95 -0
  16. package/apps/studio/bin/_import-tokens.mjs +1201 -0
  17. package/apps/studio/bin/_ingest-footage.mjs +386 -0
  18. package/apps/studio/bin/_probe-footage-playwright.mjs +269 -0
  19. package/apps/studio/bin/_transcribe.mjs +419 -0
  20. package/apps/studio/bin/_transcribe.test.mjs +80 -0
  21. package/apps/studio/bin/_video-playwright.mjs +141 -71
  22. package/apps/studio/bin/audio-search.sh +28 -0
  23. package/apps/studio/bin/generate.sh +154 -0
  24. package/apps/studio/bin/import-asset.sh +34 -0
  25. package/apps/studio/bin/import-brand.sh +29 -0
  26. package/apps/studio/bin/import-tokens.sh +33 -0
  27. package/apps/studio/bin/ingest-footage.sh +27 -0
  28. package/apps/studio/bin/photo-adjust.sh +163 -0
  29. package/apps/studio/bin/photo-bg-remove.sh +258 -0
  30. package/apps/studio/bin/probe-footage.sh +28 -0
  31. package/apps/studio/bin/read-annotations.mjs +125 -2
  32. package/apps/studio/bin/transcribe.sh +39 -0
  33. package/apps/studio/canvas-edit.ts +656 -12
  34. package/apps/studio/canvas-lib.tsx +637 -10
  35. package/apps/studio/canvas-pipeline.ts +65 -7
  36. package/apps/studio/canvas-shell.tsx +156 -16
  37. package/apps/studio/client/app.jsx +2385 -699
  38. package/apps/studio/client/export-center.jsx +35 -1
  39. package/apps/studio/client/generate-dialog.jsx +352 -0
  40. package/apps/studio/client/github.js +18 -0
  41. package/apps/studio/client/inspector-controls.jsx +781 -0
  42. package/apps/studio/client/panels/BrandUploadPanel.jsx +233 -0
  43. package/apps/studio/client/panels/ChatPanel.jsx +15 -33
  44. package/apps/studio/client/panels/GitPanel.jsx +8 -0
  45. package/apps/studio/client/panels/IntroVideoDialog.jsx +44 -0
  46. package/apps/studio/client/panels/OnboardingWizard.jsx +12 -0
  47. package/apps/studio/client/panels/ReadinessList.jsx +227 -7
  48. package/apps/studio/client/panels/RepoBranchSwitcher.jsx +133 -21
  49. package/apps/studio/client/panels/SettingsPanel.jsx +828 -0
  50. package/apps/studio/client/panels/SetupChecklist.jsx +223 -0
  51. package/apps/studio/client/panels/StickerPicker.jsx +160 -0
  52. package/apps/studio/client/panels/TimelinePanel.jsx +15 -2
  53. package/apps/studio/client/photo-knobs.jsx +432 -0
  54. package/apps/studio/client/styles/3-shell-maude.css +376 -28
  55. package/apps/studio/client/styles/4-components.css +223 -0
  56. package/apps/studio/client/styles/6-acp-chat.css +86 -0
  57. package/apps/studio/client/tour/quick-setup-tour.js +39 -0
  58. package/apps/studio/commands/annotation-strokes-command.ts +13 -3
  59. package/apps/studio/commands/edit-source-command.ts +31 -4
  60. package/apps/studio/config.schema.json +70 -0
  61. package/apps/studio/context-menu.tsx +42 -8
  62. package/apps/studio/context.ts +16 -0
  63. package/apps/studio/design-setup-readiness.ts +115 -0
  64. package/apps/studio/dist/client.bundle.js +5572 -21
  65. package/apps/studio/dist/comment-mount.js +2 -2
  66. package/apps/studio/dist/runtime/.min-sizes.json +1 -0
  67. package/apps/studio/dist/runtime/@imgly_background-removal.js +5543 -0
  68. package/apps/studio/dist/runtime/pixi-js.js +519 -519
  69. package/apps/studio/dist/styles.css +1 -1
  70. package/apps/studio/dom-selection.ts +25 -0
  71. package/apps/studio/draw/palette.ts +34 -0
  72. package/apps/studio/exporters/jobs.ts +47 -5
  73. package/apps/studio/exporters/video.ts +24 -4
  74. package/apps/studio/footage/schema.test.ts +287 -0
  75. package/apps/studio/footage/schema.ts +662 -0
  76. package/apps/studio/footage-store.ts +235 -0
  77. package/apps/studio/fs-watch.ts +10 -0
  78. package/apps/studio/generation/adapters/elevenlabs.ts +370 -0
  79. package/apps/studio/generation/adapters/gemini.ts +542 -0
  80. package/apps/studio/generation/adapters/groq.test.ts +80 -0
  81. package/apps/studio/generation/adapters/groq.ts +247 -0
  82. package/apps/studio/generation/audio-library.test.ts +95 -0
  83. package/apps/studio/generation/audio-library.ts +156 -0
  84. package/apps/studio/generation/captions.test.ts +78 -0
  85. package/apps/studio/generation/captions.ts +132 -0
  86. package/apps/studio/generation/download.ts +76 -0
  87. package/apps/studio/generation/elevenlabs.test.ts +223 -0
  88. package/apps/studio/generation/gemini.test.ts +350 -0
  89. package/apps/studio/generation/jobs.test.ts +128 -0
  90. package/apps/studio/generation/jobs.ts +243 -0
  91. package/apps/studio/generation/keys.test.ts +75 -0
  92. package/apps/studio/generation/keys.ts +162 -0
  93. package/apps/studio/generation/prefs.test.ts +95 -0
  94. package/apps/studio/generation/prefs.ts +82 -0
  95. package/apps/studio/generation/registry.ts +88 -0
  96. package/apps/studio/generation/types.test.ts +123 -0
  97. package/apps/studio/generation/types.ts +266 -0
  98. package/apps/studio/generation/whisper-models.test.ts +152 -0
  99. package/apps/studio/generation/whisper-models.ts +257 -0
  100. package/apps/studio/generation/whisper-spike-results.md +61 -0
  101. package/apps/studio/git/endpoints.ts +68 -7
  102. package/apps/studio/git/service.ts +199 -21
  103. package/apps/studio/github/service.ts +67 -0
  104. package/apps/studio/handoff.ts +3 -2
  105. package/apps/studio/http.ts +1039 -22
  106. package/apps/studio/input-router.tsx +10 -0
  107. package/apps/studio/inspect.ts +53 -1
  108. package/apps/studio/media/intro.mp4 +0 -0
  109. package/apps/studio/media-commit-chain.ts +119 -0
  110. package/apps/studio/paths.ts +20 -0
  111. package/apps/studio/photo/filters.ts +285 -0
  112. package/apps/studio/photo/pipeline.ts +607 -0
  113. package/apps/studio/photo/schema.ts +367 -0
  114. package/apps/studio/photo-store.ts +154 -0
  115. package/apps/studio/readiness.ts +108 -20
  116. package/apps/studio/runtime-bundle.ts +29 -6
  117. package/apps/studio/scaffold-design.ts +1145 -0
  118. package/apps/studio/server.ts +18 -2
  119. package/apps/studio/stickers/figjam-doodle/manifest.json +104 -0
  120. package/apps/studio/stickers/figjam-doodle/slice1.png +0 -0
  121. package/apps/studio/stickers/figjam-doodle/slice10.png +0 -0
  122. package/apps/studio/stickers/figjam-doodle/slice11.png +0 -0
  123. package/apps/studio/stickers/figjam-doodle/slice12.png +0 -0
  124. package/apps/studio/stickers/figjam-doodle/slice13.png +0 -0
  125. package/apps/studio/stickers/figjam-doodle/slice14.png +0 -0
  126. package/apps/studio/stickers/figjam-doodle/slice15.png +0 -0
  127. package/apps/studio/stickers/figjam-doodle/slice16.png +0 -0
  128. package/apps/studio/stickers/figjam-doodle/slice17.png +0 -0
  129. package/apps/studio/stickers/figjam-doodle/slice18.png +0 -0
  130. package/apps/studio/stickers/figjam-doodle/slice19.png +0 -0
  131. package/apps/studio/stickers/figjam-doodle/slice2.png +0 -0
  132. package/apps/studio/stickers/figjam-doodle/slice20.png +0 -0
  133. package/apps/studio/stickers/figjam-doodle/slice21.png +0 -0
  134. package/apps/studio/stickers/figjam-doodle/slice22.png +0 -0
  135. package/apps/studio/stickers/figjam-doodle/slice23.png +0 -0
  136. package/apps/studio/stickers/figjam-doodle/slice24.png +0 -0
  137. package/apps/studio/stickers/figjam-doodle/slice3.png +0 -0
  138. package/apps/studio/stickers/figjam-doodle/slice4.png +0 -0
  139. package/apps/studio/stickers/figjam-doodle/slice5.png +0 -0
  140. package/apps/studio/stickers/figjam-doodle/slice6.png +0 -0
  141. package/apps/studio/stickers/figjam-doodle/slice7.png +0 -0
  142. package/apps/studio/stickers/figjam-doodle/slice8.png +0 -0
  143. package/apps/studio/stickers/figjam-doodle/slice9.png +0 -0
  144. package/apps/studio/stickers/life-style/best.png +0 -0
  145. package/apps/studio/stickers/life-style/come-on.png +0 -0
  146. package/apps/studio/stickers/life-style/cut.png +0 -0
  147. package/apps/studio/stickers/life-style/detox.png +0 -0
  148. package/apps/studio/stickers/life-style/just.png +0 -0
  149. package/apps/studio/stickers/life-style/manifest.json +68 -0
  150. package/apps/studio/stickers/life-style/mirror.png +0 -0
  151. package/apps/studio/stickers/life-style/nice.png +0 -0
  152. package/apps/studio/stickers/life-style/objects.png +0 -0
  153. package/apps/studio/stickers/life-style/ok.png +0 -0
  154. package/apps/studio/stickers/life-style/queen.png +0 -0
  155. package/apps/studio/stickers/life-style/star.png +0 -0
  156. package/apps/studio/stickers/life-style/sun.png +0 -0
  157. package/apps/studio/stickers/life-style/water.png +0 -0
  158. package/apps/studio/stickers/life-style/yeah.png +0 -0
  159. package/apps/studio/stickers/life-style/you-can.png +0 -0
  160. package/apps/studio/stickers/opposing-thoughts/check-the-deets.png +0 -0
  161. package/apps/studio/stickers/opposing-thoughts/cut-it.png +0 -0
  162. package/apps/studio/stickers/opposing-thoughts/dope.png +0 -0
  163. package/apps/studio/stickers/opposing-thoughts/fresh.png +0 -0
  164. package/apps/studio/stickers/opposing-thoughts/hot.png +0 -0
  165. package/apps/studio/stickers/opposing-thoughts/idea.png +0 -0
  166. package/apps/studio/stickers/opposing-thoughts/keep-exploring.png +0 -0
  167. package/apps/studio/stickers/opposing-thoughts/killed-it.png +0 -0
  168. package/apps/studio/stickers/opposing-thoughts/love-it.png +0 -0
  169. package/apps/studio/stickers/opposing-thoughts/manifest.json +88 -0
  170. package/apps/studio/stickers/opposing-thoughts/not-sure.png +0 -0
  171. package/apps/studio/stickers/opposing-thoughts/ok.png +0 -0
  172. package/apps/studio/stickers/opposing-thoughts/pure-gold.png +0 -0
  173. package/apps/studio/stickers/opposing-thoughts/save-for-later.png +0 -0
  174. package/apps/studio/stickers/opposing-thoughts/steal-this.png +0 -0
  175. package/apps/studio/stickers/opposing-thoughts/take-a-peek.png +0 -0
  176. package/apps/studio/stickers/opposing-thoughts/this-or-that.png +0 -0
  177. package/apps/studio/stickers/opposing-thoughts/thoughts.png +0 -0
  178. package/apps/studio/stickers/opposing-thoughts/vibes.png +0 -0
  179. package/apps/studio/stickers/opposing-thoughts/winner.png +0 -0
  180. package/apps/studio/stickers/opposing-thoughts/wip.png +0 -0
  181. package/apps/studio/stickers/project-status/group-100.png +0 -0
  182. package/apps/studio/stickers/project-status/group-101.png +0 -0
  183. package/apps/studio/stickers/project-status/group-102.png +0 -0
  184. package/apps/studio/stickers/project-status/group-103.png +0 -0
  185. package/apps/studio/stickers/project-status/group-104.png +0 -0
  186. package/apps/studio/stickers/project-status/group-105.png +0 -0
  187. package/apps/studio/stickers/project-status/group-106.png +0 -0
  188. package/apps/studio/stickers/project-status/group-107.png +0 -0
  189. package/apps/studio/stickers/project-status/group-108.png +0 -0
  190. package/apps/studio/stickers/project-status/group-109.png +0 -0
  191. package/apps/studio/stickers/project-status/group-110.png +0 -0
  192. package/apps/studio/stickers/project-status/group-111.png +0 -0
  193. package/apps/studio/stickers/project-status/group-112.png +0 -0
  194. package/apps/studio/stickers/project-status/group-113.png +0 -0
  195. package/apps/studio/stickers/project-status/group-114.png +0 -0
  196. package/apps/studio/stickers/project-status/group-115.png +0 -0
  197. package/apps/studio/stickers/project-status/group-117.png +0 -0
  198. package/apps/studio/stickers/project-status/group-118.png +0 -0
  199. package/apps/studio/stickers/project-status/group-119.png +0 -0
  200. package/apps/studio/stickers/project-status/group-120.png +0 -0
  201. package/apps/studio/stickers/project-status/group-121.png +0 -0
  202. package/apps/studio/stickers/project-status/group-122.png +0 -0
  203. package/apps/studio/stickers/project-status/group-41.png +0 -0
  204. package/apps/studio/stickers/project-status/group-42.png +0 -0
  205. package/apps/studio/stickers/project-status/group-43.png +0 -0
  206. package/apps/studio/stickers/project-status/group-44.png +0 -0
  207. package/apps/studio/stickers/project-status/group-45.png +0 -0
  208. package/apps/studio/stickers/project-status/group-46.png +0 -0
  209. package/apps/studio/stickers/project-status/group-47.png +0 -0
  210. package/apps/studio/stickers/project-status/group-48.png +0 -0
  211. package/apps/studio/stickers/project-status/group-49.png +0 -0
  212. package/apps/studio/stickers/project-status/group-50.png +0 -0
  213. package/apps/studio/stickers/project-status/group-51.png +0 -0
  214. package/apps/studio/stickers/project-status/group-52.png +0 -0
  215. package/apps/studio/stickers/project-status/group-53.png +0 -0
  216. package/apps/studio/stickers/project-status/group-54.png +0 -0
  217. package/apps/studio/stickers/project-status/group-55.png +0 -0
  218. package/apps/studio/stickers/project-status/group-56.png +0 -0
  219. package/apps/studio/stickers/project-status/group-57.png +0 -0
  220. package/apps/studio/stickers/project-status/group-58.png +0 -0
  221. package/apps/studio/stickers/project-status/group-59.png +0 -0
  222. package/apps/studio/stickers/project-status/group-60.png +0 -0
  223. package/apps/studio/stickers/project-status/group-61.png +0 -0
  224. package/apps/studio/stickers/project-status/group-62.png +0 -0
  225. package/apps/studio/stickers/project-status/group-63.png +0 -0
  226. package/apps/studio/stickers/project-status/group-64.png +0 -0
  227. package/apps/studio/stickers/project-status/group-65.png +0 -0
  228. package/apps/studio/stickers/project-status/group-66.png +0 -0
  229. package/apps/studio/stickers/project-status/group-67.png +0 -0
  230. package/apps/studio/stickers/project-status/group-68.png +0 -0
  231. package/apps/studio/stickers/project-status/group-69.png +0 -0
  232. package/apps/studio/stickers/project-status/group-70.png +0 -0
  233. package/apps/studio/stickers/project-status/group-71.png +0 -0
  234. package/apps/studio/stickers/project-status/group-72.png +0 -0
  235. package/apps/studio/stickers/project-status/group-73.png +0 -0
  236. package/apps/studio/stickers/project-status/group-74.png +0 -0
  237. package/apps/studio/stickers/project-status/group-75.png +0 -0
  238. package/apps/studio/stickers/project-status/group-76.png +0 -0
  239. package/apps/studio/stickers/project-status/group-77.png +0 -0
  240. package/apps/studio/stickers/project-status/group-78.png +0 -0
  241. package/apps/studio/stickers/project-status/group-79.png +0 -0
  242. package/apps/studio/stickers/project-status/group-80.png +0 -0
  243. package/apps/studio/stickers/project-status/group-81.png +0 -0
  244. package/apps/studio/stickers/project-status/group-82.png +0 -0
  245. package/apps/studio/stickers/project-status/group-83.png +0 -0
  246. package/apps/studio/stickers/project-status/group-84.png +0 -0
  247. package/apps/studio/stickers/project-status/group-85.png +0 -0
  248. package/apps/studio/stickers/project-status/group-86.png +0 -0
  249. package/apps/studio/stickers/project-status/group-87.png +0 -0
  250. package/apps/studio/stickers/project-status/group-88.png +0 -0
  251. package/apps/studio/stickers/project-status/group-89.png +0 -0
  252. package/apps/studio/stickers/project-status/group-90.png +0 -0
  253. package/apps/studio/stickers/project-status/group-91.png +0 -0
  254. package/apps/studio/stickers/project-status/group-92.png +0 -0
  255. package/apps/studio/stickers/project-status/group-93.png +0 -0
  256. package/apps/studio/stickers/project-status/group-94.png +0 -0
  257. package/apps/studio/stickers/project-status/group-96.png +0 -0
  258. package/apps/studio/stickers/project-status/group-97.png +0 -0
  259. package/apps/studio/stickers/project-status/group-98.png +0 -0
  260. package/apps/studio/stickers/project-status/group-99.png +0 -0
  261. package/apps/studio/stickers/project-status/manifest.json +328 -0
  262. package/apps/studio/test/_helpers.ts +15 -2
  263. package/apps/studio/test/acp-bootstrap-brief.test.ts +11 -0
  264. package/apps/studio/test/acp-bridge.test.ts +34 -1
  265. package/apps/studio/test/acp-commands.test.ts +2 -1
  266. package/apps/studio/test/acp-env.test.ts +30 -0
  267. package/apps/studio/test/acp-plugin-bootstrap.test.ts +23 -57
  268. package/apps/studio/test/acp-session-plugins.test.ts +72 -1
  269. package/apps/studio/test/annotation-strokes-command.test.ts +17 -0
  270. package/apps/studio/test/annotations-layer.test.ts +174 -0
  271. package/apps/studio/test/asset-api.test.ts +3 -3
  272. package/apps/studio/test/canvas-edit.test.ts +17 -6
  273. package/apps/studio/test/canvas-origin-gate.test.ts +50 -0
  274. package/apps/studio/test/csp-canvas-shell.test.ts +11 -0
  275. package/apps/studio/test/csrf-write-guard.test.ts +23 -1
  276. package/apps/studio/test/design-setup-readiness.test.ts +155 -0
  277. package/apps/studio/test/dynamic-text-edit.test.ts +162 -0
  278. package/apps/studio/test/edit-source-command.test.ts +23 -0
  279. package/apps/studio/test/element-structural-edit.test.ts +154 -0
  280. package/apps/studio/test/fixtures/fake-claude-auth.mjs +13 -0
  281. package/apps/studio/test/footage-store.test.ts +100 -0
  282. package/apps/studio/test/generate-route.test.ts +106 -0
  283. package/apps/studio/test/git-branches.test.ts +97 -0
  284. package/apps/studio/test/github-api.test.ts +56 -1
  285. package/apps/studio/test/import-asset-browser.test.ts +64 -0
  286. package/apps/studio/test/import-asset-route.test.ts +71 -0
  287. package/apps/studio/test/import-asset.test.ts +399 -0
  288. package/apps/studio/test/import-brand-browser.test.ts +88 -0
  289. package/apps/studio/test/import-brand-route.test.ts +120 -0
  290. package/apps/studio/test/import-brand.test.ts +206 -0
  291. package/apps/studio/test/import-tokens.test.ts +722 -0
  292. package/apps/studio/test/input-router.test.ts +33 -0
  293. package/apps/studio/test/inspect-script-syntax.test.ts +53 -0
  294. package/apps/studio/test/media-commit-chain.test.ts +210 -0
  295. package/apps/studio/test/photo-bg-remove-validation.test.ts +71 -0
  296. package/apps/studio/test/photo-canvas-bundle.test.ts +61 -0
  297. package/apps/studio/test/photo-edit-api.test.ts +201 -0
  298. package/apps/studio/test/photo-filters.test.ts +149 -0
  299. package/apps/studio/test/photo-pipeline.test.ts +106 -0
  300. package/apps/studio/test/photo-taxonomy.test.ts +96 -0
  301. package/apps/studio/test/read-annotations.test.ts +164 -0
  302. package/apps/studio/test/readiness.test.ts +13 -11
  303. package/apps/studio/test/scaffold-design.test.ts +122 -0
  304. package/apps/studio/test/shell-importmap.test.ts +49 -0
  305. package/apps/studio/test/text-editability-stamp.test.ts +131 -0
  306. package/apps/studio/test/timeline-parse.test.ts +57 -0
  307. package/apps/studio/test/tool-palette-insert-anchor.test.ts +5 -3
  308. package/apps/studio/test/tour-overlay.test.tsx +16 -0
  309. package/apps/studio/test/undo-stack.test.ts +33 -0
  310. package/apps/studio/test/video-asset.test.ts +5 -5
  311. package/apps/studio/test/video-render-bridge.test.ts +23 -1
  312. package/apps/studio/text-caret.ts +239 -0
  313. package/apps/studio/tool-palette.tsx +49 -21
  314. package/apps/studio/ui-prefs.ts +130 -0
  315. package/apps/studio/undo-stack.ts +94 -2
  316. package/apps/studio/use-annotation-resize.tsx +4 -4
  317. package/apps/studio/use-canvas-media-drop.tsx +40 -1
  318. package/apps/studio/use-chrome-visibility.tsx +8 -2
  319. package/apps/studio/use-selection-set.tsx +21 -0
  320. package/apps/studio/video-comp.tsx +48 -7
  321. package/apps/studio/whats-new.json +149 -0
  322. package/apps/studio/ws.ts +5 -0
  323. package/cli/bin/maude.mjs +6 -6
  324. package/cli/commands/design.mjs +67 -3
  325. package/cli/lib/gitignore-block.mjs +2 -0
  326. package/cli/lib/pkg-root.mjs +107 -0
  327. package/cli/lib/pkg-root.test.mjs +79 -0
  328. package/cli/lib/reconstruct-toolset.test.mjs +194 -0
  329. package/cli/lib/update-check.mjs +8 -0
  330. package/package.json +13 -11
  331. package/plugins/design/dependencies.json +18 -0
  332. package/plugins/design/templates/_shell.html +1 -0
@@ -126,84 +126,132 @@ try {
126
126
  // — both fall through to the frame-step path below.
127
127
  const useRenderer = !!renderLib && format !== 'gif' && !!compId;
128
128
 
129
+ // When the whole-comp renderer path throws we DON'T fail the export. The most
130
+ // common cause is a `RangeError: Maximum call stack size exceeded` from
131
+ // @remotion/web-renderer's guardless recursive DOM precompositing on a
132
+ // deeply-nested comp (RCA issue-video-mp4-rendermediaonweb-stack-overflow):
133
+ // one native recursion level per nested opacity/transform/filter/mask layer,
134
+ // no depth cap. Instead we degrade to the frame-step screenshot + mediabunny
135
+ // path below, which goes through Chromium's native compositor and is immune to
136
+ // that recursion. The one cost is audio — the frame-step path is video-only —
137
+ // so a comp that overflows the audio renderer still exports, just muted. That
138
+ // beats a hard failure with no file. `video.ts` always passes --encode-lib
139
+ // (only --render-lib is conditional), so the fallback has all it needs here.
140
+ let renderFallbackReason = null;
141
+
129
142
  if (useRenderer) {
130
- const t0 = Date.now();
131
- const libSrc = readFileSync(renderLib, 'utf8');
132
- await page.addScriptTag({ content: libSrc, type: 'module' });
133
- await page.waitForFunction(() => typeof window.__maudeRenderVideo__ === 'function', {
134
- timeout: timeoutMs,
135
- });
143
+ try {
144
+ const t0 = Date.now();
145
+ const libSrc = readFileSync(renderLib, 'utf8');
146
+ await page.addScriptTag({ content: libSrc, type: 'module' });
147
+ await page.waitForFunction(() => typeof window.__maudeRenderVideo__ === 'function', {
148
+ timeout: timeoutMs,
149
+ });
136
150
 
137
- const explicitFrames = Number(framesArg);
138
- const frameRange =
139
- Number.isFinite(explicitFrames) && explicitFrames > 0 ? [0, explicitFrames - 1] : null;
151
+ const explicitFrames = Number(framesArg);
152
+ const frameRange =
153
+ Number.isFinite(explicitFrames) && explicitFrames > 0 ? [0, explicitFrames - 1] : null;
140
154
 
141
- const rendered = await page.evaluate(
142
- async ({ compId, container, scale, muted, frameRange, licenseKey }) => {
143
- return window.__maude_render_video__(compId, {
144
- container,
145
- scale,
146
- muted,
155
+ const rendered = await page.evaluate(
156
+ async ({ compId, container, scale, muted, frameRange, licenseKey }) => {
157
+ return window.__maude_render_video__(compId, {
158
+ container,
159
+ scale,
160
+ muted,
161
+ frameRange,
162
+ licenseKey,
163
+ });
164
+ },
165
+ {
166
+ compId,
167
+ container: format,
168
+ scale: deviceScaleFactor,
169
+ muted: !wantAudio,
147
170
  frameRange,
148
171
  licenseKey,
149
- });
150
- },
151
- {
152
- compId,
153
- container: format,
154
- scale: deviceScaleFactor,
155
- muted: !wantAudio,
156
- frameRange,
157
- licenseKey,
158
- }
159
- );
172
+ }
173
+ );
160
174
 
161
- writeFileSync(out, Buffer.from(rendered.b64, 'base64'));
175
+ writeFileSync(out, Buffer.from(rendered.b64, 'base64'));
162
176
 
163
- // Comp meta for the summary (diagnostic only — video.ts reads `container`).
164
- const compMeta = await page.evaluate(
165
- (id) =>
166
- (typeof window.__maude_comps__ === 'function' ? window.__maude_comps__() : []).find(
167
- (c) => c.id === id
168
- ) ?? null,
169
- compId
170
- );
171
- const frameCount = frameRange
172
- ? frameRange[1] - frameRange[0] + 1
173
- : (compMeta?.durationInFrames ?? 0);
174
-
175
- const result = {
176
- fps: compMeta?.fps ?? null,
177
- frameCount,
178
- width: Math.round((compMeta?.width ?? 0) * deviceScaleFactor),
179
- height: Math.round((compMeta?.height ?? 0) * deviceScaleFactor),
180
- out,
181
- bytes: rendered.bytes,
182
- container: rendered.container,
183
- codec: rendered.videoCodec,
184
- audioCodec: rendered.audioCodec,
185
- };
186
- const ms = Date.now() - t0;
187
- console.error(
188
- `✓ rendered ${rendered.container}/${rendered.videoCodec}` +
189
- `${rendered.audioCodec ? `+${rendered.audioCodec}` : ' (muted)'} → ${out} (${rendered.bytes} B) in ${ms}ms`
190
- );
191
- console.log(JSON.stringify(result));
192
- } else {
193
- await frameStepCapture({
194
- page,
195
- handle,
196
- compId,
197
- fpsArg,
198
- framesArg,
199
- dumpDir,
200
- encodeLib,
201
- format,
202
- out,
203
- mode,
204
- deviceScaleFactor,
205
- timeoutMs,
206
- });
177
+ // Comp meta for the summary (diagnostic only — video.ts reads `container`).
178
+ const compMeta = await page.evaluate(
179
+ (id) =>
180
+ (typeof window.__maude_comps__ === 'function' ? window.__maude_comps__() : []).find(
181
+ (c) => c.id === id
182
+ ) ?? null,
183
+ compId
184
+ );
185
+ const frameCount = frameRange
186
+ ? frameRange[1] - frameRange[0] + 1
187
+ : (compMeta?.durationInFrames ?? 0);
188
+
189
+ const result = {
190
+ fps: compMeta?.fps ?? null,
191
+ frameCount,
192
+ width: Math.round((compMeta?.width ?? 0) * deviceScaleFactor),
193
+ height: Math.round((compMeta?.height ?? 0) * deviceScaleFactor),
194
+ out,
195
+ bytes: rendered.bytes,
196
+ container: rendered.container,
197
+ codec: rendered.videoCodec,
198
+ audioCodec: rendered.audioCodec,
199
+ };
200
+ const ms = Date.now() - t0;
201
+ console.error(
202
+ `✓ rendered ${rendered.container}/${rendered.videoCodec}` +
203
+ `${rendered.audioCodec ? `+${rendered.audioCodec}` : ' (muted)'} → ${out} (${rendered.bytes} B) in ${ms}ms`
204
+ );
205
+ console.log(JSON.stringify(result));
206
+ } catch (err) {
207
+ // Collapse newlines — the message carries an in-page (untrusted canvas,
208
+ // DDR-054) error + stack, and it flows to console.error / the job's
209
+ // persisted error, so a forged "\n[FATAL] …" line can't be injected into
210
+ // the dev-server's stderr or the history ledger.
211
+ renderFallbackReason = oneLine(err instanceof Error ? err.message : String(err));
212
+ console.error(
213
+ `⚠ renderMediaOnWeb failed (${renderFallbackReason}); falling back to ` +
214
+ 'frame-step screenshot capture — video will export WITHOUT audio'
215
+ );
216
+ }
217
+ }
218
+
219
+ // Frame-step path: the normal route for gif / ordinary / comp-less artboards
220
+ // (useRenderer === false), AND the graceful-degradation fallback when the
221
+ // renderer above threw (renderFallbackReason !== null).
222
+ if (!useRenderer || renderFallbackReason !== null) {
223
+ try {
224
+ await frameStepCapture({
225
+ page,
226
+ handle,
227
+ compId,
228
+ fpsArg,
229
+ framesArg,
230
+ dumpDir,
231
+ encodeLib,
232
+ format,
233
+ out,
234
+ mode,
235
+ deviceScaleFactor,
236
+ timeoutMs,
237
+ fallbackReason: renderFallbackReason,
238
+ });
239
+ } catch (fallbackErr) {
240
+ // If we only reached the frame-step path because the renderer already
241
+ // failed, surface BOTH failures so a genuine bug isn't hidden behind the
242
+ // fallback's own error.
243
+ if (renderFallbackReason !== null) {
244
+ const fb = oneLine(
245
+ fallbackErr instanceof Error ? fallbackErr.message : String(fallbackErr)
246
+ );
247
+ throw new Error(
248
+ `video export failed on both paths — renderMediaOnWeb: ${renderFallbackReason}; ` +
249
+ `frame-step fallback: ${fb}`,
250
+ { cause: fallbackErr }
251
+ );
252
+ }
253
+ throw fallbackErr;
254
+ }
207
255
  }
208
256
  } finally {
209
257
  await browser.close();
@@ -227,6 +275,10 @@ async function frameStepCapture({
227
275
  mode,
228
276
  deviceScaleFactor,
229
277
  timeoutMs,
278
+ // Set (to the renderer's error message) only when this run is the
279
+ // graceful-degradation fallback for a failed renderMediaOnWeb path; stamps
280
+ // `degraded`/`audioDropped` onto the stdout summary so video.ts can warn.
281
+ fallbackReason = null,
230
282
  }) {
231
283
  const rect0 = await handle.evaluate((el) => {
232
284
  const r = el.getBoundingClientRect();
@@ -352,10 +404,22 @@ async function frameStepCapture({
352
404
  { b64, isGif }
353
405
  );
354
406
  }
407
+ // Machine-readable progress (stdout) — spawnShim parses `MAUDE_PROGRESS`
408
+ // lines → onProgress → job.progress → the live bar in the Exports panel, so
409
+ // a long frame-step render (the renderMediaOnWeb-overflow fallback) shows
410
+ // "N of M" instead of a static "Exporting…". Filtered out of the summary
411
+ // stdout the exporter reads. Human log stays throttled on stderr.
412
+ console.log(`MAUDE_PROGRESS {"current":${f + 1},"total":${frameCount}}`);
355
413
  if (f % 30 === 0) console.error(`frame ${f + 1}/${frameCount}`);
356
414
  }
357
415
 
358
416
  let result = { fps, frameCount, width: outW, height: outH, framePaths };
417
+ // Degradation marker — this run only encodes video (no audio), so when we're
418
+ // standing in for a failed audio renderer, tell the exporter the export is
419
+ // degraded and audio was dropped (RCA issue-video-mp4-rendermediaonweb-stack-overflow).
420
+ if (fallbackReason !== null) {
421
+ result = { ...result, degraded: true, audioDropped: true, fallbackReason };
422
+ }
359
423
  if (encoding) {
360
424
  const enc = await page.evaluate(
361
425
  async ({ isGif }) =>
@@ -450,3 +514,9 @@ async function seekFrame(page, frame, fps, mode) {
450
514
  function cssEscape(s) {
451
515
  return String(s).replace(/["\\\]]/g, '\\$&');
452
516
  }
517
+
518
+ /** Collapse CR/LF runs to a single space — used to neutralize log/ledger
519
+ * injection from untrusted in-page (canvas-origin, DDR-054) error text. */
520
+ function oneLine(s) {
521
+ return String(s).replace(/[\r\n]+/g, ' ');
522
+ }
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env bash
2
+ # audio-search.sh — feature-ai-media-generation (Task 2.5, DDR-164). Reuse-before-
3
+ # you-pay for AUDIO: before generating a new music/SFX/VO track, search the
4
+ # project's own generated audio + the user's ElevenLabs history and prefer an
5
+ # existing suitable track over spending credits. The search + reuse run
6
+ # server-side (the key is resolved by the sidecar), so this is a pure fetch to
7
+ # the running dev server — mirrors generate.sh.
8
+ #
9
+ # Reached via `maude design audio-search` (never a raw bin path — DDR-062).
10
+ #
11
+ # Usage:
12
+ # audio-search.sh --query "<text>" [--root <repo>] [--reuse <historyId>] [--json]
13
+ #
14
+ # Requires a running dev server (caller runs `maude design server-up` first).
15
+ #
16
+ # Stdout (last line, --reuse): the localized /assets/<sha8>.mp3 path.
17
+ # Exit: 0 ok / 1 server problem / 2 bad args / 3 search/reuse failed.
18
+
19
+ set -euo pipefail
20
+
21
+ if ! command -v bun >/dev/null 2>&1; then
22
+ echo "audio-search.sh: bun is required (hard dependency — see plugins/design/dependencies.json)." >&2
23
+ echo " Install: curl -fsSL https://bun.sh/install | bash" >&2
24
+ exit 1
25
+ fi
26
+
27
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
28
+ exec bun run "$SCRIPT_DIR/_audio-search.mjs" "$@"
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env bash
2
+ # generate.sh — feature-ai-media-generation (Phase 0, DDR-16x). Headless BYOK
3
+ # AI-media generation: POST a GenRequest to the running dev server's privileged
4
+ # /_api/generate-jobs route, poll the job to completion, and print the produced
5
+ # content-addressed asset path (`/assets/<sha8>.<ext>`).
6
+ #
7
+ # The thin, non-browser sibling of the studio generate dialog — the provider call
8
+ # happens SERVER-SIDE (the sidecar resolves the key from the OS keychain /
9
+ # ~/.config/maude/keys.json and calls the provider directly), so this verb is a
10
+ # pure JSON curl + poll, exactly like photo-adjust.sh. No client-side inference,
11
+ # so a harness canvas + agent-browser would be pure overhead.
12
+ #
13
+ # Reached via `maude design generate` (never a raw bin path — DDR-062).
14
+ #
15
+ # Usage:
16
+ # generate.sh --prompt "<text>" [--provider gemini|elevenlabs] [--model <id>]
17
+ # [--modality image|audio|video] [--aspect 16:9] [--source assets/<sha8>.<ext>]
18
+ # [--kind music|sfx|tts] [--voice <voice_id>] [--duration <seconds>]
19
+ # [--root <repo>] [--timeout <sec>]
20
+ #
21
+ # --source turns an IMAGE call into a maskless EDIT (Nano Banana): the content-
22
+ # addressed source image is read server-side into the request and the prompt
23
+ # describes the change; a NEW content-addressed asset is produced (the original
24
+ # is never mutated). For --modality video it is the image-to-video SEED (a still
25
+ # → a clip, so a generated clip can match a generated hero's style).
26
+ #
27
+ # --modality audio (provider elevenlabs): --kind music (default) | sfx | tts.
28
+ # tts needs --voice <voice_id>; music/sfx take an optional --duration in seconds.
29
+ # Produces assets/<sha8>.mp3. (Transcription is a separate verb: `maude design
30
+ # transcribe`, which writes SRT/VTT.)
31
+ #
32
+ # --modality video (provider gemini / Veo 3.1): ASYNC — the clip takes ~1–10 min;
33
+ # the poll timeout defaults to 600s for video (180s otherwise). Produces
34
+ # assets/<sha8>.mp4 + a provenance assets/<sha8>.footage.json stub so the clip is
35
+ # reel-ready (see /design:reel Step 1.5).
36
+ #
37
+ # The key is NEVER passed here — it lives server-side. Add it in Settings
38
+ # (⌘,) or drop it into ~/.config/maude/keys.json (mode 0600).
39
+ #
40
+ # Requires a running dev server (caller runs `maude design server-up` first);
41
+ # reads the port from <designRoot>/_server.json.
42
+ #
43
+ # Stdout (last line): the produced asset path `/assets/<sha8>.<ext>` (for $(...)).
44
+ # Stderr: progress / diagnostics.
45
+ # Exit: 0 ok / 1 server problem / 2 bad args / 3 generation failed.
46
+
47
+ set -euo pipefail
48
+
49
+ PROMPT="" PROVIDER="gemini" MODEL="" MODALITY="image" ASPECT="" SOURCE="" REPO="" TIMEOUT=""
50
+ # Audio params (Phase 2) — kind = music|sfx|tts; voice = an ElevenLabs voice_id
51
+ # (required for tts); duration = seconds (music/sfx length).
52
+ KIND="" VOICE="" DURATION=""
53
+
54
+ while [ $# -gt 0 ]; do
55
+ case "$1" in
56
+ --prompt) PROMPT="$2"; shift 2 ;;
57
+ --provider) PROVIDER="$2"; shift 2 ;;
58
+ --model) MODEL="$2"; shift 2 ;;
59
+ --modality) MODALITY="$2"; shift 2 ;;
60
+ --aspect) ASPECT="$2"; shift 2 ;;
61
+ --source) SOURCE="$2"; shift 2 ;;
62
+ --kind) KIND="$2"; shift 2 ;;
63
+ --voice) VOICE="$2"; shift 2 ;;
64
+ --duration) DURATION="$2"; shift 2 ;;
65
+ --root) REPO="$2"; shift 2 ;;
66
+ --timeout) TIMEOUT="$2"; shift 2 ;;
67
+ --help|-h) sed -n '2,41p' "$0" | sed 's/^# \?//'; exit 0 ;;
68
+ *) echo "generate.sh: unknown arg '$1'" >&2; exit 2 ;;
69
+ esac
70
+ done
71
+
72
+ # generate.sh produces MEDIA (image / audio) from a prompt. Transcription is a
73
+ # different shape (audio → captions) reached via `maude design transcribe`, which
74
+ # writes SRT/VTT files — not this verb, whose contract is "print the produced
75
+ # asset path".
76
+ [ -n "$PROMPT" ] || { echo "generate.sh: --prompt is required" >&2; exit 2; }
77
+ command -v jq >/dev/null 2>&1 || { echo "generate.sh: jq is required" >&2; exit 1; }
78
+
79
+ # Async video (Veo) takes minutes — default the poll window wider than the
80
+ # seconds-fast image/audio calls unless the caller pinned --timeout explicitly.
81
+ if [ -z "$TIMEOUT" ]; then
82
+ if [ "$MODALITY" = "video" ]; then TIMEOUT="600"; else TIMEOUT="180"; fi
83
+ fi
84
+
85
+ if [ -z "$REPO" ]; then
86
+ REPO="${CLAUDE_PROJECT_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
87
+ fi
88
+ DESIGN_ROOT="$REPO/.design"
89
+ [ -d "$DESIGN_ROOT" ] || { echo "generate.sh: no .design/ under $REPO" >&2; exit 1; }
90
+
91
+ STATE="$DESIGN_ROOT/_server.json"
92
+ [ -f "$STATE" ] || { echo "generate.sh: no _server.json (start the dev server first)" >&2; exit 1; }
93
+ PORT=$(jq -r '.port // empty' "$STATE" 2>/dev/null)
94
+ [ -n "$PORT" ] || { echo "generate.sh: could not read port from $STATE" >&2; exit 1; }
95
+
96
+ BASE="http://127.0.0.1:$PORT/_api/generate-jobs"
97
+
98
+ # Normalize a --source to the `assets/<sha8>.<ext>` form the route validates
99
+ # (strip a leading slash the canvas-relative writers emit).
100
+ SOURCE="${SOURCE#/}"
101
+
102
+ # Build the audio params object (only the set keys) — audioKind / voice_id /
103
+ # durationSeconds are opaque to the spine; each adapter validates its own subset.
104
+ PARAMS=$(jq -n --arg kind "$KIND" --arg voice "$VOICE" --arg dur "$DURATION" '
105
+ {}
106
+ + (if $kind != "" then { audioKind: $kind } else {} end)
107
+ + (if $voice != "" then { voice_id: $voice } else {} end)
108
+ + (if $dur != "" then { durationSeconds: ($dur|tonumber) } else {} end)')
109
+
110
+ # Build the request body — jq handles all prompt escaping. Omit empty optionals.
111
+ BODY=$(jq -n \
112
+ --arg modality "$MODALITY" --arg provider "$PROVIDER" --arg model "$MODEL" \
113
+ --arg prompt "$PROMPT" --arg aspect "$ASPECT" --arg source "$SOURCE" \
114
+ --argjson params "$PARAMS" '
115
+ { modality: $modality, provider: $provider }
116
+ + (if $prompt != "" then { prompt: $prompt } else {} end)
117
+ + (if $model != "" then { model: $model } else {} end)
118
+ + (if $aspect != "" then { aspectRatio: $aspect } else {} end)
119
+ + (if $source != "" then { sourceAsset: $source } else {} end)
120
+ + (if ($params|length) > 0 then { params: $params } else {} end)')
121
+
122
+ echo "generate.sh: submitting to $PROVIDER ($MODALITY)…" >&2
123
+ RESP=$(curl -s -X POST -H 'Content-Type: application/json' -d "$BODY" "$BASE")
124
+ JOB_ID=$(printf '%s' "$RESP" | jq -r '.jobId // empty' 2>/dev/null || echo "")
125
+ if [ -z "$JOB_ID" ]; then
126
+ echo "generate.sh: enqueue rejected: $RESP" >&2
127
+ exit 3
128
+ fi
129
+ echo "generate.sh: job $JOB_ID queued — polling…" >&2
130
+
131
+ # Poll the job list until this job is done/failed, or the timeout elapses.
132
+ DEADLINE=$(( $(date +%s) + TIMEOUT ))
133
+ while :; do
134
+ JOBS=$(curl -s "$BASE" 2>/dev/null || echo '{}')
135
+ JOB=$(printf '%s' "$JOBS" | jq -c --arg id "$JOB_ID" '.jobs[]? | select(.id == $id)' 2>/dev/null || echo "")
136
+ STATUS=$(printf '%s' "$JOB" | jq -r '.status // empty' 2>/dev/null || echo "")
137
+ case "$STATUS" in
138
+ done)
139
+ ASSET=$(printf '%s' "$JOB" | jq -r '.assets[0] // empty' 2>/dev/null || echo "")
140
+ [ -n "$ASSET" ] || { echo "generate.sh: job done but produced no asset" >&2; exit 3; }
141
+ # Normalize to the leading-slash canvas-relative form writers use.
142
+ printf '/%s\n' "${ASSET#/}"
143
+ exit 0 ;;
144
+ failed)
145
+ ERR=$(printf '%s' "$JOB" | jq -r '.error // "unknown error"' 2>/dev/null || echo "unknown")
146
+ echo "generate.sh: generation failed: $ERR" >&2
147
+ exit 3 ;;
148
+ esac
149
+ if [ "$(date +%s)" -ge "$DEADLINE" ]; then
150
+ echo "generate.sh: timed out after ${TIMEOUT}s (job still $STATUS)" >&2
151
+ exit 3
152
+ fi
153
+ sleep 2
154
+ done
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bash
2
+ # import-asset.sh — hardened local-file SVG/PDF ingestion. Thin shim over
3
+ # _import-asset.mjs; reached via `maude design import-asset` (DDR-062), never
4
+ # a raw bin path. See _import-asset.mjs + DDR-167 for the full security
5
+ # rationale. Requires bun (not the node/bun fallback fetch-asset.sh uses) —
6
+ # _import-asset.mjs imports the `.ts` SVGO engine module directly, same
7
+ # constraint as svg-optimize.sh.
8
+ #
9
+ # Usage:
10
+ # import-asset.sh <local-path> --root <repo> [--design-root .design]
11
+ # [--kind svg|pdf|raster] [--json]
12
+ #
13
+ # stdout on success = one reference path per line (e.g. /assets/a44d3d60.svg).
14
+ # PDF import is not yet available (DDR-167 addendum) — the verb accepts a
15
+ # .pdf input and fails loud naming why, rather than silently rejecting it as
16
+ # an unknown flag. `raster` (PNG/JPEG, magic-byte sniffed) content-addresses
17
+ # a local image as-is — added for DDR-174/T15's vision-reconstruction source.
18
+ #
19
+ # Exit: 0 ok · 1 not-yet-available/other · 2 usage · 3 sanitize/validation
20
+ # reject · 4 read/parse error · 5 unsupported media type ·
21
+ # 6 write/containment error.
22
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
23
+
24
+ case "$1" in
25
+ --help|-h) sed -n '2,17p' "$0" | sed 's/^# \?//'; exit 0 ;;
26
+ esac
27
+
28
+ if ! command -v bun >/dev/null 2>&1; then
29
+ echo "import-asset.sh: bun is required (hard dependency — see plugins/design/dependencies.json)." >&2
30
+ echo " Install: curl -fsSL https://bun.sh/install | bash" >&2
31
+ exit 1
32
+ fi
33
+
34
+ exec bun run "$SCRIPT_DIR/_import-asset.mjs" "$@"
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env bash
2
+ # import-brand.sh — brand-file typed-cue extraction (DDR-173). Thin shim over
3
+ # _import-brand.mjs; reached via `maude design import-brand` (DDR-062), never
4
+ # a raw bin path. Operates ONLY on an already-DDR-167-sanitized SVG asset
5
+ # (as produced by `maude design import-asset`) — never re-reads or
6
+ # re-sanitizes the original brand file (DDR-173 Decision 2: no parallel,
7
+ # ungated read path). Requires bun — _import-brand.mjs imports
8
+ # _import-tokens.mjs's `.mjs` grammar reuse and happy-dom directly.
9
+ #
10
+ # Usage:
11
+ # import-brand.sh <sanitized-svg-path> --root <repo> [--design-root .design] [--json]
12
+ #
13
+ # stdout on success = the typed payload `{ palette, fonts, logoRef, logoRasterRef }`.
14
+ #
15
+ # Exit: 0 ok · 1 other · 2 usage · 3 validation/hardening reject ·
16
+ # 4 read/parse error · 6 write/containment error.
17
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
18
+
19
+ case "$1" in
20
+ --help|-h) sed -n '2,15p' "$0" | sed 's/^# \?//'; exit 0 ;;
21
+ esac
22
+
23
+ if ! command -v bun >/dev/null 2>&1; then
24
+ echo "import-brand.sh: bun is required (hard dependency — see plugins/design/dependencies.json)." >&2
25
+ echo " Install: curl -fsSL https://bun.sh/install | bash" >&2
26
+ exit 1
27
+ fi
28
+
29
+ exec bun run "$SCRIPT_DIR/_import-brand.mjs" "$@"
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env bash
2
+ # import-tokens.sh — token-file import (W3C design-tokens / Style-Dictionary
3
+ # JSON / raw CSS custom properties -> the DS CSS-variable contract). Thin
4
+ # shim over _import-tokens.mjs; reached via `maude design import-tokens`
5
+ # (DDR-062), never a raw bin path. See _import-tokens.mjs + DDR-172 for the
6
+ # full mapping contract + security rationale. Requires bun — _import-tokens.mjs
7
+ # imports the `.ts` palette/paths modules directly, same constraint as
8
+ # import-asset.sh.
9
+ #
10
+ # All args are forwarded quoted ("$@") — never unquoted or eval-expanded
11
+ # (DDR-172 Decision 8 wrapper-hygiene requirement; the charset/shape
12
+ # validation itself happens in _import-tokens.mjs, not here).
13
+ #
14
+ # Usage:
15
+ # import-tokens.sh <token-file> --root <repo> [--design-root .design]
16
+ # [--ds <name> | --new-ds <name>] [--theme <name>]
17
+ # [--force-insert] [--json]
18
+ #
19
+ # Exit: 0 ok · 1 other · 2 usage · 3 validation/mapping reject ·
20
+ # 4 read/parse error · 5 unsupported format · 6 write/containment error.
21
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
22
+
23
+ case "$1" in
24
+ --help|-h) sed -n '2,16p' "$0" | sed 's/^# \?//'; exit 0 ;;
25
+ esac
26
+
27
+ if ! command -v bun >/dev/null 2>&1; then
28
+ echo "import-tokens.sh: bun is required (hard dependency — see plugins/design/dependencies.json)." >&2
29
+ echo " Install: curl -fsSL https://bun.sh/install | bash" >&2
30
+ exit 1
31
+ fi
32
+
33
+ exec bun run "$SCRIPT_DIR/_import-tokens.mjs" "$@"
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env bash
2
+ # ingest-footage.sh — thin shim over _ingest-footage.mjs; reached via
3
+ # `maude design ingest-footage` (DDR-062), never a raw bin path. See
4
+ # _ingest-footage.mjs for the full rationale (feature-footage-analysis-director).
5
+ #
6
+ # Usage:
7
+ # ingest-footage.sh <dir> --root <repo> [--design-root .design]
8
+ # [--recursive] [--max-bytes N]
9
+ #
10
+ # stdout on success = a JSON manifest { clips, skipped, assetsDir }.
11
+ # Exit: 0 ok (even with skips) · 2 usage · 6 write/containment error · 1 other.
12
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
13
+
14
+ case "$1" in
15
+ --help|-h) sed -n '2,14p' "$0" | sed 's/^# \?//'; exit 0 ;;
16
+ esac
17
+
18
+ # Prefer node (always present with a maude install); fall back to bun in a dev
19
+ # tree that has bun but a shimmed node. The module is pure Node ESM — no .ts.
20
+ if command -v node >/dev/null 2>&1; then
21
+ exec node "$SCRIPT_DIR/_ingest-footage.mjs" "$@"
22
+ elif command -v bun >/dev/null 2>&1; then
23
+ exec bun run "$SCRIPT_DIR/_ingest-footage.mjs" "$@"
24
+ else
25
+ echo "ingest-footage.sh: node or bun is required." >&2
26
+ exit 1
27
+ fi