@agent-native/core 0.129.1 → 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 (596) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +78 -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/mcp/build-server.ts +20 -2
  58. package/corpus/core/src/observability/traces.ts +48 -12
  59. package/corpus/core/src/org/handlers.ts +52 -1
  60. package/corpus/core/src/org/migrations.ts +4 -0
  61. package/corpus/core/src/org/plugin.ts +14 -0
  62. package/corpus/core/src/org/schema.ts +1 -0
  63. package/corpus/core/src/org/types.ts +8 -0
  64. package/corpus/core/src/org/workspace-url.ts +74 -0
  65. package/corpus/core/src/resources/handlers.ts +35 -5
  66. package/corpus/core/src/scripts/runner.ts +183 -5
  67. package/corpus/core/src/server/action-routes.ts +32 -2
  68. package/corpus/core/src/server/agent-chat-plugin.ts +29 -0
  69. package/corpus/core/src/server/agent-teams.ts +10 -1
  70. package/corpus/core/src/server/auth.ts +33 -7
  71. package/corpus/core/src/server/embed-route.ts +9 -0
  72. package/corpus/core/src/server/embed-session.ts +62 -3
  73. package/corpus/core/src/server/open-route.ts +20 -6
  74. package/corpus/core/src/server/prompts/framework-core-compact.ts +1 -1
  75. package/corpus/core/src/server/prompts/framework-core.ts +1 -0
  76. package/corpus/core/src/server/request-context.ts +36 -1
  77. package/corpus/core/src/shared/embed-auth.ts +1 -0
  78. package/corpus/core/src/shared/html-document.ts +115 -0
  79. package/corpus/core/src/shared/index.ts +1 -0
  80. package/corpus/core/src/sharing/access.ts +8 -1
  81. package/corpus/core/src/sharing/registry.ts +11 -2
  82. package/corpus/core/src/workspace-files/actions.ts +100 -0
  83. package/corpus/core/src/workspace-files/tool.ts +4 -0
  84. package/corpus/templates/analytics/.agents/skills/analysis-workspace/SKILL.md +4 -0
  85. package/corpus/templates/analytics/.agents/skills/hubspot/SKILL.md +9 -1
  86. package/corpus/templates/analytics/AGENTS.md +17 -24
  87. package/corpus/templates/analytics/actions/data-source-status.ts +11 -1
  88. package/corpus/templates/analytics/app/i18n-data.ts +34 -0
  89. package/corpus/templates/analytics/app/lib/data-source-status.ts +86 -0
  90. package/corpus/templates/analytics/app/lib/native-mcp-exclusions.ts +9 -0
  91. package/corpus/templates/analytics/app/pages/DataSources.tsx +184 -20
  92. package/corpus/templates/analytics/changelog/2026-07-28-native-analytics-data-sources-no-longer-show-duplicate-mc.md +6 -0
  93. package/corpus/templates/analytics/changelog/2026-07-29-exports-now-appear-in-chat-with-a-direct-download-instead-of.md +6 -0
  94. package/corpus/templates/analytics/changelog/2026-07-29-queued-chat-prompts-no-longer-resend-after-analytics-navigat.md +6 -0
  95. package/corpus/templates/analytics/changelog/2026-07-29-scheduled-dashboard-emails-load-every-panel-reliably-without.md +6 -0
  96. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +6 -3
  97. package/corpus/templates/analytics/server/lib/credential-keys.ts +1 -1
  98. package/corpus/templates/analytics/server/lib/hubspot.ts +1 -1
  99. package/corpus/templates/analytics/server/lib/provider-credentials.ts +55 -1
  100. package/corpus/templates/analytics/server/plugins/agent-chat.ts +123 -27
  101. package/corpus/templates/analytics/server/routes/[...page].get.ts +2 -7
  102. package/corpus/templates/analytics/vite.config.ts +7 -0
  103. package/corpus/templates/brain/actions/list-connection-providers.ts +100 -2
  104. package/corpus/templates/brain/app/lib/brain.ts +10 -0
  105. package/corpus/templates/brain/app/routes/sources.tsx +15 -4
  106. package/corpus/templates/brain/changelog/2026-07-29-brain-automatically-retries-failed-source-syncs-and-guides-y.md +6 -0
  107. package/corpus/templates/brain/jobs/process-ingest-queue.ts +13 -0
  108. package/corpus/templates/brain/server/jobs/sync-sources.ts +27 -22
  109. package/corpus/templates/brain/server/plugins/agent-chat.ts +2 -1
  110. package/corpus/templates/brain/server/routes/api/brain/queue/run.post.ts +7 -1
  111. package/corpus/templates/clips/AGENTS.md +1 -1
  112. package/corpus/templates/clips/actions/create-recording-agent-link.ts +11 -1
  113. package/corpus/templates/clips/actions/update-comment.ts +68 -0
  114. package/corpus/templates/clips/app/components/editor/editor-layout.tsx +0 -1
  115. package/corpus/templates/clips/app/components/player/comments-panel.tsx +221 -65
  116. package/corpus/templates/clips/app/components/player/video-player.tsx +101 -27
  117. package/corpus/templates/clips/app/i18n/en-US.ts +2 -1
  118. package/corpus/templates/clips/app/routes/bug-report.done.tsx +48 -27
  119. package/corpus/templates/clips/app/routes/bug-report.tsx +43 -4
  120. package/corpus/templates/clips/app/routes/record.tsx +2 -0
  121. package/corpus/templates/clips/changelog/2026-07-29-clip-playback-now-recovers-instead-of-getting-stuck-when-a-b.md +6 -0
  122. package/corpus/templates/clips/changelog/2026-07-29-comments-can-now-be-edited-after-posting.md +6 -0
  123. package/corpus/templates/clips/changelog/2026-07-29-download-actions-now-use-a-shorter-clearer-label.md +6 -0
  124. package/corpus/templates/clips/changelog/2026-07-29-embedded-bug-reports-now-return-a-temporary-agent-readable.md +6 -0
  125. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +1 -1
  126. package/corpus/templates/clips/desktop/src-tauri/src/system_audio.rs +21 -1
  127. package/corpus/templates/clips/shared/bug-report.ts +99 -0
  128. package/corpus/templates/content/actions/_content-database-personal-view.ts +7 -1
  129. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +5 -2
  130. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +20 -8
  131. package/corpus/templates/content/changelog/2026-07-29-missing-databases-no-longer-trigger-repeated-personal-view-e.md +6 -0
  132. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +83 -47
  133. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +474 -55
  134. package/corpus/templates/design/.generated/bridge/embedded-wheel.generated.ts +3 -0
  135. package/corpus/templates/design/.generated/bridge/hit-test.generated.ts +18 -1
  136. package/corpus/templates/design/.generated/bridge/source-location.generated.ts +348 -0
  137. package/corpus/templates/design/actions/add-localhost-screens.ts +2 -7
  138. package/corpus/templates/design/actions/apply-visual-edit.ts +7 -1
  139. package/corpus/templates/design/actions/connect-localhost.ts +5 -9
  140. package/corpus/templates/design/actions/create-component.ts +16 -13
  141. package/corpus/templates/design/actions/grant-localhost-write-consent.ts +2 -7
  142. package/corpus/templates/design/actions/list-design-source-capabilities.ts +4 -7
  143. package/corpus/templates/design/actions/list-local-files.ts +26 -50
  144. package/corpus/templates/design/actions/list-localhost-connections.ts +2 -7
  145. package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +2 -2
  146. package/corpus/templates/design/actions/open-visual-edit.ts +234 -135
  147. package/corpus/templates/design/actions/read-local-file.ts +26 -50
  148. package/corpus/templates/design/actions/request-localhost-write-consent.ts +2 -7
  149. package/corpus/templates/design/actions/write-local-file.ts +31 -73
  150. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +307 -133
  151. package/corpus/templates/design/app/components/design/EditPanel.tsx +94 -22
  152. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +137 -60
  153. package/corpus/templates/design/app/components/design/ResponsiveInteractBar.tsx +75 -14
  154. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +755 -97
  155. package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +8 -0
  156. package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +24 -1
  157. package/corpus/templates/design/app/components/design/bridge/source-location.bridge.ts +530 -0
  158. package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbenchLoader.tsx +278 -0
  159. package/corpus/templates/design/app/components/design/code-workbench/editor/MonacoHost.tsx +32 -12
  160. package/corpus/templates/design/app/components/design/code-workbench/editor/monaco-setup.ts +14 -3
  161. package/corpus/templates/design/app/components/design/code-workbench/explorer/ExplorerView.tsx +87 -24
  162. package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +36 -0
  163. package/corpus/templates/design/app/components/design/code-workbench/store.tsx +2 -1
  164. package/corpus/templates/design/app/components/design/code-workbench/workspace/localhost-provider.ts +48 -8
  165. package/corpus/templates/design/app/components/design/design-canvas/content-size-report.ts +3 -13
  166. package/corpus/templates/design/app/components/design/design-canvas/embedded-frame.ts +4 -2
  167. package/corpus/templates/design/app/components/design/design-canvas/hit-test.ts +3 -13
  168. package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +3 -1
  169. package/corpus/templates/design/app/components/design/edit-panel/inspect-code-source.ts +93 -0
  170. package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +4 -2
  171. package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +35 -0
  172. package/corpus/templates/design/app/components/design/multi-screen/iframe-targeting.ts +24 -0
  173. package/corpus/templates/design/app/components/design/multi-screen/types.ts +9 -0
  174. package/corpus/templates/design/app/components/design/types.ts +29 -0
  175. package/corpus/templates/design/app/components/layout/Layout.tsx +7 -4
  176. package/corpus/templates/design/app/hooks/use-navigation-state.ts +3 -0
  177. package/corpus/templates/design/app/i18n-data.ts +153 -46
  178. package/corpus/templates/design/app/i18n-responsive-interact.ts +12 -12
  179. package/corpus/templates/design/app/lib/design-editor-route.ts +23 -0
  180. package/corpus/templates/design/app/pages/VisualEdit.tsx +19 -6
  181. package/corpus/templates/design/app/pages/design-editor/action-error.ts +19 -0
  182. package/corpus/templates/design/app/pages/design-editor/canvas-primitive-insert.ts +29 -0
  183. package/corpus/templates/design/app/pages/design-editor/clone-and-pen-edit.ts +6 -0
  184. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +277 -15
  185. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +75 -9
  186. package/corpus/templates/design/app/pages/design-editor/layer-state-scope.ts +28 -0
  187. package/corpus/templates/design/app/pages/design-editor/live-screen-layer-drop.ts +41 -0
  188. package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +496 -41
  189. package/corpus/templates/design/app/pages/design-editor/pending-live-edit-unload-guard.ts +27 -0
  190. package/corpus/templates/design/app/pages/design-editor/pending-structure-verification.ts +10 -0
  191. package/corpus/templates/design/app/pages/design-editor/react-semantic-handoff.ts +168 -9
  192. package/corpus/templates/design/app/pages/design-editor/responsive-interact.ts +41 -3
  193. package/corpus/templates/design/app/pages/design-editor/screen-command-utils.ts +5 -0
  194. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +42 -13
  195. package/corpus/templates/design/app/pages/design-editor/source-location.ts +180 -0
  196. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +17 -0
  197. package/corpus/templates/design/app/public-routes.ts +1 -0
  198. package/corpus/templates/design/app/routes/visual-edit.$id.tsx +15 -0
  199. package/corpus/templates/design/changelog/2026-06-29-screen-overview-is-easier-to-find-and-named-screens-open-dir.md +1 -1
  200. package/corpus/templates/design/changelog/2026-07-28-deleting-a-selected-element-now-removes-it-from-the-live-pre.md +6 -0
  201. package/corpus/templates/design/changelog/2026-07-28-deleting-an-element-on-a-connected-localhost-screen-now-queu.md +6 -0
  202. package/corpus/templates/design/changelog/2026-07-28-interact-mode-now-shows-a-responsive-device-preview-with-pre.md +6 -0
  203. package/corpus/templates/design/changelog/2026-07-28-layer-hide-and-lock-now-apply-to-the-live-preview-instead-of.md +6 -0
  204. package/corpus/templates/design/changelog/2026-07-28-layers-panel-selections-on-a-connected-localhost-screen-can-.md +6 -0
  205. package/corpus/templates/design/changelog/2026-07-28-locked-layers-now-show-a-subtle-dashed-outline-in-the-live-p.md +6 -0
  206. package/corpus/templates/design/changelog/2026-07-28-the-apply-design-updates-button-now-counts-pending-live-text.md +6 -0
  207. package/corpus/templates/design/changelog/2026-07-28-the-design-canvas-no-longer-stalls-on-a-render-loop-while-a-.md +6 -0
  208. package/corpus/templates/design/changelog/2026-07-28-visual-edit-on-a-local-dev-server-no-longer-requires-signing.md +6 -0
  209. package/corpus/templates/design/changelog/2026-07-28-visual-edits-on-a-react-19-app-no-longer-report-a-source-lin.md +6 -0
  210. package/corpus/templates/design/changelog/2026-07-29-an-edit-that-cannot-be-written-to-source-now-names-the-reaso.md +6 -0
  211. package/corpus/templates/design/changelog/2026-07-29-applying-a-primitive-dropped-onto-a-connected-localhost-scre.md +6 -0
  212. package/corpus/templates/design/changelog/2026-07-29-changing-a-style-in-the-inspector-now-updates-a-connected-lo.md +6 -0
  213. package/corpus/templates/design/changelog/2026-07-29-choosing-edit-or-annotate-from-a-focused-screen-now-returns-.md +6 -0
  214. package/corpus/templates/design/changelog/2026-07-29-concurrent-source-edits-now-return-a-clear-conflict-response.md +6 -0
  215. package/corpus/templates/design/changelog/2026-07-29-creating-a-component-from-an-element-that-repeats-in-the-sou.md +6 -0
  216. package/corpus/templates/design/changelog/2026-07-29-deleting-an-element-you-just-dropped-onto-a-live-screen-no-l.md +6 -0
  217. package/corpus/templates/design/changelog/2026-07-29-dragging-a-layer-across-screens-no-longer-dies-when-the-poin.md +6 -0
  218. package/corpus/templates/design/changelog/2026-07-29-dragging-an-element-from-a-stored-screen-into-a-live-localho.md +6 -0
  219. package/corpus/templates/design/changelog/2026-07-29-drawing-a-box-on-the-canvas-and-dragging-it-into-a-connected.md +6 -0
  220. package/corpus/templates/design/changelog/2026-07-29-fixed-a-loading-screen-flicker-when-reopening-designs-with-a.md +6 -0
  221. package/corpus/templates/design/changelog/2026-07-29-interact-mode-has-edit-and-annotate-buttons-again-so-you-can.md +6 -0
  222. package/corpus/templates/design/changelog/2026-07-29-layer-groups-can-be-dropped-onto-live-localhost-screens.md +6 -0
  223. package/corpus/templates/design/changelog/2026-07-29-localhost-source-errors-now-say-what-actually-went-wrong-whi.md +6 -0
  224. package/corpus/templates/design/changelog/2026-07-29-opening-or-refreshing-a-live-localhost-screen-in-single-scre.md +6 -0
  225. package/corpus/templates/design/changelog/2026-07-29-redo-after-undoing-a-drop-onto-a-live-screen-puts-the-elemen.md +6 -0
  226. package/corpus/templates/design/changelog/2026-07-29-shapes-can-be-drawn-directly-onto-live-localhost-screens.md +6 -0
  227. package/corpus/templates/design/changelog/2026-07-29-shapes-drawn-on-the-canvas-board-now-appear-immediately-inst.md +6 -0
  228. package/corpus/templates/design/changelog/2026-07-29-style-edits-on-a-running-localhost-screen-now-preview-live-a.md +6 -0
  229. package/corpus/templates/design/changelog/2026-07-29-the-apply-design-updates-control-now-appears-as-a-clean-conn.md +6 -0
  230. package/corpus/templates/design/changelog/2026-07-29-visual-edits-on-a-mapped-component-instance-now-tell-the-age.md +6 -0
  231. package/corpus/templates/design/server/lib/design-data-access.ts +21 -7
  232. package/corpus/templates/design/server/lib/localhost-connection.ts +240 -0
  233. package/corpus/templates/design/server/routes/[...page].get.ts +2 -5
  234. package/corpus/templates/design/server/source-workspace.ts +2 -0
  235. package/corpus/templates/design/shared/code-layer.ts +43 -0
  236. package/corpus/templates/design/shared/html-content.ts +26 -0
  237. package/corpus/templates/design/shared/html-integrity.ts +21 -1
  238. package/corpus/templates/design/shared/local-jsx-visual-edit.ts +15 -0
  239. package/corpus/templates/design/shared/source-mode.ts +76 -0
  240. package/corpus/templates/dispatch/changelog/2026-07-29-workspace-members-without-admin-access-now-see-a-clear-permi.md +6 -0
  241. package/corpus/templates/dispatch/server/lib/usage-metrics.ts +2 -1
  242. package/corpus/templates/plan/app/lib/plan-annotation-runtime.ts +3 -4
  243. package/corpus/templates/plan/server/routes/[...page].get.ts +2 -5
  244. package/corpus/templates/slides/actions/patch-deck.ts +29 -17
  245. package/corpus/toolkit/CHANGELOG.md +6 -0
  246. package/corpus/toolkit/package.json +1 -1
  247. package/corpus/toolkit/src/composer/ComposerPlusMenu.tsx +3 -2
  248. package/dist/action-ui.d.ts +1 -0
  249. package/dist/action-ui.d.ts.map +1 -1
  250. package/dist/action-ui.js +1 -0
  251. package/dist/action-ui.js.map +1 -1
  252. package/dist/action.d.ts +5 -1
  253. package/dist/action.d.ts.map +1 -1
  254. package/dist/action.js.map +1 -1
  255. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  256. package/dist/agent/engine/ai-sdk-engine.js +13 -5
  257. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  258. package/dist/agent/harness/runner.d.ts.map +1 -1
  259. package/dist/agent/harness/runner.js +5 -0
  260. package/dist/agent/harness/runner.js.map +1 -1
  261. package/dist/agent/production-agent.d.ts +16 -0
  262. package/dist/agent/production-agent.d.ts.map +1 -1
  263. package/dist/agent/production-agent.js +18 -1
  264. package/dist/agent/production-agent.js.map +1 -1
  265. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  266. package/dist/agent/run-loop-with-resume.js +6 -0
  267. package/dist/agent/run-loop-with-resume.js.map +1 -1
  268. package/dist/agent/run-manager.d.ts +14 -0
  269. package/dist/agent/run-manager.d.ts.map +1 -1
  270. package/dist/agent/run-manager.js +91 -1
  271. package/dist/agent/run-manager.js.map +1 -1
  272. package/dist/agent/thread-data-builder.d.ts +3 -0
  273. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  274. package/dist/agent/thread-data-builder.js +35 -3
  275. package/dist/agent/thread-data-builder.js.map +1 -1
  276. package/dist/agent/types.d.ts +2 -0
  277. package/dist/agent/types.d.ts.map +1 -1
  278. package/dist/agent/types.js.map +1 -1
  279. package/dist/chat-threads/store.d.ts.map +1 -1
  280. package/dist/chat-threads/store.js +4 -6
  281. package/dist/chat-threads/store.js.map +1 -1
  282. package/dist/cli/create.d.ts +66 -6
  283. package/dist/cli/create.d.ts.map +1 -1
  284. package/dist/cli/create.js +765 -66
  285. package/dist/cli/create.js.map +1 -1
  286. package/dist/cli/design-connect.d.ts.map +1 -1
  287. package/dist/cli/design-connect.js +2 -7
  288. package/dist/cli/design-connect.js.map +1 -1
  289. package/dist/cli/index.js +5 -3
  290. package/dist/cli/index.js.map +1 -1
  291. package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
  292. package/dist/cli/skills-content/design-visual-edit-skill.d.ts.map +1 -1
  293. package/dist/cli/skills-content/design-visual-edit-skill.js +83 -47
  294. package/dist/cli/skills-content/design-visual-edit-skill.js.map +1 -1
  295. package/dist/client/AssistantChat.d.ts.map +1 -1
  296. package/dist/client/AssistantChat.js +16 -9
  297. package/dist/client/AssistantChat.js.map +1 -1
  298. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  299. package/dist/client/agent-chat-adapter.js +21 -0
  300. package/dist/client/agent-chat-adapter.js.map +1 -1
  301. package/dist/client/blocks/library/wireframe-kit.d.ts +2 -0
  302. package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -1
  303. package/dist/client/blocks/library/wireframe-kit.js +8 -2
  304. package/dist/client/blocks/library/wireframe-kit.js.map +1 -1
  305. package/dist/client/chat/index.d.ts +1 -1
  306. package/dist/client/chat/index.d.ts.map +1 -1
  307. package/dist/client/chat/index.js +1 -1
  308. package/dist/client/chat/index.js.map +1 -1
  309. package/dist/client/chat/message-components.d.ts +17 -0
  310. package/dist/client/chat/message-components.d.ts.map +1 -1
  311. package/dist/client/chat/message-components.js +24 -2
  312. package/dist/client/chat/message-components.js.map +1 -1
  313. package/dist/client/chat/run-recovery.d.ts +6 -0
  314. package/dist/client/chat/run-recovery.d.ts.map +1 -1
  315. package/dist/client/chat/run-recovery.js +13 -3
  316. package/dist/client/chat/run-recovery.js.map +1 -1
  317. package/dist/client/chat/widgets/DataTableWidget.d.ts.map +1 -1
  318. package/dist/client/chat/widgets/DataTableWidget.js +2 -3
  319. package/dist/client/chat/widgets/DataTableWidget.js.map +1 -1
  320. package/dist/client/chat/widgets/WorkspaceFileWidget.d.ts +5 -0
  321. package/dist/client/chat/widgets/WorkspaceFileWidget.d.ts.map +1 -0
  322. package/dist/client/chat/widgets/WorkspaceFileWidget.js +34 -0
  323. package/dist/client/chat/widgets/WorkspaceFileWidget.js.map +1 -0
  324. package/dist/client/chat/widgets/builtin-tool-renderers.d.ts.map +1 -1
  325. package/dist/client/chat/widgets/builtin-tool-renderers.js +13 -1
  326. package/dist/client/chat/widgets/builtin-tool-renderers.js.map +1 -1
  327. package/dist/client/chat/widgets/workspace-file-result.d.ts +12 -0
  328. package/dist/client/chat/widgets/workspace-file-result.d.ts.map +1 -0
  329. package/dist/client/chat/widgets/workspace-file-result.js +34 -0
  330. package/dist/client/chat/widgets/workspace-file-result.js.map +1 -0
  331. package/dist/client/embed-auth.d.ts.map +1 -1
  332. package/dist/client/embed-auth.js +2 -1
  333. package/dist/client/embed-auth.js.map +1 -1
  334. package/dist/client/org/InvitationBanner.d.ts +5 -2
  335. package/dist/client/org/InvitationBanner.d.ts.map +1 -1
  336. package/dist/client/org/InvitationBanner.js +9 -2
  337. package/dist/client/org/InvitationBanner.js.map +1 -1
  338. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  339. package/dist/client/org/OrgSwitcher.js +3 -2
  340. package/dist/client/org/OrgSwitcher.js.map +1 -1
  341. package/dist/client/org/TeamPage.d.ts.map +1 -1
  342. package/dist/client/org/TeamPage.js +27 -3
  343. package/dist/client/org/TeamPage.js.map +1 -1
  344. package/dist/client/org/WorkspaceNotice.d.ts +18 -0
  345. package/dist/client/org/WorkspaceNotice.d.ts.map +1 -0
  346. package/dist/client/org/WorkspaceNotice.js +56 -0
  347. package/dist/client/org/WorkspaceNotice.js.map +1 -0
  348. package/dist/client/org/hooks.d.ts +1 -0
  349. package/dist/client/org/hooks.d.ts.map +1 -1
  350. package/dist/client/org/hooks.js +12 -0
  351. package/dist/client/org/hooks.js.map +1 -1
  352. package/dist/client/org/index.d.ts +2 -1
  353. package/dist/client/org/index.d.ts.map +1 -1
  354. package/dist/client/org/index.js +2 -1
  355. package/dist/client/org/index.js.map +1 -1
  356. package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
  357. package/dist/client/resources/McpIntegrationDialog.js +8 -12
  358. package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
  359. package/dist/client/resources/ResourcesPanel.d.ts +3 -0
  360. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  361. package/dist/client/resources/ResourcesPanel.js +49 -20
  362. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  363. package/dist/client/resources/mcp-integration-catalog.d.ts +1 -0
  364. package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
  365. package/dist/client/resources/mcp-integration-catalog.js +3 -0
  366. package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
  367. package/dist/client/resources/use-resources.d.ts +1 -0
  368. package/dist/client/resources/use-resources.d.ts.map +1 -1
  369. package/dist/client/resources/use-resources.js +3 -0
  370. package/dist/client/resources/use-resources.js.map +1 -1
  371. package/dist/client/use-action.d.ts +3 -1
  372. package/dist/client/use-action.d.ts.map +1 -1
  373. package/dist/client/use-action.js +3 -1
  374. package/dist/client/use-action.js.map +1 -1
  375. package/dist/client/widgets/index.d.ts +1 -1
  376. package/dist/client/widgets/index.d.ts.map +1 -1
  377. package/dist/client/widgets/index.js +1 -1
  378. package/dist/client/widgets/index.js.map +1 -1
  379. package/dist/coding-tools/run-code.js +2 -1
  380. package/dist/coding-tools/run-code.js.map +1 -1
  381. package/dist/collab/awareness.d.ts +2 -2
  382. package/dist/collab/awareness.d.ts.map +1 -1
  383. package/dist/collab/routes.d.ts +1 -1
  384. package/dist/db/client.d.ts +1 -0
  385. package/dist/db/client.d.ts.map +1 -1
  386. package/dist/db/client.js +24 -3
  387. package/dist/db/client.js.map +1 -1
  388. package/dist/deploy/build.d.ts.map +1 -1
  389. package/dist/deploy/build.js +25 -3
  390. package/dist/deploy/build.js.map +1 -1
  391. package/dist/eject/remote-mcp-presets.js +1 -1
  392. package/dist/eject/remote-mcp-presets.js.map +1 -1
  393. package/dist/index.browser.d.ts +1 -1
  394. package/dist/index.browser.d.ts.map +1 -1
  395. package/dist/index.browser.js +1 -1
  396. package/dist/index.browser.js.map +1 -1
  397. package/dist/index.d.ts +1 -1
  398. package/dist/index.d.ts.map +1 -1
  399. package/dist/index.js +1 -1
  400. package/dist/index.js.map +1 -1
  401. package/dist/integrations/google-docs-poller.d.ts.map +1 -1
  402. package/dist/integrations/google-docs-poller.js +4 -1
  403. package/dist/integrations/google-docs-poller.js.map +1 -1
  404. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  405. package/dist/integrations/webhook-handler.js +23 -11
  406. package/dist/integrations/webhook-handler.js.map +1 -1
  407. package/dist/jobs/scheduler.js +4 -0
  408. package/dist/jobs/scheduler.js.map +1 -1
  409. package/dist/localization/default-messages.d.ts +3 -2
  410. package/dist/localization/default-messages.d.ts.map +1 -1
  411. package/dist/localization/default-messages.js +3 -2
  412. package/dist/localization/default-messages.js.map +1 -1
  413. package/dist/mcp/build-server.d.ts.map +1 -1
  414. package/dist/mcp/build-server.js +10 -1
  415. package/dist/mcp/build-server.js.map +1 -1
  416. package/dist/notifications/routes.d.ts +1 -1
  417. package/dist/observability/traces.d.ts.map +1 -1
  418. package/dist/observability/traces.js +27 -7
  419. package/dist/observability/traces.js.map +1 -1
  420. package/dist/org/handlers.d.ts +15 -0
  421. package/dist/org/handlers.d.ts.map +1 -1
  422. package/dist/org/handlers.js +45 -1
  423. package/dist/org/handlers.js.map +1 -1
  424. package/dist/org/migrations.d.ts.map +1 -1
  425. package/dist/org/migrations.js +4 -0
  426. package/dist/org/migrations.js.map +1 -1
  427. package/dist/org/plugin.d.ts +1 -0
  428. package/dist/org/plugin.d.ts.map +1 -1
  429. package/dist/org/plugin.js +10 -1
  430. package/dist/org/plugin.js.map +1 -1
  431. package/dist/org/schema.d.ts +19 -0
  432. package/dist/org/schema.d.ts.map +1 -1
  433. package/dist/org/schema.js +1 -0
  434. package/dist/org/schema.js.map +1 -1
  435. package/dist/org/types.d.ts +8 -0
  436. package/dist/org/types.d.ts.map +1 -1
  437. package/dist/org/types.js.map +1 -1
  438. package/dist/org/workspace-url.d.ts +32 -0
  439. package/dist/org/workspace-url.d.ts.map +1 -0
  440. package/dist/org/workspace-url.js +63 -0
  441. package/dist/org/workspace-url.js.map +1 -0
  442. package/dist/progress/routes.d.ts +1 -1
  443. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  444. package/dist/provider-api/actions/provider-api.d.ts +7 -7
  445. package/dist/resources/handlers.d.ts +2 -3
  446. package/dist/resources/handlers.d.ts.map +1 -1
  447. package/dist/resources/handlers.js +25 -5
  448. package/dist/resources/handlers.js.map +1 -1
  449. package/dist/scripts/runner.d.ts +17 -0
  450. package/dist/scripts/runner.d.ts.map +1 -1
  451. package/dist/scripts/runner.js +130 -5
  452. package/dist/scripts/runner.js.map +1 -1
  453. package/dist/secrets/routes.d.ts +9 -9
  454. package/dist/server/action-routes.d.ts.map +1 -1
  455. package/dist/server/action-routes.js +24 -2
  456. package/dist/server/action-routes.js.map +1 -1
  457. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  458. package/dist/server/agent-chat-plugin.js +26 -1
  459. package/dist/server/agent-chat-plugin.js.map +1 -1
  460. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  461. package/dist/server/agent-teams.d.ts.map +1 -1
  462. package/dist/server/agent-teams.js +10 -1
  463. package/dist/server/agent-teams.js.map +1 -1
  464. package/dist/server/auth.d.ts +22 -0
  465. package/dist/server/auth.d.ts.map +1 -1
  466. package/dist/server/auth.js +33 -7
  467. package/dist/server/auth.js.map +1 -1
  468. package/dist/server/embed-route.d.ts.map +1 -1
  469. package/dist/server/embed-route.js +6 -1
  470. package/dist/server/embed-route.js.map +1 -1
  471. package/dist/server/embed-session.d.ts +7 -0
  472. package/dist/server/embed-session.d.ts.map +1 -1
  473. package/dist/server/embed-session.js +46 -4
  474. package/dist/server/embed-session.js.map +1 -1
  475. package/dist/server/open-route.d.ts.map +1 -1
  476. package/dist/server/open-route.js +17 -7
  477. package/dist/server/open-route.js.map +1 -1
  478. package/dist/server/prompts/framework-core-compact.js +1 -1
  479. package/dist/server/prompts/framework-core-compact.js.map +1 -1
  480. package/dist/server/prompts/framework-core.d.ts.map +1 -1
  481. package/dist/server/prompts/framework-core.js +1 -0
  482. package/dist/server/prompts/framework-core.js.map +1 -1
  483. package/dist/server/request-context.d.ts +26 -0
  484. package/dist/server/request-context.d.ts.map +1 -1
  485. package/dist/server/request-context.js +18 -1
  486. package/dist/server/request-context.js.map +1 -1
  487. package/dist/shared/embed-auth.d.ts +1 -0
  488. package/dist/shared/embed-auth.d.ts.map +1 -1
  489. package/dist/shared/embed-auth.js +1 -0
  490. package/dist/shared/embed-auth.js.map +1 -1
  491. package/dist/shared/html-document.d.ts +12 -0
  492. package/dist/shared/html-document.d.ts.map +1 -0
  493. package/dist/shared/html-document.js +92 -0
  494. package/dist/shared/html-document.js.map +1 -0
  495. package/dist/shared/index.d.ts +1 -0
  496. package/dist/shared/index.d.ts.map +1 -1
  497. package/dist/shared/index.js +1 -0
  498. package/dist/shared/index.js.map +1 -1
  499. package/dist/sharing/access.d.ts +1 -0
  500. package/dist/sharing/access.d.ts.map +1 -1
  501. package/dist/sharing/access.js +8 -2
  502. package/dist/sharing/access.js.map +1 -1
  503. package/dist/sharing/registry.d.ts +3 -0
  504. package/dist/sharing/registry.d.ts.map +1 -1
  505. package/dist/sharing/registry.js.map +1 -1
  506. package/dist/workspace-files/actions.d.ts +28 -0
  507. package/dist/workspace-files/actions.d.ts.map +1 -0
  508. package/dist/workspace-files/actions.js +75 -0
  509. package/dist/workspace-files/actions.js.map +1 -0
  510. package/dist/workspace-files/tool.d.ts.map +1 -1
  511. package/dist/workspace-files/tool.js +4 -0
  512. package/dist/workspace-files/tool.js.map +1 -1
  513. package/docs/content/cloneable-saas.mdx +114 -0
  514. package/docs/content/creating-templates.mdx +28 -2
  515. package/docs/content/syncing-template-changes.mdx +7 -0
  516. package/docs/content/template-clips-developers.mdx +12 -5
  517. package/docs/content/template-dispatch-developers.mdx +1 -1
  518. package/docs/content/template-dispatch.mdx +1 -1
  519. package/package.json +2 -2
  520. package/src/action-ui.ts +1 -0
  521. package/src/action.ts +5 -1
  522. package/src/agent/engine/ai-sdk-engine.ts +15 -5
  523. package/src/agent/harness/runner.ts +5 -0
  524. package/src/agent/production-agent.ts +33 -0
  525. package/src/agent/run-loop-with-resume.ts +5 -0
  526. package/src/agent/run-manager.ts +126 -1
  527. package/src/agent/thread-data-builder.ts +47 -2
  528. package/src/agent/types.ts +2 -0
  529. package/src/chat-threads/store.ts +4 -5
  530. package/src/cli/create.ts +1139 -65
  531. package/src/cli/design-connect.ts +3 -7
  532. package/src/cli/index.ts +5 -3
  533. package/src/cli/skills-content/design-visual-edit-skill.ts +83 -47
  534. package/src/client/AssistantChat.tsx +27 -16
  535. package/src/client/agent-chat-adapter.ts +24 -0
  536. package/src/client/blocks/library/wireframe-kit.tsx +17 -2
  537. package/src/client/chat/index.ts +1 -0
  538. package/src/client/chat/message-components.tsx +104 -1
  539. package/src/client/chat/run-recovery.tsx +15 -3
  540. package/src/client/chat/widgets/DataTableWidget.tsx +10 -29
  541. package/src/client/chat/widgets/WorkspaceFileWidget.tsx +71 -0
  542. package/src/client/chat/widgets/builtin-tool-renderers.tsx +22 -0
  543. package/src/client/chat/widgets/workspace-file-result.ts +49 -0
  544. package/src/client/embed-auth.ts +2 -0
  545. package/src/client/org/InvitationBanner.tsx +14 -1
  546. package/src/client/org/OrgSwitcher.tsx +23 -0
  547. package/src/client/org/TeamPage.tsx +130 -0
  548. package/src/client/org/WorkspaceNotice.tsx +85 -0
  549. package/src/client/org/hooks.ts +14 -0
  550. package/src/client/org/index.ts +2 -0
  551. package/src/client/resources/McpIntegrationDialog.tsx +27 -40
  552. package/src/client/resources/ResourcesPanel.tsx +134 -51
  553. package/src/client/resources/mcp-integration-catalog.ts +7 -0
  554. package/src/client/resources/use-resources.ts +6 -0
  555. package/src/client/use-action.ts +3 -1
  556. package/src/client/widgets/index.ts +1 -0
  557. package/src/coding-tools/run-code.ts +2 -1
  558. package/src/db/client.ts +28 -4
  559. package/src/deploy/build.ts +31 -3
  560. package/src/eject/remote-mcp-presets.ts +1 -1
  561. package/src/index.browser.ts +1 -0
  562. package/src/index.ts +1 -0
  563. package/src/integrations/google-docs-poller.ts +3 -0
  564. package/src/integrations/webhook-handler.ts +28 -11
  565. package/src/jobs/scheduler.ts +4 -0
  566. package/src/localization/default-messages.ts +3 -2
  567. package/src/mcp/build-server.ts +20 -2
  568. package/src/observability/traces.ts +48 -12
  569. package/src/org/handlers.ts +52 -1
  570. package/src/org/migrations.ts +4 -0
  571. package/src/org/plugin.ts +14 -0
  572. package/src/org/schema.ts +1 -0
  573. package/src/org/types.ts +8 -0
  574. package/src/org/workspace-url.ts +74 -0
  575. package/src/resources/handlers.ts +35 -5
  576. package/src/scripts/runner.ts +183 -5
  577. package/src/server/__snapshots__/agent-chat-plugin.surface.spec.ts.snap +2 -1
  578. package/src/server/action-routes.ts +32 -2
  579. package/src/server/agent-chat-plugin.ts +29 -0
  580. package/src/server/agent-teams.ts +10 -1
  581. package/src/server/auth.ts +33 -7
  582. package/src/server/embed-route.ts +9 -0
  583. package/src/server/embed-session.ts +62 -3
  584. package/src/server/open-route.ts +20 -6
  585. package/src/server/prompts/framework-core-compact.ts +1 -1
  586. package/src/server/prompts/framework-core.ts +1 -0
  587. package/src/server/request-context.ts +36 -1
  588. package/src/shared/embed-auth.ts +1 -0
  589. package/src/shared/html-document.ts +115 -0
  590. package/src/shared/index.ts +1 -0
  591. package/src/sharing/access.ts +8 -1
  592. package/src/sharing/registry.ts +11 -2
  593. package/src/workspace-files/actions.ts +100 -0
  594. package/src/workspace-files/tool.ts +4 -0
  595. package/corpus/templates/design/changelog/2026-07-28-interact-mode-can-preview-designs-in-responsive-device-sizes.md +0 -6
  596. package/corpus/templates/design/changelog/2026-07-28-interact-mode-now-opens-a-full-screen-responsive-preview-wit.md +0 -6
@@ -15,6 +15,7 @@ import {
15
15
  utilityStem,
16
16
  } from "@shared/responsive-classes";
17
17
  import {
18
+ type ElementProvenanceUnavailableReason,
18
19
  normalizeDesignSourceType,
19
20
  type DesignSourceType,
20
21
  } from "@shared/source-mode";
@@ -23,6 +24,7 @@ import type { ElementInfo } from "@/components/design/types";
23
24
 
24
25
  import {
25
26
  buildReactSemanticHandoff,
27
+ buildRuntimeReactLayerStateHandoff,
26
28
  redactReactSourceAnchor,
27
29
  type ReactSourceAnchor,
28
30
  type ReactSourceScope,
@@ -35,6 +37,19 @@ export interface PendingVisualStyleEdit {
35
37
  screenName: string;
36
38
  selector: string;
37
39
  sourceId?: string | null;
40
+ /**
41
+ * The selector/node id the canvas bridge reported, kept when the host
42
+ * canonicalized the selection onto its source projection
43
+ * (canonicalElementInfoForCodeLayerNode). A localhost screen runs two
44
+ * disjoint node-id namespaces: the injected bridge stamps `runtime-…` ids on
45
+ * the live document, while the host stamps `an-…` ids on the source html it
46
+ * fetched separately. Only this pair addresses the running app, so every
47
+ * replay into the live frame must prefer it. Absent for inline/snapshot
48
+ * screens, where the bridge reuses the ids already in the document and the
49
+ * two pairs are the same value.
50
+ */
51
+ runtimeSelector?: string | null;
52
+ runtimeSourceId?: string | null;
38
53
  sourceAnchor?: ReactSourceAnchor;
39
54
  tagName?: string | null;
40
55
  classes: string[];
@@ -72,7 +87,7 @@ export interface PendingVisualStyleEdit {
72
87
  };
73
88
  }
74
89
 
75
- function pendingLiveTextEditKey(edit: PendingLiveTextEdit): string {
90
+ function pendingLiveEditSubjectKey(edit: PendingLiveNonStyleEdit): string {
76
91
  return `${edit.screenId}:${edit.sourceId?.trim() || edit.selector.trim()}`;
77
92
  }
78
93
 
@@ -82,14 +97,56 @@ export function mergePendingLiveNonStyleEdits(
82
97
  const merged: PendingLiveNonStyleEdit[] = [];
83
98
  for (const edit of edits) {
84
99
  if (edit.kind === "structure") {
100
+ // Deleting a node this session INSERTED nets to zero in source: the
101
+ // markup was never written there. Queuing both would hand the coding
102
+ // agent markup to add plus a node to delete, and an apply that runs the
103
+ // insert can resurrect exactly what the user deleted. Both entries stay
104
+ // on the undo stack, so undoing the delete re-queues the insertion.
105
+ const supersededInsertIndex = edit.removed
106
+ ? merged.findIndex(
107
+ (candidate) =>
108
+ candidate.kind === "structure" &&
109
+ Boolean(candidate.insertedHtml) &&
110
+ pendingLiveEditSubjectKey(candidate) ===
111
+ pendingLiveEditSubjectKey(edit),
112
+ )
113
+ : -1;
114
+ if (supersededInsertIndex !== -1) {
115
+ merged.splice(supersededInsertIndex, 1);
116
+ continue;
117
+ }
85
118
  merged.push(edit);
86
119
  continue;
87
120
  }
88
- const nextKey = pendingLiveTextEditKey(edit);
121
+ if (edit.kind === "layer-state") {
122
+ const nextKey = `${pendingLiveEditSubjectKey(edit)}:${edit.state}`;
123
+ const index = merged.findIndex(
124
+ (candidate) =>
125
+ candidate.kind === "layer-state" &&
126
+ `${pendingLiveEditSubjectKey(candidate)}:${candidate.state}` ===
127
+ nextKey,
128
+ );
129
+ if (index === -1) {
130
+ merged.push(edit);
131
+ continue;
132
+ }
133
+ const previous = merged[index] as PendingLiveLayerStateEdit;
134
+ if (previous.originalEnabled === edit.enabled) {
135
+ merged.splice(index, 1);
136
+ continue;
137
+ }
138
+ merged[index] = {
139
+ ...previous,
140
+ ...edit,
141
+ originalEnabled: previous.originalEnabled,
142
+ };
143
+ continue;
144
+ }
145
+ const nextKey = pendingLiveEditSubjectKey(edit);
89
146
  const index = merged.findIndex(
90
147
  (candidate) =>
91
148
  candidate.kind === "text" &&
92
- pendingLiveTextEditKey(candidate) === nextKey,
149
+ pendingLiveEditSubjectKey(candidate) === nextKey,
93
150
  );
94
151
  if (index === -1) {
95
152
  merged.push(edit);
@@ -113,7 +170,7 @@ export function pendingLiveTextUndoRevertValue(
113
170
  const currentForTarget = currentEdits.find(
114
171
  (edit): edit is PendingLiveTextEdit =>
115
172
  edit.kind === "text" &&
116
- pendingLiveTextEditKey(edit) === pendingLiveTextEditKey(nextEdit),
173
+ pendingLiveEditSubjectKey(edit) === pendingLiveEditSubjectKey(nextEdit),
117
174
  );
118
175
  return currentForTarget
119
176
  ? { value: currentForTarget.value, html: currentForTarget.html }
@@ -137,6 +194,46 @@ export interface PendingLiveTextEdit {
137
194
  updatedAt: number;
138
195
  }
139
196
 
197
+ export interface PendingLiveLayerStateEdit {
198
+ kind: "layer-state";
199
+ screenId: string;
200
+ filename: string;
201
+ screenName: string;
202
+ layerId: string;
203
+ selector: string;
204
+ sourceId?: string | null;
205
+ sourceAnchor?: ReactSourceAnchor;
206
+ tagName?: string | null;
207
+ classes: string[];
208
+ state: "hidden" | "locked";
209
+ enabled: boolean;
210
+ originalEnabled: boolean;
211
+ updatedAt: number;
212
+ }
213
+
214
+ export function pendingLiveLayerStateUndoRevertValue(
215
+ currentEdits: readonly PendingLiveNonStyleEdit[],
216
+ nextEdit: PendingLiveLayerStateEdit,
217
+ ): boolean {
218
+ const currentForTarget = currentEdits.find(
219
+ (edit): edit is PendingLiveLayerStateEdit =>
220
+ edit.kind === "layer-state" &&
221
+ edit.state === nextEdit.state &&
222
+ pendingLiveEditSubjectKey(edit) === pendingLiveEditSubjectKey(nextEdit),
223
+ );
224
+ return currentForTarget?.enabled ?? nextEdit.originalEnabled;
225
+ }
226
+
227
+ export function shouldRedoPendingLiveNonStyleBeforeStyle(
228
+ styleEntry: { edit: { updatedAt: number } } | undefined,
229
+ nonStyleEntry: { edit: { updatedAt: number } } | undefined,
230
+ ): boolean {
231
+ return Boolean(
232
+ nonStyleEntry &&
233
+ (!styleEntry || nonStyleEntry.edit.updatedAt < styleEntry.edit.updatedAt),
234
+ );
235
+ }
236
+
140
237
  export interface PendingLiveStructureEdit {
141
238
  kind: "structure";
142
239
  screenId: string;
@@ -148,6 +245,13 @@ export interface PendingLiveStructureEdit {
148
245
  anchorSelector: string;
149
246
  anchorSourceId?: string | null;
150
247
  anchorSourceAnchor?: ReactSourceAnchor;
248
+ /**
249
+ * Project-relative route module reported by the localhost manifest. A
250
+ * top-level canvas insert targets the live document body, which intentionally
251
+ * has no framework element provenance; this keeps Apply bounded to the route
252
+ * source without inventing a fake body line/column.
253
+ */
254
+ routeSourceFile?: string;
151
255
  placement: "before" | "after" | "inside";
152
256
  /** Runtime layout semantics captured at drop time. These are required for
153
257
  * the coding agent to distinguish a flow/auto-layout insertion from an
@@ -156,6 +260,20 @@ export interface PendingLiveStructureEdit {
156
260
  forceFlowPositionOverride?: boolean;
157
261
  sourceRect?: { x: number; y: number; width: number; height: number };
158
262
  anchorRect?: { x: number; y: number; width: number; height: number };
263
+ /**
264
+ * Markup this edit ADDED to the running app. Present only for a drop whose
265
+ * subject had no counterpart in the screen's source, so the coding agent
266
+ * must insert this markup rather than relocate an existing element.
267
+ */
268
+ insertedHtml?: string;
269
+ /**
270
+ * This edit DELETED the subject from the running app. A removal has no
271
+ * anchor — `anchorSelector`/`placement` carry no meaning for it — so every
272
+ * consumer that pairs a subject with a target (the semantic handoff, the
273
+ * source-path collection before apply, runtime verification) must branch on
274
+ * this instead of reading anchor fields that were never captured.
275
+ */
276
+ removed?: true;
159
277
  requestId?: string;
160
278
  updatedAt: number;
161
279
  }
@@ -258,6 +376,18 @@ function sourcePathRelativeToRoot(args: {
258
376
  return normalizeResolvablePath(relative)?.value;
259
377
  }
260
378
 
379
+ export function projectRelativeSourcePath(args: {
380
+ sourceFile?: string;
381
+ rootPath?: string;
382
+ }): string | undefined {
383
+ const sourceFile = args.sourceFile?.trim();
384
+ if (!sourceFile) return undefined;
385
+ return sourcePathRelativeToRoot({
386
+ sourceFile,
387
+ rootPath: args.rootPath,
388
+ });
389
+ }
390
+
261
391
  export function reactSourceAnchorForPendingEdit(args: {
262
392
  info?: Pick<ElementInfo, "provenance" | "sourceId" | "selector"> | null;
263
393
  id?: string;
@@ -278,6 +408,13 @@ export function reactSourceAnchorForPendingEdit(args: {
278
408
  sourceFile,
279
409
  rootPath: args.rootPath,
280
410
  });
411
+ const ownerSourceFile = provenance.ownerSourceFile?.trim();
412
+ const ownerRelPath = ownerSourceFile
413
+ ? sourcePathRelativeToRoot({
414
+ sourceFile: ownerSourceFile,
415
+ rootPath: args.rootPath,
416
+ })
417
+ : undefined;
281
418
  return {
282
419
  id:
283
420
  args.id?.trim() ||
@@ -291,7 +428,26 @@ export function reactSourceAnchorForPendingEdit(args: {
291
428
  ...(relPath ? { relPath } : {}),
292
429
  line: provenance.line,
293
430
  column: provenance.column,
431
+ // Which tier produced line/column, so no consumer can read a React 19
432
+ // owner-stack (transformed) position as the authored JSX line.
433
+ ...(provenance.method ? { method: provenance.method } : {}),
294
434
  component: provenance.component,
435
+ // The nearest component's INSTANTIATION site — the `.map()` call site for a
436
+ // mapped instance. Dropping it here is what left the handoff unable to say
437
+ // where a mapped sibling actually comes from.
438
+ ...(ownerSourceFile ? { ownerSourceFile } : {}),
439
+ ...(ownerRelPath ? { ownerRelPath } : {}),
440
+ ...(provenance.ownerLine ? { ownerLine: provenance.ownerLine } : {}),
441
+ ...(provenance.ownerColumn ? { ownerColumn: provenance.ownerColumn } : {}),
442
+ ...(provenance.ownerComponentName
443
+ ? { ownerComponent: provenance.ownerComponentName }
444
+ : {}),
445
+ // The owner's own tier: a data-attribute element can still owe its owner
446
+ // line to a transformed owner stack.
447
+ ...(provenance.ownerMethod ? { ownerMethod: provenance.ownerMethod } : {}),
448
+ // Every `.map()` sibling shares one call site, so runtimeMultiplicity alone
449
+ // cannot say WHICH instance was selected; the React key can.
450
+ ...(provenance.ownerKey ? { ownerKey: provenance.ownerKey } : {}),
295
451
  runtimeMultiplicity,
296
452
  ...(args.reason?.trim() ? { reason: args.reason.trim() } : {}),
297
453
  scope:
@@ -299,8 +455,26 @@ export function reactSourceAnchorForPendingEdit(args: {
299
455
  };
300
456
  }
301
457
 
458
+ /**
459
+ * Why an anchor could not be built: a runtime that reports it exposes no
460
+ * source locations at all is a permanent answer, not a slow one. Returns
461
+ * undefined when nothing has reported a reason yet — that case is still
462
+ * "loading", and callers must not present it as unsupported.
463
+ */
464
+ export function reactSourceAnchorUnavailableReason(
465
+ infos: ReadonlyArray<Pick<ElementInfo, "provenance"> | null | undefined>,
466
+ ): ElementProvenanceUnavailableReason | undefined {
467
+ for (const info of infos) {
468
+ const provenance = info?.provenance;
469
+ if (provenance?.sourceFile) continue;
470
+ if (provenance?.unavailableReason) return provenance.unavailableReason;
471
+ }
472
+ return undefined;
473
+ }
474
+
302
475
  export type PendingLiveNonStyleEdit =
303
476
  | PendingLiveTextEdit
477
+ | PendingLiveLayerStateEdit
304
478
  | PendingLiveStructureEdit;
305
479
  export type PendingVisualStyleUndoEntry = {
306
480
  edit: PendingVisualStyleEdit;
@@ -316,10 +490,59 @@ export type PendingLiveStructureUndoEntry = {
316
490
  kind: "structure";
317
491
  edit: PendingLiveStructureEdit;
318
492
  };
493
+ export type PendingLiveLayerStateUndoEntry = {
494
+ kind: "layer-state";
495
+ edit: PendingLiveLayerStateEdit;
496
+ revertEnabled: boolean;
497
+ };
319
498
  export type PendingLiveNonStyleUndoEntry =
320
499
  | PendingLiveTextUndoEntry
500
+ | PendingLiveLayerStateUndoEntry
321
501
  | PendingLiveStructureUndoEntry;
322
502
 
503
+ /**
504
+ * Project-relative source files that must be read before this edit can be
505
+ * handed off. A removal has no anchor, and an INSERT has no subject — its
506
+ * markup exists in no source file yet — so demanding both paths rejected every
507
+ * insert as "anchors still loading". `null` means a path this edit does need
508
+ * has not resolved yet, which is the only honest "not ready" answer.
509
+ */
510
+ export function pendingStructureEditSourcePaths(
511
+ edit: PendingLiveStructureEdit,
512
+ ): string[] | null {
513
+ const required = [
514
+ ...(edit.insertedHtml ? [] : [edit.sourceAnchor?.relPath]),
515
+ ...(edit.removed
516
+ ? []
517
+ : [
518
+ edit.anchorSourceAnchor?.relPath ??
519
+ (edit.insertedHtml ? edit.routeSourceFile : undefined),
520
+ ]),
521
+ ];
522
+ if (required.some((path) => !path)) return null;
523
+ return required as string[];
524
+ }
525
+
526
+ export type PendingStructureRedoCommand =
527
+ | { kind: "delete" }
528
+ | { kind: "insert"; html: string }
529
+ | { kind: "move" };
530
+
531
+ /**
532
+ * Which runtime command replays this edit. Undoing an insert REMOVED the node,
533
+ * so replaying it as a move would address an element that is no longer in the
534
+ * document and the bridge would return silently — a redo that reports success
535
+ * and does nothing.
536
+ */
537
+ export function pendingStructureRedoCommand(
538
+ edit: PendingLiveStructureEdit,
539
+ ): PendingStructureRedoCommand {
540
+ if (edit.removed) return { kind: "delete" };
541
+ return edit.insertedHtml
542
+ ? { kind: "insert", html: edit.insertedHtml }
543
+ : { kind: "move" };
544
+ }
545
+
323
546
  export function pendingLiveStructureEditsMatch(
324
547
  left: PendingLiveStructureEdit,
325
548
  right: PendingLiveStructureEdit,
@@ -331,6 +554,7 @@ export function pendingLiveStructureEditsMatch(
331
554
  left.anchorSelector === right.anchorSelector &&
332
555
  (left.anchorSourceId ?? "") === (right.anchorSourceId ?? "") &&
333
556
  left.placement === right.placement &&
557
+ Boolean(left.removed) === Boolean(right.removed) &&
334
558
  left.dropMode === right.dropMode &&
335
559
  Boolean(left.forceFlowPositionOverride) ===
336
560
  Boolean(right.forceFlowPositionOverride)
@@ -427,20 +651,27 @@ export function originalStylesForPendingVisualEdit(
427
651
  );
428
652
  }
429
653
 
654
+ export type PendingVisualStyleRevertPatch = PendingVisualStyleRuntimePatch & {
655
+ interactionState?: InteractionState;
656
+ };
657
+
430
658
  export function buildPendingVisualStyleRevertPatches(
431
659
  edits: readonly PendingVisualStyleEdit[],
432
- ): Array<{
433
- screenId: string;
434
- selector: string;
435
- sourceId?: string | null;
436
- styles: Record<string, string>;
437
- interactionState?: InteractionState;
438
- }> {
660
+ ): PendingVisualStyleRevertPatch[] {
439
661
  return edits
440
662
  .map((edit) => ({
441
663
  screenId: edit.screenId,
442
664
  selector: edit.selector,
443
665
  sourceId: edit.sourceId,
666
+ // Carried, not resolved: consumers replay into the live frame (prefer the
667
+ // runtime pair) and into the source projection (prefer the canonical
668
+ // one), so the patch has to keep both.
669
+ ...(edit.runtimeSelector
670
+ ? { runtimeSelector: edit.runtimeSelector }
671
+ : {}),
672
+ ...(edit.runtimeSourceId
673
+ ? { runtimeSourceId: edit.runtimeSourceId }
674
+ : {}),
444
675
  styles: edit.originalStyles,
445
676
  ...(edit.interactionState
446
677
  ? { interactionState: edit.interactionState }
@@ -449,13 +680,101 @@ export function buildPendingVisualStyleRevertPatches(
449
680
  .filter((patch) => Object.keys(patch.styles).length > 0);
450
681
  }
451
682
 
452
- export function getPendingVisualStylePropertyCount(
683
+ export type PendingVisualStyleRuntimePatch = {
684
+ screenId: string;
685
+ selector: string;
686
+ sourceId?: string | null;
687
+ runtimeSelector?: string | null;
688
+ runtimeSourceId?: string | null;
689
+ styles: Record<string, string>;
690
+ };
691
+
692
+ function nodeIdSelector(nodeId: string): string {
693
+ return `[data-agent-native-node-id="${nodeId
694
+ .replace(/\\/g, "\\\\")
695
+ .replace(/"/g, '\\"')}"]`;
696
+ }
697
+
698
+ /**
699
+ * How a pending edit addresses the RUNNING document. The runtime pair wins
700
+ * because a localhost screen's canonical selector/sourceId name nodes in the
701
+ * host's source projection, which the live frame has never seen. Candidates
702
+ * stay a runtime-first superset so nothing that used to resolve stops
703
+ * resolving, and an inline screen — which records no runtime pair — produces
704
+ * byte-identical output to the canonical-only list.
705
+ */
706
+ export function runtimeStyleTarget(target: {
707
+ selector: string;
708
+ sourceId?: string | null;
709
+ runtimeSelector?: string | null;
710
+ runtimeSourceId?: string | null;
711
+ }): { selector: string; nodeId: string | null; selectorCandidates: string[] } {
712
+ const selector = target.runtimeSelector?.trim() || target.selector;
713
+ const nodeId = target.runtimeSourceId?.trim() || target.sourceId || null;
714
+ return {
715
+ selector,
716
+ nodeId,
717
+ selectorCandidates: [
718
+ ...new Set(
719
+ [
720
+ selector,
721
+ target.selector,
722
+ nodeId ? nodeIdSelector(nodeId) : "",
723
+ target.sourceId ? nodeIdSelector(target.sourceId) : "",
724
+ ].filter(Boolean),
725
+ ),
726
+ ],
727
+ };
728
+ }
729
+
730
+ export type SendPendingVisualStyleRuntimeProperty = (
731
+ screenId: string,
732
+ selector: string,
733
+ property: string,
734
+ value: string,
735
+ options: {
736
+ selectorCandidates: string[];
737
+ nodeId?: string | null;
738
+ },
739
+ ) => boolean;
740
+
741
+ /**
742
+ * Forward, undo, and redo all use this exact per-property runtime channel.
743
+ * The screen id is part of the command boundary so a retained/remounted
744
+ * overview iframe cannot accidentally receive history intended for another
745
+ * screen.
746
+ */
747
+ export function replayPendingVisualStyleRuntimePatch(
748
+ patch: PendingVisualStyleRuntimePatch,
749
+ sendProperty: SendPendingVisualStyleRuntimeProperty,
750
+ ): boolean {
751
+ const entries = Object.entries(patch.styles);
752
+ if (entries.length === 0) return false;
753
+ const target = runtimeStyleTarget(patch);
754
+ // No candidate at all is not "apply it to the obvious element": the bridge
755
+ // falls back to its own current selection when the candidate list is empty,
756
+ // so an unaddressable revert would silently restyle whatever happens to be
757
+ // selected. Report failure and let the caller surface it.
758
+ if (target.selectorCandidates.length === 0) return false;
759
+ return entries.every(([property, value]) =>
760
+ sendProperty(patch.screenId, target.selector, property, value, {
761
+ selectorCandidates: target.selectorCandidates,
762
+ nodeId: target.nodeId,
763
+ }),
764
+ );
765
+ }
766
+
767
+ /**
768
+ * Badge number on the Apply bar: how many user-meaningful updates Apply would
769
+ * hand to the agent. A style edit is already coalesced by screen, target, and
770
+ * interaction state, so counting its individual CSS declarations inflates one
771
+ * inspector gesture into several apparent updates.
772
+ */
773
+ export function getPendingVisualEditCount(
453
774
  edits: readonly PendingVisualStyleEdit[],
775
+ liveEdits: readonly PendingLiveNonStyleEdit[] = [],
454
776
  ): number {
455
- return edits.reduce(
456
- (count, edit) => count + Object.keys(edit.styles).length,
457
- 0,
458
- );
777
+ return edits.length + liveEdits.length;
459
778
  }
460
779
 
461
780
  export function shouldBlockPendingVisualStyleNavigation(args: {
@@ -469,6 +788,22 @@ export function shouldBlockPendingVisualStyleNavigation(args: {
469
788
  );
470
789
  }
471
790
 
791
+ /**
792
+ * Inserted markup is the only unbounded field in the pending-edit payload, and
793
+ * that payload is JSON.stringified straight into an agent prompt. Truncation is
794
+ * reported so the agent never mistakes a cut-off tree for the whole node.
795
+ */
796
+ const MAX_INSERTED_HTML_LENGTH = 4_000;
797
+
798
+ function boundedInsertedHtml(html: string): {
799
+ value: string;
800
+ truncated: boolean;
801
+ } {
802
+ return html.length > MAX_INSERTED_HTML_LENGTH
803
+ ? { value: html.slice(0, MAX_INSERTED_HTML_LENGTH), truncated: true }
804
+ : { value: html, truncated: false };
805
+ }
806
+
472
807
  export function formatPendingVisualStylePrompt(args: {
473
808
  designId?: string | null;
474
809
  designTitle?: string | null;
@@ -528,34 +863,59 @@ export function formatPendingVisualStylePrompt(args: {
528
863
  html: edit.html,
529
864
  };
530
865
  }
866
+ if (edit.kind === "layer-state") {
867
+ const semanticHandoff = edit.sourceAnchor
868
+ ? buildRuntimeReactLayerStateHandoff({
869
+ subjectAnchor: edit.sourceAnchor,
870
+ screenId: edit.screenId,
871
+ state: edit.state,
872
+ enabled: edit.enabled,
873
+ })
874
+ : null;
875
+ return {
876
+ kind: edit.kind,
877
+ screenId: edit.screenId,
878
+ filename: edit.filename,
879
+ screenName: edit.screenName,
880
+ selector: edit.selector,
881
+ sourceId: edit.sourceId ?? null,
882
+ sourceAnchor: redactReactSourceAnchor(edit.sourceAnchor),
883
+ tagName: edit.tagName ?? null,
884
+ classes: edit.classes,
885
+ state: edit.state,
886
+ enabled: edit.enabled,
887
+ attributeName: `data-agent-native-${edit.state}`,
888
+ ...(semanticHandoff?.ok
889
+ ? { semanticHandoff: semanticHandoff.handoff }
890
+ : {}),
891
+ };
892
+ }
531
893
  const subjectAnchor = edit.sourceAnchor
532
894
  ? { ...edit.sourceAnchor, id: "subject" }
533
895
  : undefined;
534
896
  const targetAnchor = edit.anchorSourceAnchor
535
897
  ? { ...edit.anchorSourceAnchor, id: "target" }
536
898
  : undefined;
537
- const semanticHandoff =
538
- subjectAnchor && targetAnchor
899
+ // An insert's subject is markup that does not exist in the program yet, so
900
+ // it has no source anchor and cannot be described as a move. Telling the
901
+ // agent to relocate an element the file has never contained is worse than
902
+ // reporting nothing.
903
+ const insertedHtml = edit.insertedHtml
904
+ ? boundedInsertedHtml(edit.insertedHtml)
905
+ : undefined;
906
+ const semanticHandoff = edit.removed
907
+ ? subjectAnchor
539
908
  ? buildReactSemanticHandoff({
540
- operation: edit.placement === "inside" ? "reparent" : "move",
541
- desiredChange: [
542
- `Move the selected runtime element ${edit.placement} the target runtime element.`,
543
- edit.dropMode === "flow-insert"
544
- ? `The drop is a flow/auto-layout insertion${edit.forceFlowPositionOverride ? "; remove authored absolute positioning so the moved element participates in the target container's layout" : "; preserve normal flow participation"}.`
545
- : edit.dropMode === "absolute-container"
546
- ? "The target is an absolute-positioning container; preserve absolute positioning and rebase the moved element's visual offset from sourceRect into the target anchorRect coordinate space."
547
- : "Preserve the runtime layout behavior observed in the preview.",
548
- ].join(" "),
549
- sourceAnchors: [subjectAnchor, targetAnchor],
909
+ operation: "remove",
910
+ desiredChange:
911
+ "Delete the selected runtime element from the source that renders it. The live preview already shows it gone; remove its markup (and anything that exists only to render it) without disturbing sibling layout or behavior.",
912
+ sourceAnchors: [subjectAnchor],
550
913
  runtimeRelationship: {
551
- kind: edit.placement,
914
+ kind: "remove",
552
915
  subjectAnchorIds: ["subject"],
553
- targetAnchorId: "target",
554
916
  screenId: edit.screenId,
555
- description: `${edit.selector} ${edit.placement} ${edit.anchorSelector}`,
917
+ description: `remove ${edit.selector}`,
556
918
  },
557
- // The packet intentionally starts without a hash: its execution
558
- // contract requires read-local-file before every write.
559
919
  versionHashes: [],
560
920
  })
561
921
  : {
@@ -563,9 +923,71 @@ export function formatPendingVisualStylePrompt(args: {
563
923
  rejection: {
564
924
  code: "missing-source-provenance" as const,
565
925
  reason:
566
- "Exact subject and target source anchors were not both available for this React structure edit.",
926
+ "The removed element's source anchor was not available for this runtime deletion.",
567
927
  },
568
- };
928
+ }
929
+ : insertedHtml
930
+ ? targetAnchor
931
+ ? buildReactSemanticHandoff({
932
+ operation: "insert",
933
+ desiredChange: [
934
+ `Add the new markup in insertedHtml ${edit.placement} the target runtime element.`,
935
+ insertedHtml.truncated
936
+ ? "The markup below was truncated for prompt size; read the running preview or ask before writing it verbatim."
937
+ : "The markup is already positioned for the drop point.",
938
+ edit.dropMode === "absolute-container"
939
+ ? "The target is an absolute-positioning container; keep the inline left/top offsets."
940
+ : "This is a flow/auto-layout insertion; the markup carries no absolute positioning.",
941
+ ].join(" "),
942
+ sourceAnchors: [targetAnchor],
943
+ runtimeRelationship: {
944
+ kind: edit.placement,
945
+ subjectAnchorIds: [],
946
+ targetAnchorId: "target",
947
+ screenId: edit.screenId,
948
+ description: `insert ${edit.selector} ${edit.placement} ${edit.anchorSelector}`,
949
+ },
950
+ versionHashes: [],
951
+ })
952
+ : {
953
+ ok: false as const,
954
+ rejection: {
955
+ code: "missing-source-provenance" as const,
956
+ reason:
957
+ "The insertion target's source anchor was not available for this runtime insert.",
958
+ },
959
+ }
960
+ : subjectAnchor && targetAnchor
961
+ ? buildReactSemanticHandoff({
962
+ operation: edit.placement === "inside" ? "reparent" : "move",
963
+ desiredChange: [
964
+ `Move the selected runtime element ${edit.placement} the target runtime element.`,
965
+ edit.dropMode === "flow-insert"
966
+ ? `The drop is a flow/auto-layout insertion${edit.forceFlowPositionOverride ? "; remove authored absolute positioning so the moved element participates in the target container's layout" : "; preserve normal flow participation"}.`
967
+ : edit.dropMode === "absolute-container"
968
+ ? "The target is an absolute-positioning container; preserve absolute positioning and rebase the moved element's visual offset from sourceRect into the target anchorRect coordinate space."
969
+ : "Preserve the runtime layout behavior observed in the preview.",
970
+ ].join(" "),
971
+ sourceAnchors: [subjectAnchor, targetAnchor],
972
+ runtimeRelationship: {
973
+ kind: edit.placement,
974
+ subjectAnchorIds: ["subject"],
975
+ targetAnchorId: "target",
976
+ screenId: edit.screenId,
977
+ description: `${edit.selector} ${edit.placement} ${edit.anchorSelector}`,
978
+ },
979
+ // The packet intentionally starts without a hash: its execution
980
+ // contract requires read-local-file before every write.
981
+ versionHashes: [],
982
+ })
983
+ : {
984
+ ok: false as const,
985
+ rejection: {
986
+ code: "missing-source-provenance" as const,
987
+ reason:
988
+ "Exact subject and target source anchors were not both available for this React structure edit.",
989
+ },
990
+ };
569
991
  return {
570
992
  kind: edit.kind,
571
993
  screenId: edit.screenId,
@@ -574,16 +996,33 @@ export function formatPendingVisualStylePrompt(args: {
574
996
  selector: edit.selector,
575
997
  sourceId: edit.sourceId ?? null,
576
998
  sourceAnchor: redactReactSourceAnchor(edit.sourceAnchor),
577
- anchorSelector: edit.anchorSelector,
578
- anchorSourceId: edit.anchorSourceId ?? null,
579
- anchorSourceAnchor: redactReactSourceAnchor(edit.anchorSourceAnchor),
580
- placement: edit.placement,
999
+ // A removal has no anchor; emitting empty anchor fields alongside a
1000
+ // meaningless placement reads as a half-captured move.
1001
+ ...(edit.removed
1002
+ ? { removed: true as const }
1003
+ : {
1004
+ anchorSelector: edit.anchorSelector,
1005
+ anchorSourceId: edit.anchorSourceId ?? null,
1006
+ anchorSourceAnchor: redactReactSourceAnchor(
1007
+ edit.anchorSourceAnchor,
1008
+ ),
1009
+ placement: edit.placement,
1010
+ }),
581
1011
  ...(edit.dropMode ? { dropMode: edit.dropMode } : {}),
1012
+ ...(edit.routeSourceFile
1013
+ ? { routeSourceFile: edit.routeSourceFile }
1014
+ : {}),
582
1015
  ...(edit.forceFlowPositionOverride
583
1016
  ? { forceFlowPositionOverride: true }
584
1017
  : {}),
585
1018
  ...(edit.sourceRect ? { sourceRect: edit.sourceRect } : {}),
586
1019
  ...(edit.anchorRect ? { anchorRect: edit.anchorRect } : {}),
1020
+ ...(insertedHtml
1021
+ ? {
1022
+ insertedHtml: insertedHtml.value,
1023
+ ...(insertedHtml.truncated ? { insertedHtmlTruncated: true } : {}),
1024
+ }
1025
+ : {}),
587
1026
  ...(semanticHandoff.ok
588
1027
  ? { semanticHandoff: semanticHandoff.handoff }
589
1028
  : { semanticHandoffFailure: semanticHandoff.rejection }),
@@ -600,7 +1039,7 @@ export function formatPendingVisualStylePrompt(args: {
600
1039
  ? `Active localhost connection id: "${args.localhostConnectionId}".`
601
1040
  : "",
602
1041
  "",
603
- "Use the Design source tools to make the source match the current live canvas preview. Read each target screen, resolve source ids/selectors through the code-layer projection, then apply the style, text, and structure changes with focused source edits. Preserve layout, behavior, and unrelated styling.",
1042
+ "Use the Design source tools to make the source match the current live canvas preview. Read each target screen, resolve source ids/selectors through the code-layer projection, then apply the style, text, layer-state, and structure changes with focused source edits. Preserve layout, behavior, and unrelated styling.",
604
1043
  hasReactSourceAnchors
605
1044
  ? "React sourceAnchor fields are source provenance; runtime source ids and selectors are correlation hints only. For a single-instance leaf text, literal className/class, or flat literal style-object edit, call apply-visual-edit with source.kind=local-file plus designId, connectionId, the verified project-relative path, and target.sourceAnchor. First omit persist and inspect proposedDiff; then retry with persist=true only when the diff matches the preview. That write still requires human localhost consent and exact version-hash concurrency. Verify every file, line, column, component, and surrounding control flow before editing. Never use a generic AST reparent, group, wrapper, breakpoint, dynamic expression, repeated render, or shared component transform through this path. For semantic structure edits, follow the embedded semanticHandoff packet and use this exact guarded sequence: read-local-file, capture its versionHash, obtain human write consent, write-local-file with expectedVersionHash and requireExpectedVersionHash: true, then keep the preview pending until HMR proves the intended runtime relationship. On a version conflict, re-read and re-plan; never overwrite blindly."
606
1045
  : "",
@@ -610,13 +1049,29 @@ export function formatPendingVisualStylePrompt(args: {
610
1049
  hasBreakpointScopedEdits
611
1050
  ? "Edits that carry a `breakpoint` field were made while a narrower breakpoint frame was active: apply them as width-scoped overrides (apply-visual-edit with `activeFrameWidthPx` set to breakpoint.activeWidthPx), NOT as base writes — base values must keep rendering at wider viewports. When breakpoint.editScope is `only`, confine the override to breakpoint.activeWidthPx through breakpoint.upperBoundPx; otherwise use the normal desktop-down cascade."
612
1051
  : "",
1052
+ (args.liveEdits ?? []).some(
1053
+ (edit) => edit.kind === "structure" && edit.removed,
1054
+ )
1055
+ ? "Structure edits carrying `removed: true` are DELETIONS, not moves: the element is already gone from the live preview and must be deleted from the source that renders it. Do not re-create it, and do not read its absent anchor as a half-captured move."
1056
+ : "",
1057
+ (args.liveEdits ?? []).some(
1058
+ (edit) =>
1059
+ edit.kind === "structure" &&
1060
+ Boolean(edit.insertedHtml) &&
1061
+ Boolean(edit.routeSourceFile) &&
1062
+ !edit.anchorSourceAnchor,
1063
+ )
1064
+ ? "A live insert with `routeSourceFile` but no `anchorSourceAnchor` was drawn directly on the screen frame, so its runtime target is the document body rather than a framework-owned element. Treat `routeSourceFile` as the bounded source target, inspect that route's root markup/component, and add `insertedHtml` as a top-level positioned child that matches the live preview. Do not fabricate a body source line or write outside that file unless the route delegates its root markup and you can verify the exact delegated source."
1065
+ : "",
613
1066
  args.edits.some((edit) => edit.interactionState)
614
1067
  ? "Edits that carry an `interactionState` field are pseudo-class overrides, not base styles. Apply each property only to that exact state (`hover`, `focus`, `focus-visible`, `active`, or `disabled`) while preserving the element's default styling and its other states."
615
1068
  : "",
616
1069
  "",
617
1070
  "Pending style edits:",
618
1071
  JSON.stringify(editPayload, null, 2),
619
- liveEditPayload.length > 0 ? "Pending text/structure edits:" : "",
1072
+ liveEditPayload.length > 0
1073
+ ? "Pending text/layer-state/structure edits:"
1074
+ : "",
620
1075
  liveEditPayload.length > 0 ? JSON.stringify(liveEditPayload, null, 2) : "",
621
1076
  ]
622
1077
  .filter((line) => line !== "")