@agent-native/core 0.92.7 → 0.92.9

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 (295) 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 +17 -3
  42. package/corpus/core/src/client/AgentPanel.tsx +8 -1
  43. package/corpus/core/src/client/agent-chat-adapter.ts +12 -7
  44. package/corpus/core/src/client/composer/TiptapComposer.tsx +1 -1
  45. package/corpus/core/src/client/index.ts +4 -0
  46. package/corpus/core/src/client/org/TeamPage.tsx +41 -26
  47. package/corpus/core/src/client/use-action.ts +113 -1
  48. package/corpus/core/src/db/client.ts +12 -2
  49. package/corpus/core/src/db/create-get-db.ts +4 -1
  50. package/corpus/core/src/scripts/agent-engines/manage-agent-engine.ts +1 -1
  51. package/corpus/core/src/scripts/agent-engines/set-agent-engine.ts +1 -1
  52. package/corpus/core/src/server/ssr-handler.ts +7 -0
  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.d.ts.map +1 -1
  214. package/dist/cli/recap.js +13 -3
  215. package/dist/cli/recap.js.map +1 -1
  216. package/dist/client/AgentPanel.d.ts.map +1 -1
  217. package/dist/client/AgentPanel.js +6 -1
  218. package/dist/client/AgentPanel.js.map +1 -1
  219. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  220. package/dist/client/agent-chat-adapter.js +10 -5
  221. package/dist/client/agent-chat-adapter.js.map +1 -1
  222. package/dist/client/composer/TiptapComposer.js +1 -1
  223. package/dist/client/composer/TiptapComposer.js.map +1 -1
  224. package/dist/client/index.d.ts +1 -1
  225. package/dist/client/index.d.ts.map +1 -1
  226. package/dist/client/index.js +1 -1
  227. package/dist/client/index.js.map +1 -1
  228. package/dist/client/org/TeamPage.d.ts.map +1 -1
  229. package/dist/client/org/TeamPage.js +6 -5
  230. package/dist/client/org/TeamPage.js.map +1 -1
  231. package/dist/client/use-action.d.ts +32 -0
  232. package/dist/client/use-action.d.ts.map +1 -1
  233. package/dist/client/use-action.js +68 -1
  234. package/dist/client/use-action.js.map +1 -1
  235. package/dist/collab/struct-routes.d.ts +1 -1
  236. package/dist/db/client.d.ts +3 -0
  237. package/dist/db/client.d.ts.map +1 -1
  238. package/dist/db/client.js +7 -2
  239. package/dist/db/client.js.map +1 -1
  240. package/dist/db/create-get-db.d.ts.map +1 -1
  241. package/dist/db/create-get-db.js +2 -2
  242. package/dist/db/create-get-db.js.map +1 -1
  243. package/dist/notifications/routes.d.ts +3 -3
  244. package/dist/observability/routes.d.ts +1 -1
  245. package/dist/resources/handlers.d.ts +3 -3
  246. package/dist/scripts/agent-engines/manage-agent-engine.js +1 -1
  247. package/dist/scripts/agent-engines/manage-agent-engine.js.map +1 -1
  248. package/dist/scripts/agent-engines/set-agent-engine.js +1 -1
  249. package/dist/scripts/agent-engines/set-agent-engine.js.map +1 -1
  250. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  251. package/dist/server/ssr-handler.d.ts.map +1 -1
  252. package/dist/server/ssr-handler.js +7 -0
  253. package/dist/server/ssr-handler.js.map +1 -1
  254. package/dist/server/transcribe-voice.js +1 -1
  255. package/dist/server/transcribe-voice.js.map +1 -1
  256. package/dist/usage/store.d.ts.map +1 -1
  257. package/dist/usage/store.js +13 -4
  258. package/dist/usage/store.js.map +1 -1
  259. package/dist/vite/client.d.ts.map +1 -1
  260. package/dist/vite/client.js +36 -1
  261. package/dist/vite/client.js.map +1 -1
  262. package/docs/content/a2a-protocol.mdx +12 -0
  263. package/docs/content/locales/ar-SA/a2a-protocol.mdx +12 -0
  264. package/docs/content/locales/ar-SA/pr-visual-recap.mdx +3 -3
  265. package/docs/content/locales/ar-SA/pure-agent-apps.mdx +4 -0
  266. package/docs/content/locales/de-DE/a2a-protocol.mdx +12 -0
  267. package/docs/content/locales/de-DE/pr-visual-recap.mdx +3 -3
  268. package/docs/content/locales/de-DE/pure-agent-apps.mdx +4 -0
  269. package/docs/content/locales/es-ES/a2a-protocol.mdx +12 -0
  270. package/docs/content/locales/es-ES/pr-visual-recap.mdx +3 -3
  271. package/docs/content/locales/es-ES/pure-agent-apps.mdx +4 -0
  272. package/docs/content/locales/fr-FR/a2a-protocol.mdx +12 -0
  273. package/docs/content/locales/fr-FR/pr-visual-recap.mdx +3 -3
  274. package/docs/content/locales/fr-FR/pure-agent-apps.mdx +4 -0
  275. package/docs/content/locales/hi-IN/a2a-protocol.mdx +12 -0
  276. package/docs/content/locales/hi-IN/pr-visual-recap.mdx +3 -3
  277. package/docs/content/locales/hi-IN/pure-agent-apps.mdx +4 -0
  278. package/docs/content/locales/ja-JP/a2a-protocol.mdx +12 -0
  279. package/docs/content/locales/ja-JP/pr-visual-recap.mdx +3 -3
  280. package/docs/content/locales/ja-JP/pure-agent-apps.mdx +4 -0
  281. package/docs/content/locales/ko-KR/a2a-protocol.mdx +12 -0
  282. package/docs/content/locales/ko-KR/pr-visual-recap.mdx +3 -3
  283. package/docs/content/locales/ko-KR/pure-agent-apps.mdx +4 -0
  284. package/docs/content/locales/pt-BR/a2a-protocol.mdx +12 -0
  285. package/docs/content/locales/pt-BR/pr-visual-recap.mdx +3 -3
  286. package/docs/content/locales/pt-BR/pure-agent-apps.mdx +4 -0
  287. package/docs/content/locales/zh-CN/a2a-protocol.mdx +12 -0
  288. package/docs/content/locales/zh-CN/pr-visual-recap.mdx +3 -3
  289. package/docs/content/locales/zh-CN/pure-agent-apps.mdx +4 -0
  290. package/docs/content/locales/zh-TW/a2a-protocol.mdx +12 -0
  291. package/docs/content/locales/zh-TW/pr-visual-recap.mdx +3 -3
  292. package/docs/content/locales/zh-TW/pure-agent-apps.mdx +4 -0
  293. package/docs/content/pr-visual-recap.mdx +3 -3
  294. package/docs/content/pure-agent-apps.mdx +22 -0
  295. package/package.json +2 -2
@@ -0,0 +1,438 @@
1
+ import type { CanvasFrameGeometryById } from "@shared/canvas-frames";
2
+ import {
3
+ DEFAULT_CANVAS_MAX_ZOOM,
4
+ DEFAULT_CANVAS_MIN_ZOOM,
5
+ getCameraForBounds,
6
+ getFrameGroupBounds,
7
+ type FrameEntry,
8
+ } from "@shared/canvas-math";
9
+ import type { SetStateAction } from "react";
10
+
11
+ import { getInitialFrameGeometry } from "@/components/design/multi-screen/frame-geometry";
12
+ import { OVERVIEW_FRAME_WIDTH } from "@/components/design/multi-screen/overview-layout";
13
+ import type {
14
+ FrameGeometry,
15
+ Point,
16
+ } from "@/components/design/multi-screen/types";
17
+
18
+ export const DEFAULT_OVERVIEW_ZOOM = 60;
19
+
20
+ /**
21
+ * Vector-edit foundations (P5 integration): resolves the canvas-space point
22
+ * where a screen's own screen-content-local (0,0) sits — i.e.
23
+ * `VectorEditOverlayState.originCanvas` — for a committed pen path owned by
24
+ * `screenId`.
25
+ *
26
+ * Mirrors the exact same fallback-merge (`getInitialFrameGeometry(index,
27
+ * ...)` overridden by any persisted `canvasFrameGeometryById` entry) that
28
+ * `getSelectedScreenGeometryForInspector` above and MultiScreenCanvas's own
29
+ * internal frame-geometry resolution both use, so the overlay lines up with
30
+ * whatever frame position is actually rendered on screen.
31
+ *
32
+ * The reserved board file (`__board__.html`, see shared/board-file.ts) is the
33
+ * one exception: `handleBoardDrawPrimitive`/`persistDraftPrimitive` commit
34
+ * board primitives with a 1:1 `{x:0,y:0,width:1,height:1}` frame (no offset
35
+ * subtraction — see MultiScreenCanvas's persistDraftPrimitive), so a board
36
+ * pen path's nodes are already in absolute canvas coordinates and
37
+ * `originCanvas` is `{0, 0}`.
38
+ *
39
+ * Returns `null` when the screen can't be resolved (not in `overviewScreens`
40
+ * and not the board file) — the caller should not enter vector-edit mode in
41
+ * that case.
42
+ */
43
+ export function getScreenFrameOriginCanvas(args: {
44
+ screenId: string;
45
+ overviewScreens: Array<{
46
+ id: string;
47
+ width?: number;
48
+ height?: number;
49
+ }>;
50
+ canvasFrameGeometryById: CanvasFrameGeometryById;
51
+ boardFileId?: string | null;
52
+ }): Point | null {
53
+ if (args.boardFileId && args.screenId === args.boardFileId) {
54
+ return { x: 0, y: 0 };
55
+ }
56
+ const screenIndex = args.overviewScreens.findIndex(
57
+ (screen) => screen.id === args.screenId,
58
+ );
59
+ if (screenIndex < 0) return null;
60
+ const screen = args.overviewScreens[screenIndex];
61
+ if (!screen) return null;
62
+ const fallbackGeometry = getInitialFrameGeometry(screenIndex, {
63
+ width: screen.width ?? 1280,
64
+ height: screen.height ?? 2560,
65
+ });
66
+ const persistedGeometry = args.canvasFrameGeometryById[args.screenId] ?? {};
67
+ return {
68
+ x: persistedGeometry.x ?? fallbackGeometry.x,
69
+ y: persistedGeometry.y ?? fallbackGeometry.y,
70
+ };
71
+ }
72
+
73
+ /**
74
+ * Resolves every overview screen's effective canvas-space frame geometry —
75
+ * persisted `canvasFrameGeometryById` entry merged over the same
76
+ * `getInitialFrameGeometry(index, ...)` fallback `getSelectedScreenGeometryForInspector`
77
+ * and `getScreenFrameOriginCanvas` above already use — as `FrameEntry[]` for
78
+ * `@shared/canvas-math` bounds/fit helpers (`getFrameGroupBounds`,
79
+ * `getCameraForBounds`). Optionally includes the board frame (real Figma has
80
+ * no board-file equivalent, but a design with only board primitives and no
81
+ * screens should still have something to fit to).
82
+ */
83
+ export function getAllScreenFrameEntries(args: {
84
+ overviewScreens: Array<{
85
+ id: string;
86
+ width?: number;
87
+ height?: number;
88
+ }>;
89
+ canvasFrameGeometryById: CanvasFrameGeometryById;
90
+ boardFrameGeometry?: FrameGeometry;
91
+ boardFileId?: string | null;
92
+ }): FrameEntry[] {
93
+ const entries: FrameEntry[] = args.overviewScreens.map((screen, index) => {
94
+ const fallbackGeometry = getInitialFrameGeometry(index, {
95
+ width: screen.width ?? 1280,
96
+ height: screen.height ?? 2560,
97
+ });
98
+ const persistedGeometry = args.canvasFrameGeometryById[screen.id] ?? {};
99
+ return {
100
+ id: screen.id,
101
+ geometry: { ...fallbackGeometry, ...persistedGeometry },
102
+ };
103
+ });
104
+ if (
105
+ args.boardFileId &&
106
+ args.boardFrameGeometry &&
107
+ !entries.some((entry) => entry.id === args.boardFileId)
108
+ ) {
109
+ entries.push({ id: args.boardFileId, geometry: args.boardFrameGeometry });
110
+ }
111
+ return entries;
112
+ }
113
+
114
+ /**
115
+ * Hit-tests a canvas-space point (the same coordinate system
116
+ * `getAllScreenFrameEntries` resolves frame geometry into) against every real
117
+ * screen frame — excluding `excludeFileId` (the board file itself, which is
118
+ * only a paste-target FALLBACK, never a hit-testable "screen" to drop into).
119
+ * Used by overview image/content paste (see handlePastedImageFiles) to decide
120
+ * whether a paste anchor point lands on a screen — and if so, which one — so
121
+ * the paste can be inserted into that screen's own local coordinate space
122
+ * instead of always landing on the shared board file.
123
+ *
124
+ * When multiple frames overlap at the point (frames can be freely dragged on
125
+ * top of each other), the LAST matching entry wins — `overviewScreens`/
126
+ * `getAllScreenFrameEntries` order screens back-to-front by z, matching
127
+ * MultiScreenCanvas's own render order, so this picks the topmost screen at
128
+ * that point, same as a real click would hit.
129
+ */
130
+ export function findScreenFrameAtCanvasPoint(
131
+ point: { x: number; y: number },
132
+ frames: FrameEntry[],
133
+ excludeFileId?: string | null,
134
+ ): FrameEntry | null {
135
+ let match: FrameEntry | null = null;
136
+ for (const frame of frames) {
137
+ if (excludeFileId && frame.id === excludeFileId) continue;
138
+ const { x, y, width, height } = frame.geometry;
139
+ if (
140
+ point.x >= x &&
141
+ point.x <= x + width &&
142
+ point.y >= y &&
143
+ point.y <= y + height
144
+ ) {
145
+ match = frame;
146
+ }
147
+ }
148
+ return match;
149
+ }
150
+
151
+ /**
152
+ * Figma's Shift+1 ("Zoom to fit") / Shift+2 ("Zoom to selection"): compute the
153
+ * real fit zoom + canvas offset for a set of frames within the given viewport
154
+ * size, via the shared `getCameraForBounds` fit-viewport math (already used
155
+ * nowhere else in this app — this is the first caller — so this is a thin
156
+ * wrapper that resolves the frame-entries-to-bounds step and clamps to the
157
+ * shared canvas zoom range). Returns null when there is nothing to fit
158
+ * (no frames, or a degenerate/zero-size viewport).
159
+ */
160
+ export function computeFitCameraForFrames(
161
+ frames: readonly FrameEntry[],
162
+ viewport: { width: number; height: number },
163
+ options?: { paddingScreenPx?: number },
164
+ ) {
165
+ if (frames.length === 0) return null;
166
+ if (viewport.width <= 0 || viewport.height <= 0) return null;
167
+ const bounds = getFrameGroupBounds(frames);
168
+ if (!bounds) return null;
169
+ return getCameraForBounds(bounds, viewport, {
170
+ paddingScreenPx: options?.paddingScreenPx ?? 64,
171
+ minZoom: DEFAULT_CANVAS_MIN_ZOOM,
172
+ maxZoom: DEFAULT_CANVAS_MAX_ZOOM,
173
+ fallbackZoom: 100,
174
+ });
175
+ }
176
+
177
+ export function getOverviewZoomScale(args: {
178
+ frameWidth: number | null | undefined;
179
+ sourceWidth: number | null | undefined;
180
+ }) {
181
+ const frameWidth =
182
+ typeof args.frameWidth === "number" && args.frameWidth > 0
183
+ ? args.frameWidth
184
+ : OVERVIEW_FRAME_WIDTH;
185
+ const sourceWidth =
186
+ typeof args.sourceWidth === "number" && args.sourceWidth > 0
187
+ ? args.sourceWidth
188
+ : 1280;
189
+ return frameWidth / sourceWidth;
190
+ }
191
+
192
+ export function getOverviewDisplayZoom(
193
+ canvasZoom: number,
194
+ overviewZoomScale: number,
195
+ ) {
196
+ const scale = overviewZoomScale > 0 ? overviewZoomScale : 1;
197
+ return canvasZoom * scale;
198
+ }
199
+
200
+ export function getOverviewCanvasZoom(
201
+ displayZoom: number,
202
+ overviewZoomScale: number,
203
+ ) {
204
+ const scale = overviewZoomScale > 0 ? overviewZoomScale : 1;
205
+ return displayZoom / scale;
206
+ }
207
+
208
+ export function getDefaultOverviewCanvasZoom(overviewZoomScale: number) {
209
+ return getOverviewCanvasZoom(DEFAULT_OVERVIEW_ZOOM, overviewZoomScale);
210
+ }
211
+
212
+ /**
213
+ * Board-zoom-corruption fix (observed in the wild as a 10241.49% displayed
214
+ * zoom): the overview zoom SCALE basis must always be a real overview screen.
215
+ * When `activeFileId` flips to the board file (creating a text primitive on
216
+ * the empty board, clicking a board element, …) or to any non-screen file
217
+ * (e.g. a CSS support file), the old `activeFile?.id ?? activeFileId ??
218
+ * overviewScreens[0]?.id` resolution made that file the basis: it has no
219
+ * entry in `overviewScreens` OR `canvasFrames`, so BOTH getOverviewZoomScale
220
+ * inputs fell back (320/1280 = 0.25) while `explicitOverviewCanvasZoom`
221
+ * stayed pinned to a value established under the real screen's scale —
222
+ * garbage displayed zoom. This helper only accepts a candidate that is a
223
+ * known overview screen (and never the board, even if a future
224
+ * `overviewScreens` regression let the board leak into the list), otherwise
225
+ * it falls back to the first real overview screen.
226
+ */
227
+ export function resolveOverviewZoomBasisScreenId(args: {
228
+ candidateFileId: string | null | undefined;
229
+ boardFileId: string | null | undefined;
230
+ overviewScreenIds: readonly string[];
231
+ }): string | null {
232
+ const boardId = args.boardFileId ?? null;
233
+ const candidate = args.candidateFileId ?? null;
234
+ if (
235
+ candidate &&
236
+ candidate !== boardId &&
237
+ args.overviewScreenIds.includes(candidate)
238
+ ) {
239
+ return candidate;
240
+ }
241
+ return (
242
+ args.overviewScreenIds.find((screenId) => screenId !== boardId) ?? null
243
+ );
244
+ }
245
+
246
+ /**
247
+ * Displayed overview zooms below this are unrenderable garbage, not a
248
+ * deliberate camera position — the wheel/pinch path can't legitimately reach
249
+ * them (MultiScreenCanvas clamps its canvas zoom well above the product of
250
+ * this with any real screen scale).
251
+ */
252
+ export const MIN_RENDERABLE_OVERVIEW_DISPLAY_ZOOM = 0.01;
253
+
254
+ /**
255
+ * Board-zoom-corruption fix, defensive layer: when the zoom-scale BASIS
256
+ * IDENTITY changes (a different screen becomes the basis), a pinned
257
+ * `explicitOverviewCanvasZoom` was established under the OLD basis' scale.
258
+ * A normal screen-to-screen basis change only shifts the displayed zoom
259
+ * label by the two screens' native-scale ratio (camera untouched) — that is
260
+ * intended Figma-like behavior and must NOT reset the camera. But if the new
261
+ * basis' scale turns the pinned value into a displayed zoom outside the
262
+ * editor's absolute zoom range (non-finite, unrenderably small, or above
263
+ * DEFAULT_CANVAS_MAX_ZOOM), the pin is provably garbage for this basis:
264
+ * invalidate it so the derivation re-anchors at the default overview zoom
265
+ * instead of showing a corrupted percentage.
266
+ */
267
+ export function shouldResetExplicitOverviewZoomOnBasisChange(args: {
268
+ previousBasisScreenId: string | null;
269
+ nextBasisScreenId: string | null;
270
+ explicitOverviewCanvasZoom: number | null;
271
+ nextOverviewZoomScale: number;
272
+ }): boolean {
273
+ if (args.explicitOverviewCanvasZoom === null) return false;
274
+ if (args.previousBasisScreenId === args.nextBasisScreenId) return false;
275
+ const nextDisplayZoom = getOverviewDisplayZoom(
276
+ args.explicitOverviewCanvasZoom,
277
+ args.nextOverviewZoomScale,
278
+ );
279
+ return (
280
+ !Number.isFinite(nextDisplayZoom) ||
281
+ nextDisplayZoom < MIN_RENDERABLE_OVERVIEW_DISPLAY_ZOOM ||
282
+ nextDisplayZoom > DEFAULT_CANVAS_MAX_ZOOM
283
+ );
284
+ }
285
+
286
+ /**
287
+ * Final sanity clamp on the DISPLAYED overview zoom (the number the zoom
288
+ * field shows and zoom-relative flows consume). Non-finite/non-positive
289
+ * products (a corrupted basis flip) fall back to the default overview zoom;
290
+ * anything above the editor's absolute max zoom is capped there. The lower
291
+ * bound is deliberately NOT floored to DEFAULT_CANVAS_MIN_ZOOM: a legit
292
+ * canvas zoom near the minimum times a sub-1 screen scale can display below
293
+ * 2% and must not be misreported (it would desync the displayed value from
294
+ * the real camera and drift zoom-relative round-trips).
295
+ */
296
+ export function clampOverviewDisplayZoom(displayZoom: number): number {
297
+ if (!Number.isFinite(displayZoom) || displayZoom <= 0) {
298
+ return DEFAULT_OVERVIEW_ZOOM;
299
+ }
300
+ return Math.min(displayZoom, DEFAULT_CANVAS_MAX_ZOOM);
301
+ }
302
+
303
+ export function resolveZoomUpdate(
304
+ update: SetStateAction<number>,
305
+ current: number,
306
+ ) {
307
+ return typeof update === "function" ? update(current) : update;
308
+ }
309
+
310
+ /**
311
+ * Figma-style zoom stepping: doubling/halving anchors relative to 100%
312
+ * (…6.25, 12.5, 25, 50, 100, 200, 400, 800…) instead of a small fixed preset
313
+ * list that stalls once it runs out of entries. Used by the keyboard/menu
314
+ * zoom in/out handlers so they never stop stepping above/below the old
315
+ * ZOOM_PRESETS bounds — clamped to the shared canvas zoom range so the
316
+ * result always matches what the wheel/pinch zoom path allows.
317
+ */
318
+ export function getNextZoomStepUp(
319
+ current: number,
320
+ { min = DEFAULT_CANVAS_MIN_ZOOM, max = DEFAULT_CANVAS_MAX_ZOOM } = {},
321
+ ): number {
322
+ if (!Number.isFinite(current) || current <= 0) return Math.min(100, max);
323
+ // Anchor exponent: how many doublings 100 * 2^n is from `current`. Round up
324
+ // (with a small epsilon so an exact anchor doesn't get skipped by float
325
+ // error) to find the next anchor strictly greater than current.
326
+ const exponent = Math.floor(Math.log2(current / 100) + 1e-9) + 1;
327
+ const next = 100 * Math.pow(2, exponent);
328
+ return clampZoom(next, min, max);
329
+ }
330
+
331
+ export function getNextZoomStepDown(
332
+ current: number,
333
+ { min = DEFAULT_CANVAS_MIN_ZOOM, max = DEFAULT_CANVAS_MAX_ZOOM } = {},
334
+ ): number {
335
+ if (!Number.isFinite(current) || current <= 0) return Math.max(100, min);
336
+ const exponent = Math.ceil(Math.log2(current / 100) - 1e-9) - 1;
337
+ const prev = 100 * Math.pow(2, exponent);
338
+ return clampZoom(prev, min, max);
339
+ }
340
+
341
+ export function clampZoom(
342
+ zoom: number,
343
+ min: number = DEFAULT_CANVAS_MIN_ZOOM,
344
+ max: number = DEFAULT_CANVAS_MAX_ZOOM,
345
+ ): number {
346
+ if (!Number.isFinite(zoom)) return min;
347
+ return Math.min(max, Math.max(min, zoom));
348
+ }
349
+
350
+ /**
351
+ * Camera-restore sanity ceiling (item 5): the shared canvas zoom range
352
+ * (DEFAULT_CANVAS_MIN_ZOOM..DEFAULT_CANVAS_MAX_ZOOM, up to 25600%) is sized
353
+ * for a deliberate "zoom in on this one selection" gesture, not for restoring
354
+ * a "where I left off" per-screen memory. A corrupted/degenerate remembered
355
+ * zoom (e.g. 1506%/3968%, observed in the field) is technically within that
356
+ * absolute range but re-entering a screen at it shows an unrecognizable
357
+ * close-up of whatever happens to sit at the scroll container's default
358
+ * (0,0) origin — effectively "lands on empty canvas" from the user's
359
+ * perspective, since single-screen mode has no separate persisted pan
360
+ * position to also restore in sync. Restoring a saner default here is this
361
+ * app's equivalent of a fit-all fallback.
362
+ */
363
+ export const MAX_SANE_SCREEN_ENTRY_ZOOM = 400;
364
+
365
+ /**
366
+ * Per-screen zoom memory: resolve which zoom `enterSingleScreen` should
367
+ * restore for a given target screen id. Looks up the screen's last-
368
+ * remembered zoom in the `screenZoomById` map (populated as the user zooms
369
+ * while a screen is focused); falls back to `defaultZoom` (FOCUSED_SCREEN_ZOOM
370
+ * in practice) for a screen's first visit, when no target id is known, or
371
+ * when the remembered value is missing/non-finite/outside the shared canvas
372
+ * zoom range, or so extreme (see MAX_SANE_SCREEN_ENTRY_ZOOM) that restoring it
373
+ * would show unrecognizable content instead of the screen the user expects.
374
+ * Pure/extracted so this lookup rule is unit-testable without mounting the
375
+ * full DesignEditor component.
376
+ */
377
+ export function resolveScreenEntryZoom(
378
+ targetFileId: string | null | undefined,
379
+ screenZoomById: ReadonlyMap<string, number>,
380
+ defaultZoom: number,
381
+ ): number {
382
+ if (!targetFileId) return defaultZoom;
383
+ const remembered = screenZoomById.get(targetFileId);
384
+ if (remembered === undefined) return defaultZoom;
385
+ if (!Number.isFinite(remembered) || remembered <= 0) return defaultZoom;
386
+ const clamped = clampZoom(remembered);
387
+ return clamped > MAX_SANE_SCREEN_ENTRY_ZOOM ? defaultZoom : clamped;
388
+ }
389
+
390
+ /**
391
+ * BP-DEEP v2 item 2 (full-view mode flicker) — the Figma-style "zoom far
392
+ * enough out of a focused screen and you pop back to the overview" heuristic
393
+ * must only fire when the user actually ZOOMS OUT ACROSS the threshold while
394
+ * already settled in single-screen view. The previous level-triggered check
395
+ * (`zoom < threshold` → pop) also fired on ENTRY: enterSingleScreen restores
396
+ * the screen's remembered zoom, and when that remembered value was below the
397
+ * threshold the editor flashed into full view for one frame and immediately
398
+ * bounced back to overview — Steve's "Full view flickers then bounces" bug.
399
+ * Edge-triggering on the previous observed single-view zoom means entry
400
+ * (previousZoom === null — the tracking ref resets whenever single view is
401
+ * left) can never bounce, and an entry that legitimately restores e.g. 30%
402
+ * stays a focused 30% view until the user crosses the threshold from above.
403
+ * Pure/extracted for unit tests.
404
+ */
405
+ export function shouldPopToOverviewOnZoomOut(args: {
406
+ /** Last zoom observed while ALREADY in single view; null right after
407
+ * entering single view (or when single view isn't active/edit-mode). */
408
+ previousZoom: number | null;
409
+ zoom: number;
410
+ threshold: number;
411
+ }): boolean {
412
+ if (!Number.isFinite(args.zoom)) return false;
413
+ if (args.zoom >= args.threshold) return false;
414
+ return args.previousZoom !== null && args.previousZoom >= args.threshold;
415
+ }
416
+
417
+ /**
418
+ * Fix-wave (zoom presets) — an explicit destination zoom (a "Zoom to
419
+ * 50/100/200%" menu preset, or a typed zoom-% commit) crosses
420
+ * OVERVIEW_ZOOM_THRESHOLD from above just as easily as a real zoom-out
421
+ * gesture does (e.g. the default single-view zoom is 100%, and "Zoom to 50%"
422
+ * lands under the 60% threshold) — `shouldPopToOverviewOnZoomOut` alone can't
423
+ * tell the two apart from the raw before/after zoom numbers. Callers that
424
+ * fire an explicit destination zoom mark the NEXT zoom-change observation as
425
+ * suppressed; this combines that one-shot flag with the edge-trigger check so
426
+ * "Zoom to 50%" always stays in single view regardless of the zoom it
427
+ * started from, while continuous zoom-out (scroll/pinch/the zoom-out button)
428
+ * is untouched and still pops at the threshold like Figma.
429
+ */
430
+ export function shouldPopToOverviewOnZoomChange(args: {
431
+ previousZoom: number | null;
432
+ zoom: number;
433
+ threshold: number;
434
+ suppressExplicitZoom: boolean;
435
+ }): boolean {
436
+ if (args.suppressExplicitZoom) return false;
437
+ return shouldPopToOverviewOnZoomOut(args);
438
+ }