@agent-native/core 0.129.2 → 0.130.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 (589) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +72 -0
  3. package/corpus/core/docs/content/cloneable-saas.mdx +114 -0
  4. package/corpus/core/docs/content/creating-templates.mdx +28 -2
  5. package/corpus/core/docs/content/syncing-template-changes.mdx +7 -0
  6. package/corpus/core/docs/content/template-clips-developers.mdx +12 -5
  7. package/corpus/core/docs/content/template-dispatch-developers.mdx +1 -1
  8. package/corpus/core/docs/content/template-dispatch.mdx +1 -1
  9. package/corpus/core/package.json +1 -1
  10. package/corpus/core/src/action-ui.ts +1 -0
  11. package/corpus/core/src/action.ts +5 -1
  12. package/corpus/core/src/agent/engine/ai-sdk-engine.ts +15 -5
  13. package/corpus/core/src/agent/harness/runner.ts +5 -0
  14. package/corpus/core/src/agent/production-agent.ts +33 -0
  15. package/corpus/core/src/agent/run-loop-with-resume.ts +5 -0
  16. package/corpus/core/src/agent/run-manager.ts +126 -1
  17. package/corpus/core/src/agent/thread-data-builder.ts +47 -2
  18. package/corpus/core/src/agent/types.ts +2 -0
  19. package/corpus/core/src/chat-threads/store.ts +4 -5
  20. package/corpus/core/src/cli/create.ts +1139 -65
  21. package/corpus/core/src/cli/design-connect.ts +3 -7
  22. package/corpus/core/src/cli/index.ts +5 -3
  23. package/corpus/core/src/cli/skills-content/design-visual-edit-skill.ts +83 -47
  24. package/corpus/core/src/client/AssistantChat.tsx +27 -16
  25. package/corpus/core/src/client/agent-chat-adapter.ts +24 -0
  26. package/corpus/core/src/client/blocks/library/wireframe-kit.tsx +17 -2
  27. package/corpus/core/src/client/chat/index.ts +1 -0
  28. package/corpus/core/src/client/chat/message-components.tsx +104 -1
  29. package/corpus/core/src/client/chat/run-recovery.tsx +15 -3
  30. package/corpus/core/src/client/chat/widgets/DataTableWidget.tsx +10 -29
  31. package/corpus/core/src/client/chat/widgets/WorkspaceFileWidget.tsx +71 -0
  32. package/corpus/core/src/client/chat/widgets/builtin-tool-renderers.tsx +22 -0
  33. package/corpus/core/src/client/chat/widgets/workspace-file-result.ts +49 -0
  34. package/corpus/core/src/client/embed-auth.ts +2 -0
  35. package/corpus/core/src/client/org/InvitationBanner.tsx +14 -1
  36. package/corpus/core/src/client/org/OrgSwitcher.tsx +23 -0
  37. package/corpus/core/src/client/org/TeamPage.tsx +130 -0
  38. package/corpus/core/src/client/org/WorkspaceNotice.tsx +85 -0
  39. package/corpus/core/src/client/org/hooks.ts +14 -0
  40. package/corpus/core/src/client/org/index.ts +2 -0
  41. package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +27 -40
  42. package/corpus/core/src/client/resources/ResourcesPanel.tsx +134 -51
  43. package/corpus/core/src/client/resources/mcp-integration-catalog.ts +7 -0
  44. package/corpus/core/src/client/resources/use-resources.ts +6 -0
  45. package/corpus/core/src/client/use-action.ts +3 -1
  46. package/corpus/core/src/client/widgets/index.ts +1 -0
  47. package/corpus/core/src/coding-tools/run-code.ts +2 -1
  48. package/corpus/core/src/db/client.ts +28 -4
  49. package/corpus/core/src/deploy/build.ts +31 -3
  50. package/corpus/core/src/eject/remote-mcp-presets.ts +1 -1
  51. package/corpus/core/src/index.browser.ts +1 -0
  52. package/corpus/core/src/index.ts +1 -0
  53. package/corpus/core/src/integrations/google-docs-poller.ts +3 -0
  54. package/corpus/core/src/integrations/webhook-handler.ts +28 -11
  55. package/corpus/core/src/jobs/scheduler.ts +4 -0
  56. package/corpus/core/src/localization/default-messages.ts +3 -2
  57. package/corpus/core/src/observability/traces.ts +48 -12
  58. package/corpus/core/src/org/handlers.ts +52 -1
  59. package/corpus/core/src/org/migrations.ts +4 -0
  60. package/corpus/core/src/org/plugin.ts +14 -0
  61. package/corpus/core/src/org/schema.ts +1 -0
  62. package/corpus/core/src/org/types.ts +8 -0
  63. package/corpus/core/src/org/workspace-url.ts +74 -0
  64. package/corpus/core/src/resources/handlers.ts +35 -5
  65. package/corpus/core/src/scripts/runner.ts +183 -5
  66. package/corpus/core/src/server/action-routes.ts +32 -2
  67. package/corpus/core/src/server/agent-chat-plugin.ts +29 -0
  68. package/corpus/core/src/server/agent-teams.ts +10 -1
  69. package/corpus/core/src/server/auth.ts +33 -7
  70. package/corpus/core/src/server/embed-route.ts +9 -0
  71. package/corpus/core/src/server/embed-session.ts +62 -3
  72. package/corpus/core/src/server/open-route.ts +20 -6
  73. package/corpus/core/src/server/prompts/framework-core-compact.ts +1 -1
  74. package/corpus/core/src/server/prompts/framework-core.ts +1 -0
  75. package/corpus/core/src/server/request-context.ts +36 -1
  76. package/corpus/core/src/shared/embed-auth.ts +1 -0
  77. package/corpus/core/src/shared/html-document.ts +115 -0
  78. package/corpus/core/src/shared/index.ts +1 -0
  79. package/corpus/core/src/sharing/access.ts +8 -1
  80. package/corpus/core/src/sharing/registry.ts +11 -2
  81. package/corpus/core/src/workspace-files/actions.ts +100 -0
  82. package/corpus/core/src/workspace-files/tool.ts +4 -0
  83. package/corpus/templates/analytics/.agents/skills/analysis-workspace/SKILL.md +4 -0
  84. package/corpus/templates/analytics/.agents/skills/hubspot/SKILL.md +9 -1
  85. package/corpus/templates/analytics/AGENTS.md +17 -24
  86. package/corpus/templates/analytics/actions/data-source-status.ts +11 -1
  87. package/corpus/templates/analytics/app/i18n-data.ts +34 -0
  88. package/corpus/templates/analytics/app/lib/data-source-status.ts +86 -0
  89. package/corpus/templates/analytics/app/lib/native-mcp-exclusions.ts +9 -0
  90. package/corpus/templates/analytics/app/pages/DataSources.tsx +184 -20
  91. package/corpus/templates/analytics/changelog/2026-07-28-native-analytics-data-sources-no-longer-show-duplicate-mc.md +6 -0
  92. package/corpus/templates/analytics/changelog/2026-07-29-exports-now-appear-in-chat-with-a-direct-download-instead-of.md +6 -0
  93. package/corpus/templates/analytics/changelog/2026-07-29-queued-chat-prompts-no-longer-resend-after-analytics-navigat.md +6 -0
  94. package/corpus/templates/analytics/changelog/2026-07-29-scheduled-dashboard-emails-load-every-panel-reliably-without.md +6 -0
  95. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +6 -3
  96. package/corpus/templates/analytics/server/lib/credential-keys.ts +1 -1
  97. package/corpus/templates/analytics/server/lib/hubspot.ts +1 -1
  98. package/corpus/templates/analytics/server/lib/provider-credentials.ts +55 -1
  99. package/corpus/templates/analytics/server/plugins/agent-chat.ts +123 -27
  100. package/corpus/templates/analytics/server/routes/[...page].get.ts +2 -7
  101. package/corpus/templates/analytics/vite.config.ts +7 -0
  102. package/corpus/templates/brain/actions/list-connection-providers.ts +100 -2
  103. package/corpus/templates/brain/app/lib/brain.ts +10 -0
  104. package/corpus/templates/brain/app/routes/sources.tsx +15 -4
  105. package/corpus/templates/brain/changelog/2026-07-29-brain-automatically-retries-failed-source-syncs-and-guides-y.md +6 -0
  106. package/corpus/templates/brain/jobs/process-ingest-queue.ts +13 -0
  107. package/corpus/templates/brain/server/jobs/sync-sources.ts +27 -22
  108. package/corpus/templates/brain/server/plugins/agent-chat.ts +2 -1
  109. package/corpus/templates/brain/server/routes/api/brain/queue/run.post.ts +7 -1
  110. package/corpus/templates/clips/AGENTS.md +1 -1
  111. package/corpus/templates/clips/actions/create-recording-agent-link.ts +11 -1
  112. package/corpus/templates/clips/actions/update-comment.ts +68 -0
  113. package/corpus/templates/clips/app/components/editor/editor-layout.tsx +0 -1
  114. package/corpus/templates/clips/app/components/player/comments-panel.tsx +221 -65
  115. package/corpus/templates/clips/app/components/player/video-player.tsx +101 -27
  116. package/corpus/templates/clips/app/i18n/en-US.ts +2 -1
  117. package/corpus/templates/clips/app/routes/bug-report.done.tsx +48 -27
  118. package/corpus/templates/clips/app/routes/bug-report.tsx +43 -4
  119. package/corpus/templates/clips/app/routes/record.tsx +2 -0
  120. package/corpus/templates/clips/changelog/2026-07-29-clip-playback-now-recovers-instead-of-getting-stuck-when-a-b.md +6 -0
  121. package/corpus/templates/clips/changelog/2026-07-29-comments-can-now-be-edited-after-posting.md +6 -0
  122. package/corpus/templates/clips/changelog/2026-07-29-download-actions-now-use-a-shorter-clearer-label.md +6 -0
  123. package/corpus/templates/clips/changelog/2026-07-29-embedded-bug-reports-now-return-a-temporary-agent-readable.md +6 -0
  124. package/corpus/templates/clips/shared/bug-report.ts +99 -0
  125. package/corpus/templates/content/actions/_content-database-personal-view.ts +7 -1
  126. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +5 -2
  127. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +20 -8
  128. package/corpus/templates/content/changelog/2026-07-29-missing-databases-no-longer-trigger-repeated-personal-view-e.md +6 -0
  129. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +83 -47
  130. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +474 -55
  131. package/corpus/templates/design/.generated/bridge/embedded-wheel.generated.ts +3 -0
  132. package/corpus/templates/design/.generated/bridge/hit-test.generated.ts +18 -1
  133. package/corpus/templates/design/.generated/bridge/source-location.generated.ts +348 -0
  134. package/corpus/templates/design/actions/add-localhost-screens.ts +2 -7
  135. package/corpus/templates/design/actions/apply-visual-edit.ts +7 -1
  136. package/corpus/templates/design/actions/connect-localhost.ts +5 -9
  137. package/corpus/templates/design/actions/create-component.ts +16 -13
  138. package/corpus/templates/design/actions/grant-localhost-write-consent.ts +2 -7
  139. package/corpus/templates/design/actions/list-design-source-capabilities.ts +4 -7
  140. package/corpus/templates/design/actions/list-local-files.ts +26 -50
  141. package/corpus/templates/design/actions/list-localhost-connections.ts +2 -7
  142. package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +2 -2
  143. package/corpus/templates/design/actions/open-visual-edit.ts +234 -135
  144. package/corpus/templates/design/actions/read-local-file.ts +26 -50
  145. package/corpus/templates/design/actions/request-localhost-write-consent.ts +2 -7
  146. package/corpus/templates/design/actions/write-local-file.ts +31 -73
  147. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +307 -133
  148. package/corpus/templates/design/app/components/design/EditPanel.tsx +94 -22
  149. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +137 -60
  150. package/corpus/templates/design/app/components/design/ResponsiveInteractBar.tsx +75 -14
  151. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +755 -97
  152. package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +8 -0
  153. package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +24 -1
  154. package/corpus/templates/design/app/components/design/bridge/source-location.bridge.ts +530 -0
  155. package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbenchLoader.tsx +278 -0
  156. package/corpus/templates/design/app/components/design/code-workbench/editor/MonacoHost.tsx +32 -12
  157. package/corpus/templates/design/app/components/design/code-workbench/editor/monaco-setup.ts +14 -3
  158. package/corpus/templates/design/app/components/design/code-workbench/explorer/ExplorerView.tsx +87 -24
  159. package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +36 -0
  160. package/corpus/templates/design/app/components/design/code-workbench/store.tsx +2 -1
  161. package/corpus/templates/design/app/components/design/code-workbench/workspace/localhost-provider.ts +48 -8
  162. package/corpus/templates/design/app/components/design/design-canvas/content-size-report.ts +3 -13
  163. package/corpus/templates/design/app/components/design/design-canvas/embedded-frame.ts +4 -2
  164. package/corpus/templates/design/app/components/design/design-canvas/hit-test.ts +3 -13
  165. package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +3 -1
  166. package/corpus/templates/design/app/components/design/edit-panel/inspect-code-source.ts +93 -0
  167. package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +4 -2
  168. package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +35 -0
  169. package/corpus/templates/design/app/components/design/multi-screen/iframe-targeting.ts +24 -0
  170. package/corpus/templates/design/app/components/design/multi-screen/types.ts +9 -0
  171. package/corpus/templates/design/app/components/design/types.ts +29 -0
  172. package/corpus/templates/design/app/components/layout/Layout.tsx +7 -4
  173. package/corpus/templates/design/app/hooks/use-navigation-state.ts +3 -0
  174. package/corpus/templates/design/app/i18n-data.ts +153 -46
  175. package/corpus/templates/design/app/i18n-responsive-interact.ts +12 -12
  176. package/corpus/templates/design/app/lib/design-editor-route.ts +23 -0
  177. package/corpus/templates/design/app/pages/VisualEdit.tsx +19 -6
  178. package/corpus/templates/design/app/pages/design-editor/action-error.ts +19 -0
  179. package/corpus/templates/design/app/pages/design-editor/canvas-primitive-insert.ts +29 -0
  180. package/corpus/templates/design/app/pages/design-editor/clone-and-pen-edit.ts +6 -0
  181. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +277 -15
  182. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +75 -9
  183. package/corpus/templates/design/app/pages/design-editor/layer-state-scope.ts +28 -0
  184. package/corpus/templates/design/app/pages/design-editor/live-screen-layer-drop.ts +41 -0
  185. package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +496 -41
  186. package/corpus/templates/design/app/pages/design-editor/pending-live-edit-unload-guard.ts +27 -0
  187. package/corpus/templates/design/app/pages/design-editor/pending-structure-verification.ts +10 -0
  188. package/corpus/templates/design/app/pages/design-editor/react-semantic-handoff.ts +168 -9
  189. package/corpus/templates/design/app/pages/design-editor/responsive-interact.ts +41 -3
  190. package/corpus/templates/design/app/pages/design-editor/screen-command-utils.ts +5 -0
  191. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +42 -13
  192. package/corpus/templates/design/app/pages/design-editor/source-location.ts +180 -0
  193. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +17 -0
  194. package/corpus/templates/design/app/public-routes.ts +1 -0
  195. package/corpus/templates/design/app/routes/visual-edit.$id.tsx +15 -0
  196. package/corpus/templates/design/changelog/2026-06-29-screen-overview-is-easier-to-find-and-named-screens-open-dir.md +1 -1
  197. package/corpus/templates/design/changelog/2026-07-28-deleting-a-selected-element-now-removes-it-from-the-live-pre.md +6 -0
  198. package/corpus/templates/design/changelog/2026-07-28-deleting-an-element-on-a-connected-localhost-screen-now-queu.md +6 -0
  199. package/corpus/templates/design/changelog/2026-07-28-interact-mode-now-shows-a-responsive-device-preview-with-pre.md +6 -0
  200. package/corpus/templates/design/changelog/2026-07-28-layer-hide-and-lock-now-apply-to-the-live-preview-instead-of.md +6 -0
  201. package/corpus/templates/design/changelog/2026-07-28-layers-panel-selections-on-a-connected-localhost-screen-can-.md +6 -0
  202. package/corpus/templates/design/changelog/2026-07-28-locked-layers-now-show-a-subtle-dashed-outline-in-the-live-p.md +6 -0
  203. package/corpus/templates/design/changelog/2026-07-28-the-apply-design-updates-button-now-counts-pending-live-text.md +6 -0
  204. package/corpus/templates/design/changelog/2026-07-28-the-design-canvas-no-longer-stalls-on-a-render-loop-while-a-.md +6 -0
  205. package/corpus/templates/design/changelog/2026-07-28-visual-edit-on-a-local-dev-server-no-longer-requires-signing.md +6 -0
  206. package/corpus/templates/design/changelog/2026-07-28-visual-edits-on-a-react-19-app-no-longer-report-a-source-lin.md +6 -0
  207. package/corpus/templates/design/changelog/2026-07-29-an-edit-that-cannot-be-written-to-source-now-names-the-reaso.md +6 -0
  208. package/corpus/templates/design/changelog/2026-07-29-applying-a-primitive-dropped-onto-a-connected-localhost-scre.md +6 -0
  209. package/corpus/templates/design/changelog/2026-07-29-changing-a-style-in-the-inspector-now-updates-a-connected-lo.md +6 -0
  210. package/corpus/templates/design/changelog/2026-07-29-choosing-edit-or-annotate-from-a-focused-screen-now-returns-.md +6 -0
  211. package/corpus/templates/design/changelog/2026-07-29-concurrent-source-edits-now-return-a-clear-conflict-response.md +6 -0
  212. package/corpus/templates/design/changelog/2026-07-29-creating-a-component-from-an-element-that-repeats-in-the-sou.md +6 -0
  213. package/corpus/templates/design/changelog/2026-07-29-deleting-an-element-you-just-dropped-onto-a-live-screen-no-l.md +6 -0
  214. package/corpus/templates/design/changelog/2026-07-29-dragging-a-layer-across-screens-no-longer-dies-when-the-poin.md +6 -0
  215. package/corpus/templates/design/changelog/2026-07-29-dragging-an-element-from-a-stored-screen-into-a-live-localho.md +6 -0
  216. package/corpus/templates/design/changelog/2026-07-29-drawing-a-box-on-the-canvas-and-dragging-it-into-a-connected.md +6 -0
  217. package/corpus/templates/design/changelog/2026-07-29-fixed-a-loading-screen-flicker-when-reopening-designs-with-a.md +6 -0
  218. package/corpus/templates/design/changelog/2026-07-29-interact-mode-has-edit-and-annotate-buttons-again-so-you-can.md +6 -0
  219. package/corpus/templates/design/changelog/2026-07-29-layer-groups-can-be-dropped-onto-live-localhost-screens.md +6 -0
  220. package/corpus/templates/design/changelog/2026-07-29-localhost-source-errors-now-say-what-actually-went-wrong-whi.md +6 -0
  221. package/corpus/templates/design/changelog/2026-07-29-opening-or-refreshing-a-live-localhost-screen-in-single-scre.md +6 -0
  222. package/corpus/templates/design/changelog/2026-07-29-redo-after-undoing-a-drop-onto-a-live-screen-puts-the-elemen.md +6 -0
  223. package/corpus/templates/design/changelog/2026-07-29-shapes-can-be-drawn-directly-onto-live-localhost-screens.md +6 -0
  224. package/corpus/templates/design/changelog/2026-07-29-shapes-drawn-on-the-canvas-board-now-appear-immediately-inst.md +6 -0
  225. package/corpus/templates/design/changelog/2026-07-29-style-edits-on-a-running-localhost-screen-now-preview-live-a.md +6 -0
  226. package/corpus/templates/design/changelog/2026-07-29-the-apply-design-updates-control-now-appears-as-a-clean-conn.md +6 -0
  227. package/corpus/templates/design/changelog/2026-07-29-visual-edits-on-a-mapped-component-instance-now-tell-the-age.md +6 -0
  228. package/corpus/templates/design/server/lib/design-data-access.ts +21 -7
  229. package/corpus/templates/design/server/lib/localhost-connection.ts +240 -0
  230. package/corpus/templates/design/server/routes/[...page].get.ts +2 -5
  231. package/corpus/templates/design/server/source-workspace.ts +2 -0
  232. package/corpus/templates/design/shared/code-layer.ts +43 -0
  233. package/corpus/templates/design/shared/html-content.ts +26 -0
  234. package/corpus/templates/design/shared/html-integrity.ts +21 -1
  235. package/corpus/templates/design/shared/local-jsx-visual-edit.ts +15 -0
  236. package/corpus/templates/design/shared/source-mode.ts +76 -0
  237. package/corpus/templates/dispatch/changelog/2026-07-29-workspace-members-without-admin-access-now-see-a-clear-permi.md +6 -0
  238. package/corpus/templates/dispatch/server/lib/usage-metrics.ts +2 -1
  239. package/corpus/templates/plan/app/lib/plan-annotation-runtime.ts +3 -4
  240. package/corpus/templates/plan/server/routes/[...page].get.ts +2 -5
  241. package/corpus/templates/slides/actions/patch-deck.ts +29 -17
  242. package/corpus/toolkit/CHANGELOG.md +6 -0
  243. package/corpus/toolkit/package.json +1 -1
  244. package/corpus/toolkit/src/composer/ComposerPlusMenu.tsx +3 -2
  245. package/dist/action-ui.d.ts +1 -0
  246. package/dist/action-ui.d.ts.map +1 -1
  247. package/dist/action-ui.js +1 -0
  248. package/dist/action-ui.js.map +1 -1
  249. package/dist/action.d.ts +5 -1
  250. package/dist/action.d.ts.map +1 -1
  251. package/dist/action.js.map +1 -1
  252. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  253. package/dist/agent/engine/ai-sdk-engine.js +13 -5
  254. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  255. package/dist/agent/harness/runner.d.ts.map +1 -1
  256. package/dist/agent/harness/runner.js +5 -0
  257. package/dist/agent/harness/runner.js.map +1 -1
  258. package/dist/agent/production-agent.d.ts +16 -0
  259. package/dist/agent/production-agent.d.ts.map +1 -1
  260. package/dist/agent/production-agent.js +18 -1
  261. package/dist/agent/production-agent.js.map +1 -1
  262. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  263. package/dist/agent/run-loop-with-resume.js +6 -0
  264. package/dist/agent/run-loop-with-resume.js.map +1 -1
  265. package/dist/agent/run-manager.d.ts +14 -0
  266. package/dist/agent/run-manager.d.ts.map +1 -1
  267. package/dist/agent/run-manager.js +91 -1
  268. package/dist/agent/run-manager.js.map +1 -1
  269. package/dist/agent/thread-data-builder.d.ts +3 -0
  270. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  271. package/dist/agent/thread-data-builder.js +35 -3
  272. package/dist/agent/thread-data-builder.js.map +1 -1
  273. package/dist/agent/types.d.ts +2 -0
  274. package/dist/agent/types.d.ts.map +1 -1
  275. package/dist/agent/types.js.map +1 -1
  276. package/dist/chat-threads/store.d.ts.map +1 -1
  277. package/dist/chat-threads/store.js +4 -6
  278. package/dist/chat-threads/store.js.map +1 -1
  279. package/dist/cli/create.d.ts +66 -6
  280. package/dist/cli/create.d.ts.map +1 -1
  281. package/dist/cli/create.js +765 -66
  282. package/dist/cli/create.js.map +1 -1
  283. package/dist/cli/design-connect.d.ts.map +1 -1
  284. package/dist/cli/design-connect.js +2 -7
  285. package/dist/cli/design-connect.js.map +1 -1
  286. package/dist/cli/index.js +5 -3
  287. package/dist/cli/index.js.map +1 -1
  288. package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
  289. package/dist/cli/skills-content/design-visual-edit-skill.d.ts.map +1 -1
  290. package/dist/cli/skills-content/design-visual-edit-skill.js +83 -47
  291. package/dist/cli/skills-content/design-visual-edit-skill.js.map +1 -1
  292. package/dist/client/AssistantChat.d.ts.map +1 -1
  293. package/dist/client/AssistantChat.js +16 -9
  294. package/dist/client/AssistantChat.js.map +1 -1
  295. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  296. package/dist/client/agent-chat-adapter.js +21 -0
  297. package/dist/client/agent-chat-adapter.js.map +1 -1
  298. package/dist/client/blocks/library/wireframe-kit.d.ts +2 -0
  299. package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -1
  300. package/dist/client/blocks/library/wireframe-kit.js +8 -2
  301. package/dist/client/blocks/library/wireframe-kit.js.map +1 -1
  302. package/dist/client/chat/index.d.ts +1 -1
  303. package/dist/client/chat/index.d.ts.map +1 -1
  304. package/dist/client/chat/index.js +1 -1
  305. package/dist/client/chat/index.js.map +1 -1
  306. package/dist/client/chat/message-components.d.ts +17 -0
  307. package/dist/client/chat/message-components.d.ts.map +1 -1
  308. package/dist/client/chat/message-components.js +24 -2
  309. package/dist/client/chat/message-components.js.map +1 -1
  310. package/dist/client/chat/run-recovery.d.ts +6 -0
  311. package/dist/client/chat/run-recovery.d.ts.map +1 -1
  312. package/dist/client/chat/run-recovery.js +13 -3
  313. package/dist/client/chat/run-recovery.js.map +1 -1
  314. package/dist/client/chat/widgets/DataTableWidget.d.ts.map +1 -1
  315. package/dist/client/chat/widgets/DataTableWidget.js +2 -3
  316. package/dist/client/chat/widgets/DataTableWidget.js.map +1 -1
  317. package/dist/client/chat/widgets/WorkspaceFileWidget.d.ts +5 -0
  318. package/dist/client/chat/widgets/WorkspaceFileWidget.d.ts.map +1 -0
  319. package/dist/client/chat/widgets/WorkspaceFileWidget.js +34 -0
  320. package/dist/client/chat/widgets/WorkspaceFileWidget.js.map +1 -0
  321. package/dist/client/chat/widgets/builtin-tool-renderers.d.ts.map +1 -1
  322. package/dist/client/chat/widgets/builtin-tool-renderers.js +13 -1
  323. package/dist/client/chat/widgets/builtin-tool-renderers.js.map +1 -1
  324. package/dist/client/chat/widgets/workspace-file-result.d.ts +12 -0
  325. package/dist/client/chat/widgets/workspace-file-result.d.ts.map +1 -0
  326. package/dist/client/chat/widgets/workspace-file-result.js +34 -0
  327. package/dist/client/chat/widgets/workspace-file-result.js.map +1 -0
  328. package/dist/client/embed-auth.d.ts.map +1 -1
  329. package/dist/client/embed-auth.js +2 -1
  330. package/dist/client/embed-auth.js.map +1 -1
  331. package/dist/client/org/InvitationBanner.d.ts +5 -2
  332. package/dist/client/org/InvitationBanner.d.ts.map +1 -1
  333. package/dist/client/org/InvitationBanner.js +9 -2
  334. package/dist/client/org/InvitationBanner.js.map +1 -1
  335. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  336. package/dist/client/org/OrgSwitcher.js +3 -2
  337. package/dist/client/org/OrgSwitcher.js.map +1 -1
  338. package/dist/client/org/TeamPage.d.ts.map +1 -1
  339. package/dist/client/org/TeamPage.js +27 -3
  340. package/dist/client/org/TeamPage.js.map +1 -1
  341. package/dist/client/org/WorkspaceNotice.d.ts +18 -0
  342. package/dist/client/org/WorkspaceNotice.d.ts.map +1 -0
  343. package/dist/client/org/WorkspaceNotice.js +56 -0
  344. package/dist/client/org/WorkspaceNotice.js.map +1 -0
  345. package/dist/client/org/hooks.d.ts +1 -0
  346. package/dist/client/org/hooks.d.ts.map +1 -1
  347. package/dist/client/org/hooks.js +12 -0
  348. package/dist/client/org/hooks.js.map +1 -1
  349. package/dist/client/org/index.d.ts +2 -1
  350. package/dist/client/org/index.d.ts.map +1 -1
  351. package/dist/client/org/index.js +2 -1
  352. package/dist/client/org/index.js.map +1 -1
  353. package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
  354. package/dist/client/resources/McpIntegrationDialog.js +8 -12
  355. package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
  356. package/dist/client/resources/ResourcesPanel.d.ts +3 -0
  357. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  358. package/dist/client/resources/ResourcesPanel.js +49 -20
  359. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  360. package/dist/client/resources/mcp-integration-catalog.d.ts +1 -0
  361. package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
  362. package/dist/client/resources/mcp-integration-catalog.js +3 -0
  363. package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
  364. package/dist/client/resources/use-resources.d.ts +1 -0
  365. package/dist/client/resources/use-resources.d.ts.map +1 -1
  366. package/dist/client/resources/use-resources.js +3 -0
  367. package/dist/client/resources/use-resources.js.map +1 -1
  368. package/dist/client/use-action.d.ts +3 -1
  369. package/dist/client/use-action.d.ts.map +1 -1
  370. package/dist/client/use-action.js +3 -1
  371. package/dist/client/use-action.js.map +1 -1
  372. package/dist/client/widgets/index.d.ts +1 -1
  373. package/dist/client/widgets/index.d.ts.map +1 -1
  374. package/dist/client/widgets/index.js +1 -1
  375. package/dist/client/widgets/index.js.map +1 -1
  376. package/dist/coding-tools/run-code.js +2 -1
  377. package/dist/coding-tools/run-code.js.map +1 -1
  378. package/dist/collab/awareness.d.ts +2 -2
  379. package/dist/collab/awareness.d.ts.map +1 -1
  380. package/dist/db/client.d.ts +1 -0
  381. package/dist/db/client.d.ts.map +1 -1
  382. package/dist/db/client.js +24 -3
  383. package/dist/db/client.js.map +1 -1
  384. package/dist/deploy/build.d.ts.map +1 -1
  385. package/dist/deploy/build.js +25 -3
  386. package/dist/deploy/build.js.map +1 -1
  387. package/dist/eject/remote-mcp-presets.js +1 -1
  388. package/dist/eject/remote-mcp-presets.js.map +1 -1
  389. package/dist/index.browser.d.ts +1 -1
  390. package/dist/index.browser.d.ts.map +1 -1
  391. package/dist/index.browser.js +1 -1
  392. package/dist/index.browser.js.map +1 -1
  393. package/dist/index.d.ts +1 -1
  394. package/dist/index.d.ts.map +1 -1
  395. package/dist/index.js +1 -1
  396. package/dist/index.js.map +1 -1
  397. package/dist/integrations/google-docs-poller.d.ts.map +1 -1
  398. package/dist/integrations/google-docs-poller.js +4 -1
  399. package/dist/integrations/google-docs-poller.js.map +1 -1
  400. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  401. package/dist/integrations/webhook-handler.js +23 -11
  402. package/dist/integrations/webhook-handler.js.map +1 -1
  403. package/dist/jobs/scheduler.js +4 -0
  404. package/dist/jobs/scheduler.js.map +1 -1
  405. package/dist/localization/default-messages.d.ts +3 -2
  406. package/dist/localization/default-messages.d.ts.map +1 -1
  407. package/dist/localization/default-messages.js +3 -2
  408. package/dist/localization/default-messages.js.map +1 -1
  409. package/dist/notifications/routes.d.ts +1 -1
  410. package/dist/observability/routes.d.ts +3 -3
  411. package/dist/observability/traces.d.ts.map +1 -1
  412. package/dist/observability/traces.js +27 -7
  413. package/dist/observability/traces.js.map +1 -1
  414. package/dist/org/handlers.d.ts +15 -0
  415. package/dist/org/handlers.d.ts.map +1 -1
  416. package/dist/org/handlers.js +45 -1
  417. package/dist/org/handlers.js.map +1 -1
  418. package/dist/org/migrations.d.ts.map +1 -1
  419. package/dist/org/migrations.js +4 -0
  420. package/dist/org/migrations.js.map +1 -1
  421. package/dist/org/plugin.d.ts +1 -0
  422. package/dist/org/plugin.d.ts.map +1 -1
  423. package/dist/org/plugin.js +10 -1
  424. package/dist/org/plugin.js.map +1 -1
  425. package/dist/org/schema.d.ts +19 -0
  426. package/dist/org/schema.d.ts.map +1 -1
  427. package/dist/org/schema.js +1 -0
  428. package/dist/org/schema.js.map +1 -1
  429. package/dist/org/types.d.ts +8 -0
  430. package/dist/org/types.d.ts.map +1 -1
  431. package/dist/org/types.js.map +1 -1
  432. package/dist/org/workspace-url.d.ts +32 -0
  433. package/dist/org/workspace-url.d.ts.map +1 -0
  434. package/dist/org/workspace-url.js +63 -0
  435. package/dist/org/workspace-url.js.map +1 -0
  436. package/dist/progress/routes.d.ts +1 -1
  437. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  438. package/dist/provider-api/actions/provider-api.d.ts +7 -7
  439. package/dist/resources/handlers.d.ts +2 -3
  440. package/dist/resources/handlers.d.ts.map +1 -1
  441. package/dist/resources/handlers.js +25 -5
  442. package/dist/resources/handlers.js.map +1 -1
  443. package/dist/scripts/runner.d.ts +17 -0
  444. package/dist/scripts/runner.d.ts.map +1 -1
  445. package/dist/scripts/runner.js +130 -5
  446. package/dist/scripts/runner.js.map +1 -1
  447. package/dist/server/action-routes.d.ts.map +1 -1
  448. package/dist/server/action-routes.js +24 -2
  449. package/dist/server/action-routes.js.map +1 -1
  450. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  451. package/dist/server/agent-chat-plugin.js +26 -1
  452. package/dist/server/agent-chat-plugin.js.map +1 -1
  453. package/dist/server/agent-teams.d.ts.map +1 -1
  454. package/dist/server/agent-teams.js +10 -1
  455. package/dist/server/agent-teams.js.map +1 -1
  456. package/dist/server/auth.d.ts +22 -0
  457. package/dist/server/auth.d.ts.map +1 -1
  458. package/dist/server/auth.js +33 -7
  459. package/dist/server/auth.js.map +1 -1
  460. package/dist/server/embed-route.d.ts.map +1 -1
  461. package/dist/server/embed-route.js +6 -1
  462. package/dist/server/embed-route.js.map +1 -1
  463. package/dist/server/embed-session.d.ts +7 -0
  464. package/dist/server/embed-session.d.ts.map +1 -1
  465. package/dist/server/embed-session.js +46 -4
  466. package/dist/server/embed-session.js.map +1 -1
  467. package/dist/server/open-route.d.ts.map +1 -1
  468. package/dist/server/open-route.js +17 -7
  469. package/dist/server/open-route.js.map +1 -1
  470. package/dist/server/prompts/framework-core-compact.js +1 -1
  471. package/dist/server/prompts/framework-core-compact.js.map +1 -1
  472. package/dist/server/prompts/framework-core.d.ts.map +1 -1
  473. package/dist/server/prompts/framework-core.js +1 -0
  474. package/dist/server/prompts/framework-core.js.map +1 -1
  475. package/dist/server/realtime-token.d.ts +1 -1
  476. package/dist/server/request-context.d.ts +26 -0
  477. package/dist/server/request-context.d.ts.map +1 -1
  478. package/dist/server/request-context.js +18 -1
  479. package/dist/server/request-context.js.map +1 -1
  480. package/dist/server/transcribe-voice.d.ts +1 -1
  481. package/dist/shared/embed-auth.d.ts +1 -0
  482. package/dist/shared/embed-auth.d.ts.map +1 -1
  483. package/dist/shared/embed-auth.js +1 -0
  484. package/dist/shared/embed-auth.js.map +1 -1
  485. package/dist/shared/html-document.d.ts +12 -0
  486. package/dist/shared/html-document.d.ts.map +1 -0
  487. package/dist/shared/html-document.js +92 -0
  488. package/dist/shared/html-document.js.map +1 -0
  489. package/dist/shared/index.d.ts +1 -0
  490. package/dist/shared/index.d.ts.map +1 -1
  491. package/dist/shared/index.js +1 -0
  492. package/dist/shared/index.js.map +1 -1
  493. package/dist/sharing/access.d.ts +1 -0
  494. package/dist/sharing/access.d.ts.map +1 -1
  495. package/dist/sharing/access.js +8 -2
  496. package/dist/sharing/access.js.map +1 -1
  497. package/dist/sharing/registry.d.ts +3 -0
  498. package/dist/sharing/registry.d.ts.map +1 -1
  499. package/dist/sharing/registry.js.map +1 -1
  500. package/dist/workspace-files/actions.d.ts +28 -0
  501. package/dist/workspace-files/actions.d.ts.map +1 -0
  502. package/dist/workspace-files/actions.js +75 -0
  503. package/dist/workspace-files/actions.js.map +1 -0
  504. package/dist/workspace-files/tool.d.ts.map +1 -1
  505. package/dist/workspace-files/tool.js +4 -0
  506. package/dist/workspace-files/tool.js.map +1 -1
  507. package/docs/content/cloneable-saas.mdx +114 -0
  508. package/docs/content/creating-templates.mdx +28 -2
  509. package/docs/content/syncing-template-changes.mdx +7 -0
  510. package/docs/content/template-clips-developers.mdx +12 -5
  511. package/docs/content/template-dispatch-developers.mdx +1 -1
  512. package/docs/content/template-dispatch.mdx +1 -1
  513. package/package.json +2 -2
  514. package/src/action-ui.ts +1 -0
  515. package/src/action.ts +5 -1
  516. package/src/agent/engine/ai-sdk-engine.ts +15 -5
  517. package/src/agent/harness/runner.ts +5 -0
  518. package/src/agent/production-agent.ts +33 -0
  519. package/src/agent/run-loop-with-resume.ts +5 -0
  520. package/src/agent/run-manager.ts +126 -1
  521. package/src/agent/thread-data-builder.ts +47 -2
  522. package/src/agent/types.ts +2 -0
  523. package/src/chat-threads/store.ts +4 -5
  524. package/src/cli/create.ts +1139 -65
  525. package/src/cli/design-connect.ts +3 -7
  526. package/src/cli/index.ts +5 -3
  527. package/src/cli/skills-content/design-visual-edit-skill.ts +83 -47
  528. package/src/client/AssistantChat.tsx +27 -16
  529. package/src/client/agent-chat-adapter.ts +24 -0
  530. package/src/client/blocks/library/wireframe-kit.tsx +17 -2
  531. package/src/client/chat/index.ts +1 -0
  532. package/src/client/chat/message-components.tsx +104 -1
  533. package/src/client/chat/run-recovery.tsx +15 -3
  534. package/src/client/chat/widgets/DataTableWidget.tsx +10 -29
  535. package/src/client/chat/widgets/WorkspaceFileWidget.tsx +71 -0
  536. package/src/client/chat/widgets/builtin-tool-renderers.tsx +22 -0
  537. package/src/client/chat/widgets/workspace-file-result.ts +49 -0
  538. package/src/client/embed-auth.ts +2 -0
  539. package/src/client/org/InvitationBanner.tsx +14 -1
  540. package/src/client/org/OrgSwitcher.tsx +23 -0
  541. package/src/client/org/TeamPage.tsx +130 -0
  542. package/src/client/org/WorkspaceNotice.tsx +85 -0
  543. package/src/client/org/hooks.ts +14 -0
  544. package/src/client/org/index.ts +2 -0
  545. package/src/client/resources/McpIntegrationDialog.tsx +27 -40
  546. package/src/client/resources/ResourcesPanel.tsx +134 -51
  547. package/src/client/resources/mcp-integration-catalog.ts +7 -0
  548. package/src/client/resources/use-resources.ts +6 -0
  549. package/src/client/use-action.ts +3 -1
  550. package/src/client/widgets/index.ts +1 -0
  551. package/src/coding-tools/run-code.ts +2 -1
  552. package/src/db/client.ts +28 -4
  553. package/src/deploy/build.ts +31 -3
  554. package/src/eject/remote-mcp-presets.ts +1 -1
  555. package/src/index.browser.ts +1 -0
  556. package/src/index.ts +1 -0
  557. package/src/integrations/google-docs-poller.ts +3 -0
  558. package/src/integrations/webhook-handler.ts +28 -11
  559. package/src/jobs/scheduler.ts +4 -0
  560. package/src/localization/default-messages.ts +3 -2
  561. package/src/observability/traces.ts +48 -12
  562. package/src/org/handlers.ts +52 -1
  563. package/src/org/migrations.ts +4 -0
  564. package/src/org/plugin.ts +14 -0
  565. package/src/org/schema.ts +1 -0
  566. package/src/org/types.ts +8 -0
  567. package/src/org/workspace-url.ts +74 -0
  568. package/src/resources/handlers.ts +35 -5
  569. package/src/scripts/runner.ts +183 -5
  570. package/src/server/__snapshots__/agent-chat-plugin.surface.spec.ts.snap +2 -1
  571. package/src/server/action-routes.ts +32 -2
  572. package/src/server/agent-chat-plugin.ts +29 -0
  573. package/src/server/agent-teams.ts +10 -1
  574. package/src/server/auth.ts +33 -7
  575. package/src/server/embed-route.ts +9 -0
  576. package/src/server/embed-session.ts +62 -3
  577. package/src/server/open-route.ts +20 -6
  578. package/src/server/prompts/framework-core-compact.ts +1 -1
  579. package/src/server/prompts/framework-core.ts +1 -0
  580. package/src/server/request-context.ts +36 -1
  581. package/src/shared/embed-auth.ts +1 -0
  582. package/src/shared/html-document.ts +115 -0
  583. package/src/shared/index.ts +1 -0
  584. package/src/sharing/access.ts +8 -1
  585. package/src/sharing/registry.ts +11 -2
  586. package/src/workspace-files/actions.ts +100 -0
  587. package/src/workspace-files/tool.ts +4 -0
  588. package/corpus/templates/design/changelog/2026-07-28-interact-mode-can-preview-designs-in-responsive-device-sizes.md +0 -6
  589. package/corpus/templates/design/changelog/2026-07-28-interact-mode-now-opens-a-full-screen-responsive-preview-wit.md +0 -6
@@ -6,6 +6,7 @@ import {
6
6
  import { useT } from "@agent-native/core/client/i18n";
7
7
  import { type ReviewThread } from "@agent-native/core/client/review";
8
8
  import type { ReviewComment } from "@agent-native/core/review";
9
+ import { injectDocumentMarkup } from "@agent-native/core/shared";
9
10
  import {
10
11
  DEFAULT_CANVAS_MAX_ZOOM,
11
12
  DEFAULT_CANVAS_MIN_ZOOM,
@@ -54,6 +55,7 @@ import {
54
55
  useDesktopDesignNativePreview,
55
56
  } from "@/lib/desktop-design-preview";
56
57
  import { cn } from "@/lib/utils";
58
+ import { runtimeStyleTarget } from "@/pages/design-editor/pending-edits";
57
59
 
58
60
  import { editorChromeBridgeScript } from "../../../.generated/bridge/editor-chrome.generated";
59
61
  import { embeddedWheelBridgeScript } from "../../../.generated/bridge/embedded-wheel.generated";
@@ -117,6 +119,7 @@ import type {
117
119
  ElementInfo,
118
120
  ElementSelectionIntent,
119
121
  DeviceFrameType,
122
+ RuntimeStructureInsertRequest,
120
123
  RuntimeStructureMoveRequest,
121
124
  RuntimeVerificationRequest,
122
125
  } from "./types";
@@ -325,6 +328,20 @@ const LIVE_REFLOW_ENABLED = true;
325
328
  */
326
329
  const SELECTED_LAYER_DRAG_PRIORITY_ENABLED = true;
327
330
 
331
+ /**
332
+ * A style replay into the live iframe. `runtimeSelector`/`runtimeSourceId` are
333
+ * the only pair that resolves in a localhost document — see
334
+ * `runtimeStyleTarget` for the two-namespace problem they exist for.
335
+ */
336
+ type StyleReplayPatch = {
337
+ selector: string;
338
+ sourceId?: string | null;
339
+ runtimeSelector?: string | null;
340
+ runtimeSourceId?: string | null;
341
+ styles: Record<string, string>;
342
+ interactionState?: string;
343
+ };
344
+
328
345
  interface DesignCanvasProps {
329
346
  content: string;
330
347
  contentKey?: string;
@@ -419,13 +436,12 @@ interface DesignCanvasProps {
419
436
  runtimeReplacementKey?: string;
420
437
  styleRevertRequest?: {
421
438
  requestId: number;
422
- patches: Array<{
423
- selector: string;
424
- sourceId?: string | null;
425
- styles: Record<string, string>;
426
- interactionState?: string;
427
- }>;
439
+ patches: Array<StyleReplayPatch>;
428
440
  } | null;
441
+ /** Steady-state live style previews replayed after this iframe document
442
+ * announces readiness. Entries are screen-scoped so a sibling canvas can
443
+ * never receive another screen's pending edit. */
444
+ pendingStylePreviewPatches?: Array<StyleReplayPatch & { screenId: string }>;
429
445
  styleBaselineResetRequest?: number | null;
430
446
  textRevertRequest?: {
431
447
  requestId: number;
@@ -442,6 +458,10 @@ interface DesignCanvasProps {
442
458
  } | null;
443
459
  /** One-shot host request to optimistically move a runtime-only layer. */
444
460
  runtimeStructureMoveRequest?: RuntimeStructureMoveRequest | null;
461
+ /** One-shot host request to insert new markup into the running DOM. */
462
+ runtimeStructureInsertRequest?: RuntimeStructureInsertRequest | null;
463
+ /** The bridge could not honor a runtimeStructureInsertRequest. */
464
+ onRuntimeStructureInsertRejected?: (reason: string) => void;
445
465
  /** Mounts a separate hidden runtime only after a guarded source hash
446
466
  * changes. The editable iframe remains untouched and fully undoable. */
447
467
  runtimeVerificationRequest?: RuntimeVerificationRequest | null;
@@ -501,6 +521,9 @@ interface DesignCanvasProps {
501
521
  sourceRect?: { x: number; y: number; width: number; height: number };
502
522
  anchorRect?: { x: number; y: number; width: number; height: number };
503
523
  anchorElementInfo?: ElementInfo;
524
+ /** Set when the subject is markup this change introduced, not an
525
+ * element the running app already had. */
526
+ insertedHtml?: string;
504
527
  },
505
528
  ) => boolean | "pending" | void;
506
529
  onVisualDuplicateChange?: (
@@ -630,6 +653,7 @@ interface DesignCanvasProps {
630
653
  * 100% height.
631
654
  */
632
655
  previewWidthPx?: number;
656
+ previewHeightPx?: number;
633
657
  /**
634
658
  * Shader-fill CSS preview to apply to a selected element inside the iframe.
635
659
  *
@@ -875,7 +899,7 @@ const LIVE_EDIT_SAME_INSTANCE_MAX_REARM_DELAY_MS = 16_000;
875
899
  const LIVE_EDIT_SAME_INSTANCE_ERROR_CEILING_MS = 48_000;
876
900
 
877
901
  // Successful bridge registrations belong to the localhost bridge process,
878
- // not to one React DesignCanvas instance. Overview -> Full view currently
902
+ // not to one React DesignCanvas instance. Canvas -> responsive Interact
879
903
  // replaces the overview canvas component with a focused canvas component; a
880
904
  // component-local registration flag made that transition mount an empty
881
905
  // srcdoc first and then replace it with the live URL after an identical POST.
@@ -1037,10 +1061,13 @@ export function DesignCanvas({
1037
1061
  runtimeReplacementContent,
1038
1062
  runtimeReplacementKey,
1039
1063
  styleRevertRequest,
1064
+ pendingStylePreviewPatches,
1040
1065
  styleBaselineResetRequest,
1041
1066
  textRevertRequest,
1042
1067
  structureAckRequest,
1043
1068
  runtimeStructureMoveRequest,
1069
+ runtimeStructureInsertRequest,
1070
+ onRuntimeStructureInsertRejected,
1044
1071
  runtimeVerificationRequest,
1045
1072
  embeddedFrameBackground,
1046
1073
  transparentBackground = false,
@@ -1103,6 +1130,7 @@ export function DesignCanvas({
1103
1130
  motionDefaultEase,
1104
1131
  motionDurationMs,
1105
1132
  previewWidthPx,
1133
+ previewHeightPx,
1106
1134
  onComponentSourceJump,
1107
1135
  shaderFillPreview,
1108
1136
  gradientEditTarget,
@@ -1176,20 +1204,82 @@ export function DesignCanvas({
1176
1204
  pendingOneShotMessagesRef.current = [];
1177
1205
  queued.forEach((message) => win.postMessage(message, "*"));
1178
1206
  }, []);
1179
- const postOneShotBridgeMessage = useCallback((message: unknown) => {
1180
- const iframe = iframeRef.current;
1181
- const win = iframe?.contentWindow;
1182
- // A one-shot prop can arrive in the same render that first creates the
1183
- // iframe. Keep it queued even when the ref/contentWindow is not attached
1184
- // yet; otherwise the effect records its request id as handled and the
1185
- // command is lost permanently before the bridge can announce readiness.
1186
- if (!win || !bridgeReadyRef.current) {
1187
- pendingOneShotMessagesRef.current.push(message);
1188
- return true;
1189
- }
1190
- win.postMessage(message, "*");
1191
- return true;
1207
+ const bridgeReadinessProbeTimerRef = useRef<number | undefined>(undefined);
1208
+ const probeBridgeReadinessUntilDrained = useCallback(() => {
1209
+ if (bridgeReadinessProbeTimerRef.current !== undefined) return;
1210
+ let attempts = 0;
1211
+ const probe = () => {
1212
+ const win = iframeRef.current?.contentWindow;
1213
+ const drained = pendingOneShotMessagesRef.current.length === 0;
1214
+ // 20 x 250ms covers a frame still finishing navigation without leaving a
1215
+ // timer running against a frame that has no bridge at all (interact-mode
1216
+ // documents never inject one, and must keep queueing as before).
1217
+ if (!win || drained || attempts >= 20) {
1218
+ window.clearInterval(bridgeReadinessProbeTimerRef.current);
1219
+ bridgeReadinessProbeTimerRef.current = undefined;
1220
+ return;
1221
+ }
1222
+ attempts += 1;
1223
+ win.postMessage(
1224
+ {
1225
+ type: "agent-native:text-edit-status",
1226
+ correlationId: "",
1227
+ nodeId: "",
1228
+ },
1229
+ "*",
1230
+ );
1231
+ };
1232
+ probe();
1233
+ if (pendingOneShotMessagesRef.current.length === 0) return;
1234
+ bridgeReadinessProbeTimerRef.current = window.setInterval(probe, 250);
1192
1235
  }, []);
1236
+ useEffect(
1237
+ () => () => {
1238
+ if (bridgeReadinessProbeTimerRef.current !== undefined) {
1239
+ window.clearInterval(bridgeReadinessProbeTimerRef.current);
1240
+ bridgeReadinessProbeTimerRef.current = undefined;
1241
+ }
1242
+ },
1243
+ [],
1244
+ );
1245
+ const postOneShotBridgeMessage = useCallback(
1246
+ (message: unknown) => {
1247
+ const iframe = iframeRef.current;
1248
+ const win = iframe?.contentWindow;
1249
+ // A one-shot prop can arrive in the same render that first creates the
1250
+ // iframe. Keep it queued even when the ref/contentWindow is not attached
1251
+ // yet; otherwise the effect records its request id as handled and the
1252
+ // command is lost permanently before the bridge can announce readiness.
1253
+ if (!win || !bridgeReadyRef.current) {
1254
+ pendingOneShotMessagesRef.current.push(message);
1255
+ // The readiness recovery in the message handler below is PASSIVE: it
1256
+ // waits for the frame to say something first. A live-edit screen keeps
1257
+ // its already-loaded iframe across a canvas remount, so a replacement
1258
+ // instance never sees `editor-chrome-ready`, and an idle frame says
1259
+ // nothing on its own — every inspector style commit then sat here
1260
+ // reporting success while the running app never changed, until some
1261
+ // unrelated hover/selection happened to talk and flushed the backlog.
1262
+ // Ask instead of waiting: `agent-native:text-edit-status` is the
1263
+ // cheapest bridge round trip (no DOM walk with an empty nodeId), its
1264
+ // reply is a trusted message from the current frame, and that reply is
1265
+ // what marks the bridge ready and drains this queue. A frame with no
1266
+ // bridge attached simply never answers, so the queue keeps its original
1267
+ // meaning.
1268
+ // ...and keep asking. A single probe is fire-and-forget: if it lands
1269
+ // while the frame is mid-navigation (or before its bridge listener is
1270
+ // attached) nothing answers, and because the frame is otherwise idle
1271
+ // nothing ever asks again — the queue strands and every queued command
1272
+ // keeps reporting success. Undo of a live style edit is the visible
1273
+ // case: the revert never reaches the running app. Retry on a bounded
1274
+ // schedule and stop as soon as the queue drains.
1275
+ if (win) probeBridgeReadinessUntilDrained();
1276
+ return true;
1277
+ }
1278
+ win.postMessage(message, "*");
1279
+ return true;
1280
+ },
1281
+ [probeBridgeReadinessUntilDrained],
1282
+ );
1193
1283
  const [renderedContent, setRenderedContent] = useState(content);
1194
1284
  // True while a drawing send is capturing/compositing/uploading the
1195
1285
  // annotated screenshot (see design-canvas/annotation-snapshot.ts). Drives
@@ -1360,8 +1450,11 @@ export function DesignCanvas({
1360
1450
  );
1361
1451
  // Keep the installed gesture script identical between overview and focused
1362
1452
  // mode. The live flags are posted below; baking `isEmbeddedFrame` into the
1363
- // script changed the bridge key during Full view and defeated the
1453
+ // script changed the bridge key during responsive Interact and defeated the
1364
1454
  // registration handoff cache, forcing an avoidable iframe navigation.
1455
+ // interactMode remains baked: un-baking its first-paint safety flag made the
1456
+ // responsive iframe render blank in live verification. The live message
1457
+ // below is additive; it does not replace the correct initial script.
1365
1458
  const embeddedGestureBridgeForCurrentState = useMemo(
1366
1459
  () =>
1367
1460
  EMBEDDED_WHEEL_BRIDGE_SCRIPT.replace(
@@ -1475,10 +1568,11 @@ export function DesignCanvas({
1475
1568
  editMode,
1476
1569
  hasLiveEditorBridge: usesLiveEditEditorBridge,
1477
1570
  });
1478
- // Null only while an entitled viewer's keyed bridge is still registering, so
1479
- // the frame mounts once directly at the proxied document (resolveLiveEditPreviewUrl's
1480
- // flash/state-loss note). A viewer with no previewToken has no bridge to wait
1481
- // for, so it loads the dev server directly rather than degrading to a snapshot.
1571
+ // Null only while an entitled viewer's keyed bridge is still registering.
1572
+ // During that interval the loading surface renders without an iframe; once
1573
+ // registration succeeds, the one real proxied document mounts directly.
1574
+ // A viewer with no previewToken has no bridge to wait for, so it loads the
1575
+ // dev server directly rather than degrading to a snapshot.
1482
1576
  const externalPreviewUrl =
1483
1577
  liveEditExternalPreviewUrl ??
1484
1578
  (usesLiveEditInjectedBridge ? null : rawExternalPreviewUrl);
@@ -2099,14 +2193,10 @@ export function DesignCanvas({
2099
2193
  // switching the active surface (board ↔ screen) or toggling Edit ⇄ Preview
2100
2194
  // never rebuilds srcdoc / reloads every screen iframe.
2101
2195
  const srcdoc = useMemo(() => {
2102
- if (externalPreviewUrl) return undefined;
2103
- // Never boot the raw localhost URL (or an editor-enabled srcdoc) while
2104
- // the keyed live-edit bridge is still registering. The opaque placeholder
2105
- // stays behind the visible loading surface; the real iframe mounts once,
2106
- // directly at the authenticated proxied document.
2107
- if (waitingForLiveEditBridge) {
2108
- return '<!doctype html><html><head><meta charset="utf-8"></head><body></body></html>';
2109
- }
2196
+ // A URL-backed screen is never an inline document, including while its
2197
+ // keyed bridge registration is pending. The loading surface waits without
2198
+ // mounting an iframe, then mounts the real `src` exactly once.
2199
+ if (rawExternalPreviewUrl) return undefined;
2110
2200
  const editorChromeBridge = interactMode
2111
2201
  ? ""
2112
2202
  : createEditorBridgeThemeScript(readEditorBridgeThemeVars()) +
@@ -2174,16 +2264,8 @@ export function DesignCanvas({
2174
2264
  contentOffsetY: embeddedFrame?.contentOffsetY ?? 0,
2175
2265
  });
2176
2266
  let frameDocument: string;
2177
- if (frameContent.includes("</body>")) {
2178
- frameDocument = frameContent.replace(
2179
- "</body>", // i18n-ignore generated iframe HTML injection
2180
- bridgeToInject + "</body>", // i18n-ignore generated iframe HTML injection
2181
- ); // i18n-ignore generated iframe HTML injection
2182
- } else if (frameContent.includes("</html>")) {
2183
- frameDocument = frameContent.replace(
2184
- "</html>", // i18n-ignore generated iframe HTML injection
2185
- bridgeToInject + "</html>", // i18n-ignore generated iframe HTML injection
2186
- ); // i18n-ignore generated iframe HTML injection
2267
+ if (/<\/(?:body|html)\s*>/i.test(frameContent)) {
2268
+ frameDocument = injectDocumentMarkup(frameContent, bridgeToInject);
2187
2269
  } else {
2188
2270
  // No body/html tags — wrap it
2189
2271
  const frameStyle = [
@@ -2215,14 +2297,13 @@ export function DesignCanvas({
2215
2297
  // eslint-disable-next-line react-hooks/exhaustive-deps
2216
2298
  }, [
2217
2299
  boardSurface,
2218
- externalPreviewUrl,
2300
+ rawExternalPreviewUrl,
2219
2301
  interactMode,
2220
2302
  isEmbeddedFrame,
2221
2303
  embeddedFrameBackground,
2222
2304
  embeddedGestureBridgeForCurrentState,
2223
2305
  iframeRenderContent,
2224
2306
  transparentBackground,
2225
- waitingForLiveEditBridge,
2226
2307
  ]);
2227
2308
 
2228
2309
  // PERF (soak measurement 2): contentHash walks the full srcdoc string
@@ -2248,13 +2329,15 @@ export function DesignCanvas({
2248
2329
  previousIframeDocumentIdentityRef.current = iframeDocumentIdentity;
2249
2330
  bridgeReadyRef.current = false;
2250
2331
  }
2332
+ // No snapshot is ever painted over the live frame, not even for the few
2333
+ // frames of a document swap. Covering the real iframe with a frozen copy is
2334
+ // the same false-success shape as rendering the snapshot outright: when the
2335
+ // swap stalls, the canvas keeps showing a screen that looks correct and
2336
+ // responds to nothing. A brief flash is the honest signal.
2251
2337
  const liveEditDocumentPending =
2252
2338
  usesLiveEditEditorBridge &&
2253
2339
  Boolean(externalPreviewUrl) &&
2254
2340
  readyIframeDocumentIdentity !== iframeDocumentIdentity;
2255
- const liveEditTransitionFallbackHtml = liveEditDocumentPending
2256
- ? activeExternalSnapshotHtml
2257
- : undefined;
2258
2341
 
2259
2342
  // Listen for messages from the iframe
2260
2343
  useEffect(() => {
@@ -2356,6 +2439,20 @@ export function DesignCanvas({
2356
2439
  }
2357
2440
  return;
2358
2441
  }
2442
+ // Any other trusted message from the CURRENT frame proves the chrome
2443
+ // bridge is live in the document that is in the iframe right now.
2444
+ // Readiness must follow the document, not the one-time handshake: a
2445
+ // live-edit screen keeps its already-loaded iframe across a canvas
2446
+ // remount, so a later instance never sees `editor-chrome-ready` and
2447
+ // `bridgeReadyRef` stays false forever. Every one-shot command then
2448
+ // lands in `pendingOneShotMessagesRef` and nothing ever flushes it —
2449
+ // the drop, the text edit, the delete all report success and do
2450
+ // nothing. Re-derive readiness here so the queue always drains.
2451
+ if (trustedCurrentFrame && !bridgeReadyRef.current) {
2452
+ bridgeReadyRef.current = true;
2453
+ setReadyIframeDocumentIdentity(iframeDocumentIdentity);
2454
+ flushPendingOneShotMessages();
2455
+ }
2359
2456
  if (e.data.type === "agent-native:runtime-layer-snapshot") {
2360
2457
  const payload = e.data.payload;
2361
2458
  if (
@@ -2525,6 +2622,10 @@ export function DesignCanvas({
2525
2622
  }
2526
2623
  return;
2527
2624
  }
2625
+ if (e.data.type === "runtime-structure-insert-rejected") {
2626
+ onRuntimeStructureInsertRejected?.(String(e.data.reason || "unknown"));
2627
+ return;
2628
+ }
2528
2629
  if (e.data.type === "visual-structure-change") {
2529
2630
  const selector = String(e.data.selector || "");
2530
2631
  const anchorSelector = String(e.data.anchorSelector || "");
@@ -2600,6 +2701,10 @@ export function DesignCanvas({
2600
2701
  anchorElementInfo: isElementInfoPayload(e.data.anchorPayload)
2601
2702
  ? e.data.anchorPayload
2602
2703
  : undefined,
2704
+ insertedHtml:
2705
+ typeof e.data.insertedHtml === "string"
2706
+ ? e.data.insertedHtml
2707
+ : undefined,
2603
2708
  },
2604
2709
  );
2605
2710
  dndHostLog("persist:result", {
@@ -2933,6 +3038,7 @@ export function DesignCanvas({
2933
3038
  onIframeContextMenu,
2934
3039
  onEditorDragStateChange,
2935
3040
  onVisualStructureChange,
3041
+ onRuntimeStructureInsertRejected,
2936
3042
  onVisualDuplicateChange,
2937
3043
  onZoomChange,
2938
3044
  deviceFrame,
@@ -3274,15 +3380,33 @@ export function DesignCanvas({
3274
3380
  ]);
3275
3381
 
3276
3382
  // Overview/focused placement is presentation state, not document identity.
3277
- // Update gesture routing in place so entering Full view reuses the same
3383
+ // Update gesture routing in place when entering responsive Interact.
3278
3384
  // registered bridge key instead of rebuilding the injected script.
3385
+ //
3386
+ // readyIframeDocumentIdentity is a dep purely to re-fire this on every
3387
+ // (re)ready handshake: a document swap resets bridgeReadyRef and wipes
3388
+ // pendingOneShotMessagesRef (see the contentKey-change effect above), which
3389
+ // silently drops this message if it was still queued when the swap
3390
+ // happened. Its own value isn't read here — only bridgeReadyRef.current
3391
+ // (already true by the time the ready handler flips this state) matters,
3392
+ // so re-running always sends live instead of re-queuing into the
3393
+ // just-cleared queue.
3279
3394
  useEffect(() => {
3280
3395
  postOneShotBridgeMessage({
3281
3396
  type: "embedded-canvas-gesture-mode",
3282
3397
  wheelEnabled: isEmbeddedFrame,
3283
3398
  spaceKeyForwardingEnabled: interactMode || readOnly,
3399
+ // Interact hands the app its own native interaction back; every other
3400
+ // mode keeps the editing shield armed.
3401
+ editingSafetyEnabled: !interactMode,
3284
3402
  });
3285
- }, [interactMode, isEmbeddedFrame, postOneShotBridgeMessage, readOnly]);
3403
+ }, [
3404
+ interactMode,
3405
+ isEmbeddedFrame,
3406
+ postOneShotBridgeMessage,
3407
+ readOnly,
3408
+ readyIframeDocumentIdentity,
3409
+ ]);
3286
3410
 
3287
3411
  // The board iframe is a finite paint window over an infinite logical
3288
3412
  // canvas. Re-centering that window must update its CSS/bridge coordinate
@@ -3478,8 +3602,8 @@ export function DesignCanvas({
3478
3602
  options?: { selectorCandidates?: string[]; nodeId?: string | null },
3479
3603
  ) => {
3480
3604
  const iframe = iframeRef.current;
3481
- if (!iframe?.contentWindow) return;
3482
- postOneShotBridgeMessage({
3605
+ if (!iframe?.contentWindow) return false;
3606
+ return postOneShotBridgeMessage({
3483
3607
  type: "style-change",
3484
3608
  selector,
3485
3609
  property,
@@ -3490,6 +3614,19 @@ export function DesignCanvas({
3490
3614
  },
3491
3615
  [postOneShotBridgeMessage],
3492
3616
  );
3617
+ const sendStyleChangeForScreen = useCallback(
3618
+ (
3619
+ targetScreenId: string,
3620
+ selector: string,
3621
+ property: string,
3622
+ value: string,
3623
+ options?: { selectorCandidates?: string[]; nodeId?: string | null },
3624
+ ) => {
3625
+ if (!screenId || targetScreenId !== screenId) return false;
3626
+ return sendStyleChange(selector, property, value, options);
3627
+ },
3628
+ [screenId, sendStyleChange],
3629
+ );
3493
3630
 
3494
3631
  const sendInteractionStatePreviewStyle = useCallback(
3495
3632
  (args: {
@@ -3512,46 +3649,57 @@ export function DesignCanvas({
3512
3649
  );
3513
3650
 
3514
3651
  const lastStyleRevertRequestIdRef = useRef<number | null>(null);
3652
+ const replayStylePatches = useCallback(
3653
+ (patches: Array<StyleReplayPatch>) => {
3654
+ for (const patch of patches) {
3655
+ const target = runtimeStyleTarget(patch);
3656
+ if (target.selectorCandidates.length === 0) continue;
3657
+ if (patch.interactionState) {
3658
+ sendInteractionStatePreviewStyle({
3659
+ selector: target.selector,
3660
+ selectorCandidates: target.selectorCandidates,
3661
+ nodeId: target.nodeId,
3662
+ state: patch.interactionState,
3663
+ styles: patch.styles,
3664
+ });
3665
+ continue;
3666
+ }
3667
+ for (const [property, value] of Object.entries(patch.styles)) {
3668
+ postOneShotBridgeMessage({
3669
+ type: "style-change",
3670
+ selector: target.selector,
3671
+ property,
3672
+ value,
3673
+ selectorCandidates: target.selectorCandidates,
3674
+ nodeId: target.nodeId ?? "",
3675
+ });
3676
+ }
3677
+ }
3678
+ },
3679
+ [postOneShotBridgeMessage, sendInteractionStatePreviewStyle],
3680
+ );
3515
3681
  useEffect(() => {
3516
3682
  if (!styleRevertRequest) return;
3517
3683
  if (lastStyleRevertRequestIdRef.current === styleRevertRequest.requestId) {
3518
3684
  return;
3519
3685
  }
3520
3686
  lastStyleRevertRequestIdRef.current = styleRevertRequest.requestId;
3521
- for (const patch of styleRevertRequest.patches) {
3522
- const selectorCandidates = [
3523
- patch.selector,
3524
- patch.sourceId
3525
- ? `[data-agent-native-node-id="${String(patch.sourceId)
3526
- .replace(/\\/g, "\\\\")
3527
- .replace(/"/g, '\\"')}"]`
3528
- : "",
3529
- ].filter(Boolean);
3530
- if (patch.interactionState) {
3531
- sendInteractionStatePreviewStyle({
3532
- selector: patch.selector,
3533
- selectorCandidates,
3534
- nodeId: patch.sourceId,
3535
- state: patch.interactionState,
3536
- styles: patch.styles,
3537
- });
3538
- continue;
3539
- }
3540
- for (const [property, value] of Object.entries(patch.styles)) {
3541
- postOneShotBridgeMessage({
3542
- type: "style-change",
3543
- selector: patch.selector,
3544
- property,
3545
- value,
3546
- selectorCandidates,
3547
- nodeId: patch.sourceId ?? "",
3548
- });
3549
- }
3550
- }
3687
+ replayStylePatches(styleRevertRequest.patches);
3688
+ }, [replayStylePatches, styleRevertRequest]);
3689
+
3690
+ useEffect(() => {
3691
+ if (!screenId) return;
3692
+ replayStylePatches(
3693
+ (pendingStylePreviewPatches ?? []).filter(
3694
+ (patch) => patch.screenId === screenId,
3695
+ ),
3696
+ );
3551
3697
  }, [
3552
- postOneShotBridgeMessage,
3553
- sendInteractionStatePreviewStyle,
3554
- styleRevertRequest,
3698
+ contentKey,
3699
+ pendingStylePreviewPatches,
3700
+ readyIframeDocumentIdentity,
3701
+ replayStylePatches,
3702
+ screenId,
3555
3703
  ]);
3556
3704
 
3557
3705
  const lastStyleBaselineResetRequestRef = useRef<number | null>(null);
@@ -3635,6 +3783,28 @@ export function DesignCanvas({
3635
3783
  });
3636
3784
  }, [postOneShotBridgeMessage, runtimeStructureMoveRequest]);
3637
3785
 
3786
+ const lastRuntimeStructureInsertRequestIdRef = useRef<number | null>(null);
3787
+ useEffect(() => {
3788
+ if (!runtimeStructureInsertRequest) return;
3789
+ if (
3790
+ lastRuntimeStructureInsertRequestIdRef.current ===
3791
+ runtimeStructureInsertRequest.requestId
3792
+ ) {
3793
+ return;
3794
+ }
3795
+ lastRuntimeStructureInsertRequestIdRef.current =
3796
+ runtimeStructureInsertRequest.requestId;
3797
+ postOneShotBridgeMessage({
3798
+ type: "runtime-structure-insert",
3799
+ requestId: runtimeStructureInsertRequest.requestId,
3800
+ html: runtimeStructureInsertRequest.html,
3801
+ anchorSelector: runtimeStructureInsertRequest.anchor.selector,
3802
+ anchorSourceId: runtimeStructureInsertRequest.anchor.sourceId,
3803
+ anchorPendingNodeId: runtimeStructureInsertRequest.anchor.pendingNodeId,
3804
+ placement: runtimeStructureInsertRequest.placement,
3805
+ });
3806
+ }, [postOneShotBridgeMessage, runtimeStructureInsertRequest]);
3807
+
3638
3808
  /**
3639
3809
  * Send a motion-preview scrub tick to the iframe. `t` is the normalised
3640
3810
  * playhead position in [0, 1]. Tracks must have been loaded first via the
@@ -3839,13 +4009,21 @@ export function DesignCanvas({
3839
4009
  }, [replaceRuntimeContentInPlace, runtimeReplacementEnabled]);
3840
4010
 
3841
4011
  const deleteRuntimeElement = useCallback(
3842
- (selector?: string | null, candidates?: string[]) => {
4012
+ (
4013
+ selector?: string | null,
4014
+ candidates?: string[],
4015
+ // Present when the host queued this deletion as a pending live edit; the
4016
+ // bridge keeps the detached node under this id so a later
4017
+ // visual-structure-ack with applied:false can put it back.
4018
+ requestId?: string,
4019
+ ) => {
3843
4020
  const iframe = iframeRef.current;
3844
4021
  if (!iframe?.contentWindow) return false;
3845
4022
  return postOneShotBridgeMessage({
3846
4023
  type: "delete-element",
3847
4024
  selector: selector ?? "",
3848
4025
  selectorCandidates: candidates ?? [],
4026
+ requestId,
3849
4027
  });
3850
4028
  },
3851
4029
  [postOneShotBridgeMessage],
@@ -3855,6 +4033,7 @@ export function DesignCanvas({
3855
4033
  useEffect(() => {
3856
4034
  if (!registerRuntimeBridge) return;
3857
4035
  (window as any).__designCanvasSendStyle = sendStyleChange;
4036
+ (window as any).__designCanvasSendStyleForScreen = sendStyleChangeForScreen;
3858
4037
  (window as any).__designCanvasSendInteractionStatePreviewStyle =
3859
4038
  sendInteractionStatePreviewStyle;
3860
4039
  (window as any).__designCanvasReplaceContent =
@@ -3875,6 +4054,12 @@ export function DesignCanvas({
3875
4054
  if ((window as any).__designCanvasSendStyle === sendStyleChange) {
3876
4055
  delete (window as any).__designCanvasSendStyle;
3877
4056
  }
4057
+ if (
4058
+ (window as any).__designCanvasSendStyleForScreen ===
4059
+ sendStyleChangeForScreen
4060
+ ) {
4061
+ delete (window as any).__designCanvasSendStyleForScreen;
4062
+ }
3878
4063
  if (
3879
4064
  (window as any).__designCanvasSendInteractionStatePreviewStyle ===
3880
4065
  sendInteractionStatePreviewStyle
@@ -3921,6 +4106,7 @@ export function DesignCanvas({
3921
4106
  }, [
3922
4107
  deleteRuntimeElement,
3923
4108
  registerRuntimeBridge,
4109
+ sendStyleChangeForScreen,
3924
4110
  replacePreviewContentFromHost,
3925
4111
  sendStyleChange,
3926
4112
  sendInteractionStatePreviewStyle,
@@ -3959,6 +4145,12 @@ export function DesignCanvas({
3959
4145
  previewWidthPx !== null && previewWidthPx !== undefined
3960
4146
  ? `${previewWidthPx}px`
3961
4147
  : iframeWidth;
4148
+ const resolvedHeight =
4149
+ previewHeightPx !== null && previewHeightPx !== undefined
4150
+ ? `${previewHeightPx}px`
4151
+ : deviceFrame === "none"
4152
+ ? "100%"
4153
+ : (iframeHeight ?? undefined);
3962
4154
  const focusScrollSurface = useCallback(() => {
3963
4155
  const surface = scrollContainerRef.current;
3964
4156
  if (!surface || document.activeElement === surface) return;
@@ -4147,9 +4339,7 @@ export function DesignCanvas({
4147
4339
  ? embeddedFrameFluid
4148
4340
  ? "100%"
4149
4341
  : embeddedFrame.viewportHeight
4150
- : deviceFrame === "none"
4151
- ? "100%"
4152
- : (iframeHeight ?? undefined),
4342
+ : resolvedHeight,
4153
4343
  // BP-DEEP item 2: when a breakpoint chip constrains the viewport
4154
4344
  // (previewWidthPx) the wrapper is NARROWER than the canvas, so there
4155
4345
  // is no horizontal overflow for the scroll-centering effect above to
@@ -4191,55 +4381,39 @@ export function DesignCanvas({
4191
4381
  )}
4192
4382
  />
4193
4383
  ) : null}
4194
- {liveEditTransitionFallbackHtml ? (
4384
+ {rawExternalPreviewUrl && !externalPreviewUrl ? null : (
4195
4385
  <iframe
4196
- data-live-edit-transition-fallback
4197
- srcDoc={liveEditTransitionFallbackHtml}
4198
- sandbox=""
4199
- aria-hidden="true"
4200
- tabIndex={-1}
4201
- className="pointer-events-none absolute inset-0 block h-full w-full border-0 bg-transparent"
4386
+ key={iframeDocumentIdentity}
4387
+ ref={iframeRef}
4388
+ src={externalPreviewUrl ?? undefined}
4389
+ srcDoc={externalPreviewUrl ? undefined : srcdoc}
4390
+ sandbox={getDesignCanvasIframeSandbox({
4391
+ externalPreview: Boolean(externalPreviewUrl),
4392
+ readOnly,
4393
+ })}
4394
+ data-design-preview-iframe
4395
+ {...{
4396
+ [SESSION_REPLAY_IFRAME_ATTRIBUTE]: !externalPreviewUrl
4397
+ ? ""
4398
+ : undefined,
4399
+ }}
4400
+ data-screen-iframe-id={
4401
+ boardSurface ? undefined : (previewFrameId ?? screenId ?? undefined)
4402
+ }
4403
+ data-design-source-type={
4404
+ sourceType ??
4405
+ (externalPreviewUrl
4406
+ ? "localhost" // inferred — content is a URL
4407
+ : "inline")
4408
+ }
4409
+ className="relative block h-full w-full border-0 bg-transparent"
4202
4410
  style={{
4203
4411
  background: iframeBackgroundColor,
4204
4412
  backgroundColor: iframeBackgroundColor,
4205
4413
  }}
4206
- title=""
4414
+ title={t("designEditor.designPreview")}
4207
4415
  />
4208
- ) : null}
4209
- <iframe
4210
- key={iframeDocumentIdentity}
4211
- ref={iframeRef}
4212
- src={externalPreviewUrl ?? undefined}
4213
- srcDoc={externalPreviewUrl ? undefined : srcdoc}
4214
- sandbox={getDesignCanvasIframeSandbox({
4215
- externalPreview: Boolean(externalPreviewUrl),
4216
- readOnly,
4217
- })}
4218
- data-design-preview-iframe
4219
- {...{
4220
- [SESSION_REPLAY_IFRAME_ATTRIBUTE]: !externalPreviewUrl
4221
- ? ""
4222
- : undefined,
4223
- }}
4224
- data-screen-iframe-id={
4225
- boardSurface ? undefined : (previewFrameId ?? screenId ?? undefined)
4226
- }
4227
- data-design-source-type={
4228
- sourceType ??
4229
- (externalPreviewUrl
4230
- ? "localhost" // inferred — content is a URL
4231
- : "inline")
4232
- }
4233
- className={cn(
4234
- "relative block h-full w-full border-0 bg-transparent",
4235
- liveEditTransitionFallbackHtml && "pointer-events-none opacity-0",
4236
- )}
4237
- style={{
4238
- background: iframeBackgroundColor,
4239
- backgroundColor: iframeBackgroundColor,
4240
- }}
4241
- title={t("designEditor.designPreview")}
4242
- />
4416
+ )}
4243
4417
  {runtimeVerificationUrl ? (
4244
4418
  <iframe
4245
4419
  key={`${runtimeVerificationUrl}::${runtimeVerificationRequest?.requestId ?? 0}`}
@@ -4335,7 +4509,7 @@ export function DesignCanvas({
4335
4509
  ) : null}
4336
4510
  {waitingForEditableExternalSnapshot ||
4337
4511
  waitingForLiveEditBridge ||
4338
- (liveEditDocumentPending && !liveEditTransitionFallbackHtml) ? (
4512
+ liveEditDocumentPending ? (
4339
4513
  <div className="pointer-events-auto absolute inset-0 z-10 flex items-center justify-center bg-background/85 px-4 text-center text-sm text-muted-foreground">
4340
4514
  {waitingForLiveEditBridge &&
4341
4515
  bridgeRegistrationError?.bridgeKey === liveEditBridgeKey ? (