@agent-native/core 0.92.6 → 0.92.8

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 (297) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +18 -0
  3. package/corpus/core/docs/content/a2a-protocol.mdx +12 -0
  4. package/corpus/core/docs/content/locales/ar-SA/a2a-protocol.mdx +12 -0
  5. package/corpus/core/docs/content/locales/ar-SA/pr-visual-recap.mdx +3 -3
  6. package/corpus/core/docs/content/locales/ar-SA/pure-agent-apps.mdx +4 -0
  7. package/corpus/core/docs/content/locales/de-DE/a2a-protocol.mdx +12 -0
  8. package/corpus/core/docs/content/locales/de-DE/pr-visual-recap.mdx +3 -3
  9. package/corpus/core/docs/content/locales/de-DE/pure-agent-apps.mdx +4 -0
  10. package/corpus/core/docs/content/locales/es-ES/a2a-protocol.mdx +12 -0
  11. package/corpus/core/docs/content/locales/es-ES/pr-visual-recap.mdx +3 -3
  12. package/corpus/core/docs/content/locales/es-ES/pure-agent-apps.mdx +4 -0
  13. package/corpus/core/docs/content/locales/fr-FR/a2a-protocol.mdx +12 -0
  14. package/corpus/core/docs/content/locales/fr-FR/pr-visual-recap.mdx +3 -3
  15. package/corpus/core/docs/content/locales/fr-FR/pure-agent-apps.mdx +4 -0
  16. package/corpus/core/docs/content/locales/hi-IN/a2a-protocol.mdx +12 -0
  17. package/corpus/core/docs/content/locales/hi-IN/pr-visual-recap.mdx +3 -3
  18. package/corpus/core/docs/content/locales/hi-IN/pure-agent-apps.mdx +4 -0
  19. package/corpus/core/docs/content/locales/ja-JP/a2a-protocol.mdx +12 -0
  20. package/corpus/core/docs/content/locales/ja-JP/pr-visual-recap.mdx +3 -3
  21. package/corpus/core/docs/content/locales/ja-JP/pure-agent-apps.mdx +4 -0
  22. package/corpus/core/docs/content/locales/ko-KR/a2a-protocol.mdx +12 -0
  23. package/corpus/core/docs/content/locales/ko-KR/pr-visual-recap.mdx +3 -3
  24. package/corpus/core/docs/content/locales/ko-KR/pure-agent-apps.mdx +4 -0
  25. package/corpus/core/docs/content/locales/pt-BR/a2a-protocol.mdx +12 -0
  26. package/corpus/core/docs/content/locales/pt-BR/pr-visual-recap.mdx +3 -3
  27. package/corpus/core/docs/content/locales/pt-BR/pure-agent-apps.mdx +4 -0
  28. package/corpus/core/docs/content/locales/zh-CN/a2a-protocol.mdx +12 -0
  29. package/corpus/core/docs/content/locales/zh-CN/pr-visual-recap.mdx +3 -3
  30. package/corpus/core/docs/content/locales/zh-CN/pure-agent-apps.mdx +4 -0
  31. package/corpus/core/docs/content/locales/zh-TW/a2a-protocol.mdx +12 -0
  32. package/corpus/core/docs/content/locales/zh-TW/pr-visual-recap.mdx +3 -3
  33. package/corpus/core/docs/content/locales/zh-TW/pure-agent-apps.mdx +4 -0
  34. package/corpus/core/docs/content/pr-visual-recap.mdx +3 -3
  35. package/corpus/core/docs/content/pure-agent-apps.mdx +22 -0
  36. package/corpus/core/package.json +1 -1
  37. package/corpus/core/src/agent/engine/builtin.ts +1 -1
  38. package/corpus/core/src/agent/model-config.ts +30 -30
  39. package/corpus/core/src/agent/production-agent.ts +129 -7
  40. package/corpus/core/src/cli/design-connect.ts +438 -83
  41. package/corpus/core/src/cli/recap.ts +2 -2
  42. package/corpus/core/src/cli/sync-builder-starter-manifest.ts +1 -1
  43. package/corpus/core/src/client/AgentPanel.tsx +8 -1
  44. package/corpus/core/src/client/agent-chat-adapter.ts +12 -7
  45. package/corpus/core/src/client/composer/TiptapComposer.tsx +1 -1
  46. package/corpus/core/src/client/index.ts +4 -0
  47. package/corpus/core/src/client/org/TeamPage.tsx +41 -26
  48. package/corpus/core/src/client/use-action.ts +113 -1
  49. package/corpus/core/src/db/client.ts +12 -2
  50. package/corpus/core/src/db/create-get-db.ts +4 -1
  51. package/corpus/core/src/scripts/agent-engines/manage-agent-engine.ts +1 -1
  52. package/corpus/core/src/scripts/agent-engines/set-agent-engine.ts +1 -1
  53. package/corpus/core/src/server/transcribe-voice.ts +1 -1
  54. package/corpus/core/src/usage/store.ts +13 -4
  55. package/corpus/core/src/vite/client.ts +38 -1
  56. package/corpus/templates/analytics/AGENTS.md +3 -0
  57. package/corpus/templates/analytics/actions/get-data-program.ts +78 -0
  58. package/corpus/templates/analytics/actions/list-data-programs.ts +49 -0
  59. package/corpus/templates/analytics/app/global.css +11 -0
  60. package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +163 -17
  61. package/corpus/templates/analytics/app/i18n/zh-TW.ts +2 -0
  62. package/corpus/templates/analytics/app/i18n-data.ts +20 -0
  63. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/ChartCard.tsx +96 -3
  64. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +3 -1
  65. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +61 -4
  66. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +40 -2
  67. package/corpus/templates/analytics/changelog/2026-07-09-analytics-no-longer-forgets-successful-data-queries-when-a-l.md +6 -0
  68. package/corpus/templates/analytics/changelog/2026-07-09-dashboard-charts-keep-consistent-spacing-when-they-stack-ver.md +6 -0
  69. package/corpus/templates/analytics/changelog/2026-07-09-dashboard-charts-tables-and-extensions-can-be-selected-and-d.md +6 -0
  70. package/corpus/templates/analytics/changelog/2026-07-09-long-running-analytics-requests-now-recover-automatically-wh.md +6 -0
  71. package/corpus/templates/analytics/server/db/index.ts +6 -0
  72. package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +1 -7
  73. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +102 -15
  74. package/corpus/templates/content/app/hooks/use-content-database.ts +52 -0
  75. package/corpus/templates/content/app/hooks/use-document-properties.ts +50 -6
  76. package/corpus/templates/content/app/i18n/zh-TW.ts +2 -0
  77. package/corpus/templates/content/app/i18n-data.ts +28 -0
  78. package/corpus/templates/content/changelog/2026-07-09-notion-conflict-warnings-no-longer-flash-during-normal-synce.md +6 -0
  79. package/corpus/templates/content/changelog/2026-07-09-property-menus-and-delete-confirmations-now-open-visibly-and.md +6 -0
  80. package/corpus/templates/content/server/lib/notion-sync.ts +130 -28
  81. package/corpus/templates/design/actions/add-breakpoint.ts +48 -68
  82. package/corpus/templates/design/actions/add-localhost-screens.ts +496 -61
  83. package/corpus/templates/design/actions/apply-component-prop-edit.ts +2 -18
  84. package/corpus/templates/design/actions/apply-design-token-edit.ts +51 -82
  85. package/corpus/templates/design/actions/apply-tweaks.ts +63 -41
  86. package/corpus/templates/design/actions/capture-design-state.ts +2 -2
  87. package/corpus/templates/design/actions/connect-localhost.ts +58 -12
  88. package/corpus/templates/design/actions/create-component.ts +2 -18
  89. package/corpus/templates/design/actions/create-design-branch.ts +38 -18
  90. package/corpus/templates/design/actions/create-fusion-app.ts +15 -11
  91. package/corpus/templates/design/actions/delete-file.ts +19 -34
  92. package/corpus/templates/design/actions/deploy-design-preview.ts +59 -27
  93. package/corpus/templates/design/actions/deploy-fusion-app.ts +22 -15
  94. package/corpus/templates/design/actions/export-pdf.ts +2 -1
  95. package/corpus/templates/design/actions/export-zip.ts +9 -3
  96. package/corpus/templates/design/actions/generate-design.ts +107 -70
  97. package/corpus/templates/design/actions/get-component-details.ts +2 -18
  98. package/corpus/templates/design/actions/get-design-branch-diff.ts +2 -3
  99. package/corpus/templates/design/actions/get-design-surface-index.ts +2 -18
  100. package/corpus/templates/design/actions/get-design.ts +2 -1
  101. package/corpus/templates/design/actions/grant-localhost-write-consent.ts +7 -1
  102. package/corpus/templates/design/actions/import-design-tokens.ts +114 -76
  103. package/corpus/templates/design/actions/index-components.ts +2 -18
  104. package/corpus/templates/design/actions/list-design-source-capabilities.ts +23 -28
  105. package/corpus/templates/design/actions/list-local-files.ts +9 -2
  106. package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +82 -98
  107. package/corpus/templates/design/actions/open-component-source.ts +2 -18
  108. package/corpus/templates/design/actions/open-visual-edit.ts +19 -1
  109. package/corpus/templates/design/actions/present-design-variants.ts +70 -70
  110. package/corpus/templates/design/actions/preview-component-prop-edit.ts +4 -14
  111. package/corpus/templates/design/actions/read-local-file.ts +9 -2
  112. package/corpus/templates/design/actions/remove-breakpoint.ts +40 -61
  113. package/corpus/templates/design/actions/rename-screen.ts +425 -0
  114. package/corpus/templates/design/actions/request-localhost-write-consent.ts +12 -2
  115. package/corpus/templates/design/actions/revoke-localhost-write-consent.ts +9 -2
  116. package/corpus/templates/design/actions/sync-fusion-app.ts +56 -39
  117. package/corpus/templates/design/actions/update-design.ts +376 -61
  118. package/corpus/templates/design/actions/update-file.ts +455 -188
  119. package/corpus/templates/design/actions/write-local-file.ts +10 -2
  120. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +685 -608
  121. package/corpus/templates/design/app/components/design/LayersPanel.tsx +43 -15
  122. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +576 -2015
  123. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +62 -14
  124. package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +263 -25
  125. package/corpus/templates/design/app/components/design/design-canvas/annotation-submit.ts +34 -0
  126. package/corpus/templates/design/app/components/design/design-canvas/coordinate-transforms.ts +40 -0
  127. package/corpus/templates/design/app/components/design/design-canvas/creation.ts +47 -0
  128. package/corpus/templates/design/app/components/design/design-canvas/element-payload.ts +27 -0
  129. package/corpus/templates/design/app/components/design/design-canvas/embedded-frame.ts +62 -0
  130. package/corpus/templates/design/app/components/design/design-canvas/external-preview.ts +137 -0
  131. package/corpus/templates/design/app/components/design/design-canvas/file-drop.ts +10 -0
  132. package/corpus/templates/design/app/components/design/design-canvas/hit-test.ts +23 -0
  133. package/corpus/templates/design/app/components/design/design-canvas/iframe-events.ts +23 -0
  134. package/corpus/templates/design/app/components/design/design-canvas/iframe-pan.ts +177 -0
  135. package/corpus/templates/design/app/components/design/design-canvas/motion-types.ts +7 -0
  136. package/corpus/templates/design/app/components/design/design-canvas/pending-text-edit.ts +62 -0
  137. package/corpus/templates/design/app/components/design/index.ts +2 -2
  138. package/corpus/templates/design/app/components/design/multi-screen/canvas-tools.ts +100 -0
  139. package/corpus/templates/design/app/components/design/multi-screen/coordinate-transforms.ts +81 -0
  140. package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +23 -13
  141. package/corpus/templates/design/app/components/design/multi-screen/culling.ts +238 -19
  142. package/corpus/templates/design/app/components/design/multi-screen/draft-primitives.ts +424 -0
  143. package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +341 -0
  144. package/corpus/templates/design/app/components/design/multi-screen/iframe-targeting.ts +52 -0
  145. package/corpus/templates/design/app/components/design/multi-screen/overview-layout.ts +62 -0
  146. package/corpus/templates/design/app/components/design/multi-screen/primitive-drop-target.ts +283 -0
  147. package/corpus/templates/design/app/components/design/multi-screen/screen-content-cache.ts +272 -0
  148. package/corpus/templates/design/app/components/design/multi-screen/types.ts +5 -1
  149. package/corpus/templates/design/app/components/design/multi-screen/wheel-gesture-state.ts +12 -0
  150. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +325 -84
  151. package/corpus/templates/design/app/hooks/use-navigation-state.ts +15 -1
  152. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +119 -47
  153. package/corpus/templates/design/app/i18n/zh-TW.ts +9 -0
  154. package/corpus/templates/design/app/i18n-data.ts +223 -0
  155. package/corpus/templates/design/app/lib/design-save-outbox.ts +379 -0
  156. package/corpus/templates/design/app/lib/png-clipboard.ts +113 -0
  157. package/corpus/templates/design/app/pages/design-editor/canvas-primitives.ts +229 -0
  158. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +918 -0
  159. package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +43 -0
  160. package/corpus/templates/design/app/pages/design-editor/cross-screen-text-color.ts +336 -0
  161. package/corpus/templates/design/app/pages/design-editor/data-operations.ts +270 -0
  162. package/corpus/templates/design/app/pages/design-editor/dom-guards.ts +24 -0
  163. package/corpus/templates/design/app/pages/design-editor/dom-utils.ts +11 -0
  164. package/corpus/templates/design/app/pages/design-editor/editor-session.ts +20 -0
  165. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +408 -0
  166. package/corpus/templates/design/app/pages/design-editor/export-capture.ts +115 -0
  167. package/corpus/templates/design/app/pages/design-editor/geometry-persistence.ts +93 -0
  168. package/corpus/templates/design/app/pages/design-editor/history.ts +169 -0
  169. package/corpus/templates/design/app/pages/design-editor/layout-operations.ts +185 -0
  170. package/corpus/templates/design/app/pages/design-editor/motion-state.ts +309 -0
  171. package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +438 -0
  172. package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +510 -0
  173. package/corpus/templates/design/app/pages/design-editor/portable-style.ts +115 -0
  174. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +337 -0
  175. package/corpus/templates/design/app/pages/design-editor/style-utils.ts +5 -0
  176. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +92 -0
  177. package/corpus/templates/design/app/pages/design-editor/tweak-save.ts +87 -0
  178. package/corpus/templates/design/app/pages/design-editor/types.ts +36 -0
  179. package/corpus/templates/design/app/routes/design.$id.tsx +11 -1
  180. package/corpus/templates/design/changelog/2026-07-09-design-edits-canvas-positions-tools-and-tab-context-now-pers.md +6 -0
  181. package/corpus/templates/design/changelog/2026-07-09-figma-style-shortcuts-drawing-annotations-and-cross-screen-d.md +6 -0
  182. package/corpus/templates/design/changelog/2026-07-09-hand-and-scale-tools-now-keep-their-active-toolbar-identity-.md +6 -0
  183. package/corpus/templates/design/changelog/2026-07-09-large-multi-screen-designs-now-stay-responsive-during-long-c.md +6 -0
  184. package/corpus/templates/design/changelog/2026-07-09-layer-drags-now-land-exactly-where-the-insertion-indicator-s.md +6 -0
  185. package/corpus/templates/design/server/db/index.ts +2 -52
  186. package/corpus/templates/design/server/db/schema.ts +16 -0
  187. package/corpus/templates/design/server/lib/design-data-access.ts +70 -0
  188. package/corpus/templates/design/server/lib/design-data-mutation.ts +249 -0
  189. package/corpus/templates/design/server/lib/fusion-screens.ts +89 -76
  190. package/corpus/templates/design/server/lib/import-design-files.ts +76 -35
  191. package/corpus/templates/design/server/lib/verify-write-grant.ts +7 -2
  192. package/corpus/templates/design/server/plugins/db.ts +19 -0
  193. package/corpus/templates/design/server/source-workspace.ts +12 -13
  194. package/corpus/templates/design/shared/resolve-tweaks.ts +15 -0
  195. package/corpus/templates/design/shared/screen-rename.ts +42 -0
  196. package/corpus/templates/design/shared/source-mode.ts +84 -4
  197. package/dist/agent/engine/builder-engine.d.ts +1 -1
  198. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  199. package/dist/agent/engine/builtin.js +1 -1
  200. package/dist/agent/engine/builtin.js.map +1 -1
  201. package/dist/agent/model-config.d.ts +9 -9
  202. package/dist/agent/model-config.d.ts.map +1 -1
  203. package/dist/agent/model-config.js +30 -30
  204. package/dist/agent/model-config.js.map +1 -1
  205. package/dist/agent/production-agent.d.ts +60 -1
  206. package/dist/agent/production-agent.d.ts.map +1 -1
  207. package/dist/agent/production-agent.js +106 -7
  208. package/dist/agent/production-agent.js.map +1 -1
  209. package/dist/cli/design-connect.d.ts +30 -1
  210. package/dist/cli/design-connect.d.ts.map +1 -1
  211. package/dist/cli/design-connect.js +359 -75
  212. package/dist/cli/design-connect.js.map +1 -1
  213. package/dist/cli/recap.js +2 -2
  214. package/dist/cli/recap.js.map +1 -1
  215. package/dist/cli/sync-builder-starter-manifest.js +1 -1
  216. package/dist/cli/sync-builder-starter-manifest.js.map +1 -1
  217. package/dist/client/AgentPanel.d.ts.map +1 -1
  218. package/dist/client/AgentPanel.js +6 -1
  219. package/dist/client/AgentPanel.js.map +1 -1
  220. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  221. package/dist/client/agent-chat-adapter.js +10 -5
  222. package/dist/client/agent-chat-adapter.js.map +1 -1
  223. package/dist/client/composer/TiptapComposer.js +1 -1
  224. package/dist/client/composer/TiptapComposer.js.map +1 -1
  225. package/dist/client/index.d.ts +1 -1
  226. package/dist/client/index.d.ts.map +1 -1
  227. package/dist/client/index.js +1 -1
  228. package/dist/client/index.js.map +1 -1
  229. package/dist/client/org/TeamPage.d.ts.map +1 -1
  230. package/dist/client/org/TeamPage.js +6 -5
  231. package/dist/client/org/TeamPage.js.map +1 -1
  232. package/dist/client/use-action.d.ts +32 -0
  233. package/dist/client/use-action.d.ts.map +1 -1
  234. package/dist/client/use-action.js +68 -1
  235. package/dist/client/use-action.js.map +1 -1
  236. package/dist/collab/awareness.d.ts +2 -2
  237. package/dist/collab/awareness.d.ts.map +1 -1
  238. package/dist/collab/routes.d.ts +1 -1
  239. package/dist/db/client.d.ts +3 -0
  240. package/dist/db/client.d.ts.map +1 -1
  241. package/dist/db/client.js +7 -2
  242. package/dist/db/client.js.map +1 -1
  243. package/dist/db/create-get-db.d.ts.map +1 -1
  244. package/dist/db/create-get-db.js +2 -2
  245. package/dist/db/create-get-db.js.map +1 -1
  246. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  247. package/dist/notifications/routes.d.ts +1 -1
  248. package/dist/observability/routes.d.ts +5 -5
  249. package/dist/progress/routes.d.ts +1 -1
  250. package/dist/resources/handlers.d.ts +1 -1
  251. package/dist/scripts/agent-engines/manage-agent-engine.js +1 -1
  252. package/dist/scripts/agent-engines/manage-agent-engine.js.map +1 -1
  253. package/dist/scripts/agent-engines/set-agent-engine.js +1 -1
  254. package/dist/scripts/agent-engines/set-agent-engine.js.map +1 -1
  255. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  256. package/dist/server/transcribe-voice.js +1 -1
  257. package/dist/server/transcribe-voice.js.map +1 -1
  258. package/dist/usage/store.d.ts.map +1 -1
  259. package/dist/usage/store.js +13 -4
  260. package/dist/usage/store.js.map +1 -1
  261. package/dist/vite/client.d.ts.map +1 -1
  262. package/dist/vite/client.js +36 -1
  263. package/dist/vite/client.js.map +1 -1
  264. package/docs/content/a2a-protocol.mdx +12 -0
  265. package/docs/content/locales/ar-SA/a2a-protocol.mdx +12 -0
  266. package/docs/content/locales/ar-SA/pr-visual-recap.mdx +3 -3
  267. package/docs/content/locales/ar-SA/pure-agent-apps.mdx +4 -0
  268. package/docs/content/locales/de-DE/a2a-protocol.mdx +12 -0
  269. package/docs/content/locales/de-DE/pr-visual-recap.mdx +3 -3
  270. package/docs/content/locales/de-DE/pure-agent-apps.mdx +4 -0
  271. package/docs/content/locales/es-ES/a2a-protocol.mdx +12 -0
  272. package/docs/content/locales/es-ES/pr-visual-recap.mdx +3 -3
  273. package/docs/content/locales/es-ES/pure-agent-apps.mdx +4 -0
  274. package/docs/content/locales/fr-FR/a2a-protocol.mdx +12 -0
  275. package/docs/content/locales/fr-FR/pr-visual-recap.mdx +3 -3
  276. package/docs/content/locales/fr-FR/pure-agent-apps.mdx +4 -0
  277. package/docs/content/locales/hi-IN/a2a-protocol.mdx +12 -0
  278. package/docs/content/locales/hi-IN/pr-visual-recap.mdx +3 -3
  279. package/docs/content/locales/hi-IN/pure-agent-apps.mdx +4 -0
  280. package/docs/content/locales/ja-JP/a2a-protocol.mdx +12 -0
  281. package/docs/content/locales/ja-JP/pr-visual-recap.mdx +3 -3
  282. package/docs/content/locales/ja-JP/pure-agent-apps.mdx +4 -0
  283. package/docs/content/locales/ko-KR/a2a-protocol.mdx +12 -0
  284. package/docs/content/locales/ko-KR/pr-visual-recap.mdx +3 -3
  285. package/docs/content/locales/ko-KR/pure-agent-apps.mdx +4 -0
  286. package/docs/content/locales/pt-BR/a2a-protocol.mdx +12 -0
  287. package/docs/content/locales/pt-BR/pr-visual-recap.mdx +3 -3
  288. package/docs/content/locales/pt-BR/pure-agent-apps.mdx +4 -0
  289. package/docs/content/locales/zh-CN/a2a-protocol.mdx +12 -0
  290. package/docs/content/locales/zh-CN/pr-visual-recap.mdx +3 -3
  291. package/docs/content/locales/zh-CN/pure-agent-apps.mdx +4 -0
  292. package/docs/content/locales/zh-TW/a2a-protocol.mdx +12 -0
  293. package/docs/content/locales/zh-TW/pr-visual-recap.mdx +3 -3
  294. package/docs/content/locales/zh-TW/pure-agent-apps.mdx +4 -0
  295. package/docs/content/pr-visual-recap.mdx +3 -3
  296. package/docs/content/pure-agent-apps.mdx +22 -0
  297. package/package.json +2 -2
@@ -0,0 +1,510 @@
1
+ import {
2
+ applyVisualEdit,
3
+ type ApplyVisualEditResult,
4
+ } from "@shared/code-layer";
5
+ import {
6
+ duplicateStatePreviewRules,
7
+ type InteractionState,
8
+ upsertStateStyles,
9
+ } from "@shared/interaction-states";
10
+ import {
11
+ planBreakpointStyleWrite,
12
+ utilityStem,
13
+ } from "@shared/responsive-classes";
14
+ import {
15
+ normalizeDesignSourceType,
16
+ type DesignSourceType,
17
+ } from "@shared/source-mode";
18
+
19
+ import type { ElementInfo } from "@/components/design/types";
20
+
21
+ import { camelStyleProperty } from "./style-utils";
22
+
23
+ export interface PendingVisualStyleEdit {
24
+ screenId: string;
25
+ filename: string;
26
+ screenName: string;
27
+ selector: string;
28
+ sourceId?: string | null;
29
+ tagName?: string | null;
30
+ classes: string[];
31
+ styles: Record<string, string>;
32
+ /**
33
+ * Inline style values to replay when the user discards the live preview.
34
+ * Missing authored inline values are stored as "" so the bridge removes the
35
+ * temporary inline style and lets the app's real CSS win again.
36
+ */
37
+ originalStyles: Record<string, string>;
38
+ updatedAt: number;
39
+ /**
40
+ * §6.4 — breakpoint scope active when the edit was made. When present the
41
+ * edit must be applied as a width-scoped override (apply-visual-edit with
42
+ * `activeFrameWidthPx`), not a base write. `upperBoundPx` is the Framer
43
+ * cascade bound (just below the next-wider frame); null means the active
44
+ * frame was the widest context (base edit).
45
+ */
46
+ breakpoint?: {
47
+ activeWidthPx: number;
48
+ upperBoundPx: number | null;
49
+ };
50
+ }
51
+
52
+ function pendingLiveTextEditKey(edit: PendingLiveTextEdit): string {
53
+ return `${edit.screenId}:${edit.sourceId?.trim() || edit.selector.trim()}`;
54
+ }
55
+
56
+ export function mergePendingLiveNonStyleEdits(
57
+ edits: readonly PendingLiveNonStyleEdit[],
58
+ ): PendingLiveNonStyleEdit[] {
59
+ const merged: PendingLiveNonStyleEdit[] = [];
60
+ for (const edit of edits) {
61
+ if (edit.kind === "structure") {
62
+ merged.push(edit);
63
+ continue;
64
+ }
65
+ const nextKey = pendingLiveTextEditKey(edit);
66
+ const index = merged.findIndex(
67
+ (candidate) =>
68
+ candidate.kind === "text" &&
69
+ pendingLiveTextEditKey(candidate) === nextKey,
70
+ );
71
+ if (index === -1) {
72
+ merged.push(edit);
73
+ continue;
74
+ }
75
+ const previous = merged[index] as PendingLiveTextEdit;
76
+ merged[index] = {
77
+ ...previous,
78
+ ...edit,
79
+ originalValue: previous.originalValue,
80
+ originalHtml: previous.originalHtml,
81
+ };
82
+ }
83
+ return merged;
84
+ }
85
+
86
+ export function pendingLiveTextUndoRevertValue(
87
+ currentEdits: readonly PendingLiveNonStyleEdit[],
88
+ nextEdit: PendingLiveTextEdit,
89
+ ): { value: string; html?: string } {
90
+ const currentForTarget = currentEdits.find(
91
+ (edit): edit is PendingLiveTextEdit =>
92
+ edit.kind === "text" &&
93
+ pendingLiveTextEditKey(edit) === pendingLiveTextEditKey(nextEdit),
94
+ );
95
+ return currentForTarget
96
+ ? { value: currentForTarget.value, html: currentForTarget.html }
97
+ : { value: nextEdit.originalValue, html: nextEdit.originalHtml };
98
+ }
99
+
100
+ export interface PendingLiveTextEdit {
101
+ kind: "text";
102
+ screenId: string;
103
+ filename: string;
104
+ screenName: string;
105
+ selector: string;
106
+ sourceId?: string | null;
107
+ tagName?: string | null;
108
+ classes: string[];
109
+ value: string;
110
+ html?: string;
111
+ originalValue: string;
112
+ originalHtml?: string;
113
+ updatedAt: number;
114
+ }
115
+
116
+ export interface PendingLiveStructureEdit {
117
+ kind: "structure";
118
+ screenId: string;
119
+ filename: string;
120
+ screenName: string;
121
+ selector: string;
122
+ sourceId?: string | null;
123
+ anchorSelector: string;
124
+ anchorSourceId?: string | null;
125
+ placement: "before" | "after" | "inside";
126
+ requestId?: string;
127
+ updatedAt: number;
128
+ }
129
+
130
+ export type PendingLiveNonStyleEdit =
131
+ | PendingLiveTextEdit
132
+ | PendingLiveStructureEdit;
133
+ export type PendingVisualStyleUndoEntry = {
134
+ edit: PendingVisualStyleEdit;
135
+ revertStyles: Record<string, string>;
136
+ };
137
+ export type PendingLiveTextUndoEntry = {
138
+ kind: "text";
139
+ edit: PendingLiveTextEdit;
140
+ revertValue: string;
141
+ revertHtml?: string;
142
+ };
143
+ export type PendingLiveStructureUndoEntry = {
144
+ kind: "structure";
145
+ edit: PendingLiveStructureEdit;
146
+ };
147
+ export type PendingLiveNonStyleUndoEntry =
148
+ | PendingLiveTextUndoEntry
149
+ | PendingLiveStructureUndoEntry;
150
+
151
+ function pendingVisualStyleEditKey(edit: PendingVisualStyleEdit): string {
152
+ return [
153
+ edit.screenId,
154
+ edit.sourceId?.trim() || edit.selector.trim() || "unknown",
155
+ ].join("::");
156
+ }
157
+
158
+ export function mergePendingVisualStyleEdit(
159
+ edits: readonly PendingVisualStyleEdit[],
160
+ nextEdit: PendingVisualStyleEdit,
161
+ ): PendingVisualStyleEdit[] {
162
+ const nextKey = pendingVisualStyleEditKey(nextEdit);
163
+ let merged = false;
164
+ const next = edits.map((edit) => {
165
+ if (pendingVisualStyleEditKey(edit) !== nextKey) return edit;
166
+ merged = true;
167
+ return {
168
+ ...edit,
169
+ ...nextEdit,
170
+ classes: nextEdit.classes.length > 0 ? nextEdit.classes : edit.classes,
171
+ styles: { ...edit.styles, ...nextEdit.styles },
172
+ originalStyles: {
173
+ ...nextEdit.originalStyles,
174
+ ...edit.originalStyles,
175
+ },
176
+ };
177
+ });
178
+ return merged ? next : [...edits, nextEdit];
179
+ }
180
+
181
+ export function mergePendingVisualStyleEdits(
182
+ edits: readonly PendingVisualStyleEdit[],
183
+ ): PendingVisualStyleEdit[] {
184
+ return edits.reduce<PendingVisualStyleEdit[]>(
185
+ (merged, edit) => mergePendingVisualStyleEdit(merged, edit),
186
+ [],
187
+ );
188
+ }
189
+
190
+ export function pendingVisualStyleUndoRevertStyles(
191
+ currentEdits: readonly PendingVisualStyleEdit[],
192
+ nextEdit: PendingVisualStyleEdit,
193
+ ): Record<string, string> {
194
+ const currentForTarget = currentEdits.find(
195
+ (edit) =>
196
+ pendingVisualStyleEditKey(edit) === pendingVisualStyleEditKey(nextEdit),
197
+ );
198
+ return Object.fromEntries(
199
+ Object.keys(nextEdit.styles).map((property) => [
200
+ property,
201
+ currentForTarget?.styles[property] ??
202
+ nextEdit.originalStyles[property] ??
203
+ "",
204
+ ]),
205
+ );
206
+ }
207
+
208
+ function styleLookup(
209
+ styles: Record<string, string> | undefined,
210
+ property: string,
211
+ ): string | undefined {
212
+ if (!styles) return undefined;
213
+ const camel = camelStyleProperty(property);
214
+ const kebab = property.replace(
215
+ /[A-Z]/g,
216
+ (match) => `-${match.toLowerCase()}`,
217
+ );
218
+ return styles[property] ?? styles[camel] ?? styles[kebab];
219
+ }
220
+
221
+ export function originalStylesForPendingVisualEdit(
222
+ styles: Record<string, string>,
223
+ primaryInfo?: Pick<ElementInfo, "computedStyles" | "inlineStyles"> | null,
224
+ fallbackInfo?: Pick<ElementInfo, "computedStyles" | "inlineStyles"> | null,
225
+ ): Record<string, string> {
226
+ const sourceInfo = primaryInfo ?? fallbackInfo ?? null;
227
+ const inlineStyles = sourceInfo?.inlineStyles;
228
+ const computedStyles = sourceInfo?.computedStyles;
229
+ return Object.fromEntries(
230
+ Object.keys(styles).map((property) => {
231
+ const inlineValue = styleLookup(inlineStyles, property);
232
+ if (inlineValue !== undefined) return [property, inlineValue];
233
+ if (inlineStyles) return [property, ""];
234
+ return [property, styleLookup(computedStyles, property) ?? ""];
235
+ }),
236
+ );
237
+ }
238
+
239
+ export function buildPendingVisualStyleRevertPatches(
240
+ edits: readonly PendingVisualStyleEdit[],
241
+ ): Array<{
242
+ screenId: string;
243
+ selector: string;
244
+ sourceId?: string | null;
245
+ styles: Record<string, string>;
246
+ }> {
247
+ return edits
248
+ .map((edit) => ({
249
+ screenId: edit.screenId,
250
+ selector: edit.selector,
251
+ sourceId: edit.sourceId,
252
+ styles: edit.originalStyles,
253
+ }))
254
+ .filter((patch) => Object.keys(patch.styles).length > 0);
255
+ }
256
+
257
+ export function getPendingVisualStylePropertyCount(
258
+ edits: readonly PendingVisualStyleEdit[],
259
+ ): number {
260
+ return edits.reduce(
261
+ (count, edit) => count + Object.keys(edit.styles).length,
262
+ 0,
263
+ );
264
+ }
265
+
266
+ export function shouldBlockPendingVisualStyleNavigation(args: {
267
+ hasPendingVisualStyleEdits: boolean;
268
+ currentPathname: string;
269
+ nextPathname: string;
270
+ }): boolean {
271
+ return (
272
+ args.hasPendingVisualStyleEdits &&
273
+ args.currentPathname !== args.nextPathname
274
+ );
275
+ }
276
+
277
+ export function formatPendingVisualStylePrompt(args: {
278
+ designId?: string | null;
279
+ designTitle?: string | null;
280
+ activeFileId?: string | null;
281
+ activeFilename?: string | null;
282
+ edits: readonly PendingVisualStyleEdit[];
283
+ liveEdits?: readonly PendingLiveNonStyleEdit[];
284
+ }): string {
285
+ const title = args.designTitle?.trim();
286
+ const editPayload = args.edits.map((edit) => ({
287
+ screenId: edit.screenId,
288
+ filename: edit.filename,
289
+ screenName: edit.screenName,
290
+ selector: edit.selector,
291
+ sourceId: edit.sourceId ?? null,
292
+ tagName: edit.tagName ?? null,
293
+ classes: edit.classes,
294
+ styles: edit.styles,
295
+ ...(edit.breakpoint ? { breakpoint: edit.breakpoint } : {}),
296
+ }));
297
+ const hasBreakpointScopedEdits = args.edits.some(
298
+ (edit) => edit.breakpoint && edit.breakpoint.upperBoundPx !== null,
299
+ );
300
+ const liveEditPayload = (args.liveEdits ?? []).map((edit) => {
301
+ if (edit.kind === "text") {
302
+ return {
303
+ kind: edit.kind,
304
+ screenId: edit.screenId,
305
+ filename: edit.filename,
306
+ screenName: edit.screenName,
307
+ selector: edit.selector,
308
+ sourceId: edit.sourceId ?? null,
309
+ tagName: edit.tagName ?? null,
310
+ classes: edit.classes,
311
+ value: edit.value,
312
+ html: edit.html,
313
+ };
314
+ }
315
+ return {
316
+ kind: edit.kind,
317
+ screenId: edit.screenId,
318
+ filename: edit.filename,
319
+ screenName: edit.screenName,
320
+ selector: edit.selector,
321
+ sourceId: edit.sourceId ?? null,
322
+ anchorSelector: edit.anchorSelector,
323
+ anchorSourceId: edit.anchorSourceId ?? null,
324
+ placement: edit.placement,
325
+ };
326
+ });
327
+
328
+ return [
329
+ `Apply these pending live visual edits${title ? ` to "${title}"` : ""}.`,
330
+ args.designId ? `Design id: "${args.designId}".` : "",
331
+ args.activeFileId
332
+ ? `Active screen: "${args.activeFilename ?? args.activeFileId}" (${args.activeFileId}).`
333
+ : "",
334
+ "",
335
+ "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.",
336
+ hasBreakpointScopedEdits
337
+ ? "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."
338
+ : "",
339
+ "",
340
+ "Pending style edits:",
341
+ JSON.stringify(editPayload, null, 2),
342
+ liveEditPayload.length > 0 ? "Pending text/structure edits:" : "",
343
+ liveEditPayload.length > 0 ? JSON.stringify(liveEditPayload, null, 2) : "",
344
+ ]
345
+ .filter((line) => line !== "")
346
+ .join("\n");
347
+ }
348
+
349
+ export function resolveOverviewScreenSourceType(
350
+ screen:
351
+ | { sourceType?: unknown; bridgeUrl?: string | null }
352
+ | null
353
+ | undefined,
354
+ fallbackSourceType: DesignSourceType = "inline",
355
+ ): DesignSourceType {
356
+ if (!screen) return fallbackSourceType;
357
+ return (
358
+ normalizeDesignSourceType(screen.sourceType) ??
359
+ (screen.bridgeUrl ? "localhost" : undefined) ??
360
+ fallbackSourceType
361
+ );
362
+ }
363
+
364
+ export function shouldShowPendingVisualStyleApply(args: {
365
+ edits: readonly PendingVisualStyleEdit[];
366
+ liveEdits?: readonly PendingLiveNonStyleEdit[];
367
+ screenSourceTypes: ReadonlyMap<string, unknown>;
368
+ fallbackSourceType?: unknown;
369
+ }): boolean {
370
+ const allEdits = [...args.edits, ...(args.liveEdits ?? [])];
371
+ return (
372
+ allEdits.length > 0 &&
373
+ allEdits.every(
374
+ (edit) =>
375
+ normalizeDesignSourceType(
376
+ args.screenSourceTypes.get(edit.screenId) ?? args.fallbackSourceType,
377
+ ) === "localhost",
378
+ )
379
+ );
380
+ }
381
+
382
+ /**
383
+ * §6.4 — One scoped style write (Framer cascade). Routes a single
384
+ * (property, value) edit through the class-vs-media decision
385
+ * (`planBreakpointStyleWrite`) for the active breakpoint scope:
386
+ *
387
+ * - `upperBoundPx == null` (base editing): plain inline-style edit that
388
+ * cascades down to every narrower breakpoint unless overridden there.
389
+ * - Tailwind-utility value: width-scoped responsive class
390
+ * (`max-[<bound>px]:utility`), falling back to the media path if the
391
+ * class patch is rejected.
392
+ * - Raw CSS value: managed `@media (max-width: <bound>px)` rule in the
393
+ * `<style data-agent-native-breakpoints>` block.
394
+ *
395
+ * Scoped failures return the failing patch rather than silently mutating
396
+ * the base layer — callers surface `result.message`.
397
+ */
398
+ export function applyScopedVisualStyleEdit(args: {
399
+ content: string;
400
+ target: { nodeId: string } | { selector: string };
401
+ property: string;
402
+ value: string;
403
+ upperBoundPx: number | null;
404
+ }): ApplyVisualEditResult {
405
+ const { content, target, property, value, upperBoundPx } = args;
406
+ const plan = planBreakpointStyleWrite({ property, value, upperBoundPx });
407
+ if (plan.mode === "class") {
408
+ const rcPatch = applyVisualEdit(content, {
409
+ kind: "responsive-class",
410
+ target,
411
+ // `prefix` is ignored when maxWidthPx is set (desktop-down scope).
412
+ prefix: "base",
413
+ maxWidthPx: plan.boundPx,
414
+ operation: "replace",
415
+ utility: plan.utility,
416
+ stem: utilityStem(plan.utility),
417
+ });
418
+ if (rcPatch.result.status === "applied") return rcPatch;
419
+ // Fall through to the media path so the edit still lands scoped.
420
+ }
421
+ if (
422
+ plan.mode !== "base" &&
423
+ upperBoundPx !== null &&
424
+ upperBoundPx !== undefined
425
+ ) {
426
+ return applyVisualEdit(content, {
427
+ kind: "breakpoint-style",
428
+ target,
429
+ maxWidthPx: upperBoundPx,
430
+ property,
431
+ value,
432
+ operation: "set",
433
+ });
434
+ }
435
+ return applyVisualEdit(content, { kind: "style", target, property, value });
436
+ }
437
+
438
+ /**
439
+ * Pure decision behind commitVisualStyles' commit-or-fail outcome, extracted
440
+ * so the fail-loud contract is unit-testable:
441
+ *
442
+ * - scoped patch applied → its content wins;
443
+ * - scoped patch failed while a BREAKPOINT scope is active → hard error
444
+ * (the legacy selector fallback is a BASE write and would clobber every
445
+ * viewport width with a value the user meant to scope — §6.4);
446
+ * - scoped patch failed on BASE scope → the legacy selector-based
447
+ * inline-style fallback may stand in, but ONLY when it actually resolved
448
+ * (queryUniqueSelector demands exactly one match — never a guessy write);
449
+ * - nothing resolved → hard error. Callers MUST surface `error` loudly
450
+ * (toast), never swallow it: a silent no-op here leaves the inspector
451
+ * displaying a value that was never persisted.
452
+ */
453
+ export function resolveVisualStyleCommitContent(args: {
454
+ scopedContent: string;
455
+ scopedFailure: string | null;
456
+ legacyFallbackContent: string | null;
457
+ breakpointScoped: boolean;
458
+ }): { content: string } | { error: string | null } {
459
+ if (!args.scopedFailure) return { content: args.scopedContent };
460
+ if (args.breakpointScoped) return { error: args.scopedFailure };
461
+ if (args.legacyFallbackContent)
462
+ return { content: args.legacyFallbackContent };
463
+ return { error: args.scopedFailure };
464
+ }
465
+
466
+ /**
467
+ * Interaction-states phase 2 — the pure content transform behind
468
+ * `commitInteractionStateStyles` (DesignEditor's useCallback wrapper, which
469
+ * only resolves `activeFile`/`selectedElement`/`canEditDesign` and calls
470
+ * `applyFileContentUpdate`). Extracted as a top-level function so it's
471
+ * unit-testable the same way `applyScopedVisualStyleEdit` is above.
472
+ *
473
+ * Writes every property in `styles` into the managed
474
+ * `[data-agent-native-node-id="<nodeId>"]:<state> { … }` rule
475
+ * (`upsertStateStyles`) and regenerates that rule's forced-preview twin
476
+ * (`duplicateStatePreviewRules`) in one pass, so a caller that folds the
477
+ * result into a single `applyFileContentUpdate`/history-recording call gets
478
+ * exactly one undo step for the whole commit — see
479
+ * `shared/interaction-states.ts`'s module doc for the twin-rule mechanism.
480
+ */
481
+ export function applyInteractionStateStyleCommit(
482
+ content: string,
483
+ nodeId: string,
484
+ state: InteractionState,
485
+ styles: Record<string, string>,
486
+ ): string {
487
+ const withStateStyles = upsertStateStyles(content, nodeId, state, styles);
488
+ return duplicateStatePreviewRules(withStateStyles);
489
+ }
490
+
491
+ /**
492
+ * Interaction-states phase 2 — the pure decision behind `statePreviewTarget`,
493
+ * the value DesignEditor forwards into both the single-screen and overview
494
+ * `DesignCanvas` instances' `statePreviewTarget` prop, which in turn drives
495
+ * the `state-preview` postMessage that sets/clears the bridge's
496
+ * `data-an-state-preview` attribute (see interaction-states.ts's "Forced-
497
+ * preview mechanism" doc comment for the full pipeline). Returns null
498
+ * whenever there's no active non-default interaction state OR no resolvable
499
+ * single-element screen/node target — both must be present for a preview to
500
+ * make sense, matching EditPanel's InteractionStatePanel only ever offering
501
+ * the state selector for a single selection with a stable node id.
502
+ */
503
+ export function deriveStatePreviewTarget(
504
+ activeState: InteractionState | null,
505
+ screenId: string | null | undefined,
506
+ nodeId: string | null | undefined,
507
+ ): { screenId: string; nodeId: string; state: InteractionState } | null {
508
+ if (!activeState || !screenId || !nodeId) return null;
509
+ return { screenId, nodeId, state: activeState };
510
+ }
@@ -0,0 +1,115 @@
1
+ import type {
2
+ PortableStyleSnapshot,
3
+ PortableStyleSnapshotNode,
4
+ } from "@/components/design/types";
5
+
6
+ export function styleHost(element: Element): HTMLElement | SVGElement | null {
7
+ return element instanceof HTMLElement || element instanceof SVGElement
8
+ ? element
9
+ : null;
10
+ }
11
+
12
+ export function elementAtPortableStylePath(
13
+ root: Element,
14
+ node: PortableStyleSnapshotNode,
15
+ ): Element | null {
16
+ let current: Element | null = root;
17
+ for (const index of node.path) {
18
+ if (!current || !Number.isInteger(index) || index < 0) return null;
19
+ current = current.children.item(index);
20
+ }
21
+ return current;
22
+ }
23
+
24
+ const EDITOR_INTERNAL_CSS_VAR_PREFIXES = [
25
+ "--design-editor-",
26
+ "--agent-native-editor-chrome-",
27
+ "--agent-native-",
28
+ ];
29
+
30
+ export function isEditorInternalCssVar(property: string): boolean {
31
+ return EDITOR_INTERNAL_CSS_VAR_PREFIXES.some((prefix) =>
32
+ property.startsWith(prefix),
33
+ );
34
+ }
35
+
36
+ export function applyPortableStyles(
37
+ element: Element | null,
38
+ styles: Record<string, string>,
39
+ ) {
40
+ if (!element) return;
41
+ const host = styleHost(element);
42
+ if (!host) return;
43
+ Object.entries(styles).forEach(([property, value]) => {
44
+ if (!value) return;
45
+ if (property.startsWith("--")) {
46
+ if (isEditorInternalCssVar(property)) return;
47
+ host.style.setProperty(property, value);
48
+ return;
49
+ }
50
+ if (property.includes("-")) {
51
+ host.style.setProperty(property, value);
52
+ return;
53
+ }
54
+ (host.style as any)[property] = value;
55
+ });
56
+ }
57
+
58
+ export function sameStylesheetHead(
59
+ sourceHtml: string,
60
+ destHtml: string,
61
+ ): boolean {
62
+ if (typeof window === "undefined") return false;
63
+ try {
64
+ const parser = new DOMParser();
65
+ const sourceHead = parser.parseFromString(sourceHtml, "text/html").head
66
+ ?.innerHTML;
67
+ const destHead = parser.parseFromString(destHtml, "text/html").head
68
+ ?.innerHTML;
69
+ return (
70
+ typeof sourceHead === "string" &&
71
+ typeof destHead === "string" &&
72
+ sourceHead === destHead
73
+ );
74
+ } catch {
75
+ return false;
76
+ }
77
+ }
78
+
79
+ export function applyPortableStyleSnapshotToHtml(
80
+ content: string,
81
+ nodeAttrId: string,
82
+ snapshot?: PortableStyleSnapshot,
83
+ sourceContent?: string,
84
+ ): string {
85
+ if (typeof window === "undefined" || !snapshot?.nodes?.length) {
86
+ return content;
87
+ }
88
+ if (sourceContent && sameStylesheetHead(sourceContent, content)) {
89
+ return content;
90
+ }
91
+ try {
92
+ const doc = new DOMParser().parseFromString(content, "text/html");
93
+ const root = doc.querySelector(
94
+ `[data-agent-native-node-id="${CSS.escape(nodeAttrId)}"]`,
95
+ );
96
+ if (!root) return content;
97
+ let appliedAny = false;
98
+ snapshot.nodes.forEach((node) => {
99
+ const target = elementAtPortableStylePath(root, node);
100
+ if (!target) return;
101
+ const filteredEntries = Object.entries(node.styles).filter(
102
+ ([property, value]) => value && !isEditorInternalCssVar(property),
103
+ );
104
+ if (filteredEntries.length === 0) return;
105
+ applyPortableStyles(target, Object.fromEntries(filteredEntries));
106
+ appliedAny = true;
107
+ });
108
+ if (appliedAny) {
109
+ root.setAttribute("data-agent-native-preserve-styles", "true");
110
+ }
111
+ return `<!DOCTYPE html>\n${doc.documentElement.outerHTML}`;
112
+ } catch {
113
+ return content;
114
+ }
115
+ }