@agent-native/core 0.92.11 → 0.93.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 (777) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +45 -0
  3. package/corpus/core/docs/content/automation-connectors.mdx +80 -0
  4. package/corpus/core/docs/content/extensions.mdx +8 -0
  5. package/corpus/core/docs/content/locales/ar-SA/extensions.mdx +8 -0
  6. package/corpus/core/docs/content/locales/ar-SA/messaging.mdx +84 -15
  7. package/corpus/core/docs/content/locales/ar-SA/template-clips.mdx +1 -0
  8. package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +1 -0
  9. package/corpus/core/docs/content/locales/de-DE/extensions.mdx +10 -0
  10. package/corpus/core/docs/content/locales/de-DE/messaging.mdx +92 -15
  11. package/corpus/core/docs/content/locales/de-DE/template-clips.mdx +1 -0
  12. package/corpus/core/docs/content/locales/de-DE/template-design.mdx +1 -0
  13. package/corpus/core/docs/content/locales/es-ES/extensions.mdx +10 -0
  14. package/corpus/core/docs/content/locales/es-ES/messaging.mdx +91 -15
  15. package/corpus/core/docs/content/locales/es-ES/template-clips.mdx +1 -0
  16. package/corpus/core/docs/content/locales/es-ES/template-design.mdx +1 -0
  17. package/corpus/core/docs/content/locales/fr-FR/extensions.mdx +10 -0
  18. package/corpus/core/docs/content/locales/fr-FR/messaging.mdx +91 -15
  19. package/corpus/core/docs/content/locales/fr-FR/template-clips.mdx +1 -0
  20. package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +1 -0
  21. package/corpus/core/docs/content/locales/hi-IN/extensions.mdx +8 -0
  22. package/corpus/core/docs/content/locales/hi-IN/messaging.mdx +81 -15
  23. package/corpus/core/docs/content/locales/hi-IN/template-clips.mdx +1 -0
  24. package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +1 -0
  25. package/corpus/core/docs/content/locales/ja-JP/extensions.mdx +9 -0
  26. package/corpus/core/docs/content/locales/ja-JP/messaging.mdx +81 -15
  27. package/corpus/core/docs/content/locales/ja-JP/template-clips.mdx +1 -0
  28. package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +1 -0
  29. package/corpus/core/docs/content/locales/ko-KR/extensions.mdx +8 -0
  30. package/corpus/core/docs/content/locales/ko-KR/messaging.mdx +80 -15
  31. package/corpus/core/docs/content/locales/ko-KR/template-clips.mdx +1 -0
  32. package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +1 -0
  33. package/corpus/core/docs/content/locales/pt-BR/extensions.mdx +9 -0
  34. package/corpus/core/docs/content/locales/pt-BR/messaging.mdx +88 -15
  35. package/corpus/core/docs/content/locales/pt-BR/template-clips.mdx +1 -0
  36. package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +1 -0
  37. package/corpus/core/docs/content/locales/zh-CN/extensions.mdx +6 -0
  38. package/corpus/core/docs/content/locales/zh-CN/messaging.mdx +78 -15
  39. package/corpus/core/docs/content/locales/zh-CN/template-clips.mdx +1 -0
  40. package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +1 -0
  41. package/corpus/core/docs/content/locales/zh-TW/extensions.mdx +6 -0
  42. package/corpus/core/docs/content/locales/zh-TW/messaging.mdx +78 -15
  43. package/corpus/core/docs/content/locales/zh-TW/template-clips.mdx +1 -0
  44. package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +1 -0
  45. package/corpus/core/docs/content/messaging.mdx +227 -45
  46. package/corpus/core/docs/content/template-clips.mdx +3 -0
  47. package/corpus/core/docs/content/template-design.mdx +4 -0
  48. package/corpus/core/package.json +5 -1
  49. package/corpus/core/src/a2a/artifact-response.ts +131 -2
  50. package/corpus/core/src/a2a/client.ts +10 -0
  51. package/corpus/core/src/a2a/handlers.ts +40 -76
  52. package/corpus/core/src/a2a/types.ts +2 -0
  53. package/corpus/core/src/agent/durable-background.ts +24 -0
  54. package/corpus/core/src/agent/production-agent.ts +48 -5
  55. package/corpus/core/src/agent/run-manager.ts +171 -20
  56. package/corpus/core/src/agent/run-store.ts +297 -42
  57. package/corpus/core/src/agent/types.ts +23 -0
  58. package/corpus/core/src/audit/record.ts +31 -0
  59. package/corpus/core/src/audit/store.ts +69 -3
  60. package/corpus/core/src/audit/types.ts +13 -0
  61. package/corpus/core/src/automation/index.ts +802 -0
  62. package/corpus/core/src/cli/create.ts +12 -5
  63. package/corpus/core/src/cli/design-connect.ts +596 -36
  64. package/corpus/core/src/client/AgentPanel.tsx +51 -6
  65. package/corpus/core/src/client/AssistantChat.tsx +274 -147
  66. package/corpus/core/src/client/MultiTabAssistantChat.tsx +3 -0
  67. package/corpus/core/src/client/RunStuckBanner.tsx +69 -20
  68. package/corpus/core/src/client/agent-chat-adapter.ts +110 -17
  69. package/corpus/core/src/client/automation.ts +22 -0
  70. package/corpus/core/src/client/chat/run-recovery.tsx +67 -50
  71. package/corpus/core/src/client/composer/TiptapComposer.tsx +8 -0
  72. package/corpus/core/src/client/index.ts +30 -0
  73. package/corpus/core/src/client/integrations/api.ts +295 -0
  74. package/corpus/core/src/client/integrations/index.ts +26 -0
  75. package/corpus/core/src/client/transcription/use-live-transcription.ts +68 -5
  76. package/corpus/core/src/client/use-run-stuck-detection.ts +41 -3
  77. package/corpus/core/src/deploy/build.ts +59 -3
  78. package/corpus/core/src/deploy/workspace-deploy.ts +37 -2
  79. package/corpus/core/src/file-upload/types.ts +2 -0
  80. package/corpus/core/src/index.ts +37 -0
  81. package/corpus/core/src/integrations/a2a-continuations-store.ts +6 -4
  82. package/corpus/core/src/integrations/adapters/discord.ts +362 -0
  83. package/corpus/core/src/integrations/adapters/index.ts +29 -0
  84. package/corpus/core/src/integrations/adapters/microsoft-teams.ts +411 -0
  85. package/corpus/core/src/integrations/adapters/slack.ts +861 -27
  86. package/corpus/core/src/integrations/adapters/telegram.ts +54 -15
  87. package/corpus/core/src/integrations/adapters/whatsapp.ts +41 -17
  88. package/corpus/core/src/integrations/catalog.ts +571 -0
  89. package/corpus/core/src/integrations/controls-store.ts +187 -0
  90. package/corpus/core/src/integrations/index.ts +100 -0
  91. package/corpus/core/src/integrations/installations-store.ts +677 -0
  92. package/corpus/core/src/integrations/integration-memory.ts +187 -0
  93. package/corpus/core/src/integrations/pending-tasks-retry-job.ts +6 -6
  94. package/corpus/core/src/integrations/pending-tasks-store.ts +83 -5
  95. package/corpus/core/src/integrations/plugin.ts +685 -47
  96. package/corpus/core/src/integrations/scope-store.ts +498 -0
  97. package/corpus/core/src/integrations/slack-manifest.ts +78 -0
  98. package/corpus/core/src/integrations/slack-oauth.ts +343 -0
  99. package/corpus/core/src/integrations/types.ts +179 -0
  100. package/corpus/core/src/integrations/usage-budget-store.ts +906 -0
  101. package/corpus/core/src/integrations/webhook-handler.ts +562 -51
  102. package/corpus/core/src/jobs/scheduler.ts +100 -2
  103. package/corpus/core/src/jobs/tools.ts +45 -9
  104. package/corpus/core/src/provider-api/index.ts +72 -1
  105. package/corpus/core/src/resources/handlers.ts +88 -14
  106. package/corpus/core/src/resources/script-helpers.ts +36 -7
  107. package/corpus/core/src/resources/store.ts +59 -52
  108. package/corpus/core/src/scripts/call-agent.ts +107 -1
  109. package/corpus/core/src/server/agent-chat-plugin.ts +294 -119
  110. package/corpus/core/src/server/auth.ts +10 -14
  111. package/corpus/core/src/server/builder-design-systems.ts +16 -1
  112. package/corpus/core/src/server/edge.ts +18 -0
  113. package/corpus/core/src/server/index.ts +26 -0
  114. package/corpus/core/src/server/request-context.ts +18 -0
  115. package/corpus/core/src/server/social-og-image.ts +3 -2
  116. package/corpus/core/src/styles/agent-native.css +62 -44
  117. package/corpus/core/src/templates/default/.agents/skills/capture-learnings/SKILL.md +22 -9
  118. package/corpus/core/src/templates/default/AGENTS.md +7 -3
  119. package/corpus/core/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +1 -1
  120. package/corpus/core/src/templates/workspace-core/.agents/skills/capture-learnings/SKILL.md +22 -9
  121. package/corpus/core/src/templates/workspace-core/.agents/skills/extension-points/SKILL.md +6 -3
  122. package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +25 -0
  123. package/corpus/core/src/templates/workspace-core/.agents/skills/integration-webhooks/SKILL.md +15 -0
  124. package/corpus/core/src/templates/workspace-core/AGENTS.md +3 -2
  125. package/corpus/core/src/usage/store.ts +37 -2
  126. package/corpus/templates/analytics/.agents/skills/capture-learnings/SKILL.md +22 -9
  127. package/corpus/templates/analytics/.agents/skills/provider-api/SKILL.md +23 -0
  128. package/corpus/templates/analytics/.builder/skills/provider-api/SKILL.md +15 -0
  129. package/corpus/templates/analytics/actions/save-monitor.ts +25 -2
  130. package/corpus/templates/analytics/app/lib/data-sources.ts +28 -0
  131. package/corpus/templates/analytics/changelog/2026-07-10-agent-created-uptime-monitors-now-return-a-direct-link-to-th.md +6 -0
  132. package/corpus/templates/analytics/changelog/2026-07-10-dashboard-email-reports-still-arrive-when-screenshot-capture-temporarily-fails.md +6 -0
  133. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +3 -7
  134. package/corpus/templates/analytics/server/lib/credential-keys.ts +12 -0
  135. package/corpus/templates/analytics/server/lib/dashboard-report.ts +5 -1
  136. package/corpus/templates/analytics/server/lib/provider-credentials.ts +2 -0
  137. package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +16 -0
  138. package/corpus/templates/assets/.agents/skills/capture-learnings/SKILL.md +22 -9
  139. package/corpus/templates/brain/.agents/skills/capture-learnings/SKILL.md +22 -9
  140. package/corpus/templates/calendar/.agents/skills/capture-learnings/SKILL.md +22 -9
  141. package/corpus/templates/calendar/app/components/calendar/CommandPalette.tsx +98 -108
  142. package/corpus/templates/calendar/app/components/calendar/EventAttendeesSection.tsx +97 -90
  143. package/corpus/templates/calendar/changelog/2026-07-10-event-guest-details-and-option-menus-now-use-valid-accessibl.md +6 -0
  144. package/corpus/templates/calendar/changelog/2026-07-10-natural-language-event-phrases-stay-available-as-quick-creat.md +6 -0
  145. package/corpus/templates/chat/.agents/skills/capture-learnings/SKILL.md +22 -9
  146. package/corpus/templates/chat/changelog/2026-07-10-chat-now-makes-ai-connection-setup-clear-without-shifting-th.md +6 -0
  147. package/corpus/templates/clips/.agents/skills/capture-learnings/SKILL.md +22 -9
  148. package/corpus/templates/clips/.agents/skills/recording/SKILL.md +17 -1
  149. package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +8 -0
  150. package/corpus/templates/clips/AGENTS.md +8 -3
  151. package/corpus/templates/clips/actions/finalize-recording.ts +63 -23
  152. package/corpus/templates/clips/actions/get-recording-player-data.ts +6 -2
  153. package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +72 -9
  154. package/corpus/templates/clips/actions/list-recordings.ts +19 -3
  155. package/corpus/templates/clips/actions/navigate.ts +2 -0
  156. package/corpus/templates/clips/actions/reprocess-recording.ts +20 -6
  157. package/corpus/templates/clips/actions/request-transcript.ts +16 -31
  158. package/corpus/templates/clips/actions/view-screen.ts +57 -5
  159. package/corpus/templates/clips/app/components/layout/Header.tsx +1 -0
  160. package/corpus/templates/clips/app/components/library/empty-state.tsx +2 -0
  161. package/corpus/templates/clips/app/components/library/library-grid.tsx +69 -42
  162. package/corpus/templates/clips/app/components/library/library-layout.tsx +15 -1
  163. package/corpus/templates/clips/app/components/library/recording-card.tsx +81 -68
  164. package/corpus/templates/clips/app/components/library/search-bar.tsx +4 -3
  165. package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +9 -3
  166. package/corpus/templates/clips/app/components/player/share-dialog.tsx +1 -1
  167. package/corpus/templates/clips/app/components/player/transcript-panel.tsx +27 -5
  168. package/corpus/templates/clips/app/hooks/use-library.ts +1 -1
  169. package/corpus/templates/clips/app/hooks/use-navigation-state.ts +10 -2
  170. package/corpus/templates/clips/app/hooks/use-player-shortcuts.ts +1 -0
  171. package/corpus/templates/clips/app/i18n/ar-SA.ts +7 -1
  172. package/corpus/templates/clips/app/i18n/de-DE.ts +7 -1
  173. package/corpus/templates/clips/app/i18n/en-US.ts +7 -1
  174. package/corpus/templates/clips/app/i18n/es-ES.ts +7 -1
  175. package/corpus/templates/clips/app/i18n/fr-FR.ts +7 -1
  176. package/corpus/templates/clips/app/i18n/hi-IN.ts +7 -1
  177. package/corpus/templates/clips/app/i18n/ja-JP.ts +7 -1
  178. package/corpus/templates/clips/app/i18n/ko-KR.ts +7 -1
  179. package/corpus/templates/clips/app/i18n/pt-BR.ts +7 -1
  180. package/corpus/templates/clips/app/i18n/zh-CN.ts +8 -1
  181. package/corpus/templates/clips/app/i18n/zh-TW.ts +8 -1
  182. package/corpus/templates/clips/app/lib/recording-visibility.ts +70 -0
  183. package/corpus/templates/clips/app/routes/_app.shared.tsx +20 -0
  184. package/corpus/templates/clips/app/routes/download.tsx +24 -8
  185. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +115 -2
  186. package/corpus/templates/clips/app/routes/record.tsx +62 -0
  187. package/corpus/templates/clips/app/routes/share.$shareId.tsx +25 -16
  188. package/corpus/templates/clips/changelog/2026-07-10-clips-desktop-is-now-available-for-linux-with-appimage-debia.md +6 -0
  189. package/corpus/templates/clips/changelog/2026-07-10-clips-downloads-updates-sooner-in-the-background-and-offers-.md +6 -0
  190. package/corpus/templates/clips/changelog/2026-07-10-clips-shared-with-you-now-appear-in-a-searchable-shared-with.md +6 -0
  191. package/corpus/templates/clips/changelog/2026-07-10-clips-with-missing-mobile-video-frames-can-be-repaired-witho.md +6 -0
  192. package/corpus/templates/clips/changelog/2026-07-10-fixed-copying-agent-responses-and-transcript-text-from-recor.md +6 -0
  193. package/corpus/templates/clips/changelog/2026-07-10-mobile-camera-recordings-pause-while-backgrounded.md +6 -0
  194. package/corpus/templates/clips/changelog/2026-07-10-mp4-downloads-now-show-progress-immediately-after-the-option.md +6 -0
  195. package/corpus/templates/clips/changelog/2026-07-10-recording-pages-now-open-as-soon-as-you-stop-with-a-share-li.md +6 -0
  196. package/corpus/templates/clips/changelog/2026-07-10-recordings-now-seek-smoothly-downloads-use-the-correct-file-.md +6 -0
  197. package/corpus/templates/clips/changelog/2026-07-10-s3-compatible-storage-now-saves-hosted-recordings-without-re.md +6 -0
  198. package/corpus/templates/clips/desktop/README.md +22 -6
  199. package/corpus/templates/clips/desktop/package.json +1 -1
  200. package/corpus/templates/clips/desktop/src/app.tsx +32 -19
  201. package/corpus/templates/clips/desktop/src/components/ReadinessPanel.tsx +15 -9
  202. package/corpus/templates/clips/desktop/src/lib/finalization-guard.ts +22 -0
  203. package/corpus/templates/clips/desktop/src/lib/permissions.ts +3 -1
  204. package/corpus/templates/clips/desktop/src/lib/recorder.ts +97 -120
  205. package/corpus/templates/clips/desktop/src/lib/updater.ts +26 -4
  206. package/corpus/templates/clips/desktop/src/overlays/finalizing.tsx +4 -8
  207. package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +1 -1
  208. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +2 -2
  209. package/corpus/templates/clips/desktop/src-tauri/src/permission_status.rs +11 -7
  210. package/corpus/templates/clips/desktop/src-tauri/tauri.linux.conf.json +11 -0
  211. package/corpus/templates/clips/netlify.toml +3 -0
  212. package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +106 -0
  213. package/corpus/templates/clips/server/lib/public-agent-context.ts +9 -1
  214. package/corpus/templates/clips/server/lib/resumable-upload-provider.ts +52 -0
  215. package/corpus/templates/clips/server/lib/s3-upload-provider.ts +433 -85
  216. package/corpus/templates/clips/server/lib/video-remux.ts +114 -0
  217. package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +109 -0
  218. package/corpus/templates/clips/server/routes/api/clips-updater.json.get.ts +22 -11
  219. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +4 -2
  220. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +47 -5
  221. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +10 -2
  222. package/corpus/templates/clips/shared/share-loader-response.ts +12 -0
  223. package/corpus/templates/clips/shared/transcript-status.ts +40 -0
  224. package/corpus/templates/content/.agents/skills/capture-learnings/SKILL.md +22 -9
  225. package/corpus/templates/content/.agents/skills/content/SKILL.md +57 -5
  226. package/corpus/templates/content/AGENTS.md +65 -55
  227. package/corpus/templates/content/actions/_builder-cms-read-client.ts +92 -23
  228. package/corpus/templates/content/actions/_database-source-utils.ts +207 -41
  229. package/corpus/templates/content/actions/_property-utils.ts +30 -2
  230. package/corpus/templates/content/actions/add-content-database-source-field-property.ts +316 -121
  231. package/corpus/templates/content/actions/attach-content-database-source.ts +41 -17
  232. package/corpus/templates/content/actions/change-content-database-source-role.ts +46 -8
  233. package/corpus/templates/content/actions/submit-content-database-form.ts +497 -0
  234. package/corpus/templates/content/actions/suggest-source-join-key.ts +8 -1
  235. package/corpus/templates/content/actions/update-content-database-view.ts +8 -1
  236. package/corpus/templates/content/actions/view-screen.ts +4 -1
  237. package/corpus/templates/content/agent-native.app-skill.json +1 -1
  238. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +250 -64
  239. package/corpus/templates/content/app/components/editor/database/FormView.tsx +460 -0
  240. package/corpus/templates/content/app/components/editor/database/navigation-state.ts +3 -0
  241. package/corpus/templates/content/app/components/editor/database/settings.tsx +30 -37
  242. package/corpus/templates/content/app/components/editor/database/shared.tsx +2 -0
  243. package/corpus/templates/content/app/components/editor/database/view-config.ts +29 -1
  244. package/corpus/templates/content/app/components/ui/textarea.tsx +1 -0
  245. package/corpus/templates/content/app/hooks/use-content-database.ts +22 -0
  246. package/corpus/templates/content/app/i18n/zh-TW.ts +21 -0
  247. package/corpus/templates/content/app/i18n-data.ts +225 -0
  248. package/corpus/templates/content/changelog/2026-07-09-builder-source-refreshes-now-keep-mapped-fields-such-as-topi.md +6 -0
  249. package/corpus/templates/content/changelog/2026-07-10-builder-backed-properties-now-load-current-source-values-as-.md +6 -0
  250. package/corpus/templates/content/changelog/2026-07-10-builder-database-refreshes-now-stay-explicit-and-accurate.md +6 -0
  251. package/corpus/templates/content/changelog/2026-07-10-database-form-views-now-collect-ordered-required-answers-and.md +6 -0
  252. package/corpus/templates/content/changelog/2026-07-10-database-tables-now-use-a-quieter-more-compact-layout-with-c.md +6 -0
  253. package/corpus/templates/content/changelog/2026-07-10-slack-intake-routes-to-content-database-forms.md +6 -0
  254. package/corpus/templates/content/parity/matrix.md +1 -0
  255. package/corpus/templates/content/parity/matrix.ts +18 -0
  256. package/corpus/templates/content/shared/api.ts +28 -1
  257. package/corpus/templates/content/shared/database-form.ts +53 -0
  258. package/corpus/templates/design/.agents/skills/capture-learnings/SKILL.md +22 -9
  259. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +26 -0
  260. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +85 -12
  261. package/corpus/templates/design/AGENTS.md +72 -18
  262. package/corpus/templates/design/DESIGN.md +1 -1
  263. package/corpus/templates/design/DEVELOPING.md +1 -1
  264. package/corpus/templates/design/FIGMA_INTEROPERABILITY.md +116 -0
  265. package/corpus/templates/design/actions/create-design-from-template.ts +220 -0
  266. package/corpus/templates/design/actions/create-design-system.ts +92 -16
  267. package/corpus/templates/design/actions/delete-design-template.ts +28 -0
  268. package/corpus/templates/design/actions/delete-file.ts +7 -0
  269. package/corpus/templates/design/actions/edit-design.ts +3 -0
  270. package/corpus/templates/design/actions/export-design-as-figma-svg.ts +137 -5
  271. package/corpus/templates/design/actions/export-pdf.ts +1 -1
  272. package/corpus/templates/design/actions/generate-design.ts +3 -0
  273. package/corpus/templates/design/actions/get-design-snapshot.ts +9 -0
  274. package/corpus/templates/design/actions/get-figma-connection-status.ts +26 -0
  275. package/corpus/templates/design/actions/get-figma-design-context.ts +138 -0
  276. package/corpus/templates/design/actions/get-figma-styles.ts +2 -2
  277. package/corpus/templates/design/actions/import-figma-clipboard.ts +112 -16
  278. package/corpus/templates/design/actions/import-figma-frame.ts +15 -4
  279. package/corpus/templates/design/actions/index-design-system-with-builder.ts +4 -0
  280. package/corpus/templates/design/actions/list-design-templates.ts +118 -0
  281. package/corpus/templates/design/actions/navigate.ts +16 -2
  282. package/corpus/templates/design/actions/provider-api-request.ts +11 -1
  283. package/corpus/templates/design/actions/save-design-as-template.ts +156 -0
  284. package/corpus/templates/design/actions/set-active-breakpoint.ts +13 -4
  285. package/corpus/templates/design/actions/take-design-screenshot.ts +73 -3
  286. package/corpus/templates/design/actions/update-file.ts +39 -22
  287. package/corpus/templates/design/actions/view-screen.ts +36 -1
  288. package/corpus/templates/design/actions/write-local-file.ts +50 -38
  289. package/corpus/templates/design/app/components/design/AutoLayoutSuggestionDialog.tsx +151 -0
  290. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +20 -0
  291. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +251 -22
  292. package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +3 -3
  293. package/corpus/templates/design/app/components/design/DesignImportPanel.tsx +384 -9
  294. package/corpus/templates/design/app/components/design/EditPanel.tsx +105 -32
  295. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +58 -28
  296. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +6 -0
  297. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +539 -53
  298. package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +40 -0
  299. package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +1 -0
  300. package/corpus/templates/design/app/components/design/code-workbench/explorer/ExplorerView.tsx +1 -0
  301. package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +5 -1
  302. package/corpus/templates/design/app/components/design/code-workbench/workspace/create-providers.ts +2 -0
  303. package/corpus/templates/design/app/components/design/code-workbench/workspace/localhost-provider.ts +3 -1
  304. package/corpus/templates/design/app/components/design/code-workbench/workspace/types.ts +2 -0
  305. package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +19 -0
  306. package/corpus/templates/design/app/components/design/edit-panel/frame-presets-panel.tsx +1 -0
  307. package/corpus/templates/design/app/components/design/edit-panel/interaction-state-helpers.ts +27 -0
  308. package/corpus/templates/design/app/components/design/inspector/InteractionStatePanel.tsx +137 -81
  309. package/corpus/templates/design/app/components/design/inspector/frame-size-presets.ts +25 -5
  310. package/corpus/templates/design/app/components/design/multi-screen/chrome-transitions.ts +1 -1
  311. package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +220 -3
  312. package/corpus/templates/design/app/components/design/multi-screen/overview-layout.ts +13 -0
  313. package/corpus/templates/design/app/components/design/multi-screen/types.ts +22 -1
  314. package/corpus/templates/design/app/components/design/types.ts +4 -0
  315. package/corpus/templates/design/app/components/design-system/ProductionDesignSystemShowcase.tsx +208 -0
  316. package/corpus/templates/design/app/components/editor/FigmaLinkComposerBubble.tsx +321 -0
  317. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +24 -4
  318. package/corpus/templates/design/app/components/layout/Layout.tsx +16 -2
  319. package/corpus/templates/design/app/components/layout/Sidebar.tsx +2 -0
  320. package/corpus/templates/design/app/components/templates/TemplatePreview.tsx +72 -0
  321. package/corpus/templates/design/app/global.css +2 -35
  322. package/corpus/templates/design/app/hooks/use-navigation-state.ts +10 -0
  323. package/corpus/templates/design/app/i18n/zh-TW.ts +127 -5
  324. package/corpus/templates/design/app/i18n-breakpoints.ts +209 -0
  325. package/corpus/templates/design/app/i18n-data.ts +1317 -59
  326. package/corpus/templates/design/app/i18n-template-feature.ts +458 -0
  327. package/corpus/templates/design/app/lib/design-clipboard.ts +202 -0
  328. package/corpus/templates/design/app/lib/design-file-upload.ts +87 -0
  329. package/corpus/templates/design/app/lib/design-import.ts +168 -11
  330. package/corpus/templates/design/app/lib/desktop-design-preview.ts +423 -0
  331. package/corpus/templates/design/app/lib/figma-clipboard.ts +74 -8
  332. package/corpus/templates/design/app/lib/figma-connection.ts +161 -0
  333. package/corpus/templates/design/app/lib/figma-svg-copy.ts +814 -22
  334. package/corpus/templates/design/app/lib/figma-url.ts +77 -0
  335. package/corpus/templates/design/app/lib/pending-generation.ts +35 -0
  336. package/corpus/templates/design/app/pages/DesignSystems.tsx +236 -177
  337. package/corpus/templates/design/app/pages/Index.tsx +38 -0
  338. package/corpus/templates/design/app/pages/Templates.tsx +498 -0
  339. package/corpus/templates/design/app/pages/design-editor/auto-layout-suggestion.ts +328 -0
  340. package/corpus/templates/design/app/pages/design-editor/clone-idrefs.ts +113 -0
  341. package/corpus/templates/design/app/pages/design-editor/created-screen-navigation.ts +55 -0
  342. package/corpus/templates/design/app/pages/design-editor/editor-session.ts +32 -0
  343. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +49 -2
  344. package/corpus/templates/design/app/pages/design-editor/export-capture.ts +296 -0
  345. package/corpus/templates/design/app/pages/design-editor/history.ts +101 -2
  346. package/corpus/templates/design/app/pages/design-editor/layout-operations.ts +28 -1
  347. package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +34 -0
  348. package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +202 -6
  349. package/corpus/templates/design/app/pages/design-editor/pending-structure-verification.ts +92 -0
  350. package/corpus/templates/design/app/pages/design-editor/save-failure.ts +58 -0
  351. package/corpus/templates/design/app/routes/templates.tsx +4 -6
  352. package/corpus/templates/design/changelog/2026-07-10-app-workspaces-now-use-clean-borderless-main-surfaces-throug.md +6 -0
  353. package/corpus/templates/design/changelog/2026-07-10-ask-chat-what-s-in-a-figma-file-or-frame-structure-screensho.md +6 -0
  354. package/corpus/templates/design/changelog/2026-07-10-canvas-edits-now-reject-malformed-html-before-it-can-corrupt.md +6 -0
  355. package/corpus/templates/design/changelog/2026-07-10-complex-designs-now-export-as-valid-secure-svgs-and-crisp-ra.md +6 -0
  356. package/corpus/templates/design/changelog/2026-07-10-complex-figma-masks-arcs-rich-text-transformed-images-and-ad.md +6 -0
  357. package/corpus/templates/design/changelog/2026-07-10-copied-layers-paste-across-designs-and-browser-tabs.md +6 -0
  358. package/corpus/templates/design/changelog/2026-07-10-copy-and-download-editable-figma-svg.md +6 -0
  359. package/corpus/templates/design/changelog/2026-07-10-copying-design-text-now-pastes-readable-text-into-other-apps.md +6 -0
  360. package/corpus/templates/design/changelog/2026-07-10-deleted-screens-can-be-restored-with-undo-and-removed-again-.md +6 -0
  361. package/corpus/templates/design/changelog/2026-07-10-design-changes-now-save-before-switching-apps-and-retry-when.md +6 -0
  362. package/corpus/templates/design/changelog/2026-07-10-design-stays-usable-on-phones-by-keeping-editor-panels-and-f.md +6 -0
  363. package/corpus/templates/design/changelog/2026-07-10-download-all-screens-as-one-multi-page-pdf-from-the-overview.md +6 -0
  364. package/corpus/templates/design/changelog/2026-07-10-duplicated-layers-now-keep-labels-aria-relationships-fragmen.md +6 -0
  365. package/corpus/templates/design/changelog/2026-07-10-fig-import-results-stay-compact.md +6 -0
  366. package/corpus/templates/design/changelog/2026-07-10-figma-imports-now-load-real-fonts-fix-rotated-gradient-dashe.md +6 -0
  367. package/corpus/templates/design/changelog/2026-07-10-figma-links-in-chat-and-the-import-tab-now-offer-secure-one-.md +6 -0
  368. package/corpus/templates/design/changelog/2026-07-10-fixed-cmd-z-not-restoring-content-after-an-agent-driven-desi.md +6 -0
  369. package/corpus/templates/design/changelog/2026-07-10-fixed-download-pdf-being-unreachable-from-the-export-panel-e.md +6 -0
  370. package/corpus/templates/design/changelog/2026-07-10-fixed-dragging-a-layer-out-of-an-auto-layout-row-column-no-l.md +6 -0
  371. package/corpus/templates/design/changelog/2026-07-10-fixed-figma-svg-export-text-wrapping-sizing-and-inner-layer.md +6 -0
  372. package/corpus/templates/design/changelog/2026-07-10-fixed-hiding-or-locking-one-layer-no-longer-hides-or-blocks-.md +6 -0
  373. package/corpus/templates/design/changelog/2026-07-10-fixed-png-screenshots-of-tall-screens-being-cropped-to-one-v.md +6 -0
  374. package/corpus/templates/design/changelog/2026-07-10-fixed-png-svg-exports-capturing-broken-layout-when-webfonts-.md +6 -0
  375. package/corpus/templates/design/changelog/2026-07-10-frame-tool-now-offers-standard-ad-unit-size-presets-medium-r.md +6 -0
  376. package/corpus/templates/design/changelog/2026-07-10-full-view-controls-stay-within-their-frame-instead-of-coveri.md +6 -0
  377. package/corpus/templates/design/changelog/2026-07-10-hover-focus-focus-visible-pressed-and-disabled-states-now-pr.md +6 -0
  378. package/corpus/templates/design/changelog/2026-07-10-layer-drops-now-land-in-the-intended-grid-row-stay-visually-.md +6 -0
  379. package/corpus/templates/design/changelog/2026-07-10-local-code-workspaces-now-keep-unsaved-edits-across-panel-sw.md +6 -0
  380. package/corpus/templates/design/changelog/2026-07-10-local-visual-editing-now-keeps-authenticated-sessions-shared.md +6 -0
  381. package/corpus/templates/design/changelog/2026-07-10-long-running-agent-work-no-longer-shows-a-premature-stuck-wa.md +6 -0
  382. package/corpus/templates/design/changelog/2026-07-10-managed-figma-connections-are-recognized-automatically.md +6 -0
  383. package/corpus/templates/design/changelog/2026-07-10-new-designs-can-open-directly-in-the-editor-without-a-pr.md +6 -0
  384. package/corpus/templates/design/changelog/2026-07-10-new-screens-are-selected-and-revealed-immediately.md +6 -0
  385. package/corpus/templates/design/changelog/2026-07-10-new-text-layers-undo-as-one-safe-creation.md +6 -0
  386. package/corpus/templates/design/changelog/2026-07-10-preview-and-apply-inferred-auto-layout-without-changing-yo.md +5 -0
  387. package/corpus/templates/design/changelog/2026-07-10-print-pdf-exports-and-paper-size-presets-letter-a4-now-match.md +6 -0
  388. package/corpus/templates/design/changelog/2026-07-10-responsive-frame-editing.md +6 -0
  389. package/corpus/templates/design/changelog/2026-07-10-reusable-design-templates.md +6 -0
  390. package/corpus/templates/design/changelog/2026-07-10-screen-overview-frames-now-use-a-clearer-interact-action-wit.md +6 -0
  391. package/corpus/templates/design/changelog/2026-07-10-start-designs-from-source-linked-material-3-carbon-or-primer.md +6 -0
  392. package/corpus/templates/design/changelog/2026-07-10-tweaks-guidance.md +6 -0
  393. package/corpus/templates/design/changelog/2026-07-10-uploaded-fig-files-can-now-become-editable-design-screens-wi.md +6 -0
  394. package/corpus/templates/design/e2e/helpers.ts +3 -3
  395. package/corpus/templates/design/package.json +2 -0
  396. package/corpus/templates/design/scripts/qa-figma-stress-import.ts +96 -0
  397. package/corpus/templates/design/server/db/index.ts +10 -0
  398. package/corpus/templates/design/server/db/schema.ts +44 -0
  399. package/corpus/templates/design/server/handlers/import-design-file.ts +114 -80
  400. package/corpus/templates/design/server/handlers/index-design-system-with-builder.ts +19 -6
  401. package/corpus/templates/design/server/lib/design-export.ts +240 -3
  402. package/corpus/templates/design/server/lib/design-template-data.ts +89 -0
  403. package/corpus/templates/design/server/lib/design-to-figma-svg.ts +250 -26
  404. package/corpus/templates/design/server/lib/fig-file-decoder.ts +839 -0
  405. package/corpus/templates/design/server/lib/fig-file-import.ts +287 -0
  406. package/corpus/templates/design/server/lib/fig-file-limits.ts +3 -0
  407. package/corpus/templates/design/server/lib/fig-file-to-html.ts +2568 -0
  408. package/corpus/templates/design/server/lib/figma-design-context.ts +359 -0
  409. package/corpus/templates/design/server/lib/figma-node-import.ts +478 -22
  410. package/corpus/templates/design/server/lib/figma-node-to-html.ts +554 -29
  411. package/corpus/templates/design/server/lib/local-figma-qa-upload.ts +112 -0
  412. package/corpus/templates/design/server/lib/verify-write-grant.ts +16 -2
  413. package/corpus/templates/design/server/lib/visible-clipboard-html.ts +13 -3
  414. package/corpus/templates/design/server/plugins/agent-chat.ts +7 -0
  415. package/corpus/templates/design/server/plugins/db.ts +42 -0
  416. package/corpus/templates/design/server/plugins/local-figma-qa-upload.ts +7 -0
  417. package/corpus/templates/design/server/register-secrets.ts +8 -8
  418. package/corpus/templates/design/server/routes/api/qa-figma-import-assets/[assetId].get.ts +46 -0
  419. package/corpus/templates/design/server/source-workspace.ts +104 -12
  420. package/corpus/templates/design/shared/code-layer.ts +105 -28
  421. package/corpus/templates/design/shared/design-system-templates.ts +301 -0
  422. package/corpus/templates/design/shared/design-template-presets.ts +195 -0
  423. package/corpus/templates/design/shared/figma-url.ts +8 -0
  424. package/corpus/templates/design/shared/html-integrity.ts +306 -0
  425. package/corpus/templates/design/shared/interaction-states.ts +318 -23
  426. package/corpus/templates/design/shared/locked-layers.ts +151 -0
  427. package/corpus/templates/dispatch/.agents/skills/capture-learnings/SKILL.md +22 -9
  428. package/corpus/templates/dispatch/app/i18n/zh-TW.ts +48 -0
  429. package/corpus/templates/dispatch/app/i18n-data.ts +536 -1
  430. package/corpus/templates/dispatch/changelog/2026-07-10-connect-slack-workspaces-with-oauth-and-manage-channel-ident.md +6 -0
  431. package/corpus/templates/dispatch/changelog/2026-07-10-microsoft-teams-bots-and-discord-slash-commands-can-now-conn.md +6 -0
  432. package/corpus/templates/dispatch/changelog/2026-07-10-slack-and-telegram-now-route-uptime-monitor-requests-to-anal.md +6 -0
  433. package/corpus/templates/forms/.agents/skills/capture-learnings/SKILL.md +22 -9
  434. package/corpus/templates/forms/.agents/skills/form-publishing/SKILL.md +7 -0
  435. package/corpus/templates/forms/AGENTS.md +4 -0
  436. package/corpus/templates/forms/actions/create-form.ts +44 -7
  437. package/corpus/templates/forms/actions/lib/assert-publishable-form.ts +38 -0
  438. package/corpus/templates/forms/actions/patch-form-fields.ts +4 -0
  439. package/corpus/templates/forms/actions/update-form.ts +2 -36
  440. package/corpus/templates/forms/app/i18n/ar-SA.ts +3 -0
  441. package/corpus/templates/forms/app/i18n/de-DE.ts +3 -0
  442. package/corpus/templates/forms/app/i18n/en-US.ts +3 -0
  443. package/corpus/templates/forms/app/i18n/es-ES.ts +3 -0
  444. package/corpus/templates/forms/app/i18n/fr-FR.ts +3 -0
  445. package/corpus/templates/forms/app/i18n/hi-IN.ts +3 -0
  446. package/corpus/templates/forms/app/i18n/ja-JP.ts +3 -0
  447. package/corpus/templates/forms/app/i18n/ko-KR.ts +3 -0
  448. package/corpus/templates/forms/app/i18n/pt-BR.ts +3 -0
  449. package/corpus/templates/forms/app/i18n/zh-CN.ts +2 -0
  450. package/corpus/templates/forms/app/i18n/zh-TW.ts +3 -0
  451. package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +17 -0
  452. package/corpus/templates/forms/changelog/2026-07-10-agent-created-published-forms-now-return-the-anonymous-publi.md +6 -0
  453. package/corpus/templates/forms/changelog/2026-07-10-published-forms-can-no-longer-be-edited-into-an-unusable-emp.md +6 -0
  454. package/corpus/templates/forms/server/handlers/submissions.ts +4 -3
  455. package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -0
  456. package/corpus/templates/forms/shared/types.ts +5 -0
  457. package/corpus/templates/mail/.agents/skills/capture-learnings/SKILL.md +22 -9
  458. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +2 -2
  459. package/corpus/templates/mail/changelog/2026-07-10-mail-navigation-now-uses-a-clean-borderless-drawer.md +6 -0
  460. package/corpus/templates/plan/.agents/skills/capture-learnings/SKILL.md +22 -9
  461. package/corpus/templates/plan/app/lib/plan-local-bridge.ts +4 -1
  462. package/corpus/templates/plan/changelog/2026-07-10-local-plans-now-keep-valid-content-visible-when-one-generate.md +6 -0
  463. package/corpus/templates/plan/server/lib/local-plan-files.ts +4 -1
  464. package/corpus/templates/slides/.agents/skills/capture-learnings/SKILL.md +22 -9
  465. package/dist/a2a/artifact-response.d.ts.map +1 -1
  466. package/dist/a2a/artifact-response.js +88 -2
  467. package/dist/a2a/artifact-response.js.map +1 -1
  468. package/dist/a2a/client.d.ts +9 -0
  469. package/dist/a2a/client.d.ts.map +1 -1
  470. package/dist/a2a/client.js +1 -0
  471. package/dist/a2a/client.js.map +1 -1
  472. package/dist/a2a/handlers.d.ts.map +1 -1
  473. package/dist/a2a/handlers.js +24 -69
  474. package/dist/a2a/handlers.js.map +1 -1
  475. package/dist/a2a/types.d.ts +2 -0
  476. package/dist/a2a/types.d.ts.map +1 -1
  477. package/dist/a2a/types.js.map +1 -1
  478. package/dist/agent/durable-background.d.ts +11 -0
  479. package/dist/agent/durable-background.d.ts.map +1 -1
  480. package/dist/agent/durable-background.js +17 -0
  481. package/dist/agent/durable-background.js.map +1 -1
  482. package/dist/agent/production-agent.d.ts +5 -3
  483. package/dist/agent/production-agent.d.ts.map +1 -1
  484. package/dist/agent/production-agent.js +34 -8
  485. package/dist/agent/production-agent.js.map +1 -1
  486. package/dist/agent/run-manager.d.ts +44 -2
  487. package/dist/agent/run-manager.d.ts.map +1 -1
  488. package/dist/agent/run-manager.js +124 -18
  489. package/dist/agent/run-manager.js.map +1 -1
  490. package/dist/agent/run-store.d.ts +109 -0
  491. package/dist/agent/run-store.d.ts.map +1 -1
  492. package/dist/agent/run-store.js +274 -37
  493. package/dist/agent/run-store.js.map +1 -1
  494. package/dist/agent/types.d.ts +22 -0
  495. package/dist/agent/types.d.ts.map +1 -1
  496. package/dist/agent/types.js.map +1 -1
  497. package/dist/audit/record.d.ts.map +1 -1
  498. package/dist/audit/record.js +29 -0
  499. package/dist/audit/record.js.map +1 -1
  500. package/dist/audit/store.d.ts.map +1 -1
  501. package/dist/audit/store.js +62 -3
  502. package/dist/audit/store.js.map +1 -1
  503. package/dist/audit/types.d.ts +13 -0
  504. package/dist/audit/types.d.ts.map +1 -1
  505. package/dist/audit/types.js.map +1 -1
  506. package/dist/automation/index.d.ts +193 -0
  507. package/dist/automation/index.d.ts.map +1 -0
  508. package/dist/automation/index.js +464 -0
  509. package/dist/automation/index.js.map +1 -0
  510. package/dist/cli/create.d.ts.map +1 -1
  511. package/dist/cli/create.js +10 -3
  512. package/dist/cli/create.js.map +1 -1
  513. package/dist/cli/design-connect.d.ts.map +1 -1
  514. package/dist/cli/design-connect.js +492 -35
  515. package/dist/cli/design-connect.js.map +1 -1
  516. package/dist/client/AgentPanel.d.ts +7 -1
  517. package/dist/client/AgentPanel.d.ts.map +1 -1
  518. package/dist/client/AgentPanel.js +32 -8
  519. package/dist/client/AgentPanel.js.map +1 -1
  520. package/dist/client/AssistantChat.d.ts +15 -0
  521. package/dist/client/AssistantChat.d.ts.map +1 -1
  522. package/dist/client/AssistantChat.js +115 -47
  523. package/dist/client/AssistantChat.js.map +1 -1
  524. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  525. package/dist/client/MultiTabAssistantChat.js +1 -1
  526. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  527. package/dist/client/RunStuckBanner.d.ts +14 -1
  528. package/dist/client/RunStuckBanner.d.ts.map +1 -1
  529. package/dist/client/RunStuckBanner.js +35 -7
  530. package/dist/client/RunStuckBanner.js.map +1 -1
  531. package/dist/client/agent-chat-adapter.d.ts +4 -1
  532. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  533. package/dist/client/agent-chat-adapter.js +97 -16
  534. package/dist/client/agent-chat-adapter.js.map +1 -1
  535. package/dist/client/automation.d.ts +14 -0
  536. package/dist/client/automation.d.ts.map +1 -0
  537. package/dist/client/automation.js +9 -0
  538. package/dist/client/automation.js.map +1 -0
  539. package/dist/client/chat/run-recovery.d.ts +4 -0
  540. package/dist/client/chat/run-recovery.d.ts.map +1 -1
  541. package/dist/client/chat/run-recovery.js +12 -10
  542. package/dist/client/chat/run-recovery.js.map +1 -1
  543. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  544. package/dist/client/composer/TiptapComposer.js +8 -0
  545. package/dist/client/composer/TiptapComposer.js.map +1 -1
  546. package/dist/client/index.d.ts +2 -0
  547. package/dist/client/index.d.ts.map +1 -1
  548. package/dist/client/index.js +2 -0
  549. package/dist/client/index.js.map +1 -1
  550. package/dist/client/integrations/api.d.ts +115 -0
  551. package/dist/client/integrations/api.d.ts.map +1 -0
  552. package/dist/client/integrations/api.js +123 -0
  553. package/dist/client/integrations/api.js.map +1 -0
  554. package/dist/client/integrations/index.d.ts +1 -0
  555. package/dist/client/integrations/index.d.ts.map +1 -1
  556. package/dist/client/integrations/index.js +1 -0
  557. package/dist/client/integrations/index.js.map +1 -1
  558. package/dist/client/transcription/use-live-transcription.d.ts.map +1 -1
  559. package/dist/client/transcription/use-live-transcription.js +59 -5
  560. package/dist/client/transcription/use-live-transcription.js.map +1 -1
  561. package/dist/client/use-run-stuck-detection.d.ts +16 -1
  562. package/dist/client/use-run-stuck-detection.d.ts.map +1 -1
  563. package/dist/client/use-run-stuck-detection.js +23 -4
  564. package/dist/client/use-run-stuck-detection.js.map +1 -1
  565. package/dist/collab/awareness.d.ts +2 -2
  566. package/dist/collab/awareness.d.ts.map +1 -1
  567. package/dist/deploy/build.d.ts.map +1 -1
  568. package/dist/deploy/build.js +49 -4
  569. package/dist/deploy/build.js.map +1 -1
  570. package/dist/deploy/workspace-deploy.d.ts.map +1 -1
  571. package/dist/deploy/workspace-deploy.js +31 -2
  572. package/dist/deploy/workspace-deploy.js.map +1 -1
  573. package/dist/file-upload/types.d.ts +2 -0
  574. package/dist/file-upload/types.d.ts.map +1 -1
  575. package/dist/file-upload/types.js.map +1 -1
  576. package/dist/index.d.ts +2 -0
  577. package/dist/index.d.ts.map +1 -1
  578. package/dist/index.js +2 -0
  579. package/dist/index.js.map +1 -1
  580. package/dist/integrations/a2a-continuations-store.d.ts.map +1 -1
  581. package/dist/integrations/a2a-continuations-store.js +6 -4
  582. package/dist/integrations/a2a-continuations-store.js.map +1 -1
  583. package/dist/integrations/adapters/discord.d.ts +3 -0
  584. package/dist/integrations/adapters/discord.d.ts.map +1 -0
  585. package/dist/integrations/adapters/discord.js +261 -0
  586. package/dist/integrations/adapters/discord.js.map +1 -0
  587. package/dist/integrations/adapters/index.d.ts +4 -0
  588. package/dist/integrations/adapters/index.d.ts.map +1 -0
  589. package/dist/integrations/adapters/index.js +26 -0
  590. package/dist/integrations/adapters/index.js.map +1 -0
  591. package/dist/integrations/adapters/microsoft-teams.d.ts +5 -0
  592. package/dist/integrations/adapters/microsoft-teams.d.ts.map +1 -0
  593. package/dist/integrations/adapters/microsoft-teams.js +295 -0
  594. package/dist/integrations/adapters/microsoft-teams.js.map +1 -0
  595. package/dist/integrations/adapters/slack.d.ts +8 -2
  596. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  597. package/dist/integrations/adapters/slack.js +736 -27
  598. package/dist/integrations/adapters/slack.js.map +1 -1
  599. package/dist/integrations/adapters/telegram.d.ts +0 -2
  600. package/dist/integrations/adapters/telegram.d.ts.map +1 -1
  601. package/dist/integrations/adapters/telegram.js +49 -15
  602. package/dist/integrations/adapters/telegram.js.map +1 -1
  603. package/dist/integrations/adapters/whatsapp.d.ts +0 -2
  604. package/dist/integrations/adapters/whatsapp.d.ts.map +1 -1
  605. package/dist/integrations/adapters/whatsapp.js +40 -17
  606. package/dist/integrations/adapters/whatsapp.js.map +1 -1
  607. package/dist/integrations/catalog.d.ts +75 -0
  608. package/dist/integrations/catalog.d.ts.map +1 -0
  609. package/dist/integrations/catalog.js +451 -0
  610. package/dist/integrations/catalog.js.map +1 -0
  611. package/dist/integrations/controls-store.d.ts +44 -0
  612. package/dist/integrations/controls-store.d.ts.map +1 -0
  613. package/dist/integrations/controls-store.js +129 -0
  614. package/dist/integrations/controls-store.js.map +1 -0
  615. package/dist/integrations/index.d.ts +13 -1
  616. package/dist/integrations/index.d.ts.map +1 -1
  617. package/dist/integrations/index.js +9 -0
  618. package/dist/integrations/index.js.map +1 -1
  619. package/dist/integrations/installations-store.d.ts +112 -0
  620. package/dist/integrations/installations-store.d.ts.map +1 -0
  621. package/dist/integrations/installations-store.js +493 -0
  622. package/dist/integrations/installations-store.js.map +1 -0
  623. package/dist/integrations/integration-memory.d.ts +24 -0
  624. package/dist/integrations/integration-memory.d.ts.map +1 -0
  625. package/dist/integrations/integration-memory.js +136 -0
  626. package/dist/integrations/integration-memory.js.map +1 -0
  627. package/dist/integrations/pending-tasks-retry-job.d.ts.map +1 -1
  628. package/dist/integrations/pending-tasks-retry-job.js +6 -5
  629. package/dist/integrations/pending-tasks-retry-job.js.map +1 -1
  630. package/dist/integrations/pending-tasks-store.d.ts +17 -0
  631. package/dist/integrations/pending-tasks-store.d.ts.map +1 -1
  632. package/dist/integrations/pending-tasks-store.js +71 -5
  633. package/dist/integrations/pending-tasks-store.js.map +1 -1
  634. package/dist/integrations/plugin.d.ts.map +1 -1
  635. package/dist/integrations/plugin.js +520 -35
  636. package/dist/integrations/plugin.js.map +1 -1
  637. package/dist/integrations/scope-store.d.ts +65 -0
  638. package/dist/integrations/scope-store.d.ts.map +1 -0
  639. package/dist/integrations/scope-store.js +361 -0
  640. package/dist/integrations/scope-store.js.map +1 -0
  641. package/dist/integrations/slack-manifest.d.ts +66 -0
  642. package/dist/integrations/slack-manifest.d.ts.map +1 -0
  643. package/dist/integrations/slack-manifest.js +70 -0
  644. package/dist/integrations/slack-manifest.js.map +1 -0
  645. package/dist/integrations/slack-oauth.d.ts +99 -0
  646. package/dist/integrations/slack-oauth.d.ts.map +1 -0
  647. package/dist/integrations/slack-oauth.js +226 -0
  648. package/dist/integrations/slack-oauth.js.map +1 -0
  649. package/dist/integrations/types.d.ts +144 -0
  650. package/dist/integrations/types.d.ts.map +1 -1
  651. package/dist/integrations/types.js +16 -1
  652. package/dist/integrations/types.js.map +1 -1
  653. package/dist/integrations/usage-budget-store.d.ts +84 -0
  654. package/dist/integrations/usage-budget-store.d.ts.map +1 -0
  655. package/dist/integrations/usage-budget-store.js +650 -0
  656. package/dist/integrations/usage-budget-store.js.map +1 -0
  657. package/dist/integrations/webhook-handler.d.ts +4 -0
  658. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  659. package/dist/integrations/webhook-handler.js +415 -47
  660. package/dist/integrations/webhook-handler.js.map +1 -1
  661. package/dist/jobs/scheduler.d.ts +6 -0
  662. package/dist/jobs/scheduler.d.ts.map +1 -1
  663. package/dist/jobs/scheduler.js +83 -4
  664. package/dist/jobs/scheduler.js.map +1 -1
  665. package/dist/jobs/tools.d.ts.map +1 -1
  666. package/dist/jobs/tools.js +43 -11
  667. package/dist/jobs/tools.js.map +1 -1
  668. package/dist/provider-api/index.d.ts +4 -4
  669. package/dist/provider-api/index.d.ts.map +1 -1
  670. package/dist/provider-api/index.js +72 -1
  671. package/dist/provider-api/index.js.map +1 -1
  672. package/dist/resources/handlers.d.ts.map +1 -1
  673. package/dist/resources/handlers.js +57 -15
  674. package/dist/resources/handlers.js.map +1 -1
  675. package/dist/resources/script-helpers.d.ts.map +1 -1
  676. package/dist/resources/script-helpers.js +34 -8
  677. package/dist/resources/script-helpers.js.map +1 -1
  678. package/dist/resources/store.d.ts +10 -0
  679. package/dist/resources/store.d.ts.map +1 -1
  680. package/dist/resources/store.js +54 -47
  681. package/dist/resources/store.js.map +1 -1
  682. package/dist/scripts/call-agent.d.ts.map +1 -1
  683. package/dist/scripts/call-agent.js +106 -1
  684. package/dist/scripts/call-agent.js.map +1 -1
  685. package/dist/server/agent-chat-plugin.d.ts +15 -4
  686. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  687. package/dist/server/agent-chat-plugin.js +248 -113
  688. package/dist/server/agent-chat-plugin.js.map +1 -1
  689. package/dist/server/auth.d.ts.map +1 -1
  690. package/dist/server/auth.js +10 -14
  691. package/dist/server/auth.js.map +1 -1
  692. package/dist/server/builder-design-systems.d.ts +3 -1
  693. package/dist/server/builder-design-systems.d.ts.map +1 -1
  694. package/dist/server/builder-design-systems.js +9 -2
  695. package/dist/server/builder-design-systems.js.map +1 -1
  696. package/dist/server/edge.d.ts +1 -1
  697. package/dist/server/edge.d.ts.map +1 -1
  698. package/dist/server/edge.js +1 -1
  699. package/dist/server/edge.js.map +1 -1
  700. package/dist/server/index.d.ts +2 -1
  701. package/dist/server/index.d.ts.map +1 -1
  702. package/dist/server/index.js +2 -1
  703. package/dist/server/index.js.map +1 -1
  704. package/dist/server/request-context.d.ts +18 -0
  705. package/dist/server/request-context.d.ts.map +1 -1
  706. package/dist/server/request-context.js.map +1 -1
  707. package/dist/server/social-og-image.d.ts.map +1 -1
  708. package/dist/server/social-og-image.js +3 -2
  709. package/dist/server/social-og-image.js.map +1 -1
  710. package/dist/server/transcribe-voice.d.ts +1 -1
  711. package/dist/styles/agent-native.css +62 -44
  712. package/dist/templates/default/.agents/skills/capture-learnings/SKILL.md +22 -9
  713. package/dist/templates/default/AGENTS.md +7 -3
  714. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +1 -1
  715. package/dist/templates/workspace-core/.agents/skills/capture-learnings/SKILL.md +22 -9
  716. package/dist/templates/workspace-core/.agents/skills/extension-points/SKILL.md +6 -3
  717. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +25 -0
  718. package/dist/templates/workspace-core/.agents/skills/integration-webhooks/SKILL.md +15 -0
  719. package/dist/templates/workspace-core/AGENTS.md +3 -2
  720. package/dist/usage/store.d.ts +7 -0
  721. package/dist/usage/store.d.ts.map +1 -1
  722. package/dist/usage/store.js +24 -3
  723. package/dist/usage/store.js.map +1 -1
  724. package/docs/content/automation-connectors.mdx +80 -0
  725. package/docs/content/extensions.mdx +8 -0
  726. package/docs/content/locales/ar-SA/extensions.mdx +8 -0
  727. package/docs/content/locales/ar-SA/messaging.mdx +84 -15
  728. package/docs/content/locales/ar-SA/template-clips.mdx +1 -0
  729. package/docs/content/locales/ar-SA/template-design.mdx +1 -0
  730. package/docs/content/locales/de-DE/extensions.mdx +10 -0
  731. package/docs/content/locales/de-DE/messaging.mdx +92 -15
  732. package/docs/content/locales/de-DE/template-clips.mdx +1 -0
  733. package/docs/content/locales/de-DE/template-design.mdx +1 -0
  734. package/docs/content/locales/es-ES/extensions.mdx +10 -0
  735. package/docs/content/locales/es-ES/messaging.mdx +91 -15
  736. package/docs/content/locales/es-ES/template-clips.mdx +1 -0
  737. package/docs/content/locales/es-ES/template-design.mdx +1 -0
  738. package/docs/content/locales/fr-FR/extensions.mdx +10 -0
  739. package/docs/content/locales/fr-FR/messaging.mdx +91 -15
  740. package/docs/content/locales/fr-FR/template-clips.mdx +1 -0
  741. package/docs/content/locales/fr-FR/template-design.mdx +1 -0
  742. package/docs/content/locales/hi-IN/extensions.mdx +8 -0
  743. package/docs/content/locales/hi-IN/messaging.mdx +81 -15
  744. package/docs/content/locales/hi-IN/template-clips.mdx +1 -0
  745. package/docs/content/locales/hi-IN/template-design.mdx +1 -0
  746. package/docs/content/locales/ja-JP/extensions.mdx +9 -0
  747. package/docs/content/locales/ja-JP/messaging.mdx +81 -15
  748. package/docs/content/locales/ja-JP/template-clips.mdx +1 -0
  749. package/docs/content/locales/ja-JP/template-design.mdx +1 -0
  750. package/docs/content/locales/ko-KR/extensions.mdx +8 -0
  751. package/docs/content/locales/ko-KR/messaging.mdx +80 -15
  752. package/docs/content/locales/ko-KR/template-clips.mdx +1 -0
  753. package/docs/content/locales/ko-KR/template-design.mdx +1 -0
  754. package/docs/content/locales/pt-BR/extensions.mdx +9 -0
  755. package/docs/content/locales/pt-BR/messaging.mdx +88 -15
  756. package/docs/content/locales/pt-BR/template-clips.mdx +1 -0
  757. package/docs/content/locales/pt-BR/template-design.mdx +1 -0
  758. package/docs/content/locales/zh-CN/extensions.mdx +6 -0
  759. package/docs/content/locales/zh-CN/messaging.mdx +78 -15
  760. package/docs/content/locales/zh-CN/template-clips.mdx +1 -0
  761. package/docs/content/locales/zh-CN/template-design.mdx +1 -0
  762. package/docs/content/locales/zh-TW/extensions.mdx +6 -0
  763. package/docs/content/locales/zh-TW/messaging.mdx +78 -15
  764. package/docs/content/locales/zh-TW/template-clips.mdx +1 -0
  765. package/docs/content/locales/zh-TW/template-design.mdx +1 -0
  766. package/docs/content/messaging.mdx +227 -45
  767. package/docs/content/template-clips.mdx +3 -0
  768. package/docs/content/template-design.mdx +4 -0
  769. package/package.json +5 -1
  770. package/src/templates/default/.agents/skills/capture-learnings/SKILL.md +22 -9
  771. package/src/templates/default/AGENTS.md +7 -3
  772. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +1 -1
  773. package/src/templates/workspace-core/.agents/skills/capture-learnings/SKILL.md +22 -9
  774. package/src/templates/workspace-core/.agents/skills/extension-points/SKILL.md +6 -3
  775. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +25 -0
  776. package/src/templates/workspace-core/.agents/skills/integration-webhooks/SKILL.md +15 -0
  777. package/src/templates/workspace-core/AGENTS.md +3 -2
@@ -45,6 +45,27 @@ export interface FigmaSvgExportParams {
45
45
  filename?: string;
46
46
  nodeId?: string;
47
47
  embedImages?: boolean;
48
+ width?: number;
49
+ height?: number;
50
+ }
51
+
52
+ export interface LiveFigmaSvgSource {
53
+ /** The already-rendered preview document. Geometry comes from this live DOM. */
54
+ document: Document;
55
+ /** Optional explicit root. Defaults to nodeId, then document.body. */
56
+ root?: Element | null;
57
+ /** Stored screen geometry wins over a transient iframe viewport when supplied. */
58
+ width?: number | null;
59
+ height?: number | null;
60
+ title?: string | null;
61
+ }
62
+
63
+ export interface LiveFigmaSvgSnapshot {
64
+ /** Script-free runtime snapshot supplied by the localhost editor bridge. */
65
+ html: string;
66
+ width?: number | null;
67
+ height?: number | null;
68
+ title?: string | null;
48
69
  }
49
70
 
50
71
  export interface FigmaSvgCopyEnvironment {
@@ -54,6 +75,716 @@ export interface FigmaSvgCopyEnvironment {
54
75
  callExportAction?: (
55
76
  params: FigmaSvgExportParams,
56
77
  ) => Promise<FigmaSvgExportActionResult>;
78
+ /**
79
+ * Prefer the browser's already-rendered iframe DOM. This works in hosted and
80
+ * serverless deployments without shipping Chromium and preserves live Alpine
81
+ * state, loaded fonts, responsive layout, and unsaved visual-edit previews.
82
+ */
83
+ liveSource?: LiveFigmaSvgSource | null;
84
+ /** Cross-origin localhost fallback captured by the trusted editor bridge. */
85
+ liveSnapshot?: LiveFigmaSvgSnapshot | null;
86
+ }
87
+
88
+ const XMLNS = "http://www.w3.org/2000/svg";
89
+ const MAX_CLIENT_EMBEDDED_IMAGE_BYTES = 8 * 1024 * 1024;
90
+ const CLIENT_IMAGE_MIME_TYPES = new Set([
91
+ "image/png",
92
+ "image/jpeg",
93
+ "image/webp",
94
+ "image/gif",
95
+ "image/avif",
96
+ ]);
97
+
98
+ function xml(value: unknown): string {
99
+ return String(value ?? "")
100
+ .replace(/&/g, "&amp;")
101
+ .replace(/"/g, "&quot;")
102
+ .replace(/</g, "&lt;")
103
+ .replace(/>/g, "&gt;");
104
+ }
105
+
106
+ function number(value: number): string {
107
+ if (!Number.isFinite(value)) return "0";
108
+ return String(Math.round(value * 1000) / 1000);
109
+ }
110
+
111
+ function positive(value: number | null | undefined): value is number {
112
+ return typeof value === "number" && Number.isFinite(value) && value > 0;
113
+ }
114
+
115
+ function transparent(value: string): boolean {
116
+ return (
117
+ !value ||
118
+ value === "transparent" ||
119
+ /rgba?\([^)]*(?:,|\s\/)\s*0(?:\.0+)?\s*\)$/i.test(value)
120
+ );
121
+ }
122
+
123
+ function splitCssList(value: string): string[] {
124
+ const parts: string[] = [];
125
+ let depth = 0;
126
+ let current = "";
127
+ for (const character of value) {
128
+ if (character === "(") depth += 1;
129
+ if (character === ")") depth = Math.max(0, depth - 1);
130
+ if (character === "," && depth === 0) {
131
+ parts.push(current.trim());
132
+ current = "";
133
+ } else {
134
+ current += character;
135
+ }
136
+ }
137
+ if (current.trim()) parts.push(current.trim());
138
+ return parts;
139
+ }
140
+
141
+ function simpleBoxShadow(value: string): {
142
+ color: string;
143
+ opacity: number | null;
144
+ offsetX: number;
145
+ offsetY: number;
146
+ blur: number;
147
+ spread: number;
148
+ } | null {
149
+ const shadow = splitCssList(value)[0]?.trim();
150
+ if (!shadow || /\binset\b/i.test(shadow)) return null;
151
+ const colorMatch = shadow.match(/(?:rgba?|hsla?)\([^)]*\)|#[0-9a-f]{3,8}\b/i);
152
+ if (!colorMatch) return null;
153
+ const lengths = shadow
154
+ .replace(colorMatch[0], "")
155
+ .trim()
156
+ .match(/^(-?[\d.]+)px\s+(-?[\d.]+)px\s+([\d.]+)px(?:\s+(-?[\d.]+)px)?$/);
157
+ if (!lengths) return null;
158
+
159
+ let color = colorMatch[0];
160
+ let opacity: number | null = null;
161
+ const rgba = color.match(
162
+ /^rgba\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)\s*\)$/i,
163
+ );
164
+ const modernRgb = color.match(
165
+ /^rgb\(\s*([\d.]+)\s+([\d.]+)\s+([\d.]+)\s*\/\s*([\d.]+)\s*\)$/i,
166
+ );
167
+ const alphaColor = rgba ?? modernRgb;
168
+ if (alphaColor) {
169
+ color = `rgb(${alphaColor[1]}, ${alphaColor[2]}, ${alphaColor[3]})`;
170
+ opacity = Math.max(0, Math.min(1, Number(alphaColor[4])));
171
+ }
172
+
173
+ return {
174
+ color,
175
+ opacity,
176
+ offsetX: Number(lengths[1]),
177
+ offsetY: Number(lengths[2]),
178
+ blur: Number(lengths[3]),
179
+ spread: Number(lengths[4] ?? 0),
180
+ };
181
+ }
182
+
183
+ function svgGradientFill(
184
+ backgroundImage: string,
185
+ nextId: () => string,
186
+ defs: string[],
187
+ ): string | null {
188
+ const match = backgroundImage.match(/^(linear|radial)-gradient\((.*)\)$/i);
189
+ if (!match) return null;
190
+ const parts = splitCssList(match[2]);
191
+ let angle = 180;
192
+ if (match[1].toLowerCase() === "linear" && /deg$/i.test(parts[0] || "")) {
193
+ angle = Number.parseFloat(parts.shift() || "180") || 180;
194
+ }
195
+ const stops = parts.map((part, index) => {
196
+ const stopMatch = part.match(/^(.*?)(?:\s+(-?[\d.]+)%?)?$/);
197
+ const color = stopMatch?.[1]?.trim() || part;
198
+ const explicit = stopMatch?.[2];
199
+ const offset = explicit
200
+ ? Math.max(0, Math.min(100, Number(explicit)))
201
+ : parts.length <= 1
202
+ ? 0
203
+ : (index / (parts.length - 1)) * 100;
204
+ return `<stop offset="${number(offset)}%" stop-color="${xml(color)}"/>`;
205
+ });
206
+ if (stops.length === 0) return null;
207
+ const gradientId = nextId();
208
+ if (match[1].toLowerCase() === "radial") {
209
+ defs.push(
210
+ `<radialGradient id="${gradientId}" cx="50%" cy="50%" r="50%">${stops.join("")}</radialGradient>`,
211
+ );
212
+ } else {
213
+ defs.push(
214
+ `<linearGradient id="${gradientId}" x1="0" y1="0" x2="1" y2="0" gradientTransform="rotate(${number(angle - 90)} .5 .5)">${stops.join("")}</linearGradient>`,
215
+ );
216
+ }
217
+ return `url(#${gradientId})`;
218
+ }
219
+
220
+ function safeClientFilename(title: string | null | undefined): string {
221
+ const safe = (title || "design")
222
+ .replace(/[^a-zA-Z0-9_-]/g, "-")
223
+ .replace(/-+/g, "-")
224
+ .replace(/^-|-$/g, "");
225
+ return `${safe || "design"}-figma-${Date.now()}.svg`;
226
+ }
227
+
228
+ function queryNodeById(doc: Document, nodeId: string): Element | null {
229
+ for (const element of Array.from(
230
+ doc.querySelectorAll("[data-agent-native-node-id]"),
231
+ )) {
232
+ if (element.getAttribute("data-agent-native-node-id") === nodeId) {
233
+ return element;
234
+ }
235
+ }
236
+ return null;
237
+ }
238
+
239
+ function directText(element: Element): string {
240
+ return Array.from(element.childNodes)
241
+ .filter((node) => node.nodeType === Node.TEXT_NODE)
242
+ .map((node) => node.textContent ?? "")
243
+ .join("")
244
+ .trim();
245
+ }
246
+
247
+ interface MeasuredTextLine {
248
+ text: string;
249
+ left: number;
250
+ top: number;
251
+ }
252
+
253
+ function measuredDirectTextLines(element: Element): MeasuredTextLine[] | null {
254
+ const textNodes = Array.from(element.childNodes).filter(
255
+ (node): node is Text => node.nodeType === Node.TEXT_NODE,
256
+ );
257
+ if (textNodes.length !== 1) return null;
258
+ const node = textNodes[0];
259
+ const value = node.textContent ?? "";
260
+ if (!value.trim() || value.length > 10_000) return null;
261
+ const range = element.ownerDocument.createRange();
262
+ if (typeof range.getBoundingClientRect !== "function") return null;
263
+
264
+ const lines: Array<MeasuredTextLine & { right: number; bottom: number }> = [];
265
+ try {
266
+ for (let index = 0; index < value.length; index += 1) {
267
+ const character = value[index] ?? "";
268
+ if (character === "\n" || character === "\r") continue;
269
+ range.setStart(node, index);
270
+ range.setEnd(node, index + 1);
271
+ const rect = range.getBoundingClientRect();
272
+ if (!Number.isFinite(rect.top) || rect.width <= 0 || rect.height <= 0) {
273
+ if (/\s/.test(character) && lines.length) {
274
+ lines[lines.length - 1]!.text += character;
275
+ }
276
+ continue;
277
+ }
278
+ const current = lines[lines.length - 1];
279
+ if (!current || Math.abs(current.top - rect.top) > 1) {
280
+ lines.push({
281
+ text: character,
282
+ left: rect.left,
283
+ top: rect.top,
284
+ right: rect.right,
285
+ bottom: rect.bottom,
286
+ });
287
+ } else {
288
+ current.text += character;
289
+ current.left = Math.min(current.left, rect.left);
290
+ current.top = Math.min(current.top, rect.top);
291
+ current.right = Math.max(current.right, rect.right);
292
+ current.bottom = Math.max(current.bottom, rect.bottom);
293
+ }
294
+ }
295
+ } finally {
296
+ range.detach?.();
297
+ }
298
+
299
+ return lines
300
+ .map((line) => ({
301
+ text: line.text.trim(),
302
+ left: line.left,
303
+ top: line.top,
304
+ }))
305
+ .filter((line) => line.text);
306
+ }
307
+
308
+ function sanitizeNestedSvg(element: Element): string {
309
+ const clone = element.cloneNode(true) as Element;
310
+ clone
311
+ .querySelectorAll("script, foreignObject")
312
+ .forEach((node) => node.remove());
313
+ for (const node of [clone, ...Array.from(clone.querySelectorAll("*"))]) {
314
+ for (const attribute of Array.from(node.attributes)) {
315
+ if (/^on/i.test(attribute.name)) node.removeAttribute(attribute.name);
316
+ if (
317
+ (attribute.name === "href" || attribute.name === "xlink:href") &&
318
+ /^javascript:/i.test(attribute.value.trim())
319
+ ) {
320
+ node.removeAttribute(attribute.name);
321
+ }
322
+ }
323
+ }
324
+ return new XMLSerializer().serializeToString(clone);
325
+ }
326
+
327
+ function liveSvgRoot(source: LiveFigmaSvgSource, nodeId?: string): Element {
328
+ if (nodeId) {
329
+ const selected = queryNodeById(source.document, nodeId);
330
+ if (!selected) {
331
+ throw new Error(`The selected live layer "${nodeId}" no longer exists`);
332
+ }
333
+ return selected;
334
+ }
335
+ const root = source.root ?? source.document.body;
336
+ if (!root)
337
+ throw new Error("The live preview has no renderable document body");
338
+ return root;
339
+ }
340
+
341
+ /**
342
+ * Serialize the already-laid-out iframe DOM to genuine SVG primitives. This
343
+ * deliberately emits no foreignObject: Figma imports the result as editable
344
+ * rectangles, text, images, and native SVG paths instead of one opaque blob.
345
+ */
346
+ export function buildFigmaSvgFromLiveDocument(
347
+ source: LiveFigmaSvgSource,
348
+ nodeId?: string,
349
+ ): FigmaSvgExportActionResult & { svg: string } {
350
+ const doc = source.document;
351
+ const view = doc.defaultView;
352
+ if (!view) throw new Error("The live preview is not attached to a window");
353
+ const root = liveSvgRoot(source, nodeId);
354
+ const rootRect = root.getBoundingClientRect();
355
+ const isDocumentRoot = root === doc.body || root === doc.documentElement;
356
+ const width = positive(source.width)
357
+ ? source.width
358
+ : Math.max(
359
+ 1,
360
+ rootRect.width,
361
+ isDocumentRoot ? doc.documentElement.scrollWidth : 0,
362
+ isDocumentRoot ? (doc.body?.scrollWidth ?? 0) : 0,
363
+ );
364
+ const height = positive(source.height)
365
+ ? source.height
366
+ : Math.max(
367
+ 1,
368
+ rootRect.height,
369
+ isDocumentRoot ? doc.documentElement.scrollHeight : 0,
370
+ isDocumentRoot ? (doc.body?.scrollHeight ?? 0) : 0,
371
+ );
372
+ const originX = rootRect.left;
373
+ const originY = rootRect.top;
374
+ let id = 0;
375
+ const defs: string[] = [];
376
+ const vectorized: string[] = [];
377
+ const approximated: Array<{ node: string; note: string }> = [];
378
+ const omitted: Array<{ node: string; reason: string }> = [];
379
+
380
+ const serialize = (element: Element): string => {
381
+ const style = view.getComputedStyle(element);
382
+ if (
383
+ style.display === "none" ||
384
+ style.visibility === "hidden" ||
385
+ style.opacity === "0" ||
386
+ element.getAttribute("data-agent-native-hidden") === "true" ||
387
+ element.closest("[data-agent-native-editor-chrome]")
388
+ ) {
389
+ return "";
390
+ }
391
+ const rect = element.getBoundingClientRect();
392
+ if (rect.width <= 0 || rect.height <= 0) return "";
393
+ const x = rect.left - originX;
394
+ const y = rect.top - originY;
395
+ const elementId =
396
+ element.getAttribute("data-agent-native-node-id") || `node-${++id}`;
397
+ const name =
398
+ element.getAttribute("data-agent-native-layer-name") ||
399
+ element.getAttribute("aria-label") ||
400
+ element.tagName.toLowerCase();
401
+ const opacity = Number.parseFloat(style.opacity || "1");
402
+ const opacityAttr = opacity < 1 ? ` opacity="${number(opacity)}"` : "";
403
+ const children = Array.from(element.children).map(serialize).join("");
404
+ const tag = element.tagName.toUpperCase();
405
+
406
+ if (tag === "SCRIPT" || tag === "STYLE" || tag === "LINK") return "";
407
+ if (tag === "SVG") {
408
+ vectorized.push(elementId);
409
+ return sanitizeNestedSvg(element).replace(
410
+ /^<svg\b([^>]*)>/i,
411
+ (_opening, attributes: string) => {
412
+ const cleanAttributes = attributes.replace(
413
+ /\s(?:x|y|width|height)="[^"]*"/gi,
414
+ "",
415
+ );
416
+ return `<svg x="${number(x)}" y="${number(y)}" width="${number(rect.width)}" height="${number(rect.height)}"${cleanAttributes}>`;
417
+ },
418
+ );
419
+ }
420
+ if (tag === "IMG") {
421
+ const image = element as HTMLImageElement;
422
+ const href = image.currentSrc || image.src;
423
+ if (!href) {
424
+ omitted.push({ node: elementId, reason: "Image has no source" });
425
+ return "";
426
+ }
427
+ vectorized.push(elementId);
428
+ const fit =
429
+ style.objectFit === "cover" ? "xMidYMid slice" : "xMidYMid meet";
430
+ return `<image id="${xml(elementId)}" data-name="${xml(name)}" x="${number(x)}" y="${number(y)}" width="${number(rect.width)}" height="${number(rect.height)}" href="${xml(href)}" preserveAspectRatio="${fit}"${opacityAttr}/>`;
431
+ }
432
+
433
+ const radius = Math.max(
434
+ 0,
435
+ Number.parseFloat(style.borderTopLeftRadius || "0") || 0,
436
+ );
437
+ const gradientFill = svgGradientFill(
438
+ style.backgroundImage,
439
+ () => `gradient-${++id}`,
440
+ defs,
441
+ );
442
+ if (style.transform && style.transform !== "none") {
443
+ approximated.push({
444
+ node: elementId,
445
+ note: "CSS transform flattened to its rendered bounding box",
446
+ });
447
+ }
448
+ if (
449
+ style.backgroundImage &&
450
+ style.backgroundImage !== "none" &&
451
+ !gradientFill
452
+ ) {
453
+ approximated.push({
454
+ node: elementId,
455
+ note: "Unsupported CSS background image omitted",
456
+ });
457
+ }
458
+ if (style.clipPath && style.clipPath !== "none") {
459
+ approximated.push({
460
+ node: elementId,
461
+ note: "CSS clip-path is not preserved in this SVG export",
462
+ });
463
+ }
464
+ if (
465
+ style.overflow === "hidden" ||
466
+ style.overflow === "clip" ||
467
+ style.overflowX === "hidden" ||
468
+ style.overflowX === "clip" ||
469
+ style.overflowY === "hidden" ||
470
+ style.overflowY === "clip"
471
+ ) {
472
+ approximated.push({
473
+ node: elementId,
474
+ note: "Overflow clipping is approximated; child geometry remains editable",
475
+ });
476
+ }
477
+ const fill =
478
+ gradientFill ??
479
+ (transparent(style.backgroundColor) ? "none" : style.backgroundColor);
480
+ const borderWidth = Number.parseFloat(style.borderTopWidth || "0") || 0;
481
+ const stroke =
482
+ borderWidth > 0 && style.borderTopStyle !== "none"
483
+ ? style.borderTopColor
484
+ : "none";
485
+ const dash =
486
+ style.borderTopStyle === "dashed" || style.borderTopStyle === "dotted"
487
+ ? ` stroke-dasharray="${number(borderWidth * 3)} ${number(borderWidth * 2)}"`
488
+ : "";
489
+ let filter = "";
490
+ if (style.boxShadow && style.boxShadow !== "none") {
491
+ const shadow = simpleBoxShadow(style.boxShadow);
492
+ if (shadow) {
493
+ const filterId = `shadow-${++id}`;
494
+ const floodOpacity =
495
+ shadow.opacity === null
496
+ ? ""
497
+ : ` flood-opacity="${number(shadow.opacity)}"`;
498
+ defs.push(
499
+ `<filter id="${filterId}" x="-50%" y="-50%" width="200%" height="200%"><feDropShadow dx="${number(shadow.offsetX)}" dy="${number(shadow.offsetY)}" stdDeviation="${number(shadow.blur / 2)}" flood-color="${xml(shadow.color)}"${floodOpacity}/></filter>`,
500
+ );
501
+ filter = ` filter="url(#${filterId})"`;
502
+ if (shadow.spread !== 0 || splitCssList(style.boxShadow).length > 1) {
503
+ approximated.push({
504
+ node: elementId,
505
+ note: "Shadow spread or additional shadows approximated",
506
+ });
507
+ }
508
+ } else {
509
+ approximated.push({
510
+ node: elementId,
511
+ note: "Complex box shadow omitted",
512
+ });
513
+ }
514
+ }
515
+
516
+ const text = directText(element);
517
+ const shapeNeeded =
518
+ fill !== "none" || stroke !== "none" || radius > 0 || filter !== "";
519
+ const shape = shapeNeeded
520
+ ? `<rect id="${xml(elementId)}" data-name="${xml(name)}" x="${number(x)}" y="${number(y)}" width="${number(rect.width)}" height="${number(rect.height)}" rx="${number(Math.min(radius, rect.width / 2, rect.height / 2))}" fill="${xml(fill)}" stroke="${xml(stroke)}" stroke-width="${number(borderWidth)}"${dash}${opacityAttr}${filter}/>`
521
+ : "";
522
+ let textNode = "";
523
+ if (text) {
524
+ const fontSize = Number.parseFloat(style.fontSize || "16") || 16;
525
+ const align = style.textAlign;
526
+ const anchor =
527
+ align === "center"
528
+ ? "middle"
529
+ : align === "right" || align === "end"
530
+ ? "end"
531
+ : "start";
532
+ const paddingLeft = Number.parseFloat(style.paddingLeft || "0") || 0;
533
+ const paddingRight = Number.parseFloat(style.paddingRight || "0") || 0;
534
+ const paddingTop = Number.parseFloat(style.paddingTop || "0") || 0;
535
+ const paddingBottom = Number.parseFloat(style.paddingBottom || "0") || 0;
536
+ const contentWidth = Math.max(0, rect.width - paddingLeft - paddingRight);
537
+ const textX =
538
+ anchor === "middle"
539
+ ? x + paddingLeft + contentWidth / 2
540
+ : anchor === "end"
541
+ ? x + rect.width - paddingRight
542
+ : x + paddingLeft;
543
+ const lineHeight =
544
+ Number.parseFloat(style.lineHeight || "") || fontSize * 1.2;
545
+ const contentHeight = Math.max(
546
+ 0,
547
+ rect.height - paddingTop - paddingBottom,
548
+ );
549
+ const textY =
550
+ y +
551
+ paddingTop +
552
+ Math.max(fontSize, (contentHeight - lineHeight) / 2 + fontSize);
553
+ const measuredLines = measuredDirectTextLines(element);
554
+ const textContent =
555
+ measuredLines && measuredLines.length > 1
556
+ ? measuredLines
557
+ .map(
558
+ (line) =>
559
+ `<tspan x="${number(line.left - originX)}" y="${number(line.top - originY + fontSize)}">${xml(line.text)}</tspan>`,
560
+ )
561
+ .join("")
562
+ : xml(text);
563
+ textNode = `<text data-name="${xml(name)}" x="${number(textX)}" y="${number(textY)}" fill="${xml(style.color)}" font-family="${xml(style.fontFamily)}" font-size="${number(fontSize)}" font-weight="${xml(style.fontWeight)}" font-style="${xml(style.fontStyle)}" letter-spacing="${xml(style.letterSpacing)}" text-anchor="${anchor}"${opacityAttr}>${textContent}</text>`;
564
+ }
565
+ if (shape || textNode) vectorized.push(elementId);
566
+ return `${shape}${textNode}${children}`;
567
+ };
568
+
569
+ const body = serialize(root);
570
+ if (!body)
571
+ throw new Error("The live preview has no visible exportable layers");
572
+ const title = source.title ? `<title>${xml(source.title)}</title>` : "";
573
+ const defsMarkup = defs.length ? `<defs>${defs.join("")}</defs>` : "";
574
+ return {
575
+ ok: true,
576
+ svg:
577
+ `<?xml version="1.0" encoding="UTF-8"?>\n` +
578
+ `<svg xmlns="${XMLNS}" xmlns:xlink="http://www.w3.org/1999/xlink" width="${number(width)}" height="${number(height)}" viewBox="0 0 ${number(width)} ${number(height)}">${title}${defsMarkup}${body}</svg>`,
579
+ filename: safeClientFilename(source.title),
580
+ report: {
581
+ source: "live-dom",
582
+ vectorized,
583
+ approximated,
584
+ rasterized: [],
585
+ omitted,
586
+ warnings:
587
+ approximated.length > 0
588
+ ? [
589
+ "Some live CSS effects were flattened or omitted; inspect the approximations report.",
590
+ ]
591
+ : [],
592
+ vectorizedTextCaveat:
593
+ "Figma may convert imported SVG text to outlined vector paths.",
594
+ },
595
+ };
596
+ }
597
+
598
+ function bytesToBase64(bytes: Uint8Array): string {
599
+ let binary = "";
600
+ const chunkSize = 0x8000;
601
+ for (let offset = 0; offset < bytes.length; offset += chunkSize) {
602
+ binary += String.fromCharCode(
603
+ ...bytes.subarray(offset, offset + chunkSize),
604
+ );
605
+ }
606
+ return btoa(binary);
607
+ }
608
+
609
+ async function embedLiveSvgImages(
610
+ result: FigmaSvgExportActionResult & { svg: string },
611
+ ): Promise<FigmaSvgExportActionResult & { svg: string }> {
612
+ const parsed = new DOMParser().parseFromString(result.svg, "image/svg+xml");
613
+ if (parsed.querySelector("parsererror")) return result;
614
+ const omitted: Array<{ node: string; reason: string }> = [];
615
+ await Promise.all(
616
+ Array.from(parsed.querySelectorAll("image")).map(async (image) => {
617
+ const href =
618
+ image.getAttribute("href") || image.getAttribute("xlink:href");
619
+ if (!href || !/^https?:\/\//i.test(href)) return;
620
+ try {
621
+ const response = await fetch(href, {
622
+ credentials: "omit",
623
+ redirect: "follow",
624
+ signal: AbortSignal.timeout(10_000),
625
+ });
626
+ const mimeType = (response.headers.get("content-type") || "")
627
+ .split(";", 1)[0]
628
+ .trim()
629
+ .toLowerCase();
630
+ const contentLength = Number(
631
+ response.headers.get("content-length") || 0,
632
+ );
633
+ if (
634
+ !response.ok ||
635
+ !CLIENT_IMAGE_MIME_TYPES.has(mimeType) ||
636
+ (Number.isFinite(contentLength) &&
637
+ contentLength > MAX_CLIENT_EMBEDDED_IMAGE_BYTES)
638
+ ) {
639
+ throw new Error("image response was not safe to embed");
640
+ }
641
+ const bytes = new Uint8Array(await response.arrayBuffer());
642
+ if (bytes.byteLength > MAX_CLIENT_EMBEDDED_IMAGE_BYTES) {
643
+ throw new Error("image exceeded the embed size limit");
644
+ }
645
+ image.setAttribute(
646
+ "href",
647
+ `data:${mimeType};base64,${bytesToBase64(bytes)}`,
648
+ );
649
+ image.removeAttribute("xlink:href");
650
+ } catch {
651
+ // Do not persist an expiring Figma CDN URL in a supposedly self-
652
+ // contained artifact. A missing image is explicit in the report and
653
+ // safer than an export that silently breaks hours later.
654
+ omitted.push({
655
+ node: image.getAttribute("id") || "image",
656
+ reason: "Remote image could not be safely embedded",
657
+ });
658
+ image.remove();
659
+ }
660
+ }),
661
+ );
662
+ const report =
663
+ result.report && typeof result.report === "object"
664
+ ? (result.report as Record<string, unknown>)
665
+ : {};
666
+ const previousOmitted = Array.isArray(report.omitted) ? report.omitted : [];
667
+ const previousWarnings = Array.isArray(report.warnings)
668
+ ? report.warnings
669
+ : [];
670
+ return {
671
+ ...result,
672
+ svg: new XMLSerializer().serializeToString(parsed.documentElement),
673
+ report: {
674
+ ...report,
675
+ omitted: [...previousOmitted, ...omitted],
676
+ warnings:
677
+ omitted.length > 0
678
+ ? [
679
+ ...previousWarnings,
680
+ "One or more remote images were omitted because they could not be safely embedded.",
681
+ ]
682
+ : previousWarnings,
683
+ },
684
+ };
685
+ }
686
+
687
+ /**
688
+ * Defense-in-depth sanitizer for cross-origin runtime snapshots. The bridge
689
+ * already strips active content before posting; this receiver repeats the
690
+ * policy before assigning srcdoc so a forged/stale message is still inert.
691
+ */
692
+ export function sanitizeLiveFigmaSvgSnapshotHtml(html: string): string {
693
+ const parsed = new DOMParser().parseFromString(html, "text/html");
694
+ parsed
695
+ .querySelectorAll(
696
+ "script,iframe,object,embed,base,link,meta,template,noscript,foreignObject,video,audio,source,track,animate,set",
697
+ )
698
+ .forEach((node) => node.remove());
699
+ for (const node of [
700
+ parsed.documentElement,
701
+ ...Array.from(parsed.querySelectorAll("*")),
702
+ ]) {
703
+ for (const attribute of Array.from(node.attributes)) {
704
+ const name = attribute.name.toLowerCase();
705
+ if (
706
+ name.startsWith("on") ||
707
+ name === "srcdoc" ||
708
+ name === "autofocus" ||
709
+ name === "action" ||
710
+ name === "formaction" ||
711
+ /javascript\s*:/i.test(attribute.value)
712
+ ) {
713
+ node.removeAttribute(attribute.name);
714
+ }
715
+ }
716
+ }
717
+ let head = parsed.head;
718
+ if (!head) {
719
+ head = parsed.createElement("head");
720
+ parsed.documentElement.prepend(head);
721
+ }
722
+ const csp = parsed.createElement("meta");
723
+ csp.setAttribute("http-equiv", "Content-Security-Policy");
724
+ csp.setAttribute(
725
+ "content",
726
+ "default-src 'none'; img-src data: blob:; style-src 'unsafe-inline'; font-src data:; media-src 'none'; frame-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'",
727
+ );
728
+ head.prepend(csp);
729
+ return `<!doctype html>\n${parsed.documentElement.outerHTML}`;
730
+ }
731
+
732
+ export function prepareLiveFigmaSvgSnapshotFrame(
733
+ iframe: HTMLIFrameElement,
734
+ snapshot: LiveFigmaSvgSnapshot,
735
+ ): void {
736
+ iframe.setAttribute("aria-hidden", "true");
737
+ // allow-same-origin keeps contentDocument readable; deliberately omit
738
+ // allow-scripts, allow-forms, allow-popups, and allow-top-navigation.
739
+ iframe.setAttribute("sandbox", "allow-same-origin");
740
+ iframe.setAttribute("referrerpolicy", "no-referrer");
741
+ iframe.tabIndex = -1;
742
+ iframe.style.cssText =
743
+ "position:fixed;inset:auto auto -100000px -100000px;visibility:hidden;pointer-events:none;border:0";
744
+ iframe.style.width = `${positive(snapshot.width) ? snapshot.width : 1440}px`;
745
+ iframe.style.height = `${positive(snapshot.height) ? snapshot.height : 1200}px`;
746
+ iframe.srcdoc = sanitizeLiveFigmaSvgSnapshotHtml(snapshot.html);
747
+ }
748
+
749
+ async function buildFigmaSvgFromLiveSnapshot(
750
+ snapshot: LiveFigmaSvgSnapshot,
751
+ nodeId?: string,
752
+ ): Promise<FigmaSvgExportActionResult & { svg: string }> {
753
+ if (typeof document === "undefined") {
754
+ throw new Error("Live snapshot rendering requires a browser document");
755
+ }
756
+ const iframe = document.createElement("iframe");
757
+ prepareLiveFigmaSvgSnapshotFrame(iframe, snapshot);
758
+ document.body.appendChild(iframe);
759
+ try {
760
+ await new Promise<void>((resolve, reject) => {
761
+ const timer = window.setTimeout(
762
+ () => reject(new Error("Live export snapshot timed out")),
763
+ 3_000,
764
+ );
765
+ iframe.addEventListener(
766
+ "load",
767
+ () => {
768
+ window.clearTimeout(timer);
769
+ resolve();
770
+ },
771
+ { once: true },
772
+ );
773
+ });
774
+ const doc = iframe.contentDocument;
775
+ if (!doc?.documentElement) throw new Error("Live snapshot did not render");
776
+ return buildFigmaSvgFromLiveDocument(
777
+ {
778
+ document: doc,
779
+ width: snapshot.width,
780
+ height: snapshot.height,
781
+ title: snapshot.title,
782
+ },
783
+ nodeId,
784
+ );
785
+ } finally {
786
+ iframe.remove();
787
+ }
57
788
  }
58
789
 
59
790
  function defaultFigmaSvgCopyEnvironment(): FigmaSvgCopyEnvironment {
@@ -124,6 +855,68 @@ export interface FigmaSvgCopyResult {
124
855
  report: unknown;
125
856
  }
126
857
 
858
+ function actionParams(params: FigmaSvgExportParams): FigmaSvgExportParams {
859
+ return {
860
+ ...(params.designId ? { designId: params.designId } : {}),
861
+ ...(params.fileId ? { fileId: params.fileId } : {}),
862
+ ...(params.filename ? { filename: params.filename } : {}),
863
+ ...(params.nodeId ? { nodeId: params.nodeId } : {}),
864
+ ...(params.embedImages !== undefined
865
+ ? { embedImages: params.embedImages }
866
+ : {}),
867
+ ...(positive(params.width) ? { width: params.width } : {}),
868
+ ...(positive(params.height) ? { height: params.height } : {}),
869
+ };
870
+ }
871
+
872
+ /**
873
+ * Prefer a synchronous live-DOM conversion and retain the action as a fallback
874
+ * for agent calls, non-rendered screens, and browsers that cannot expose the
875
+ * preview document. The live path is what makes exports hosted/serverless-safe.
876
+ */
877
+ export async function exportDesignAsFigmaSvg(
878
+ params: FigmaSvgExportParams,
879
+ environment: FigmaSvgCopyEnvironment = defaultFigmaSvgCopyEnvironment(),
880
+ ): Promise<FigmaSvgExportActionResult & { svg: string }> {
881
+ if (environment.liveSource) {
882
+ try {
883
+ const result = buildFigmaSvgFromLiveDocument(
884
+ environment.liveSource,
885
+ params.nodeId,
886
+ );
887
+ return params.embedImages === false
888
+ ? result
889
+ : await embedLiveSvgImages(result);
890
+ } catch {
891
+ // A detached/cross-origin preview may become unreadable between the menu
892
+ // opening and activation. The authenticated action remains the fallback.
893
+ }
894
+ }
895
+ if (environment.liveSnapshot) {
896
+ try {
897
+ const result = await buildFigmaSvgFromLiveSnapshot(
898
+ environment.liveSnapshot,
899
+ params.nodeId,
900
+ );
901
+ return params.embedImages === false
902
+ ? result
903
+ : await embedLiveSvgImages(result);
904
+ } catch {
905
+ // Snapshot may have expired during a dev-server HMR replacement.
906
+ }
907
+ }
908
+ const callExportAction =
909
+ environment.callExportAction ?? defaultCallExportAction;
910
+ const result = await callExportAction(actionParams(params));
911
+ if (!result.ok || !result.svg) {
912
+ throw new FigmaSvgCopyError(
913
+ "render-failed",
914
+ new Error(result.reason ?? "Figma SVG export failed"),
915
+ );
916
+ }
917
+ return result as FigmaSvgExportActionResult & { svg: string };
918
+ }
919
+
127
920
  /**
128
921
  * Exports a design screen (or a selected element's subtree via `nodeId`) as
129
922
  * a genuinely vector SVG through the `export-design-as-figma-svg` action,
@@ -144,33 +937,32 @@ export async function copyDesignAsFigmaSvg(
144
937
  params: FigmaSvgExportParams,
145
938
  environment: FigmaSvgCopyEnvironment = defaultFigmaSvgCopyEnvironment(),
146
939
  ): Promise<FigmaSvgCopyResult> {
147
- if (!canCopyFigmaSvgToClipboard(environment)) {
940
+ // Callers normally provide only a liveSource/liveSnapshot. Preserve the real
941
+ // browser clipboard defaults instead of treating that partial override as a
942
+ // complete environment (which made the hosted live-DOM path always report
943
+ // "unsupported" despite navigator.clipboard being available).
944
+ const resolvedEnvironment = {
945
+ ...defaultFigmaSvgCopyEnvironment(),
946
+ ...environment,
947
+ };
948
+ if (!canCopyFigmaSvgToClipboard(resolvedEnvironment)) {
148
949
  throw new FigmaSvgCopyError("unsupported");
149
950
  }
150
951
 
151
- const callExportAction =
152
- environment.callExportAction ?? defaultCallExportAction;
153
- const clipboard = environment.clipboard;
154
- const ClipboardItemCtor = environment.ClipboardItem;
952
+ const clipboard = resolvedEnvironment.clipboard;
953
+ const ClipboardItemCtor = resolvedEnvironment.ClipboardItem;
155
954
 
156
955
  let renderError: unknown;
157
- const exportPromise = callExportAction(params)
158
- .then((result) => {
159
- if (!result.ok || !result.svg) {
160
- throw new FigmaSvgCopyError(
161
- "render-failed",
162
- new Error(result.reason ?? "Figma SVG export failed"),
163
- );
164
- }
165
- return result as FigmaSvgExportActionResult & { svg: string };
166
- })
167
- .catch((error: unknown) => {
168
- renderError =
169
- error instanceof FigmaSvgCopyError
170
- ? error
171
- : new FigmaSvgCopyError("render-failed", error);
172
- throw renderError;
173
- });
956
+ const exportPromise = exportDesignAsFigmaSvg(
957
+ params,
958
+ resolvedEnvironment,
959
+ ).catch((error: unknown) => {
960
+ renderError =
961
+ error instanceof FigmaSvgCopyError
962
+ ? error
963
+ : new FigmaSvgCopyError("render-failed", error);
964
+ throw renderError;
965
+ });
174
966
  // ClipboardItem owns the promises below in real browsers. Keep a separate
175
967
  // observer so test doubles or an early clipboard rejection cannot surface an
176
968
  // unhandled action/render rejection.