@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
@@ -1,35 +1,285 @@
1
1
  import { defineAction } from "@agent-native/core";
2
2
  import { assertAccess } from "@agent-native/core/sharing";
3
- import { eq } from "drizzle-orm";
3
+ import { and, eq, isNull } from "drizzle-orm";
4
4
  import { z } from "zod";
5
5
 
6
6
  import { getDb, schema } from "../server/db/index.js";
7
7
 
8
- export default defineAction({
9
- description:
10
- "Update an existing design project. Requires editor access. " +
11
- "Only provided fields are updated; omitted fields are left unchanged.",
12
- schema: z.object({
13
- id: z.string().describe("Design ID"),
14
- title: z.string().optional().describe("New title"),
15
- description: z.string().optional().describe("New description"),
16
- data: z.string().optional().describe("Updated JSON string of design data"),
17
- projectType: z
18
- .enum(["prototype", "other"])
19
- .optional()
20
- .describe("Updated project type"),
21
- designSystemId: z
8
+ const MAX_DATA_CAS_ATTEMPTS = 5;
9
+ const MAX_DATA_OPERATION_SOURCES = 128;
10
+ const FORBIDDEN_DATA_PATH_SEGMENTS = new Set([
11
+ "__proto__",
12
+ "constructor",
13
+ "prototype",
14
+ ]);
15
+
16
+ const dataPathSchema = z
17
+ .array(
18
+ z
22
19
  .string()
23
20
  .min(1)
24
- .nullable()
25
- .optional()
26
- .describe("Design system ID to link, or null to unlink"),
21
+ .max(256)
22
+ .refine((segment) => !FORBIDDEN_DATA_PATH_SEGMENTS.has(segment), {
23
+ message: "Unsafe design data path segment",
24
+ }),
25
+ )
26
+ .min(1)
27
+ .max(8);
28
+
29
+ const dataOperationSchema = z.discriminatedUnion("op", [
30
+ z.object({
31
+ op: z.literal("set"),
32
+ path: dataPathSchema,
33
+ value: z.json(),
34
+ }),
35
+ z.object({
36
+ op: z.literal("delete"),
37
+ path: dataPathSchema,
27
38
  }),
39
+ ]);
40
+
41
+ type DataOperation = z.infer<typeof dataOperationSchema>;
42
+
43
+ type DataOperationRevisions = Record<string, number>;
44
+
45
+ /**
46
+ * Normalize affected-row metadata from every createGetDb backend: libSQL,
47
+ * PGlite, Neon, postgres.js, better-sqlite3, and D1.
48
+ */
49
+ function affectedRowCount(result: unknown): number | undefined {
50
+ const candidate = result as
51
+ | {
52
+ rowsAffected?: unknown;
53
+ affectedRows?: unknown;
54
+ rowCount?: unknown;
55
+ count?: unknown;
56
+ changes?: unknown;
57
+ meta?: { changes?: unknown };
58
+ }
59
+ | undefined;
60
+ const value =
61
+ candidate?.rowsAffected ??
62
+ candidate?.affectedRows ??
63
+ candidate?.rowCount ??
64
+ candidate?.count ??
65
+ candidate?.changes ??
66
+ candidate?.meta?.changes;
67
+ return typeof value === "number" ? value : undefined;
68
+ }
69
+
70
+ function isRecord(value: unknown): value is Record<string, unknown> {
71
+ return value !== null && typeof value === "object" && !Array.isArray(value);
72
+ }
73
+
74
+ function parsePersistedDataRecord(
75
+ designId: string,
76
+ raw: string | null | undefined,
77
+ ): Record<string, unknown> {
78
+ // Legacy rows may contain SQL NULL despite the current NOT NULL schema.
79
+ // Malformed/non-object non-null values are corruption, not an empty design:
80
+ // fail loud so a patch can never silently erase the unreadable payload.
81
+ if (raw == null) return {};
82
+ try {
83
+ const parsed = JSON.parse(raw);
84
+ if (isRecord(parsed)) return parsed;
85
+ } catch {
86
+ // The dedicated error below explains why the mutation is refused.
87
+ }
88
+ throw new Error(
89
+ `Design ${designId} has invalid data JSON. Refusing to overwrite it.`,
90
+ );
91
+ }
92
+
93
+ function parseDataOperationRevisions(
94
+ designId: string,
95
+ raw: string | null | undefined,
96
+ ): DataOperationRevisions {
97
+ if (raw == null || raw === "") return {};
98
+ try {
99
+ const parsed: unknown = JSON.parse(raw);
100
+ if (!isRecord(parsed)) throw new Error("not an object");
101
+ const revisions: DataOperationRevisions = {};
102
+ for (const [source, revision] of Object.entries(parsed)) {
103
+ if (
104
+ typeof revision !== "number" ||
105
+ !Number.isSafeInteger(revision) ||
106
+ revision < 0
107
+ ) {
108
+ throw new Error("invalid revision");
109
+ }
110
+ revisions[source] = revision;
111
+ }
112
+ return revisions;
113
+ } catch {
114
+ throw new Error(
115
+ `Design ${designId} has invalid data operation revisions. Refusing an unordered write.`,
116
+ );
117
+ }
118
+ }
119
+
120
+ function withDataOperationRevision(
121
+ revisions: DataOperationRevisions,
122
+ source: string,
123
+ revision: number,
124
+ ): DataOperationRevisions {
125
+ const next = { ...revisions };
126
+ // Refresh insertion order for the active source so the bounded record keeps
127
+ // recently active tabs and evicts abandoned sessions first.
128
+ delete next[source];
129
+ next[source] = revision;
130
+ while (Object.keys(next).length > MAX_DATA_OPERATION_SOURCES) {
131
+ const oldest = Object.keys(next)[0];
132
+ if (oldest === undefined) break;
133
+ delete next[oldest];
134
+ }
135
+ return next;
136
+ }
137
+
138
+ /**
139
+ * Apply path-addressed map operations without mutating the parsed source.
140
+ *
141
+ * This is intentionally not a generic recursive merge. A missing key can mean
142
+ * either "the caller read before a peer added it" or "delete this key", so
143
+ * inferring deletion from omission would resurrect or erase frames. Explicit
144
+ * set/delete operations keep both intents unambiguous and CAS-retryable.
145
+ */
146
+ function applyDataOperations(
147
+ designId: string,
148
+ raw: string | null | undefined,
149
+ operations: DataOperation[],
150
+ ): string {
151
+ const root: Record<string, unknown> = {
152
+ ...parsePersistedDataRecord(designId, raw),
153
+ };
154
+
155
+ for (const operation of operations) {
156
+ let target: Record<string, unknown> = root;
157
+ let missingDeleteParent = false;
158
+ const parentPath = operation.path.slice(0, -1);
159
+ for (const segment of parentPath) {
160
+ const value = target[segment];
161
+ if (value === undefined) {
162
+ if (operation.op === "delete") {
163
+ missingDeleteParent = true;
164
+ break;
165
+ }
166
+ const next: Record<string, unknown> = {};
167
+ target[segment] = next;
168
+ target = next;
169
+ continue;
170
+ }
171
+ if (!isRecord(value)) {
172
+ throw new Error(
173
+ `Cannot apply design data operation through non-object path "${operation.path.join(".")}".`,
174
+ );
175
+ }
176
+ const cloned = { ...value };
177
+ target[segment] = cloned;
178
+ target = cloned;
179
+ }
180
+ if (missingDeleteParent) continue;
181
+
182
+ const leaf = operation.path[operation.path.length - 1]!;
183
+ if (operation.op === "delete") {
184
+ delete target[leaf];
185
+ } else {
186
+ target[leaf] = operation.value;
187
+ }
188
+ }
189
+
190
+ return JSON.stringify(root);
191
+ }
192
+
193
+ export default defineAction({
194
+ description:
195
+ "Update an existing design project. Requires editor access. " +
196
+ "Only provided fields are updated; omitted fields are left unchanged. " +
197
+ "For map entries such as canvasFrames, use dataOperations " +
198
+ "with explicit set/delete paths instead of a full data snapshot.",
199
+ schema: z
200
+ .object({
201
+ id: z.string().describe("Design ID"),
202
+ title: z.string().optional().describe("New title"),
203
+ description: z.string().optional().describe("New description"),
204
+ data: z
205
+ .string()
206
+ .optional()
207
+ .describe(
208
+ "Legacy partial JSON object snapshot. Concurrent conflicting snapshots are rejected; use dataOperations for map entries.",
209
+ ),
210
+ dataOperations: z
211
+ .array(dataOperationSchema)
212
+ .min(1)
213
+ .max(500)
214
+ .optional()
215
+ .describe(
216
+ "Atomic path-addressed set/delete operations for design data. Safe to CAS-retry across concurrent writers.",
217
+ ),
218
+ operationSource: z
219
+ .string()
220
+ .trim()
221
+ .min(1)
222
+ .max(128)
223
+ .optional()
224
+ .describe(
225
+ "Stable client-session id used with operationRevision to reject late out-of-order writes.",
226
+ ),
227
+ operationRevision: z
228
+ .number()
229
+ .int()
230
+ .nonnegative()
231
+ .max(Number.MAX_SAFE_INTEGER)
232
+ .optional()
233
+ .describe(
234
+ "Monotonic sequence for operationSource. Stale or duplicate revisions are successful no-ops.",
235
+ ),
236
+ projectType: z
237
+ .enum(["prototype", "other"])
238
+ .optional()
239
+ .describe("Updated project type"),
240
+ designSystemId: z
241
+ .string()
242
+ .min(1)
243
+ .nullable()
244
+ .optional()
245
+ .describe("Design system ID to link, or null to unlink"),
246
+ })
247
+ .refine(
248
+ ({ data, dataOperations }) =>
249
+ data === undefined || dataOperations === undefined,
250
+ {
251
+ message: "Provide either data or dataOperations, not both.",
252
+ path: ["dataOperations"],
253
+ },
254
+ )
255
+ .superRefine((value, context) => {
256
+ const hasSource = value.operationSource !== undefined;
257
+ const hasRevision = value.operationRevision !== undefined;
258
+ if (hasSource !== hasRevision) {
259
+ context.addIssue({
260
+ code: "custom",
261
+ path: hasSource ? ["operationRevision"] : ["operationSource"],
262
+ message:
263
+ "operationSource and operationRevision must be provided together.",
264
+ });
265
+ }
266
+ if ((hasSource || hasRevision) && !value.dataOperations) {
267
+ context.addIssue({
268
+ code: "custom",
269
+ path: ["dataOperations"],
270
+ message:
271
+ "operationSource and operationRevision require dataOperations.",
272
+ });
273
+ }
274
+ }),
28
275
  run: async ({
29
276
  id,
30
277
  title,
31
278
  description,
32
279
  data,
280
+ dataOperations,
281
+ operationSource,
282
+ operationRevision,
33
283
  projectType,
34
284
  designSystemId,
35
285
  }) => {
@@ -47,57 +297,122 @@ export default defineAction({
47
297
  }
48
298
 
49
299
  const db = getDb();
50
- const now = new Date().toISOString();
51
300
 
52
- const asRecord = (raw: string | null | undefined) => {
53
- if (!raw) return {} as Record<string, unknown>;
54
- try {
55
- const parsed = JSON.parse(raw);
56
- return parsed && typeof parsed === "object" && !Array.isArray(parsed)
57
- ? (parsed as Record<string, unknown>)
58
- : ({} as Record<string, unknown>);
59
- } catch {
60
- return {} as Record<string, unknown>;
61
- }
62
- };
63
-
64
- // Read-merge-write inside one transaction so a partial `data` update can't
65
- // race a concurrent write and either destroy framework-owned keys (e.g.
66
- // canvasFrames/tweaks) or overwrite newer server-side keys. Mirrors
67
- // generate-design's transactional read-merge.
68
- await db.transaction(async (tx) => {
69
- const updates: Record<string, unknown> = { updatedAt: now };
301
+ const staticUpdates = (): Record<string, unknown> => {
302
+ const updates: Record<string, unknown> = {
303
+ updatedAt: new Date().toISOString(),
304
+ };
70
305
  if (title !== undefined) updates.title = title;
71
306
  if (description !== undefined) updates.description = description;
72
- if (data !== undefined) {
73
- const [existing] = await tx
74
- .select({ data: schema.designs.data })
75
- .from(schema.designs)
76
- .where(eq(schema.designs.id, id));
77
- const incomingParsed = JSON.parse(data);
78
- if (
79
- incomingParsed &&
80
- typeof incomingParsed === "object" &&
81
- !Array.isArray(incomingParsed)
82
- ) {
83
- updates.data = JSON.stringify({
84
- ...asRecord(existing?.data),
85
- ...(incomingParsed as Record<string, unknown>),
86
- });
87
- } else {
88
- // Non-object JSON (array/primitive): keep the original verbatim write.
89
- updates.data = data;
90
- }
91
- }
92
307
  if (projectType !== undefined) updates.projectType = projectType;
93
308
  if (designSystemId !== undefined) updates.designSystemId = designSystemId;
309
+ return updates;
310
+ };
94
311
 
95
- await tx
312
+ if (data === undefined && dataOperations === undefined) {
313
+ await db
96
314
  .update(schema.designs)
97
- .set(updates)
315
+ .set(staticUpdates())
316
+ .where(eq(schema.designs.id, id));
317
+ return { id, updated: true };
318
+ }
319
+
320
+ const maxAttempts = dataOperations ? MAX_DATA_CAS_ATTEMPTS : 1;
321
+ for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
322
+ const [existing] = await db
323
+ .select({
324
+ data: schema.designs.data,
325
+ dataOperationRevisions: schema.designs.dataOperationRevisions,
326
+ })
327
+ .from(schema.designs)
98
328
  .where(eq(schema.designs.id, id));
99
- });
329
+ if (!existing) {
330
+ throw new Error(`Design not found: ${id}`);
331
+ }
100
332
 
101
- return { id, updated: true };
333
+ let nextData: string;
334
+ let nextOperationRevisions: string | undefined;
335
+ if (dataOperations) {
336
+ if (operationSource !== undefined && operationRevision !== undefined) {
337
+ const revisions = parseDataOperationRevisions(
338
+ id,
339
+ existing.dataOperationRevisions,
340
+ );
341
+ if ((revisions[operationSource] ?? -1) >= operationRevision) {
342
+ return { id, updated: true, stale: true };
343
+ }
344
+ nextOperationRevisions = JSON.stringify(
345
+ withDataOperationRevision(
346
+ revisions,
347
+ operationSource,
348
+ operationRevision,
349
+ ),
350
+ );
351
+ }
352
+ nextData = applyDataOperations(id, existing.data, dataOperations);
353
+ } else {
354
+ const incomingParsed = JSON.parse(data!);
355
+ nextData = isRecord(incomingParsed)
356
+ ? JSON.stringify({
357
+ ...parsePersistedDataRecord(id, existing.data),
358
+ ...incomingParsed,
359
+ })
360
+ : data!;
361
+ }
362
+
363
+ // Compare-and-swap on the exact data snapshot. Transactions at the
364
+ // default isolation level do not make a read-merge-write safe: two
365
+ // transactions can both read the same JSON and the later UPDATE can
366
+ // overwrite the first. Explicit operations are safe to re-apply to the
367
+ // latest row; a legacy full snapshot is ambiguous, so a conflict fails
368
+ // loud instead of guessing whether missing nested keys mean stale data
369
+ // or intentional deletion.
370
+ const revisionCondition =
371
+ operationSource !== undefined
372
+ ? existing.dataOperationRevisions == null
373
+ ? isNull(schema.designs.dataOperationRevisions)
374
+ : eq(
375
+ schema.designs.dataOperationRevisions,
376
+ existing.dataOperationRevisions,
377
+ )
378
+ : undefined;
379
+ const updateResult = await db
380
+ .update(schema.designs)
381
+ .set({
382
+ ...staticUpdates(),
383
+ data: nextData,
384
+ ...(nextOperationRevisions === undefined
385
+ ? {}
386
+ : { dataOperationRevisions: nextOperationRevisions }),
387
+ })
388
+ .where(
389
+ and(
390
+ eq(schema.designs.id, id),
391
+ existing.data == null
392
+ ? isNull(schema.designs.data)
393
+ : eq(schema.designs.data, existing.data),
394
+ ...(revisionCondition ? [revisionCondition] : []),
395
+ ),
396
+ );
397
+ const affected = affectedRowCount(updateResult);
398
+ if (affected === undefined) {
399
+ throw new Error(
400
+ "The database driver did not report an affected-row count for the design data update.",
401
+ );
402
+ }
403
+
404
+ if (affected > 0) {
405
+ return { id, updated: true };
406
+ }
407
+ }
408
+
409
+ if (dataOperations) {
410
+ throw new Error(
411
+ `Could not update design ${id} after ${MAX_DATA_CAS_ATTEMPTS} concurrent attempts. Re-read the design and retry.`,
412
+ );
413
+ }
414
+ throw new Error(
415
+ "Design data changed while this snapshot was being saved. Re-read the design and retry, or use dataOperations for path-addressed map edits.",
416
+ );
102
417
  },
103
418
  });