@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
@@ -0,0 +1,223 @@
1
+ // SetupChecklist — DDR-166 plan, Phase 2 (T7/T8). Design-setup progress surface
2
+ // (project / design system / first canvas / brand assets), mirroring
3
+ // ReadinessList.jsx's shape but backed by GET /_api/setup-readiness instead of
4
+ // /_api/preflight. Pure detect-and-guide: never installs or mutates anything.
5
+ //
6
+ // "Bring my existing brand" (T8) now opens the real in-app ingestion panel
7
+ // (T12, DDR-173) — `onBringBrand` is threaded down the same way `onStartTour`
8
+ // already is; when absent (an older mount site not yet updated), falls back
9
+ // to the public docs link this used to be a stub for.
10
+
11
+ import { useCallback, useEffect, useState } from 'react';
12
+
13
+ /** Fetch + cache the design-setup readiness report. `refresh()` re-probes. */
14
+ export function useSetupReadiness(enabled = true) {
15
+ const [report, setReport] = useState(null); // { ready, items } | null
16
+ const [loading, setLoading] = useState(enabled);
17
+
18
+ const refresh = useCallback(() => {
19
+ setLoading(true);
20
+ return fetch('/_api/setup-readiness')
21
+ .then((r) => r.json())
22
+ .then((d) => {
23
+ setReport(d && Array.isArray(d.items) ? d : null);
24
+ setLoading(false);
25
+ return d;
26
+ })
27
+ .catch(() => {
28
+ setReport(null);
29
+ setLoading(false);
30
+ return null;
31
+ });
32
+ }, []);
33
+
34
+ useEffect(() => {
35
+ if (!enabled) return undefined;
36
+ let alive = true;
37
+ fetch('/_api/setup-readiness')
38
+ .then((r) => r.json())
39
+ .then((d) => alive && (setReport(d && Array.isArray(d.items) ? d : null), setLoading(false)))
40
+ .catch(() => alive && (setReport(null), setLoading(false)));
41
+ return () => {
42
+ alive = false;
43
+ };
44
+ }, [enabled]);
45
+
46
+ return { report, loading, refresh };
47
+ }
48
+
49
+ function StatusIcon({ present }) {
50
+ if (present)
51
+ return (
52
+ <svg
53
+ width="14"
54
+ height="14"
55
+ viewBox="0 0 16 16"
56
+ fill="none"
57
+ stroke="currentColor"
58
+ strokeWidth="1.6"
59
+ strokeLinecap="round"
60
+ strokeLinejoin="round"
61
+ aria-hidden="true"
62
+ >
63
+ <polyline points="3 8.4 6.4 11.8 13 4.4" />
64
+ </svg>
65
+ );
66
+ return (
67
+ <svg
68
+ width="14"
69
+ height="14"
70
+ viewBox="0 0 16 16"
71
+ fill="none"
72
+ stroke="currentColor"
73
+ strokeWidth="1.6"
74
+ strokeLinecap="round"
75
+ strokeLinejoin="round"
76
+ aria-hidden="true"
77
+ >
78
+ <circle cx="8" cy="8" r="5.5" />
79
+ </svg>
80
+ );
81
+ }
82
+
83
+ export function SetupChecklist({ report, loading, refresh, onStartTour, onBringBrand }) {
84
+ return (
85
+ <div className="setup-cl">
86
+ <ul className="setup-cl-list">
87
+ {report?.items?.map((it) => (
88
+ <li
89
+ key={it.id}
90
+ className={`setup-cl-row setup-cl-row--${it.status}`}
91
+ data-testid={`setup-cl-row-${it.id}`}
92
+ >
93
+ <span className="setup-cl-ic" aria-hidden="true">
94
+ <StatusIcon present={it.status === 'present'} />
95
+ </span>
96
+ <span className="setup-cl-tx">
97
+ <span className="setup-cl-label">{it.label}</span>
98
+ <span className="setup-cl-detail">{it.detail}</span>
99
+ </span>
100
+ </li>
101
+ ))}
102
+ </ul>
103
+ <div className="setup-cl-foot">
104
+ {onStartTour && (
105
+ <button
106
+ type="button"
107
+ data-testid="setup-cl-start-tour"
108
+ className="btn btn--primary btn--sm"
109
+ onClick={onStartTour}
110
+ >
111
+ Start guided setup
112
+ </button>
113
+ )}
114
+ {onBringBrand ? (
115
+ <button
116
+ type="button"
117
+ data-testid="onboarding-bring-brand"
118
+ className="btn btn--ghost btn--sm setup-cl-brand"
119
+ onClick={onBringBrand}
120
+ >
121
+ Bring my existing brand
122
+ </button>
123
+ ) : (
124
+ <a
125
+ href="https://maude.sh/docs/getting-started"
126
+ target="_blank"
127
+ rel="noreferrer noopener"
128
+ data-testid="onboarding-bring-brand"
129
+ className="btn btn--ghost btn--sm setup-cl-brand"
130
+ >
131
+ Bring my existing brand
132
+ </a>
133
+ )}
134
+ {refresh && (
135
+ <button
136
+ type="button"
137
+ className="btn btn--ghost btn--sm setup-cl-recheck"
138
+ onClick={refresh}
139
+ disabled={loading}
140
+ >
141
+ {loading ? 'Checking…' : 'Re-check'}
142
+ </button>
143
+ )}
144
+ </div>
145
+ </div>
146
+ );
147
+ }
148
+
149
+ // Standalone modal, reachable from Help ▸ Quick setup… — reuses the shared
150
+ // help-modal chrome (backdrop + header + body), same shape as ReadinessDialog.
151
+ export default function SetupChecklistDialog({ open, onClose, onStartTour, onBringBrand }) {
152
+ const { report, loading, refresh } = useSetupReadiness(open);
153
+ useEffect(() => {
154
+ if (!open) return undefined;
155
+ const onKey = (e) => e.key === 'Escape' && onClose();
156
+ window.addEventListener('keydown', onKey);
157
+ return () => window.removeEventListener('keydown', onKey);
158
+ }, [open, onClose]);
159
+ if (!open) return null;
160
+ return (
161
+ <div
162
+ className="help-modal-backdrop"
163
+ role="presentation"
164
+ onMouseDown={(e) => {
165
+ if (e.target === e.currentTarget) onClose();
166
+ }}
167
+ >
168
+ <div
169
+ className="help-modal setup-cl-modal"
170
+ role="dialog"
171
+ aria-modal="true"
172
+ aria-labelledby="setup-cl-modal-title"
173
+ >
174
+ <header className="help-modal-hd">
175
+ <span className="title" id="setup-cl-modal-title">
176
+ Quick setup
177
+ </span>
178
+ <button
179
+ type="button"
180
+ className="help-modal-close"
181
+ aria-label="Close (Esc)"
182
+ onClick={onClose}
183
+ >
184
+ ×
185
+ </button>
186
+ </header>
187
+ <div className="help-modal-body">
188
+ <p className="setup-cl-note">
189
+ Empty → design system → first canvas → your first AI edit. Ask the Assistant to build
190
+ each step, or take the guided tour to see where everything lives.
191
+ </p>
192
+ {report ? (
193
+ <SetupChecklist
194
+ report={report}
195
+ loading={loading}
196
+ refresh={refresh}
197
+ onStartTour={
198
+ onStartTour
199
+ ? () => {
200
+ onClose();
201
+ onStartTour();
202
+ }
203
+ : undefined
204
+ }
205
+ onBringBrand={
206
+ onBringBrand
207
+ ? () => {
208
+ onClose();
209
+ onBringBrand();
210
+ }
211
+ : undefined
212
+ }
213
+ />
214
+ ) : (
215
+ <p className="setup-cl-note">
216
+ {loading ? 'Checking…' : "Couldn't reach the setup probe."}
217
+ </p>
218
+ )}
219
+ </div>
220
+ </div>
221
+ </div>
222
+ );
223
+ }
@@ -0,0 +1,160 @@
1
+ // StickerPicker.jsx — feature-whiteboard-annotation-improvements, Phase 4.
2
+ //
3
+ // Searchable, pack-grouped picker for MAUDE's bundled whiteboard sticker packs
4
+ // (GET /_api/stickers — main-origin only, DDR-054/DDR-088; mirrors AssetPicker's
5
+ // shell/scrim treatment in app.jsx). Triggered from the canvas-side tool
6
+ // palette's Stickers button via `postMessage({dgn:'open-sticker-picker'})`;
7
+ // `onPick(sticker)` hands the caller `{ file, keywords, url }` — app.jsx
8
+ // re-uploads the picked PNG's bytes through the existing /_api/asset lane
9
+ // (content-addressed, canvas-origin-allowlisted) and relays the resulting
10
+ // project path down to the canvas, exactly like the replace-annotation-media
11
+ // flow already does for AssetPicker.
12
+
13
+ import { useEffect, useMemo, useState } from 'react';
14
+
15
+ function StIcon({ name, size = 15 }) {
16
+ if (name === 'x') {
17
+ return (
18
+ <svg width={size} height={size} viewBox="0 0 16 16" fill="none" aria-hidden="true">
19
+ <path
20
+ d="M4 4l8 8M12 4l-8 8"
21
+ stroke="currentColor"
22
+ strokeWidth="1.6"
23
+ strokeLinecap="round"
24
+ />
25
+ </svg>
26
+ );
27
+ }
28
+ return null;
29
+ }
30
+
31
+ export default function StickerPicker({ onPick, onClose }) {
32
+ const [packs, setPacks] = useState(null); // null = loading
33
+ const [query, setQuery] = useState('');
34
+
35
+ useEffect(() => {
36
+ let alive = true;
37
+ fetch('/_api/stickers')
38
+ .then((r) => r.json())
39
+ .then((j) => alive && setPacks(j.ok ? j.packs : []))
40
+ .catch(() => alive && setPacks([]));
41
+ return () => {
42
+ alive = false;
43
+ };
44
+ }, []);
45
+
46
+ useEffect(() => {
47
+ const onKey = (e) => {
48
+ if (e.key === 'Escape') {
49
+ e.stopPropagation();
50
+ onClose();
51
+ }
52
+ };
53
+ window.addEventListener('keydown', onKey, true);
54
+ return () => window.removeEventListener('keydown', onKey, true);
55
+ }, [onClose]);
56
+
57
+ const filteredPacks = useMemo(() => {
58
+ if (!packs) return [];
59
+ const q = query.trim().toLowerCase();
60
+ if (!q) return packs;
61
+ return packs
62
+ .map((pack) => ({
63
+ ...pack,
64
+ stickers: pack.stickers.filter(
65
+ (s) =>
66
+ s.file.toLowerCase().includes(q) ||
67
+ (s.keywords || []).some((k) => k.toLowerCase().includes(q))
68
+ ),
69
+ }))
70
+ .filter((pack) => pack.stickers.length > 0);
71
+ }, [packs, query]);
72
+
73
+ const totalShown = filteredPacks.reduce((n, p) => n + p.stickers.length, 0);
74
+
75
+ return (
76
+ <div
77
+ className="st-scrim"
78
+ role="presentation"
79
+ onMouseDown={(e) => {
80
+ if (e.target === e.currentTarget) onClose();
81
+ }}
82
+ >
83
+ <div
84
+ className="st-dialog st-sticker-picker"
85
+ role="dialog"
86
+ aria-modal="true"
87
+ aria-label="Stickers"
88
+ >
89
+ <div className="st-dialog-hd">
90
+ <span className="st-dialog-title">Stickers</span>
91
+ <button type="button" className="st-iconbtn" aria-label="Close" onClick={onClose}>
92
+ <StIcon name="x" size={15} />
93
+ </button>
94
+ </div>
95
+ <div className="st-dialog-bd">
96
+ <input
97
+ className="input"
98
+ type="text"
99
+ value={query}
100
+ onChange={(e) => setQuery(e.target.value)}
101
+ placeholder="Search stickers…"
102
+ aria-label="Search stickers"
103
+ autoFocus
104
+ />
105
+ <div className="st-sp-body">
106
+ {packs == null ? (
107
+ <div className="st-sp-empty">Loading…</div>
108
+ ) : totalShown === 0 ? (
109
+ <div className="st-sp-empty">
110
+ {query.trim() ? `No stickers match "${query.trim()}"` : 'No stickers bundled'}
111
+ </div>
112
+ ) : (
113
+ filteredPacks.map((pack) => (
114
+ <div key={pack.slug}>
115
+ <div className="st-sp-pack-hd">
116
+ <span className="st-sp-pack-name">{pack.name}</span>
117
+ {pack.author && <span className="st-sp-pack-author">by {pack.author}</span>}
118
+ </div>
119
+ <div className="st-sp-grid">
120
+ {pack.stickers.map((s) => (
121
+ <button
122
+ type="button"
123
+ key={s.file}
124
+ className="st-sp-cell"
125
+ title={s.keywords?.[0] || s.file}
126
+ onClick={() => onPick(s)}
127
+ >
128
+ <img className="st-sp-thumb" src={s.url} alt={s.keywords?.[0] || s.file} loading="lazy" />
129
+ </button>
130
+ ))}
131
+ </div>
132
+ </div>
133
+ ))
134
+ )}
135
+ </div>
136
+ </div>
137
+ {packs && packs.length > 0 && (
138
+ <div className="st-sp-ft">
139
+ {packs.map((pack) => (
140
+ <span key={pack.slug}>
141
+ {pack.name}
142
+ {pack.author ? ` — ${pack.author}` : ''}
143
+ {pack.attributionUrl ? (
144
+ <>
145
+ {' '}
146
+ (
147
+ <a href={pack.attributionUrl} target="_blank" rel="noreferrer">
148
+ source
149
+ </a>
150
+ )
151
+ </>
152
+ ) : null}
153
+ </span>
154
+ ))}
155
+ </div>
156
+ )}
157
+ </div>
158
+ </div>
159
+ );
160
+ }
@@ -112,7 +112,7 @@ export default function TimelinePanel({
112
112
  total = 0,
113
113
  frame = 0,
114
114
  playing = false,
115
- loop = true,
115
+ loop = false,
116
116
  onSeek,
117
117
  onPlay,
118
118
  onPause,
@@ -145,6 +145,17 @@ export default function TimelinePanel({
145
145
  const clamped = clamp(Math.round(frame), 0, totalFrames - 1);
146
146
  const trackRef = useRef(null);
147
147
  const draggingRef = useRef(false);
148
+ const rootRef = useRef(null);
149
+ // Focus the dock the moment it opens. The transport shortcuts (Space play,
150
+ // arrow frame-step) live on the SHELL window, so they only fire when focus is
151
+ // in the shell — but opening the Timeline via ⌘⇧T while focus sat in the
152
+ // canvas iframe (the common case after any text/element interaction) used to
153
+ // leave focus stuck in the iframe, so Space/arrows silently did nothing.
154
+ // Pulling focus here on mount (mount === open, the panel is conditionally
155
+ // rendered) hands the transport keys a shell focus target immediately.
156
+ useEffect(() => {
157
+ rootRef.current?.focus();
158
+ }, []);
148
159
  // Drag-to-retime a sequence's duration: { index, startX, startDur, rowW, curDur }.
149
160
  const [retimeDrag, setRetimeDrag] = useState(null);
150
161
  // Drag the block body to move a clip's `from`: { index, startX, startFrom, rowW, curFrom }.
@@ -337,8 +348,10 @@ export default function TimelinePanel({
337
348
 
338
349
  return (
339
350
  <aside
351
+ ref={rootRef}
352
+ tabIndex={-1}
340
353
  className={`tl-panel${resizing ? ' is-resizing' : ''}${dropActive ? ' is-drop' : ''}`}
341
- style={height ? { height } : undefined}
354
+ style={{ ...(height ? { height } : {}), outline: 'none' }}
342
355
  onDragOver={(e) => {
343
356
  if (!onDropMedia || !hasFiles(e.dataTransfer)) return;
344
357
  e.preventDefault();