@agent-native/core 0.90.1 → 0.90.2

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 +14 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/client/AgentPanel.tsx +1 -1
  5. package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +11 -6
  6. package/corpus/core/src/client/use-action.ts +39 -2
  7. package/corpus/core/src/client/use-db-sync.ts +44 -18
  8. package/corpus/core/src/db/create-get-db.ts +32 -2
  9. package/corpus/core/src/server/framework-request-handler.ts +52 -4
  10. package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +5 -0
  11. package/corpus/templates/assets/.agents/skills/logo-composite/SKILL.md +34 -6
  12. package/corpus/templates/assets/AGENTS.md +23 -4
  13. package/corpus/templates/assets/actions/_generation-preset-settings.ts +48 -0
  14. package/corpus/templates/assets/actions/_helpers.ts +8 -1
  15. package/corpus/templates/assets/actions/_preset-skeleton-validation.ts +64 -0
  16. package/corpus/templates/assets/actions/create-generation-preset.ts +11 -3
  17. package/corpus/templates/assets/actions/generate-image-batch.ts +7 -2
  18. package/corpus/templates/assets/actions/generate-image.ts +342 -25
  19. package/corpus/templates/assets/actions/get-library.ts +4 -3
  20. package/corpus/templates/assets/actions/navigate.ts +2 -1
  21. package/corpus/templates/assets/actions/refresh-generation-run.ts +5 -1
  22. package/corpus/templates/assets/actions/update-asset.ts +1 -0
  23. package/corpus/templates/assets/actions/update-generation-preset.ts +8 -1
  24. package/corpus/templates/assets/actions/view-screen.ts +8 -1
  25. package/corpus/templates/assets/app/components/generation/GenerationResults.tsx +9 -1
  26. package/corpus/templates/assets/app/hooks/use-image-model-menu.ts +1 -0
  27. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +11 -0
  28. package/corpus/templates/assets/app/i18n/zh-TW.ts +64 -0
  29. package/corpus/templates/assets/app/i18n-data.ts +650 -0
  30. package/corpus/templates/assets/app/routes/asset.$id.tsx +2 -1
  31. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +44 -33
  32. package/corpus/templates/assets/app/routes/brand-kits.$id_.presets.$presetId.tsx +1474 -0
  33. package/corpus/templates/assets/app/routes/library.tsx +43 -1
  34. package/corpus/templates/assets/server/lib/generation.ts +366 -44
  35. package/corpus/templates/assets/server/lib/image-processing.ts +252 -0
  36. package/corpus/templates/assets/server/lib/preset-skeleton.ts +137 -0
  37. package/corpus/templates/assets/shared/api.ts +47 -0
  38. package/corpus/templates/clips/app/components/library/library-layout.tsx +7 -2
  39. package/corpus/templates/clips/app/components/library/sort-menu.tsx +1 -1
  40. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +114 -33
  41. package/corpus/templates/clips/app/routes/_app.library._index.tsx +27 -1
  42. package/corpus/templates/clips/app/routes/record.tsx +157 -68
  43. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +5 -5
  44. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +20 -3
  45. package/corpus/templates/clips/shared/finalize-recovery.ts +23 -3
  46. package/corpus/templates/content/AGENTS.md +52 -52
  47. package/corpus/templates/content/actions/_builder-cms-read-client.ts +188 -8
  48. package/corpus/templates/content/actions/_builder-docs-client.ts +41 -3
  49. package/corpus/templates/content/actions/_database-source-utils.ts +998 -160
  50. package/corpus/templates/content/actions/_database-utils.ts +44 -4
  51. package/corpus/templates/content/actions/_notion-action-utils.ts +6 -2
  52. package/corpus/templates/content/actions/add-content-database-source-field-property.ts +23 -1
  53. package/corpus/templates/content/actions/attach-content-database-source.ts +85 -12
  54. package/corpus/templates/content/actions/change-content-database-source-role.ts +9 -1
  55. package/corpus/templates/content/actions/delete-content-database.ts +1 -0
  56. package/corpus/templates/content/actions/get-document.ts +11 -2
  57. package/corpus/templates/content/actions/list-content-databases.ts +57 -9
  58. package/corpus/templates/content/actions/prepare-builder-source-review.ts +23 -6
  59. package/corpus/templates/content/actions/refresh-content-database-source.ts +26 -3
  60. package/corpus/templates/content/actions/restore-content-database.ts +1 -0
  61. package/corpus/templates/content/actions/update-document.ts +43 -0
  62. package/corpus/templates/content/app/components/editor/BuilderBodySyncingNotice.tsx +21 -0
  63. package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +0 -1
  64. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +70 -28
  65. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +69 -17
  66. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +4 -4
  67. package/corpus/templates/content/app/components/editor/body-hydration.ts +112 -0
  68. package/corpus/templates/content/app/components/editor/builder-body-hydration-pump.ts +52 -0
  69. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +9076 -2876
  70. package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +41 -1
  71. package/corpus/templates/content/app/components/editor/extensions/ImageBlock.tsx +36 -11
  72. package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +21 -1
  73. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +11 -1
  74. package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +11 -8
  75. package/corpus/templates/content/app/global.css +41 -0
  76. package/corpus/templates/content/app/hooks/use-content-database.ts +346 -42
  77. package/corpus/templates/content/app/hooks/use-db-sync.ts +9 -0
  78. package/corpus/templates/content/app/hooks/use-documents.ts +47 -0
  79. package/corpus/templates/content/app/hooks/use-notion.ts +12 -10
  80. package/corpus/templates/content/app/i18n/zh-TW.ts +35 -0
  81. package/corpus/templates/content/app/i18n-data.ts +355 -0
  82. package/corpus/templates/content/app/root.tsx +22 -0
  83. package/corpus/templates/content/changelog/2026-07-01-builder-database-sources-keep-loading-rows-in-the-background.md +6 -0
  84. package/corpus/templates/content/changelog/2026-07-01-builder-source-attach-starts-with-usable-rows.md +6 -0
  85. package/corpus/templates/content/changelog/2026-07-01-builder-source-attachment-now-stays-connected-after-large.md +6 -0
  86. package/corpus/templates/content/changelog/2026-07-01-builder-source-refreshes-now-show-progress-for-large-docs-blog.md +6 -0
  87. package/corpus/templates/content/changelog/2026-07-01-database-pages-now-delete-to-trash-without-route-errors.md +6 -0
  88. package/corpus/templates/content/changelog/2026-07-02-builder-source-refreshes-recover-from-stalled-background-row.md +6 -0
  89. package/corpus/templates/content/changelog/2026-07-02-builder-sourced-rows-open-with-sync-protection.md +6 -0
  90. package/corpus/templates/content/changelog/2026-07-02-database-rows-and-pages-open-faster-from-recently-loaded-dat.md +6 -0
  91. package/corpus/templates/content/changelog/2026-07-02-preview-panels-close-reliably-narrow-sidebar-row-actions-sta.md +6 -0
  92. package/corpus/templates/content/changelog/2026-07-06-builder-sync-progress-no-longer-shows-continue.md +6 -0
  93. package/corpus/templates/content/shared/api.ts +13 -0
  94. package/corpus/templates/content/shared/builder-mdx.ts +16 -3
  95. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +23 -13
  96. package/corpus/templates/design/.agents/skills/responsive-breakpoints/SKILL.md +98 -0
  97. package/corpus/templates/design/.agents/skills/shader-fills/SKILL.md +162 -0
  98. package/corpus/templates/design/AGENTS.md +9 -2
  99. package/corpus/templates/design/actions/add-breakpoint.ts +6 -3
  100. package/corpus/templates/design/actions/apply-a11y-fix.ts +57 -37
  101. package/corpus/templates/design/actions/apply-component-prop-edit.ts +41 -20
  102. package/corpus/templates/design/actions/apply-motion-edit.ts +251 -38
  103. package/corpus/templates/design/actions/apply-shader-fill.ts +90 -66
  104. package/corpus/templates/design/actions/apply-visual-edit.ts +282 -55
  105. package/corpus/templates/design/actions/create-component.ts +29 -60
  106. package/corpus/templates/design/actions/create-file.ts +9 -2
  107. package/corpus/templates/design/actions/duplicate-design.ts +31 -2
  108. package/corpus/templates/design/actions/edit-design.ts +36 -38
  109. package/corpus/templates/design/actions/generate-design-title.ts +87 -0
  110. package/corpus/templates/design/actions/generate-design.ts +53 -18
  111. package/corpus/templates/design/actions/generate-screens.ts +108 -4
  112. package/corpus/templates/design/actions/get-motion-timeline.ts +35 -7
  113. package/corpus/templates/design/actions/insert-asset.ts +34 -29
  114. package/corpus/templates/design/actions/insert-design-native-asset.ts +129 -32
  115. package/corpus/templates/design/actions/insert-figma-library-asset.ts +35 -30
  116. package/corpus/templates/design/actions/present-design-variants.ts +7 -2
  117. package/corpus/templates/design/actions/remove-motion-timeline.ts +31 -36
  118. package/corpus/templates/design/actions/update-file.ts +190 -75
  119. package/corpus/templates/design/app/components/design/BreakpointBar.tsx +403 -0
  120. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +469 -222
  121. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +708 -53
  122. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +83 -3
  123. package/corpus/templates/design/app/components/design/EditPanel.tsx +1091 -6948
  124. package/corpus/templates/design/app/components/design/LayersPanel.tsx +419 -85
  125. package/corpus/templates/design/app/components/design/MotionDock.tsx +1124 -103
  126. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +2610 -1398
  127. package/corpus/templates/design/app/components/design/ReadOnlyDesignBanner.tsx +22 -0
  128. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +2182 -235
  129. package/corpus/templates/design/app/components/design/bridge/motion-preview.bridge.ts +187 -11
  130. package/corpus/templates/design/app/components/design/bridge/shader-fill-preview.bridge.ts +376 -1
  131. package/corpus/templates/design/app/components/design/bridge/shader-runtime.bridge.ts +746 -0
  132. package/corpus/templates/design/app/components/design/canvas-primitive-style.ts +17 -0
  133. package/corpus/templates/design/app/components/design/code-workbench/SideBar.tsx +1 -1
  134. package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +1 -3
  135. package/corpus/templates/design/app/components/design/code-workbench/quickinput/QuickInput.tsx +1 -1
  136. package/corpus/templates/design/app/components/design/edit-panel/appearance-properties.tsx +518 -0
  137. package/corpus/templates/design/app/components/design/edit-panel/code-inspect-helpers.tsx +562 -0
  138. package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +763 -0
  139. package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +94 -0
  140. package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +780 -0
  141. package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +446 -0
  142. package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +79 -0
  143. package/corpus/templates/design/app/components/design/edit-panel/field-primitives.tsx +315 -0
  144. package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +344 -0
  145. package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +594 -0
  146. package/corpus/templates/design/app/components/design/edit-panel/frame-presets-panel.tsx +119 -0
  147. package/corpus/templates/design/app/components/design/edit-panel/inspector-controls.tsx +248 -0
  148. package/corpus/templates/design/app/components/design/edit-panel/interaction-state-helpers.ts +45 -0
  149. package/corpus/templates/design/app/components/design/edit-panel/layout-properties.tsx +693 -0
  150. package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +724 -0
  151. package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +207 -0
  152. package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +628 -0
  153. package/corpus/templates/design/app/components/design/edit-panel/selection-helpers.ts +91 -0
  154. package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +649 -0
  155. package/corpus/templates/design/app/components/design/edit-panel/style-change-types.ts +118 -0
  156. package/corpus/templates/design/app/components/design/edit-panel/style-options.ts +88 -0
  157. package/corpus/templates/design/app/components/design/edit-panel/transform-helpers.ts +100 -0
  158. package/corpus/templates/design/app/components/design/edit-panel/typography-helpers.ts +117 -0
  159. package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +501 -0
  160. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +91 -40
  161. package/corpus/templates/design/app/components/design/inspector/BreakpointOverrideIndicator.tsx +82 -0
  162. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +189 -87
  163. package/corpus/templates/design/app/components/design/inspector/GlslShaderPanel.tsx +1097 -0
  164. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +44 -0
  165. package/corpus/templates/design/app/components/design/inspector/InteractionStatePanel.tsx +258 -0
  166. package/corpus/templates/design/app/components/design/inspector/MotionKeyframeDiamond.tsx +144 -0
  167. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +99 -9
  168. package/corpus/templates/design/app/components/design/inspector/frame-size-presets.ts +116 -0
  169. package/corpus/templates/design/app/components/design/inspector/index.ts +26 -0
  170. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +29 -0
  171. package/corpus/templates/design/app/components/design/multi-screen/alt-hover-measurement.ts +171 -0
  172. package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +220 -0
  173. package/corpus/templates/design/app/components/design/multi-screen/chrome-transitions.ts +35 -0
  174. package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +134 -0
  175. package/corpus/templates/design/app/components/design/multi-screen/culling.ts +185 -0
  176. package/corpus/templates/design/app/components/design/multi-screen/gradient-overlay-geometry.ts +120 -0
  177. package/corpus/templates/design/app/components/design/multi-screen/types.ts +892 -0
  178. package/corpus/templates/design/app/components/design/multi-screen/vector-edit-geometry.ts +21 -0
  179. package/corpus/templates/design/app/components/design/types.ts +15 -0
  180. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +109 -5
  181. package/corpus/templates/design/app/global.css +8 -8
  182. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +259 -2
  183. package/corpus/templates/design/app/i18n/zh-TW.ts +163 -9
  184. package/corpus/templates/design/app/i18n-breakpoints.ts +205 -0
  185. package/corpus/templates/design/app/i18n-data.ts +1664 -152
  186. package/corpus/templates/design/app/i18n-motion.ts +563 -0
  187. package/corpus/templates/design/app/lib/design-import.ts +73 -0
  188. package/corpus/templates/design/app/pages/Index.tsx +41 -22
  189. package/corpus/templates/design/changelog/2026-06-29-design-inspector-controls-now-match-figmas-softer-dark-chrome.md +1 -1
  190. package/corpus/templates/design/changelog/2026-06-30-design-now-has-a-figma-style-left-rail-for-file-agent-assets.md +1 -1
  191. package/corpus/templates/design/changelog/2026-06-30-design-tools-now-use-a-quieter-figma-style-list-layout.md +1 -1
  192. package/corpus/templates/design/changelog/2026-06-30-multi-select-outlines-now-stay-consistent-across-all-screens.md +1 -1
  193. package/corpus/templates/design/changelog/2026-07-03-canvas-interactions-now-match-figma-rotation-aware-resizing-.md +1 -1
  194. package/corpus/templates/design/changelog/2026-07-03-layers-panel-matches-figma-top-layer-on-top-drag-with-auto-s.md +1 -1
  195. package/corpus/templates/design/changelog/2026-07-05-designs-get-ai-generated-names-from-your-prompt.md +6 -0
  196. package/corpus/templates/design/changelog/2026-07-05-local-code-screens-keep-their-connection-when-duplicated-and.md +6 -0
  197. package/corpus/templates/design/changelog/2026-07-05-press-a-to-draw-screens-on-the-canvas-inside-a-screen-it-dr.md +6 -0
  198. package/corpus/templates/design/changelog/2026-07-06-3d-rotation-and-perspective-controls-on-every-element.md +6 -0
  199. package/corpus/templates/design/changelog/2026-07-06-ai-generated-and-duplicated-screens-now-get-their-editor-sel.md +6 -0
  200. package/corpus/templates/design/changelog/2026-07-06-applying-shaders-and-fills-in-quick-succession-can-no-longer.md +6 -0
  201. package/corpus/templates/design/changelog/2026-07-06-breakpoint-frames-in-the-overview-now-support-click-to-selec.md +6 -0
  202. package/corpus/templates/design/changelog/2026-07-06-breakpoint-segments-in-the-inspector-now-show-a-device-icon-.md +6 -0
  203. package/corpus/templates/design/changelog/2026-07-06-breakpoint-targeting-now-lives-in-one-compact-control-in-the.md +6 -0
  204. package/corpus/templates/design/changelog/2026-07-06-canvas-edits-can-no-longer-be-overwritten-by-stale-collabora.md +6 -0
  205. package/corpus/templates/design/changelog/2026-07-06-canvas-edits-inside-screens-save-reliably-again.md +6 -0
  206. package/corpus/templates/design/changelog/2026-07-06-cleaner-inspector-removed-the-ask-ai-box-from-the-design-tab.md +6 -0
  207. package/corpus/templates/design/changelog/2026-07-06-clicking-empty-canvas-space-now-deselects-an-element-inside-.md +6 -0
  208. package/corpus/templates/design/changelog/2026-07-06-dragging-an-element-onto-a-rectangle-now-nests-it-inside-wit.md +6 -0
  209. package/corpus/templates/design/changelog/2026-07-06-dragging-screens-and-objects-on-the-canvas-is-now-much-smoot.md +6 -0
  210. package/corpus/templates/design/changelog/2026-07-06-drawing-a-shape-or-text-on-the-canvas-no-longer-flashes-away.md +6 -0
  211. package/corpus/templates/design/changelog/2026-07-06-dropping-an-element-between-two-others-inside-a-screen-now-s.md +6 -0
  212. package/corpus/templates/design/changelog/2026-07-06-duplicating-a-screen-now-places-the-copy-exactly-where-you-d.md +6 -0
  213. package/corpus/templates/design/changelog/2026-07-06-edit-gradients-directly-on-elements-inside-screens-scale-str.md +6 -0
  214. package/corpus/templates/design/changelog/2026-07-06-edits-from-collaborators-and-the-agent-now-update-the-canvas.md +6 -0
  215. package/corpus/templates/design/changelog/2026-07-06-fixed-a-bug-where-most-style-position-and-text-edits-briefly.md +6 -0
  216. package/corpus/templates/design/changelog/2026-07-06-fixed-a-confusing-raw-error-message-when-a-file-upload-fails.md +6 -0
  217. package/corpus/templates/design/changelog/2026-07-06-fixed-a-rare-case-where-an-edit-could-be-silently-overwritte.md +6 -0
  218. package/corpus/templates/design/changelog/2026-07-06-fixed-inserted-assets-sometimes-disappearing-reappearing-or-.md +6 -0
  219. package/corpus/templates/design/changelog/2026-07-06-fixed-inspector-value-scrubbing-producing-erratic-numbers-an.md +6 -0
  220. package/corpus/templates/design/changelog/2026-07-06-fixed-padding-gap-and-min-max-size-scrubbing-not-updating-th.md +6 -0
  221. package/corpus/templates/design/changelog/2026-07-06-fixed-text-stroke-color-turning-black-and-glyphs-disappearin.md +6 -0
  222. package/corpus/templates/design/changelog/2026-07-06-fixed-the-collapsed-effects-and-stroke-inspector-sections-sh.md +6 -0
  223. package/corpus/templates/design/changelog/2026-07-06-fixed-the-new-design-dialog-closing-unexpectedly-when-using-.md +6 -0
  224. package/corpus/templates/design/changelog/2026-07-06-fixed-the-typography-section-missing-when-selecting-text-nes.md +6 -0
  225. package/corpus/templates/design/changelog/2026-07-06-full-view-no-longer-flashes-back-to-the-overview-on-entry-no.md +6 -0
  226. package/corpus/templates/design/changelog/2026-07-06-keyframe-animation-timeline-per-property-keyframes-easing-cu.md +6 -0
  227. package/corpus/templates/design/changelog/2026-07-06-moving-restyling-and-scrubbing-values-on-elements-in-ai-gene.md +6 -0
  228. package/corpus/templates/design/changelog/2026-07-06-padding-and-corner-radius-value-scrubbing-now-snaps-to-whole.md +6 -0
  229. package/corpus/templates/design/changelog/2026-07-06-padding-handles-now-only-resize-on-the-handle-line-itself-sh.md +6 -0
  230. package/corpus/templates/design/changelog/2026-07-06-preview-and-edit-hover-focus-and-pressed-states-with-real-cs.md +6 -0
  231. package/corpus/templates/design/changelog/2026-07-06-promoting-an-element-to-a-component-now-works-correctly-for-.md +6 -0
  232. package/corpus/templates/design/changelog/2026-07-06-reduced-url-history-churn-and-selection-overlay-flicker-whil.md +6 -0
  233. package/corpus/templates/design/changelog/2026-07-06-removed-the-decorative-dot-before-screen-names-in-the-overvi.md +6 -0
  234. package/corpus/templates/design/changelog/2026-07-06-responsive-breakpoints-edit-at-any-width-with-cascading-over.md +6 -0
  235. package/corpus/templates/design/changelog/2026-07-06-screen-labels-no-longer-turn-blue-when-you-hover-inside-the-.md +6 -0
  236. package/corpus/templates/design/changelog/2026-07-06-scrolling-a-screen-with-an-element-selected-stays-smooth-on-.md +6 -0
  237. package/corpus/templates/design/changelog/2026-07-06-selecting-multiple-elements-and-dragging-now-moves-the-whole.md +6 -0
  238. package/corpus/templates/design/changelog/2026-07-06-selection-borders-handles-and-value-readouts-now-stay-the-sa.md +6 -0
  239. package/corpus/templates/design/changelog/2026-07-06-selection-handles-and-editing-chrome-now-stay-a-constant-siz.md +6 -0
  240. package/corpus/templates/design/changelog/2026-07-06-shader-fills-and-effects-ai-authored-or-preset-glsl-shaders-.md +6 -0
  241. package/corpus/templates/design/changelog/2026-07-06-text-drawn-on-the-canvas-now-defaults-to-white-and-inter-in-.md +6 -0
  242. package/corpus/templates/design/changelog/2026-07-06-text-dropped-into-a-shape-now-stays-readable-instead-of-disa.md +6 -0
  243. package/corpus/templates/design/changelog/2026-07-06-the-add-tweak-controls-prompt-no-longer-jumps-to-the-corner-.md +6 -0
  244. package/corpus/templates/design/changelog/2026-07-06-the-padding-value-readout-now-stays-visible-while-you-hover-.md +6 -0
  245. package/corpus/templates/design/changelog/2026-07-06-the-selected-element-attachment-now-clears-from-the-chat-com.md +6 -0
  246. package/corpus/templates/design/changelog/2026-07-06-the-zoom-menu-is-more-compact-with-tight-rows-and-right-alig.md +6 -0
  247. package/corpus/templates/design/changelog/2026-07-06-undo-and-redo-no-longer-flash-the-screen-changes-now-apply-i.md +6 -0
  248. package/corpus/templates/design/changelog/2026-07-06-zoom-presets-like-zoom-to-50-now-stay-on-the-focused-screen-.md +6 -0
  249. package/corpus/templates/design/server/lib/import-design-files.ts +11 -2
  250. package/corpus/templates/design/server/source-workspace.ts +139 -59
  251. package/corpus/templates/design/shared/board-file.ts +11 -2
  252. package/corpus/templates/design/shared/breakpoint-media.ts +543 -0
  253. package/corpus/templates/design/shared/canvas-math.ts +354 -35
  254. package/corpus/templates/design/shared/code-layer.ts +277 -8
  255. package/corpus/templates/design/shared/design-state.ts +11 -4
  256. package/corpus/templates/design/shared/interaction-states.ts +548 -0
  257. package/corpus/templates/design/shared/motion-compiler.ts +186 -23
  258. package/corpus/templates/design/shared/motion-easing.ts +294 -0
  259. package/corpus/templates/design/shared/motion-timeline.ts +400 -34
  260. package/corpus/templates/design/shared/prompt-title.ts +95 -0
  261. package/corpus/templates/design/shared/responsive-classes.ts +448 -10
  262. package/corpus/templates/design/shared/screen-annotation.ts +46 -0
  263. package/corpus/templates/design/shared/shader-fills.ts +1009 -0
  264. package/corpus/templates/design/shared/shader-presets.ts +852 -4
  265. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +15 -2
  266. package/corpus/templates/slides/app/components/editor/ImportButton.tsx +10 -1
  267. package/corpus/templates/slides/app/lib/upload-response.ts +71 -0
  268. package/dist/client/AgentPanel.js +1 -1
  269. package/dist/client/AgentPanel.js.map +1 -1
  270. package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
  271. package/dist/client/rich-markdown-editor/useCollabReconcile.js +11 -6
  272. package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
  273. package/dist/client/use-action.d.ts +3 -0
  274. package/dist/client/use-action.d.ts.map +1 -1
  275. package/dist/client/use-action.js +34 -3
  276. package/dist/client/use-action.js.map +1 -1
  277. package/dist/client/use-db-sync.d.ts +4 -0
  278. package/dist/client/use-db-sync.d.ts.map +1 -1
  279. package/dist/client/use-db-sync.js +37 -18
  280. package/dist/client/use-db-sync.js.map +1 -1
  281. package/dist/collab/routes.d.ts +1 -1
  282. package/dist/collab/struct-routes.d.ts +1 -1
  283. package/dist/db/create-get-db.d.ts +25 -0
  284. package/dist/db/create-get-db.d.ts.map +1 -1
  285. package/dist/db/create-get-db.js +25 -2
  286. package/dist/db/create-get-db.js.map +1 -1
  287. package/dist/observability/routes.d.ts +3 -3
  288. package/dist/secrets/routes.d.ts +9 -9
  289. package/dist/server/framework-request-handler.d.ts.map +1 -1
  290. package/dist/server/framework-request-handler.js +37 -1
  291. package/dist/server/framework-request-handler.js.map +1 -1
  292. package/package.json +1 -1
  293. package/corpus/templates/design/app/components/design/inspector/InspectorAiActions.tsx +0 -153
  294. package/corpus/templates/design/app/hooks/useAgentEditRequest.ts +0 -133
  295. package/corpus/templates/design/app/pages/DesignEditor.tsx +0 -22924
@@ -1,6 +1,7 @@
1
1
  import { defineAction } from "@agent-native/core";
2
2
  import {
3
3
  hasCollabState,
4
+ getText,
4
5
  applyText,
5
6
  seedFromText,
6
7
  } from "@agent-native/core/collab";
@@ -10,6 +11,8 @@ import { and, eq, sql } from "drizzle-orm";
10
11
  import { z } from "zod";
11
12
 
12
13
  import { getDb, schema } from "../server/db/index.js";
14
+ import { withSourceFileWriteLock } from "../server/source-workspace.js";
15
+ import { sourceContentHash } from "../shared/source-workspace.js";
13
16
 
14
17
  function rowsAffected(result: unknown): number | undefined {
15
18
  const candidate = result as {
@@ -22,6 +25,24 @@ function rowsAffected(result: unknown): number | undefined {
22
25
  return typeof value === "number" ? value : undefined;
23
26
  }
24
27
 
28
+ /**
29
+ * Returns `{ id, updated: true }` on success, matching the pre-existing
30
+ * contract — callers that only check `result.updated === true` see no
31
+ * behavior change.
32
+ *
33
+ * `skippedStaleMirror?: true` is added to the result ONLY in the narrow
34
+ * SQL-mirror-only staleness case: `content` was provided, `syncCollab` was
35
+ * explicitly `false`, a live collaboration document exists for this file,
36
+ * and the caller's `expectedVersionHash` no longer matches that live text.
37
+ * In that case the content column is intentionally left untouched (the live
38
+ * collab document remains the source of truth) while any `filename`/
39
+ * `fileType` updates in the same call still apply, and the action returns
40
+ * success instead of throwing. The field is omitted (not `false`) in every
41
+ * other case, so existing callers that don't check for it observe no
42
+ * difference. When `expectedVersionHash` is omitted entirely, or the hash
43
+ * matches, or `syncCollab` is left at its default `true`, or no collab state
44
+ * exists yet for the file, this skip path never triggers.
45
+ */
25
46
  export default defineAction({
26
47
  description:
27
48
  "Update an existing file in a design project. " +
@@ -42,8 +63,26 @@ export default defineAction({
42
63
  .describe(
43
64
  "Whether to mirror content updates into the live collaboration document.",
44
65
  ),
66
+ expectedVersionHash: z
67
+ .string()
68
+ .optional()
69
+ .describe(
70
+ "Optional optimistic-concurrency guard for content updates: the " +
71
+ "sourceContentHash of the live content this write was computed " +
72
+ "from (same semantics as apply-source-edit / read-source-file). " +
73
+ "When provided and the file changed since that read, the write " +
74
+ "fails loud instead of silently merging a stale full document " +
75
+ "into the collaboration state.",
76
+ ),
45
77
  }),
46
- run: async ({ id, content, filename, fileType, syncCollab }) => {
78
+ run: async ({
79
+ id,
80
+ content,
81
+ filename,
82
+ fileType,
83
+ syncCollab,
84
+ expectedVersionHash,
85
+ }) => {
47
86
  // Path traversal guard on filename
48
87
  if (
49
88
  filename &&
@@ -82,96 +121,172 @@ export default defineAction({
82
121
 
83
122
  await assertAccess("design", file.designId, "editor");
84
123
 
85
- const updates: Record<string, unknown> = { updatedAt: now };
86
- if (content !== undefined) updates.content = content;
87
- if (filename !== undefined) updates.filename = filename;
88
- if (fileType !== undefined) updates.fileType = fileType;
89
-
90
- if (filename !== undefined && isPostgres()) {
91
- await db.transaction(async (tx) => {
92
- // Postgres evaluates concurrent NOT EXISTS updates under MVCC, so a
93
- // guarded UPDATE alone can still race. Serialize design-file renames in
94
- // this rare path without using SQLite's fragile async savepoint wrapper.
95
- await (
96
- tx as unknown as { execute: (query: unknown) => Promise<unknown> }
97
- ).execute(sql`LOCK TABLE design_files IN SHARE ROW EXCLUSIVE MODE`);
98
- const [collision] = await tx
99
- .select({ id: schema.designFiles.id })
100
- .from(schema.designFiles)
101
- .where(
102
- and(
103
- eq(schema.designFiles.designId, file.designId),
104
- eq(schema.designFiles.filename, filename),
105
- ),
106
- )
107
- .limit(1);
108
- if (collision && collision.id !== id) {
109
- throw new Error(
110
- `File "${filename}" already exists in design ${file.designId}`,
111
- );
124
+ // Optimistic-concurrency guard (cross-pipeline write-race fix): a content
125
+ // update here is a FULL-document write that, when syncCollab runs, is
126
+ // char-diffed against the live collaboration text (applyText). If the
127
+ // caller computed `content` from a since-stale read — e.g. a base Fill
128
+ // style commit queued while a shader apply-source-edit landed for the
129
+ // same file that silent diff-merge is exactly how the shader/fill
130
+ // interleave corrupted or lost screen content. When the caller supplies
131
+ // the hash of the content it based this write on, verify the file still
132
+ // matches before writing and fail loud otherwise, mirroring
133
+ // writeInlineSourceFile's expectedVersionHash contract.
134
+ //
135
+ // TOCTOU fix: the hash check alone is NOT enough — two concurrent
136
+ // update-file calls can each read the same live text, each pass the hash
137
+ // check, and then both proceed to write, with the second one silently
138
+ // winning over a base it never actually re-validated against. Route the
139
+ // whole hash-check -> write -> collab-sync critical section through the
140
+ // SAME per-file in-process lock writeInlineSourceFile uses
141
+ // (withSourceFileWriteLock, server/source-workspace.ts), keyed by file
142
+ // id, so a second guarded caller's hash check runs AFTER the first
143
+ // caller's write has fully landed and observes the true current state
144
+ // (and is rejected by the hash guard instead of interleaving). Callers
145
+ // that don't pass a hash keep today's last-write-wins behavior for the
146
+ // VALUE they write, but the write itself is still serialized under the
147
+ // same lock so it can't interleave with a concurrent guarded writer's own
148
+ // read-check-write.
149
+ let skippedStaleMirror = false;
150
+
151
+ await withSourceFileWriteLock(id, async () => {
152
+ // SQL-mirror-only skip path: when the caller explicitly opted OUT of
153
+ // collab sync (syncCollab: false) and supplied an expectedVersionHash
154
+ // that no longer matches the LIVE collab text, and a live collab doc
155
+ // actually exists for this file, the caller's `content` was computed
156
+ // from a base that a live editor has since moved past. Overwriting the
157
+ // SQL mirror column with that stale content here would silently regress
158
+ // it out from under the live document (which stays the source of
159
+ // truth) the next time it's read back out of SQL. Skip the content
160
+ // write instead of throwing: filename/fileType updates in the same call
161
+ // still proceed, and the caller gets `skippedStaleMirror: true` back
162
+ // instead of a thrown error, because they explicitly said they weren't
163
+ // trying to sync into collab in the first place. Every other
164
+ // expectedVersionHash combination (syncCollab true/default, or no live
165
+ // collab state, or a matching hash, or no hash at all) is UNCHANGED.
166
+ let skipContentWrite = false;
167
+ if (expectedVersionHash !== undefined && content !== undefined) {
168
+ const collabExists = await hasCollabState(id);
169
+ let liveContent: string;
170
+ if (collabExists) {
171
+ liveContent = await getText(id, "content");
172
+ } else {
173
+ const [current] = await db
174
+ .select({ content: schema.designFiles.content })
175
+ .from(schema.designFiles)
176
+ .where(eq(schema.designFiles.id, id))
177
+ .limit(1);
178
+ liveContent = current?.content ?? "";
112
179
  }
113
- await tx
114
- .update(schema.designFiles)
115
- .set(updates)
116
- .where(eq(schema.designFiles.id, id));
117
- });
118
- } else {
119
- // Reject colliding SQLite renames as part of the write. SQLite's local
120
- // async transaction wrapper can fail under concurrent editor/collab writes,
121
- // so keep this to one guarded UPDATE instead of a SELECT-then-UPDATE window.
122
- const updateWhere =
123
- filename === undefined
124
- ? eq(schema.designFiles.id, id)
125
- : and(
126
- eq(schema.designFiles.id, id),
127
- sql`NOT EXISTS (
180
+ if (sourceContentHash(liveContent) !== expectedVersionHash) {
181
+ if (syncCollab === false && collabExists) {
182
+ skipContentWrite = true;
183
+ skippedStaleMirror = true;
184
+ } else {
185
+ throw new Error(
186
+ "File changed since it was read. Re-read the file and retry.",
187
+ );
188
+ }
189
+ }
190
+ }
191
+
192
+ const updates: Record<string, unknown> = { updatedAt: now };
193
+ if (content !== undefined && !skipContentWrite) updates.content = content;
194
+ if (filename !== undefined) updates.filename = filename;
195
+ if (fileType !== undefined) updates.fileType = fileType;
196
+
197
+ if (filename !== undefined && isPostgres()) {
198
+ await db.transaction(async (tx) => {
199
+ // Postgres evaluates concurrent NOT EXISTS updates under MVCC, so a
200
+ // guarded UPDATE alone can still race. Serialize design-file renames in
201
+ // this rare path without using SQLite's fragile async savepoint wrapper.
202
+ await (
203
+ tx as unknown as { execute: (query: unknown) => Promise<unknown> }
204
+ ).execute(sql`LOCK TABLE design_files IN SHARE ROW EXCLUSIVE MODE`);
205
+ const [collision] = await tx
206
+ .select({ id: schema.designFiles.id })
207
+ .from(schema.designFiles)
208
+ .where(
209
+ and(
210
+ eq(schema.designFiles.designId, file.designId),
211
+ eq(schema.designFiles.filename, filename),
212
+ ),
213
+ )
214
+ .limit(1);
215
+ if (collision && collision.id !== id) {
216
+ throw new Error(
217
+ `File "${filename}" already exists in design ${file.designId}`,
218
+ );
219
+ }
220
+ await tx
221
+ .update(schema.designFiles)
222
+ .set(updates)
223
+ .where(eq(schema.designFiles.id, id));
224
+ });
225
+ } else {
226
+ // Reject colliding SQLite renames as part of the write. SQLite's local
227
+ // async transaction wrapper can fail under concurrent editor/collab writes,
228
+ // so keep this to one guarded UPDATE instead of a SELECT-then-UPDATE window.
229
+ const updateWhere =
230
+ filename === undefined
231
+ ? eq(schema.designFiles.id, id)
232
+ : and(
233
+ eq(schema.designFiles.id, id),
234
+ sql`NOT EXISTS (
128
235
  SELECT 1 FROM design_files AS sibling
129
236
  WHERE sibling.design_id = ${file.designId}
130
237
  AND sibling.filename = ${filename}
131
238
  AND sibling.id <> ${id}
132
239
  )`,
133
- );
240
+ );
241
+
242
+ const updateResult = await db
243
+ .update(schema.designFiles)
244
+ .set(updates)
245
+ .where(updateWhere);
134
246
 
135
- const updateResult = await db
136
- .update(schema.designFiles)
137
- .set(updates)
138
- .where(updateWhere);
139
-
140
- if (filename !== undefined && rowsAffected(updateResult) === 0) {
141
- const [collision] = await db
142
- .select({ id: schema.designFiles.id })
143
- .from(schema.designFiles)
144
- .where(
145
- and(
146
- eq(schema.designFiles.designId, file.designId),
147
- eq(schema.designFiles.filename, filename),
148
- ),
149
- )
150
- .limit(1);
151
- if (collision && collision.id !== id) {
152
- throw new Error(
153
- `File "${filename}" already exists in design ${file.designId}`,
154
- );
247
+ if (filename !== undefined && rowsAffected(updateResult) === 0) {
248
+ const [collision] = await db
249
+ .select({ id: schema.designFiles.id })
250
+ .from(schema.designFiles)
251
+ .where(
252
+ and(
253
+ eq(schema.designFiles.designId, file.designId),
254
+ eq(schema.designFiles.filename, filename),
255
+ ),
256
+ )
257
+ .limit(1);
258
+ if (collision && collision.id !== id) {
259
+ throw new Error(
260
+ `File "${filename}" already exists in design ${file.designId}`,
261
+ );
262
+ }
155
263
  }
156
264
  }
157
- }
158
265
 
159
- // Push content through the collab layer so live editors see the change
160
- if (content !== undefined && syncCollab) {
161
- const collabExists = await hasCollabState(id);
162
- if (collabExists) {
163
- await applyText(id, content, "content", "agent");
164
- } else {
165
- await seedFromText(id, content);
266
+ // Push content through the collab layer so live editors see the change
267
+ if (content !== undefined && syncCollab) {
268
+ const collabExists = await hasCollabState(id);
269
+ if (collabExists) {
270
+ await applyText(id, content, "content", "agent");
271
+ } else {
272
+ await seedFromText(id, content);
273
+ }
166
274
  }
167
- }
275
+ });
168
276
 
169
- // Update the parent design's updatedAt timestamp
277
+ // Update the parent design's updatedAt timestamp. This still runs even
278
+ // when the content write was skipped (skippedStaleMirror): filename/
279
+ // fileType may have changed in the same call, and even a content-only
280
+ // call that hit the skip path still represents a real request the design
281
+ // was touched by, matching this action's existing unconditional-bump
282
+ // contract for every other call shape.
170
283
  await db
171
284
  .update(schema.designs)
172
285
  .set({ updatedAt: now })
173
286
  .where(eq(schema.designs.id, file.designId));
174
287
 
175
- return { id, updated: true };
288
+ return skippedStaleMirror
289
+ ? { id, updated: true, skippedStaleMirror: true }
290
+ : { id, updated: true };
176
291
  },
177
292
  });