@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.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +14 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/client/AgentPanel.tsx +1 -1
- package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +11 -6
- package/corpus/core/src/client/use-action.ts +39 -2
- package/corpus/core/src/client/use-db-sync.ts +44 -18
- package/corpus/core/src/db/create-get-db.ts +32 -2
- package/corpus/core/src/server/framework-request-handler.ts +52 -4
- package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +5 -0
- package/corpus/templates/assets/.agents/skills/logo-composite/SKILL.md +34 -6
- package/corpus/templates/assets/AGENTS.md +23 -4
- package/corpus/templates/assets/actions/_generation-preset-settings.ts +48 -0
- package/corpus/templates/assets/actions/_helpers.ts +8 -1
- package/corpus/templates/assets/actions/_preset-skeleton-validation.ts +64 -0
- package/corpus/templates/assets/actions/create-generation-preset.ts +11 -3
- package/corpus/templates/assets/actions/generate-image-batch.ts +7 -2
- package/corpus/templates/assets/actions/generate-image.ts +342 -25
- package/corpus/templates/assets/actions/get-library.ts +4 -3
- package/corpus/templates/assets/actions/navigate.ts +2 -1
- package/corpus/templates/assets/actions/refresh-generation-run.ts +5 -1
- package/corpus/templates/assets/actions/update-asset.ts +1 -0
- package/corpus/templates/assets/actions/update-generation-preset.ts +8 -1
- package/corpus/templates/assets/actions/view-screen.ts +8 -1
- package/corpus/templates/assets/app/components/generation/GenerationResults.tsx +9 -1
- package/corpus/templates/assets/app/hooks/use-image-model-menu.ts +1 -0
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +11 -0
- package/corpus/templates/assets/app/i18n/zh-TW.ts +64 -0
- package/corpus/templates/assets/app/i18n-data.ts +650 -0
- package/corpus/templates/assets/app/routes/asset.$id.tsx +2 -1
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +44 -33
- package/corpus/templates/assets/app/routes/brand-kits.$id_.presets.$presetId.tsx +1474 -0
- package/corpus/templates/assets/app/routes/library.tsx +43 -1
- package/corpus/templates/assets/server/lib/generation.ts +366 -44
- package/corpus/templates/assets/server/lib/image-processing.ts +252 -0
- package/corpus/templates/assets/server/lib/preset-skeleton.ts +137 -0
- package/corpus/templates/assets/shared/api.ts +47 -0
- package/corpus/templates/clips/app/components/library/library-layout.tsx +7 -2
- package/corpus/templates/clips/app/components/library/sort-menu.tsx +1 -1
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +114 -33
- package/corpus/templates/clips/app/routes/_app.library._index.tsx +27 -1
- package/corpus/templates/clips/app/routes/record.tsx +157 -68
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +5 -5
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +20 -3
- package/corpus/templates/clips/shared/finalize-recovery.ts +23 -3
- package/corpus/templates/content/AGENTS.md +52 -52
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +188 -8
- package/corpus/templates/content/actions/_builder-docs-client.ts +41 -3
- package/corpus/templates/content/actions/_database-source-utils.ts +998 -160
- package/corpus/templates/content/actions/_database-utils.ts +44 -4
- package/corpus/templates/content/actions/_notion-action-utils.ts +6 -2
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +23 -1
- package/corpus/templates/content/actions/attach-content-database-source.ts +85 -12
- package/corpus/templates/content/actions/change-content-database-source-role.ts +9 -1
- package/corpus/templates/content/actions/delete-content-database.ts +1 -0
- package/corpus/templates/content/actions/get-document.ts +11 -2
- package/corpus/templates/content/actions/list-content-databases.ts +57 -9
- package/corpus/templates/content/actions/prepare-builder-source-review.ts +23 -6
- package/corpus/templates/content/actions/refresh-content-database-source.ts +26 -3
- package/corpus/templates/content/actions/restore-content-database.ts +1 -0
- package/corpus/templates/content/actions/update-document.ts +43 -0
- package/corpus/templates/content/app/components/editor/BuilderBodySyncingNotice.tsx +21 -0
- package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +0 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +70 -28
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +69 -17
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +4 -4
- package/corpus/templates/content/app/components/editor/body-hydration.ts +112 -0
- package/corpus/templates/content/app/components/editor/builder-body-hydration-pump.ts +52 -0
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +9076 -2876
- package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +41 -1
- package/corpus/templates/content/app/components/editor/extensions/ImageBlock.tsx +36 -11
- package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +21 -1
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +11 -1
- package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +11 -8
- package/corpus/templates/content/app/global.css +41 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +346 -42
- package/corpus/templates/content/app/hooks/use-db-sync.ts +9 -0
- package/corpus/templates/content/app/hooks/use-documents.ts +47 -0
- package/corpus/templates/content/app/hooks/use-notion.ts +12 -10
- package/corpus/templates/content/app/i18n/zh-TW.ts +35 -0
- package/corpus/templates/content/app/i18n-data.ts +355 -0
- package/corpus/templates/content/app/root.tsx +22 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-database-sources-keep-loading-rows-in-the-background.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-source-attach-starts-with-usable-rows.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-source-attachment-now-stays-connected-after-large.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-source-refreshes-now-show-progress-for-large-docs-blog.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-database-pages-now-delete-to-trash-without-route-errors.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-builder-source-refreshes-recover-from-stalled-background-row.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-builder-sourced-rows-open-with-sync-protection.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-database-rows-and-pages-open-faster-from-recently-loaded-dat.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-preview-panels-close-reliably-narrow-sidebar-row-actions-sta.md +6 -0
- package/corpus/templates/content/changelog/2026-07-06-builder-sync-progress-no-longer-shows-continue.md +6 -0
- package/corpus/templates/content/shared/api.ts +13 -0
- package/corpus/templates/content/shared/builder-mdx.ts +16 -3
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +23 -13
- package/corpus/templates/design/.agents/skills/responsive-breakpoints/SKILL.md +98 -0
- package/corpus/templates/design/.agents/skills/shader-fills/SKILL.md +162 -0
- package/corpus/templates/design/AGENTS.md +9 -2
- package/corpus/templates/design/actions/add-breakpoint.ts +6 -3
- package/corpus/templates/design/actions/apply-a11y-fix.ts +57 -37
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +41 -20
- package/corpus/templates/design/actions/apply-motion-edit.ts +251 -38
- package/corpus/templates/design/actions/apply-shader-fill.ts +90 -66
- package/corpus/templates/design/actions/apply-visual-edit.ts +282 -55
- package/corpus/templates/design/actions/create-component.ts +29 -60
- package/corpus/templates/design/actions/create-file.ts +9 -2
- package/corpus/templates/design/actions/duplicate-design.ts +31 -2
- package/corpus/templates/design/actions/edit-design.ts +36 -38
- package/corpus/templates/design/actions/generate-design-title.ts +87 -0
- package/corpus/templates/design/actions/generate-design.ts +53 -18
- package/corpus/templates/design/actions/generate-screens.ts +108 -4
- package/corpus/templates/design/actions/get-motion-timeline.ts +35 -7
- package/corpus/templates/design/actions/insert-asset.ts +34 -29
- package/corpus/templates/design/actions/insert-design-native-asset.ts +129 -32
- package/corpus/templates/design/actions/insert-figma-library-asset.ts +35 -30
- package/corpus/templates/design/actions/present-design-variants.ts +7 -2
- package/corpus/templates/design/actions/remove-motion-timeline.ts +31 -36
- package/corpus/templates/design/actions/update-file.ts +190 -75
- package/corpus/templates/design/app/components/design/BreakpointBar.tsx +403 -0
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +469 -222
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +708 -53
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +83 -3
- package/corpus/templates/design/app/components/design/EditPanel.tsx +1091 -6948
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +419 -85
- package/corpus/templates/design/app/components/design/MotionDock.tsx +1124 -103
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +2610 -1398
- package/corpus/templates/design/app/components/design/ReadOnlyDesignBanner.tsx +22 -0
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +2182 -235
- package/corpus/templates/design/app/components/design/bridge/motion-preview.bridge.ts +187 -11
- package/corpus/templates/design/app/components/design/bridge/shader-fill-preview.bridge.ts +376 -1
- package/corpus/templates/design/app/components/design/bridge/shader-runtime.bridge.ts +746 -0
- package/corpus/templates/design/app/components/design/canvas-primitive-style.ts +17 -0
- package/corpus/templates/design/app/components/design/code-workbench/SideBar.tsx +1 -1
- package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +1 -3
- package/corpus/templates/design/app/components/design/code-workbench/quickinput/QuickInput.tsx +1 -1
- package/corpus/templates/design/app/components/design/edit-panel/appearance-properties.tsx +518 -0
- package/corpus/templates/design/app/components/design/edit-panel/code-inspect-helpers.tsx +562 -0
- package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +763 -0
- package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +94 -0
- package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +780 -0
- package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +446 -0
- package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +79 -0
- package/corpus/templates/design/app/components/design/edit-panel/field-primitives.tsx +315 -0
- package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +344 -0
- package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +594 -0
- package/corpus/templates/design/app/components/design/edit-panel/frame-presets-panel.tsx +119 -0
- package/corpus/templates/design/app/components/design/edit-panel/inspector-controls.tsx +248 -0
- package/corpus/templates/design/app/components/design/edit-panel/interaction-state-helpers.ts +45 -0
- package/corpus/templates/design/app/components/design/edit-panel/layout-properties.tsx +693 -0
- package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +724 -0
- package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +207 -0
- package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +628 -0
- package/corpus/templates/design/app/components/design/edit-panel/selection-helpers.ts +91 -0
- package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +649 -0
- package/corpus/templates/design/app/components/design/edit-panel/style-change-types.ts +118 -0
- package/corpus/templates/design/app/components/design/edit-panel/style-options.ts +88 -0
- package/corpus/templates/design/app/components/design/edit-panel/transform-helpers.ts +100 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-helpers.ts +117 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +501 -0
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +91 -40
- package/corpus/templates/design/app/components/design/inspector/BreakpointOverrideIndicator.tsx +82 -0
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +189 -87
- package/corpus/templates/design/app/components/design/inspector/GlslShaderPanel.tsx +1097 -0
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +44 -0
- package/corpus/templates/design/app/components/design/inspector/InteractionStatePanel.tsx +258 -0
- package/corpus/templates/design/app/components/design/inspector/MotionKeyframeDiamond.tsx +144 -0
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +99 -9
- package/corpus/templates/design/app/components/design/inspector/frame-size-presets.ts +116 -0
- package/corpus/templates/design/app/components/design/inspector/index.ts +26 -0
- package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +29 -0
- package/corpus/templates/design/app/components/design/multi-screen/alt-hover-measurement.ts +171 -0
- package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +220 -0
- package/corpus/templates/design/app/components/design/multi-screen/chrome-transitions.ts +35 -0
- package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +134 -0
- package/corpus/templates/design/app/components/design/multi-screen/culling.ts +185 -0
- package/corpus/templates/design/app/components/design/multi-screen/gradient-overlay-geometry.ts +120 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +892 -0
- package/corpus/templates/design/app/components/design/multi-screen/vector-edit-geometry.ts +21 -0
- package/corpus/templates/design/app/components/design/types.ts +15 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +109 -5
- package/corpus/templates/design/app/global.css +8 -8
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +259 -2
- package/corpus/templates/design/app/i18n/zh-TW.ts +163 -9
- package/corpus/templates/design/app/i18n-breakpoints.ts +205 -0
- package/corpus/templates/design/app/i18n-data.ts +1664 -152
- package/corpus/templates/design/app/i18n-motion.ts +563 -0
- package/corpus/templates/design/app/lib/design-import.ts +73 -0
- package/corpus/templates/design/app/pages/Index.tsx +41 -22
- package/corpus/templates/design/changelog/2026-06-29-design-inspector-controls-now-match-figmas-softer-dark-chrome.md +1 -1
- package/corpus/templates/design/changelog/2026-06-30-design-now-has-a-figma-style-left-rail-for-file-agent-assets.md +1 -1
- package/corpus/templates/design/changelog/2026-06-30-design-tools-now-use-a-quieter-figma-style-list-layout.md +1 -1
- package/corpus/templates/design/changelog/2026-06-30-multi-select-outlines-now-stay-consistent-across-all-screens.md +1 -1
- package/corpus/templates/design/changelog/2026-07-03-canvas-interactions-now-match-figma-rotation-aware-resizing-.md +1 -1
- package/corpus/templates/design/changelog/2026-07-03-layers-panel-matches-figma-top-layer-on-top-drag-with-auto-s.md +1 -1
- package/corpus/templates/design/changelog/2026-07-05-designs-get-ai-generated-names-from-your-prompt.md +6 -0
- package/corpus/templates/design/changelog/2026-07-05-local-code-screens-keep-their-connection-when-duplicated-and.md +6 -0
- package/corpus/templates/design/changelog/2026-07-05-press-a-to-draw-screens-on-the-canvas-inside-a-screen-it-dr.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-3d-rotation-and-perspective-controls-on-every-element.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-ai-generated-and-duplicated-screens-now-get-their-editor-sel.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-applying-shaders-and-fills-in-quick-succession-can-no-longer.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-breakpoint-frames-in-the-overview-now-support-click-to-selec.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-breakpoint-segments-in-the-inspector-now-show-a-device-icon-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-breakpoint-targeting-now-lives-in-one-compact-control-in-the.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-canvas-edits-can-no-longer-be-overwritten-by-stale-collabora.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-canvas-edits-inside-screens-save-reliably-again.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-cleaner-inspector-removed-the-ask-ai-box-from-the-design-tab.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-clicking-empty-canvas-space-now-deselects-an-element-inside-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-dragging-an-element-onto-a-rectangle-now-nests-it-inside-wit.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-dragging-screens-and-objects-on-the-canvas-is-now-much-smoot.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-drawing-a-shape-or-text-on-the-canvas-no-longer-flashes-away.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-dropping-an-element-between-two-others-inside-a-screen-now-s.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-duplicating-a-screen-now-places-the-copy-exactly-where-you-d.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-edit-gradients-directly-on-elements-inside-screens-scale-str.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-edits-from-collaborators-and-the-agent-now-update-the-canvas.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-a-bug-where-most-style-position-and-text-edits-briefly.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-a-confusing-raw-error-message-when-a-file-upload-fails.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-a-rare-case-where-an-edit-could-be-silently-overwritte.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-inserted-assets-sometimes-disappearing-reappearing-or-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-inspector-value-scrubbing-producing-erratic-numbers-an.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-padding-gap-and-min-max-size-scrubbing-not-updating-th.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-text-stroke-color-turning-black-and-glyphs-disappearin.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-the-collapsed-effects-and-stroke-inspector-sections-sh.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-the-new-design-dialog-closing-unexpectedly-when-using-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-the-typography-section-missing-when-selecting-text-nes.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-full-view-no-longer-flashes-back-to-the-overview-on-entry-no.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-keyframe-animation-timeline-per-property-keyframes-easing-cu.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-moving-restyling-and-scrubbing-values-on-elements-in-ai-gene.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-padding-and-corner-radius-value-scrubbing-now-snaps-to-whole.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-padding-handles-now-only-resize-on-the-handle-line-itself-sh.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-preview-and-edit-hover-focus-and-pressed-states-with-real-cs.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-promoting-an-element-to-a-component-now-works-correctly-for-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-reduced-url-history-churn-and-selection-overlay-flicker-whil.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-removed-the-decorative-dot-before-screen-names-in-the-overvi.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-responsive-breakpoints-edit-at-any-width-with-cascading-over.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-screen-labels-no-longer-turn-blue-when-you-hover-inside-the-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-scrolling-a-screen-with-an-element-selected-stays-smooth-on-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-selecting-multiple-elements-and-dragging-now-moves-the-whole.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-selection-borders-handles-and-value-readouts-now-stay-the-sa.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-selection-handles-and-editing-chrome-now-stay-a-constant-siz.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-shader-fills-and-effects-ai-authored-or-preset-glsl-shaders-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-text-drawn-on-the-canvas-now-defaults-to-white-and-inter-in-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-text-dropped-into-a-shape-now-stays-readable-instead-of-disa.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-add-tweak-controls-prompt-no-longer-jumps-to-the-corner-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-padding-value-readout-now-stays-visible-while-you-hover-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-selected-element-attachment-now-clears-from-the-chat-com.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-zoom-menu-is-more-compact-with-tight-rows-and-right-alig.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-undo-and-redo-no-longer-flash-the-screen-changes-now-apply-i.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-zoom-presets-like-zoom-to-50-now-stay-on-the-focused-screen-.md +6 -0
- package/corpus/templates/design/server/lib/import-design-files.ts +11 -2
- package/corpus/templates/design/server/source-workspace.ts +139 -59
- package/corpus/templates/design/shared/board-file.ts +11 -2
- package/corpus/templates/design/shared/breakpoint-media.ts +543 -0
- package/corpus/templates/design/shared/canvas-math.ts +354 -35
- package/corpus/templates/design/shared/code-layer.ts +277 -8
- package/corpus/templates/design/shared/design-state.ts +11 -4
- package/corpus/templates/design/shared/interaction-states.ts +548 -0
- package/corpus/templates/design/shared/motion-compiler.ts +186 -23
- package/corpus/templates/design/shared/motion-easing.ts +294 -0
- package/corpus/templates/design/shared/motion-timeline.ts +400 -34
- package/corpus/templates/design/shared/prompt-title.ts +95 -0
- package/corpus/templates/design/shared/responsive-classes.ts +448 -10
- package/corpus/templates/design/shared/screen-annotation.ts +46 -0
- package/corpus/templates/design/shared/shader-fills.ts +1009 -0
- package/corpus/templates/design/shared/shader-presets.ts +852 -4
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +15 -2
- package/corpus/templates/slides/app/components/editor/ImportButton.tsx +10 -1
- package/corpus/templates/slides/app/lib/upload-response.ts +71 -0
- package/dist/client/AgentPanel.js +1 -1
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +11 -6
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/dist/client/use-action.d.ts +3 -0
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +34 -3
- package/dist/client/use-action.js.map +1 -1
- package/dist/client/use-db-sync.d.ts +4 -0
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +37 -18
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/create-get-db.d.ts +25 -0
- package/dist/db/create-get-db.d.ts.map +1 -1
- package/dist/db/create-get-db.js +25 -2
- package/dist/db/create-get-db.js.map +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/framework-request-handler.d.ts.map +1 -1
- package/dist/server/framework-request-handler.js +37 -1
- package/dist/server/framework-request-handler.js.map +1 -1
- package/package.json +1 -1
- package/corpus/templates/design/app/components/design/inspector/InspectorAiActions.tsx +0 -153
- package/corpus/templates/design/app/hooks/useAgentEditRequest.ts +0 -133
- package/corpus/templates/design/app/pages/DesignEditor.tsx +0 -22924
|
@@ -3,16 +3,17 @@ import {
|
|
|
3
3
|
agentEnterDocument,
|
|
4
4
|
agentLeaveDocument,
|
|
5
5
|
agentUpdateSelection,
|
|
6
|
-
applyText,
|
|
7
|
-
getText,
|
|
8
|
-
hasCollabState,
|
|
9
|
-
seedFromText,
|
|
10
6
|
} from "@agent-native/core/collab";
|
|
11
7
|
import { accessFilter, assertAccess } from "@agent-native/core/sharing";
|
|
12
8
|
import { and, eq } from "drizzle-orm";
|
|
13
9
|
import { z } from "zod";
|
|
14
10
|
|
|
15
11
|
import { getDb, schema } from "../server/db/index.js";
|
|
12
|
+
import {
|
|
13
|
+
readLiveSourceFile,
|
|
14
|
+
writeInlineSourceFile,
|
|
15
|
+
type SourceWorkspaceFile,
|
|
16
|
+
} from "../server/source-workspace.js";
|
|
16
17
|
import {
|
|
17
18
|
applyVisualEdit,
|
|
18
19
|
type AutoLayoutEditIntent,
|
|
@@ -24,7 +25,12 @@ import {
|
|
|
24
25
|
} from "../shared/code-layer.js";
|
|
25
26
|
import { agentSelectionDescriptor } from "../shared/collab-selection.js";
|
|
26
27
|
import type { TailwindBreakpointPrefix } from "../shared/design-state.js";
|
|
27
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
breakpointUpperBoundPx,
|
|
30
|
+
planBreakpointStyleWrite,
|
|
31
|
+
utilityStem,
|
|
32
|
+
widthToPrefix,
|
|
33
|
+
} from "../shared/responsive-classes.js";
|
|
28
34
|
|
|
29
35
|
/**
|
|
30
36
|
* Short human-readable label describing an edit intent, shown next to the
|
|
@@ -38,6 +44,7 @@ function editIntentLabel(intent: EditIntent): string {
|
|
|
38
44
|
return "Editing style";
|
|
39
45
|
case "class":
|
|
40
46
|
case "responsive-class":
|
|
47
|
+
case "breakpoint-style":
|
|
41
48
|
return "Editing styles";
|
|
42
49
|
case "moveNode":
|
|
43
50
|
return "Moving element";
|
|
@@ -154,6 +161,139 @@ function scopeClassIntentToBreakpoint(
|
|
|
154
161
|
return intent;
|
|
155
162
|
}
|
|
156
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Convert a `class` or `style` intent into the equivalent Framer-scoped edit
|
|
166
|
+
* for a desktop-down max-width bound (§6.4 breakpoint bar semantics):
|
|
167
|
+
*
|
|
168
|
+
* - `class` add/replace/remove → `responsive-class` with `maxWidthPx`
|
|
169
|
+
* (writes/removes a `max-[<bound>px]:` scoped token).
|
|
170
|
+
* - `style` → the single class-vs-media decision (`planBreakpointStyleWrite`):
|
|
171
|
+
* Tailwind-utility values become scoped classes; raw CSS values become
|
|
172
|
+
* managed `@media (max-width: <bound>px)` rules via `breakpoint-style`.
|
|
173
|
+
* - Everything else passes through unchanged.
|
|
174
|
+
*/
|
|
175
|
+
function scopeIntentToFramerBound(
|
|
176
|
+
intent: EditIntent,
|
|
177
|
+
maxWidthPx: number,
|
|
178
|
+
): EditIntent {
|
|
179
|
+
if (intent.kind === "class") {
|
|
180
|
+
if (intent.operation === "add" || intent.operation === "replace") {
|
|
181
|
+
const tokens =
|
|
182
|
+
intent.operation === "replace"
|
|
183
|
+
? intent.to
|
|
184
|
+
? [intent.to]
|
|
185
|
+
: []
|
|
186
|
+
: (intent.classNames ?? (intent.className ? [intent.className] : []));
|
|
187
|
+
if (tokens.length !== 1 || !tokens[0]) return intent;
|
|
188
|
+
return {
|
|
189
|
+
kind: "responsive-class",
|
|
190
|
+
target: intent.target,
|
|
191
|
+
prefix: "base", // ignored when maxWidthPx is set
|
|
192
|
+
maxWidthPx,
|
|
193
|
+
operation: intent.operation,
|
|
194
|
+
utility: tokens[0],
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
if (intent.operation === "remove") {
|
|
198
|
+
const tokens =
|
|
199
|
+
intent.classNames ?? (intent.className ? [intent.className] : []);
|
|
200
|
+
if (tokens.length !== 1 || !tokens[0]) return intent;
|
|
201
|
+
return {
|
|
202
|
+
kind: "responsive-class",
|
|
203
|
+
target: intent.target,
|
|
204
|
+
prefix: "base",
|
|
205
|
+
maxWidthPx,
|
|
206
|
+
operation: "remove",
|
|
207
|
+
stem: stemFromToken(tokens[0]),
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
// "set" — no per-breakpoint analog.
|
|
211
|
+
return intent;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (intent.kind === "style") {
|
|
215
|
+
const plan = planBreakpointStyleWrite({
|
|
216
|
+
property: intent.property,
|
|
217
|
+
value: intent.value,
|
|
218
|
+
upperBoundPx: maxWidthPx,
|
|
219
|
+
});
|
|
220
|
+
if (plan.mode === "class") {
|
|
221
|
+
return {
|
|
222
|
+
kind: "responsive-class",
|
|
223
|
+
target: intent.target,
|
|
224
|
+
prefix: "base",
|
|
225
|
+
maxWidthPx: plan.boundPx,
|
|
226
|
+
operation: "replace",
|
|
227
|
+
utility: plan.utility,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
if (plan.mode === "media") {
|
|
231
|
+
return {
|
|
232
|
+
kind: "breakpoint-style",
|
|
233
|
+
target: intent.target,
|
|
234
|
+
maxWidthPx: plan.maxWidthPx,
|
|
235
|
+
property: plan.property,
|
|
236
|
+
value: plan.value,
|
|
237
|
+
operation: "set",
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
return intent;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return intent;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Resolve the Framer desktop-down bound for a design-file edit from the
|
|
248
|
+
* design's stored breakpoint set (+ the edited screen's primary width).
|
|
249
|
+
*
|
|
250
|
+
* - `{ kind: "bound" }` — a wider frame exists; scope below it.
|
|
251
|
+
* - `{ kind: "base" }` — the active frame IS the widest context; edits
|
|
252
|
+
* belong to the base layer (Framer semantics).
|
|
253
|
+
* - `{ kind: "unknown" }` — the design has no breakpoint set; callers fall
|
|
254
|
+
* back to the legacy min-width prefix behaviour.
|
|
255
|
+
*/
|
|
256
|
+
function resolveFramerBoundFromDesignData(
|
|
257
|
+
designData: string | null,
|
|
258
|
+
fileId: string,
|
|
259
|
+
activeFrameWidthPx: number,
|
|
260
|
+
): { kind: "bound"; boundPx: number } | { kind: "base" } | { kind: "unknown" } {
|
|
261
|
+
if (!designData) return { kind: "unknown" };
|
|
262
|
+
try {
|
|
263
|
+
const parsed = JSON.parse(designData) as Record<string, unknown>;
|
|
264
|
+
const rawSet = parsed.breakpointSet as
|
|
265
|
+
| { breakpoints?: Array<{ widthPx?: unknown }> }
|
|
266
|
+
| undefined;
|
|
267
|
+
const widths = Array.isArray(rawSet?.breakpoints)
|
|
268
|
+
? rawSet.breakpoints
|
|
269
|
+
.map((bp) => bp?.widthPx)
|
|
270
|
+
.filter(
|
|
271
|
+
(width): width is number =>
|
|
272
|
+
typeof width === "number" && Number.isFinite(width),
|
|
273
|
+
)
|
|
274
|
+
: [];
|
|
275
|
+
if (widths.length === 0) return { kind: "unknown" };
|
|
276
|
+
|
|
277
|
+
const metadataByFileId = parsed.screenMetadata as
|
|
278
|
+
| Record<string, { width?: unknown } | undefined>
|
|
279
|
+
| undefined;
|
|
280
|
+
const rawScreenWidth = metadataByFileId?.[fileId]?.width;
|
|
281
|
+
const screenWidthPx =
|
|
282
|
+
typeof rawScreenWidth === "number" && Number.isFinite(rawScreenWidth)
|
|
283
|
+
? rawScreenWidth
|
|
284
|
+
: null;
|
|
285
|
+
|
|
286
|
+
const boundPx = breakpointUpperBoundPx(
|
|
287
|
+
widths,
|
|
288
|
+
activeFrameWidthPx,
|
|
289
|
+
screenWidthPx,
|
|
290
|
+
);
|
|
291
|
+
return boundPx === null ? { kind: "base" } : { kind: "bound", boundPx };
|
|
292
|
+
} catch {
|
|
293
|
+
return { kind: "unknown" };
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
157
297
|
function parseJsonString(value: unknown): unknown {
|
|
158
298
|
if (typeof value !== "string") return value;
|
|
159
299
|
try {
|
|
@@ -226,6 +366,30 @@ const intentSchema = z.preprocess(
|
|
|
226
366
|
from: z.string().optional(),
|
|
227
367
|
to: z.string().optional(),
|
|
228
368
|
}),
|
|
369
|
+
z.object({
|
|
370
|
+
kind: z.literal("breakpoint-style"),
|
|
371
|
+
target: targetSchema,
|
|
372
|
+
maxWidthPx: z
|
|
373
|
+
.number()
|
|
374
|
+
.int()
|
|
375
|
+
.positive()
|
|
376
|
+
.describe(
|
|
377
|
+
"Inclusive upper viewport bound (px). The declaration persists as a managed '@media (max-width: <bound>px)' rule in the <style data-agent-native-breakpoints> block — the fallback for values responsive class prefixes can't express (exact px positions, rgb()/calc() values). Use breakpointUpperBoundPx semantics: just below the next-wider breakpoint frame.",
|
|
378
|
+
),
|
|
379
|
+
property: z
|
|
380
|
+
.string()
|
|
381
|
+
.describe("CSS property to set (camelCase or kebab-case)."),
|
|
382
|
+
value: z
|
|
383
|
+
.string()
|
|
384
|
+
.optional()
|
|
385
|
+
.describe("CSS value. Required for operation 'set'."),
|
|
386
|
+
operation: z
|
|
387
|
+
.enum(["set", "remove"])
|
|
388
|
+
.optional()
|
|
389
|
+
.describe(
|
|
390
|
+
"'set' (default) writes/overwrites the scoped declaration; 'remove' deletes it so the base value cascades back down.",
|
|
391
|
+
),
|
|
392
|
+
}),
|
|
229
393
|
z.object({
|
|
230
394
|
kind: z.literal("textContent"),
|
|
231
395
|
target: targetSchema,
|
|
@@ -290,28 +454,16 @@ const intentSchema = z.preprocess(
|
|
|
290
454
|
]),
|
|
291
455
|
);
|
|
292
456
|
|
|
293
|
-
async function liveContent(
|
|
294
|
-
fileId: string,
|
|
295
|
-
storedContent: string,
|
|
296
|
-
): Promise<string> {
|
|
297
|
-
try {
|
|
298
|
-
if (await hasCollabState(fileId)) {
|
|
299
|
-
const live = await getText(fileId, "content");
|
|
300
|
-
if (typeof live === "string") return live;
|
|
301
|
-
}
|
|
302
|
-
} catch {
|
|
303
|
-
// Collab reads are best-effort; SQL content remains the fallback.
|
|
304
|
-
}
|
|
305
|
-
return storedContent;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
457
|
async function resolveEditableDesignFile(
|
|
309
458
|
source: VisualEditActionSource,
|
|
310
459
|
): Promise<{
|
|
311
460
|
id: string;
|
|
312
461
|
designId: string;
|
|
313
462
|
filename: string;
|
|
463
|
+
fileType: string;
|
|
314
464
|
content: string;
|
|
465
|
+
versionHash: string;
|
|
466
|
+
designData: string | null;
|
|
315
467
|
codeLayerSource: CodeLayerSource;
|
|
316
468
|
}> {
|
|
317
469
|
if (!source.fileId && !source.designId) {
|
|
@@ -340,6 +492,7 @@ async function resolveEditableDesignFile(
|
|
|
340
492
|
filename: schema.designFiles.filename,
|
|
341
493
|
fileType: schema.designFiles.fileType,
|
|
342
494
|
content: schema.designFiles.content,
|
|
495
|
+
designData: schema.designs.data,
|
|
343
496
|
})
|
|
344
497
|
.from(schema.designFiles)
|
|
345
498
|
.innerJoin(
|
|
@@ -368,11 +521,32 @@ async function resolveEditableDesignFile(
|
|
|
368
521
|
|
|
369
522
|
await assertAccess("design", file.designId, "editor");
|
|
370
523
|
|
|
524
|
+
// Read the live (collab-authoritative, not just SQL-stored) content and
|
|
525
|
+
// capture its versionHash so the eventual persist can be conditioned on
|
|
526
|
+
// this exact base still being current — see persistDesignFileEdit below.
|
|
527
|
+
// Same read helper the 8 sibling actions (insert-design-native-asset.ts,
|
|
528
|
+
// insert-asset.ts, etc.) migrated to, closing the write-race window where
|
|
529
|
+
// a concurrent editor's change landed between this read and the raw
|
|
530
|
+
// unconditional write this action used to do.
|
|
531
|
+
const workspaceFile: SourceWorkspaceFile = {
|
|
532
|
+
id: file.id,
|
|
533
|
+
designId: file.designId,
|
|
534
|
+
filename: file.filename,
|
|
535
|
+
fileType: file.fileType,
|
|
536
|
+
content: file.content,
|
|
537
|
+
createdAt: null,
|
|
538
|
+
updatedAt: null,
|
|
539
|
+
};
|
|
540
|
+
const live = await readLiveSourceFile(workspaceFile);
|
|
541
|
+
|
|
371
542
|
return {
|
|
372
543
|
id: file.id,
|
|
373
544
|
designId: file.designId,
|
|
374
545
|
filename: file.filename,
|
|
375
|
-
|
|
546
|
+
fileType: file.fileType,
|
|
547
|
+
content: live.content,
|
|
548
|
+
versionHash: live.versionHash,
|
|
549
|
+
designData: file.designData ?? null,
|
|
376
550
|
codeLayerSource: {
|
|
377
551
|
kind: "design-file",
|
|
378
552
|
designId: file.designId,
|
|
@@ -386,30 +560,27 @@ async function resolveEditableDesignFile(
|
|
|
386
560
|
async function persistDesignFileEdit(file: {
|
|
387
561
|
id: string;
|
|
388
562
|
designId: string;
|
|
563
|
+
filename: string;
|
|
564
|
+
fileType: string;
|
|
389
565
|
content: string;
|
|
566
|
+
expectedVersionHash: string;
|
|
390
567
|
}): Promise<void> {
|
|
391
|
-
await assertAccess("design", file.designId, "editor");
|
|
392
|
-
|
|
393
|
-
const db = getDb();
|
|
394
|
-
const now = new Date().toISOString();
|
|
395
|
-
|
|
396
568
|
agentEnterDocument(file.id);
|
|
397
569
|
try {
|
|
398
|
-
await
|
|
399
|
-
.
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
.
|
|
411
|
-
|
|
412
|
-
.where(eq(schema.designs.id, file.designId));
|
|
570
|
+
await writeInlineSourceFile({
|
|
571
|
+
designId: file.designId,
|
|
572
|
+
file: {
|
|
573
|
+
id: file.id,
|
|
574
|
+
designId: file.designId,
|
|
575
|
+
filename: file.filename,
|
|
576
|
+
fileType: file.fileType,
|
|
577
|
+
content: file.content,
|
|
578
|
+
createdAt: null,
|
|
579
|
+
updatedAt: null,
|
|
580
|
+
},
|
|
581
|
+
content: file.content,
|
|
582
|
+
expectedVersionHash: file.expectedVersionHash,
|
|
583
|
+
});
|
|
413
584
|
} finally {
|
|
414
585
|
agentLeaveDocument(file.id);
|
|
415
586
|
}
|
|
@@ -419,7 +590,9 @@ export default defineAction({
|
|
|
419
590
|
description:
|
|
420
591
|
"Apply one deterministic visual edit to a code-backed HTML design layer. " +
|
|
421
592
|
"Supports safe inline style, class, and leaf textContent edits on inline/SQL HTML files; escalates ambiguous or structural edits with PatchResult statuses. " +
|
|
422
|
-
"
|
|
593
|
+
"Responsive editing (§6.4): pass activeFrameWidthPx (the active breakpoint frame width, matching the UI's breakpoint bar) to scope class AND style edits Framer-style — overrides apply below the next-wider frame and cascade down; the widest frame is the base. " +
|
|
594
|
+
"Raw CSS values persist as managed @media rules (<style data-agent-native-breakpoints>); Tailwind-utility values become max-[<bound>px]: classes. " +
|
|
595
|
+
"Pass activeBreakpoint to force legacy min-width prefix scoping for class edits, or maxWidthPx for an explicit desktop-down bound. Omit all three for base (global) behaviour.",
|
|
423
596
|
schema: z.object({
|
|
424
597
|
source: sourceSchema.describe(
|
|
425
598
|
"Edit source. Use kind=design-file with designId/filename or fileId to persist into SQL; kind=inline-html with html for a preview-only patch.",
|
|
@@ -446,7 +619,16 @@ export default defineAction({
|
|
|
446
619
|
.optional()
|
|
447
620
|
.nullable()
|
|
448
621
|
.describe(
|
|
449
|
-
"
|
|
622
|
+
"Active breakpoint frame width in pixels — matches the UI's breakpoint bar. For design-file sources whose design has a breakpoint set, 'class' AND 'style' intents are scoped Framer-style: overrides apply below the next-wider frame (max-[<bound>px]: classes, or managed @media rules for raw CSS values); the widest frame is the base and writes unscoped. When the design has no breakpoint set (or for inline-html sources) class edits fall back to the legacy min-width Tailwind prefix via widthToPrefix. Ignored when activeBreakpoint is provided.",
|
|
623
|
+
),
|
|
624
|
+
maxWidthPx: z
|
|
625
|
+
.number()
|
|
626
|
+
.int()
|
|
627
|
+
.positive()
|
|
628
|
+
.optional()
|
|
629
|
+
.nullable()
|
|
630
|
+
.describe(
|
|
631
|
+
"Explicit Framer desktop-down bound (px): scope this edit to apply at viewport widths <= this value. Overrides activeBreakpoint/activeFrameWidthPx derivation. Applies to 'class' and 'style' intents.",
|
|
450
632
|
),
|
|
451
633
|
}),
|
|
452
634
|
run: async ({
|
|
@@ -455,22 +637,36 @@ export default defineAction({
|
|
|
455
637
|
includeContent,
|
|
456
638
|
activeBreakpoint,
|
|
457
639
|
activeFrameWidthPx,
|
|
640
|
+
maxWidthPx,
|
|
458
641
|
}) => {
|
|
459
642
|
const actionSource = source as VisualEditActionSource;
|
|
460
643
|
let editIntent = intent as EditIntent;
|
|
461
644
|
|
|
462
|
-
// Breakpoint scoping
|
|
463
|
-
//
|
|
464
|
-
// `
|
|
465
|
-
//
|
|
466
|
-
//
|
|
467
|
-
//
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
editIntent
|
|
645
|
+
// Breakpoint scoping precedence (§6.4):
|
|
646
|
+
//
|
|
647
|
+
// 1. Explicit `maxWidthPx` param → Framer desktop-down scope for `class`
|
|
648
|
+
// AND `style` intents (max-[<bound>px]: classes / managed @media).
|
|
649
|
+
// 2. Explicit `activeBreakpoint` prefix → legacy min-width Tailwind
|
|
650
|
+
// prefix scoping for `class` intents (backward-compatible).
|
|
651
|
+
// 3. `activeFrameWidthPx` only → design-file sources resolve the Framer
|
|
652
|
+
// bound from the design's breakpoint set (below, after the file is
|
|
653
|
+
// loaded); other sources fall back to the legacy prefix path.
|
|
654
|
+
if (
|
|
655
|
+
maxWidthPx != null &&
|
|
656
|
+
(editIntent.kind === "class" || editIntent.kind === "style")
|
|
657
|
+
) {
|
|
658
|
+
editIntent = scopeIntentToFramerBound(editIntent, maxWidthPx);
|
|
659
|
+
} else if (
|
|
660
|
+
actionSource.kind !== "design-file" ||
|
|
661
|
+
activeBreakpoint != null
|
|
662
|
+
) {
|
|
663
|
+
const activePrefix = resolveActivePrefix(
|
|
664
|
+
activeBreakpoint,
|
|
665
|
+
activeFrameWidthPx,
|
|
666
|
+
);
|
|
667
|
+
if (activePrefix !== null && editIntent.kind === "class") {
|
|
668
|
+
editIntent = scopeClassIntentToBreakpoint(editIntent, activePrefix);
|
|
669
|
+
}
|
|
474
670
|
}
|
|
475
671
|
|
|
476
672
|
if (actionSource.kind === "inline-html") {
|
|
@@ -512,6 +708,34 @@ export default defineAction({
|
|
|
512
708
|
}
|
|
513
709
|
|
|
514
710
|
const file = await resolveEditableDesignFile(actionSource);
|
|
711
|
+
|
|
712
|
+
// §6.4 — design-file Framer scoping resolved from the stored breakpoint
|
|
713
|
+
// set (see precedence note above): the bound is just below the
|
|
714
|
+
// next-wider frame; the widest frame is the base and writes unscoped.
|
|
715
|
+
if (
|
|
716
|
+
maxWidthPx == null &&
|
|
717
|
+
activeBreakpoint == null &&
|
|
718
|
+
activeFrameWidthPx != null &&
|
|
719
|
+
(editIntent.kind === "class" || editIntent.kind === "style")
|
|
720
|
+
) {
|
|
721
|
+
const bound = resolveFramerBoundFromDesignData(
|
|
722
|
+
file.designData,
|
|
723
|
+
file.id,
|
|
724
|
+
activeFrameWidthPx,
|
|
725
|
+
);
|
|
726
|
+
if (bound.kind === "bound") {
|
|
727
|
+
editIntent = scopeIntentToFramerBound(editIntent, bound.boundPx);
|
|
728
|
+
} else if (bound.kind === "unknown" && editIntent.kind === "class") {
|
|
729
|
+
// No breakpoint set on this design — legacy min-width prefix path.
|
|
730
|
+
const activePrefix = resolveActivePrefix(null, activeFrameWidthPx);
|
|
731
|
+
if (activePrefix !== null) {
|
|
732
|
+
editIntent = scopeClassIntentToBreakpoint(editIntent, activePrefix);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
// bound.kind === "base": the active frame IS the widest context —
|
|
736
|
+
// the edit stays a plain base write that cascades down.
|
|
737
|
+
}
|
|
738
|
+
|
|
515
739
|
const patch = applyVisualEdit(file.content, editIntent, {
|
|
516
740
|
source: file.codeLayerSource,
|
|
517
741
|
});
|
|
@@ -535,7 +759,10 @@ export default defineAction({
|
|
|
535
759
|
await persistDesignFileEdit({
|
|
536
760
|
id: file.id,
|
|
537
761
|
designId: file.designId,
|
|
762
|
+
filename: file.filename,
|
|
763
|
+
fileType: file.fileType,
|
|
538
764
|
content: patch.content,
|
|
765
|
+
expectedVersionHash: file.versionHash,
|
|
539
766
|
});
|
|
540
767
|
}
|
|
541
768
|
|
|
@@ -28,15 +28,7 @@
|
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
30
|
import { defineAction } from "@agent-native/core";
|
|
31
|
-
import {
|
|
32
|
-
agentEnterDocument,
|
|
33
|
-
agentLeaveDocument,
|
|
34
|
-
agentUpdateSelection,
|
|
35
|
-
applyText,
|
|
36
|
-
getText,
|
|
37
|
-
hasCollabState,
|
|
38
|
-
seedFromText,
|
|
39
|
-
} from "@agent-native/core/collab";
|
|
31
|
+
import { agentUpdateSelection } from "@agent-native/core/collab";
|
|
40
32
|
import {
|
|
41
33
|
accessFilter,
|
|
42
34
|
assertAccess,
|
|
@@ -47,6 +39,11 @@ import { z } from "zod";
|
|
|
47
39
|
|
|
48
40
|
import { getDb, schema } from "../server/db/index.js";
|
|
49
41
|
import "../server/db/index.js"; // ensure registerShareableResource runs
|
|
42
|
+
import {
|
|
43
|
+
readLiveSourceFile,
|
|
44
|
+
writeInlineSourceFile,
|
|
45
|
+
type SourceWorkspaceFile,
|
|
46
|
+
} from "../server/source-workspace.js";
|
|
50
47
|
import { resolveSourceCapabilities } from "../shared/capability-resolver.js";
|
|
51
48
|
import { buildCodeLayerProjection } from "../shared/code-layer.js";
|
|
52
49
|
import type { CodeLayerNode, CodeLayerSource } from "../shared/code-layer.js";
|
|
@@ -209,54 +206,6 @@ export function applyComponentAnnotations(
|
|
|
209
206
|
};
|
|
210
207
|
}
|
|
211
208
|
|
|
212
|
-
// ─── DB helpers ───────────────────────────────────────────────────────────────
|
|
213
|
-
|
|
214
|
-
async function liveContent(
|
|
215
|
-
fileId: string,
|
|
216
|
-
storedContent: string,
|
|
217
|
-
): Promise<string> {
|
|
218
|
-
try {
|
|
219
|
-
if (await hasCollabState(fileId)) {
|
|
220
|
-
const live = await getText(fileId, "content");
|
|
221
|
-
if (typeof live === "string") return live;
|
|
222
|
-
}
|
|
223
|
-
} catch {
|
|
224
|
-
// Collab reads are best-effort; SQL content is the fallback.
|
|
225
|
-
}
|
|
226
|
-
return storedContent;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
async function persistEdit(file: {
|
|
230
|
-
id: string;
|
|
231
|
-
designId: string;
|
|
232
|
-
content: string;
|
|
233
|
-
}): Promise<void> {
|
|
234
|
-
await assertAccess("design", file.designId, "editor");
|
|
235
|
-
const db = getDb();
|
|
236
|
-
const now = new Date().toISOString();
|
|
237
|
-
|
|
238
|
-
agentEnterDocument(file.id);
|
|
239
|
-
try {
|
|
240
|
-
await db
|
|
241
|
-
.update(schema.designFiles)
|
|
242
|
-
.set({ content: file.content, updatedAt: now })
|
|
243
|
-
.where(eq(schema.designFiles.id, file.id));
|
|
244
|
-
|
|
245
|
-
if (await hasCollabState(file.id)) {
|
|
246
|
-
await applyText(file.id, file.content, "content", "agent");
|
|
247
|
-
} else {
|
|
248
|
-
await seedFromText(file.id, file.content);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
await db
|
|
252
|
-
.update(schema.designs)
|
|
253
|
-
.set({ updatedAt: now })
|
|
254
|
-
.where(eq(schema.designs.id, file.designId));
|
|
255
|
-
} finally {
|
|
256
|
-
agentLeaveDocument(file.id);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
209
|
// ─── Action ───────────────────────────────────────────────────────────────────
|
|
261
210
|
|
|
262
211
|
export default defineAction({
|
|
@@ -371,7 +320,26 @@ export default defineAction({
|
|
|
371
320
|
|
|
372
321
|
if (!file) throw new Error("Design HTML file not found.");
|
|
373
322
|
|
|
374
|
-
|
|
323
|
+
// Read the LIVE base (collab text when present, else the SQL row) right
|
|
324
|
+
// before transforming, and carry its versionHash through to the write
|
|
325
|
+
// below. writeInlineSourceFile re-reads the live text immediately before
|
|
326
|
+
// its own applyText/DB write and rejects if it no longer matches this
|
|
327
|
+
// hash — closing the race window where a concurrent editor/agent write
|
|
328
|
+
// lands between this read and the persist (the same stale-diff-base bug
|
|
329
|
+
// fixed for insert-design-native-asset.ts and insert-asset.ts: a diff/patch
|
|
330
|
+
// computed from a stale base, unconditionally persisted, corrupts or
|
|
331
|
+
// drops the other writer's change).
|
|
332
|
+
const workspaceFile: SourceWorkspaceFile = {
|
|
333
|
+
id: file.id,
|
|
334
|
+
designId: file.designId,
|
|
335
|
+
filename: file.filename ?? "",
|
|
336
|
+
fileType: "html",
|
|
337
|
+
content: file.content,
|
|
338
|
+
createdAt: null,
|
|
339
|
+
updatedAt: null,
|
|
340
|
+
};
|
|
341
|
+
const live = await readLiveSourceFile(workspaceFile);
|
|
342
|
+
const html = live.content;
|
|
375
343
|
|
|
376
344
|
// ── Resolve node ─────────────────────────────────────────────────────────
|
|
377
345
|
const codeLayerSource: CodeLayerSource = {
|
|
@@ -410,10 +378,11 @@ export default defineAction({
|
|
|
410
378
|
|
|
411
379
|
// ── Persist ──────────────────────────────────────────────────────────────
|
|
412
380
|
if (changed) {
|
|
413
|
-
await
|
|
414
|
-
id: file.id,
|
|
381
|
+
await writeInlineSourceFile({
|
|
415
382
|
designId: file.designId,
|
|
383
|
+
file: workspaceFile,
|
|
416
384
|
content: patchedContent,
|
|
385
|
+
expectedVersionHash: live.versionHash,
|
|
417
386
|
});
|
|
418
387
|
|
|
419
388
|
agentUpdateSelection(file.id, {
|
|
@@ -6,6 +6,7 @@ import { nanoid } from "nanoid";
|
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
|
|
8
8
|
import { getDb, schema } from "../server/db/index.js";
|
|
9
|
+
import { annotateScreenHtmlForPersist } from "../shared/screen-annotation.js";
|
|
9
10
|
|
|
10
11
|
export default defineAction({
|
|
11
12
|
description:
|
|
@@ -56,18 +57,24 @@ export default defineAction({
|
|
|
56
57
|
const id = nanoid();
|
|
57
58
|
const now = new Date().toISOString();
|
|
58
59
|
|
|
60
|
+
// Stamp missing data-agent-native-node-id attributes before persisting so
|
|
61
|
+
// the new screen is fully addressable by id-keyed editor operations from
|
|
62
|
+
// the moment it's created, instead of depending on a client-side backfill
|
|
63
|
+
// the first time someone opens it.
|
|
64
|
+
const annotatedContent = annotateScreenHtmlForPersist(content, fileType);
|
|
65
|
+
|
|
59
66
|
await db.insert(schema.designFiles).values({
|
|
60
67
|
id,
|
|
61
68
|
designId,
|
|
62
69
|
filename,
|
|
63
70
|
fileType: fileType ?? "html",
|
|
64
|
-
content,
|
|
71
|
+
content: annotatedContent,
|
|
65
72
|
createdAt: now,
|
|
66
73
|
updatedAt: now,
|
|
67
74
|
});
|
|
68
75
|
|
|
69
76
|
// Seed collab state for the new file
|
|
70
|
-
await seedFromText(id,
|
|
77
|
+
await seedFromText(id, annotatedContent);
|
|
71
78
|
|
|
72
79
|
// Update the design's updatedAt timestamp
|
|
73
80
|
await db
|
|
@@ -9,6 +9,7 @@ import { nanoid } from "nanoid";
|
|
|
9
9
|
import { z } from "zod";
|
|
10
10
|
|
|
11
11
|
import { getDb, schema } from "../server/db/index.js";
|
|
12
|
+
import { annotateScreenHtmlForPersist } from "../shared/screen-annotation.js";
|
|
12
13
|
|
|
13
14
|
export default defineAction({
|
|
14
15
|
description:
|
|
@@ -82,14 +83,42 @@ export default defineAction({
|
|
|
82
83
|
updatedAt: now,
|
|
83
84
|
});
|
|
84
85
|
|
|
85
|
-
// Copy all associated files using the pre-generated IDs
|
|
86
|
+
// Copy all associated files using the pre-generated IDs. `content` is
|
|
87
|
+
// copied verbatim, including any `data-agent-native-node-id` attributes
|
|
88
|
+
// already stamped on the source screen — those ids are NOT regenerated
|
|
89
|
+
// here.
|
|
90
|
+
//
|
|
91
|
+
// This is a deliberate simplification, not an oversight: node ids are
|
|
92
|
+
// scoped to a single file's DOM, never looked up globally. Every
|
|
93
|
+
// consumer (buildCodeLayerProjection/ensureCodeLayerNodeIdsInHtml in
|
|
94
|
+
// shared/code-layer.ts, the MultiScreenCanvas/editor-chrome bridge
|
|
95
|
+
// querySelectorAll calls) resolves ids against one screen's parsed HTML
|
|
96
|
+
// or one iframe's contentDocument, and each design's screens render in
|
|
97
|
+
// their own isolated iframe — so a duplicated screen sharing ids with its
|
|
98
|
+
// source design is harmless: there is no code path that queries two
|
|
99
|
+
// screens' DOMs together. Regenerating ids here would additionally have
|
|
100
|
+
// to rewrite every `[data-agent-native-node-id="..."]` selector embedded
|
|
101
|
+
// inline by shared/motion-compiler.ts and shared/interaction-states.ts
|
|
102
|
+
// (motion timelines and hover/focus states target nodes by id in CSS
|
|
103
|
+
// baked into the same HTML string) to keep them pointing at the
|
|
104
|
+
// corresponding element — a real rewrite with real regression risk
|
|
105
|
+
// (silently dropped motion/interaction styling on duplicated screens) to
|
|
106
|
+
// fix a collision that has no observable effect. If a future feature
|
|
107
|
+
// introduces cross-design lookups keyed on node id alone (e.g. pasting
|
|
108
|
+
// one design's screen into another), reconsider this and add an id-remap
|
|
109
|
+
// pass that also rewrites those embedded CSS selectors in lockstep.
|
|
110
|
+
//
|
|
111
|
+
// Still fill in any MISSING ids (belt-and-suspenders for designs
|
|
112
|
+
// generated/imported before ids were stamped at creation time): this only
|
|
113
|
+
// adds ids where none exist and never touches an id that's already
|
|
114
|
+
// present, so it can't disturb the existing-id-copy contract above.
|
|
86
115
|
for (const file of files) {
|
|
87
116
|
await db.insert(schema.designFiles).values({
|
|
88
117
|
id: idMap.get(file.id)!,
|
|
89
118
|
designId: newId,
|
|
90
119
|
filename: file.filename,
|
|
91
120
|
fileType: file.fileType,
|
|
92
|
-
content: file.content,
|
|
121
|
+
content: annotateScreenHtmlForPersist(file.content, file.fileType),
|
|
93
122
|
createdAt: now,
|
|
94
123
|
updatedAt: now,
|
|
95
124
|
});
|