@agent-native/core 0.80.4 → 0.80.6
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 +2 -2
- package/corpus/core/CHANGELOG.md +28 -2
- package/corpus/core/docs/content/locales/ar-SA/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/real-time-collaboration.mdx +3 -3
- package/corpus/core/docs/content/locales/de-DE/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/es-ES/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +1 -1
- package/corpus/core/docs/content/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/template-design.mdx +1 -1
- package/corpus/core/package.json +3 -7
- package/corpus/core/src/action.ts +21 -0
- package/corpus/core/src/agent/durable-background.ts +32 -11
- package/corpus/core/src/agent/production-agent.ts +11 -1
- package/corpus/core/src/agent/run-loop-with-resume.ts +3 -1
- package/corpus/core/src/brand-kit/fig/index.ts +17 -37
- package/corpus/core/src/cli/create.ts +1 -0
- package/corpus/core/src/cli/index.ts +1 -1
- package/corpus/core/src/cli/mcp-config-writers.ts +187 -51
- package/corpus/core/src/cli/skills.ts +18 -3
- package/corpus/core/src/client/AssistantChat.tsx +11 -1
- package/corpus/core/src/client/agent-chat.ts +12 -1
- package/corpus/core/src/client/composer/PromptComposer.tsx +100 -41
- package/corpus/core/src/client/org/OrgSwitcher.tsx +1 -1
- package/corpus/core/src/client/sharing/ShareButton.tsx +3 -27
- package/corpus/core/src/collab/presence.ts +1 -1
- package/corpus/core/src/mcp/connect-route.ts +34 -5
- package/corpus/core/src/server/action-discovery.ts +4 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +20 -0
- package/corpus/core/src/sharing/registry.ts +17 -0
- package/corpus/core/src/templates/default/pnpm-workspace.yaml +1 -0
- package/corpus/core/src/templates/workspace-root/pnpm-workspace.yaml +1 -0
- package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -0
- package/corpus/templates/analytics/actions/update-dashboard.ts +8 -0
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +117 -33
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +4 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +7 -0
- package/corpus/templates/analytics/changelog/2026-06-27-dashboards-can-now-nest-under-a-parent-in-the-sidebar-via-a-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-analytics-pages-now-sit-closer-under-the-header-with-tighter.md +6 -0
- package/corpus/templates/assets/actions/generate-image-batch.ts +3 -0
- package/corpus/templates/assets/actions/generate-image.ts +3 -0
- package/corpus/templates/assets/changelog/2026-06-29-longer-agent-generation-window.md +6 -0
- package/corpus/templates/assets/netlify.toml +3 -3
- package/corpus/templates/assets/server/plugins/agent-chat.ts +4 -1
- package/corpus/templates/clips/app/components/capture-install-options.tsx +7 -8
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +1 -1
- package/corpus/templates/content/AGENTS.md +57 -44
- package/corpus/templates/content/README.md +16 -0
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +125 -0
- package/corpus/templates/content/actions/_builder-cms-source-adapter.ts +28 -6
- package/corpus/templates/content/actions/_builder-cms-write-adapter.ts +238 -69
- package/corpus/templates/content/actions/_builder-cms-write-settings.ts +125 -43
- package/corpus/templates/content/actions/_database-source-utils.ts +746 -97
- package/corpus/templates/content/actions/_database-utils.ts +17 -14
- package/corpus/templates/content/actions/_federation-join.ts +14 -2
- package/corpus/templates/content/actions/_join-suggestion.ts +89 -14
- package/corpus/templates/content/actions/_local-file-documents.ts +2 -1
- package/corpus/templates/content/actions/attach-content-database-source.ts +124 -5
- package/corpus/templates/content/actions/bind-content-database-source-field.ts +256 -0
- package/corpus/templates/content/actions/change-content-database-source-role.ts +420 -0
- package/corpus/templates/content/actions/create-document.ts +8 -0
- package/corpus/templates/content/actions/execute-builder-source-batch.ts +282 -0
- package/corpus/templates/content/actions/execute-builder-source-execution.ts +220 -8
- package/corpus/templates/content/actions/get-content-database.ts +10 -2
- package/corpus/templates/content/actions/prepare-builder-source-execution.ts +19 -2
- package/corpus/templates/content/actions/prepare-builder-source-review.ts +47 -15
- package/corpus/templates/content/actions/refresh-content-database-source.ts +11 -4
- package/corpus/templates/content/actions/review-content-database-source-change-set.ts +6 -2
- package/corpus/templates/content/actions/set-content-database-source-write-mode.ts +32 -12
- package/corpus/templates/content/actions/stage-builder-revision.ts +14 -10
- package/corpus/templates/content/actions/validate-builder-source-execution.ts +25 -3
- package/corpus/templates/content/app/blocks/BuilderDocsBlocks.tsx +10 -0
- package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +1 -0
- package/corpus/templates/content/app/components/editor/ContentReferencePreview.tsx +185 -0
- package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +1520 -553
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +3 -0
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +150 -1
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +19 -0
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +647 -66
- package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +543 -204
- package/corpus/templates/content/app/components/editor/extensions/ContentReferenceNode.tsx +82 -0
- package/corpus/templates/content/app/global.css +9 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +62 -0
- package/corpus/templates/content/app/i18n/zh-TW.ts +76 -0
- package/corpus/templates/content/app/i18n-data.ts +924 -0
- package/corpus/templates/content/changelog/2026-06-29-builder-review-checks-now-preserve-publish-and-unpublish-cho.md +6 -0
- package/corpus/templates/content/changelog/2026-06-29-database-sources-can-now-be-added-as-more-rows-or-matched.md +6 -0
- package/corpus/templates/content/changelog/2026-06-29-fixed-loading-the-final-rows-in-larger-databases-without-bre.md +6 -0
- package/corpus/templates/content/changelog/2026-06-29-reusable-mdx-references-now-preview-linked-local-documents-i.md +6 -0
- package/corpus/templates/content/shared/api.ts +91 -1
- package/corpus/templates/content/shared/builder-docs-blocks.ts +8 -0
- package/corpus/templates/content/shared/builder-mdx.ts +141 -4
- package/corpus/templates/content/shared/nfm.ts +62 -0
- package/corpus/templates/content/vite.config.ts +14 -7
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +10 -11
- package/corpus/templates/design/AGENTS.md +5 -0
- package/corpus/templates/design/_gitignore +7 -0
- package/corpus/templates/design/actions/apply-visual-edit.ts +22 -12
- package/corpus/templates/design/actions/create-design-system.ts +15 -4
- package/corpus/templates/design/actions/create-file.ts +20 -1
- package/corpus/templates/design/actions/delete-design-system.ts +2 -2
- package/corpus/templates/design/actions/duplicate-design.ts +35 -9
- package/corpus/templates/design/actions/generate-design.ts +146 -69
- package/corpus/templates/design/actions/generate-screens.ts +51 -19
- package/corpus/templates/design/actions/get-design-snapshot.ts +5 -1
- package/corpus/templates/design/actions/get-design.ts +2 -0
- package/corpus/templates/design/actions/import-design-project.ts +28 -9
- package/corpus/templates/design/actions/import-document.ts +22 -8
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +6 -153
- package/corpus/templates/design/actions/navigate.ts +105 -54
- package/corpus/templates/design/actions/set-default-design-system.ts +17 -3
- package/corpus/templates/design/actions/show-design-questions.ts +2 -0
- package/corpus/templates/design/actions/update-design.ts +2 -1
- package/corpus/templates/design/actions/view-screen.ts +12 -6
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +4 -4
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +159 -41
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +8 -4
- package/corpus/templates/design/app/components/design/DrawOverlay.tsx +37 -42
- package/corpus/templates/design/app/components/design/EditPanel.tsx +336 -183
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +153 -34
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +135 -33
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +6 -0
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +2 -1
- package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +4 -10
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +84 -43
- package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +4 -4
- package/corpus/templates/design/app/components/design/inspector/{FigmaColorPicker.tsx → DesignColorPicker.tsx} +89 -62
- package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +14 -26
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +40 -12
- package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +13 -4
- package/corpus/templates/design/app/components/design/inspector/SHADER_INTEGRATION.md +13 -13
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +13 -9
- package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +13 -4
- package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +6 -6
- package/corpus/templates/design/app/components/design/inspector/{figma-icons.tsx → design-icons.tsx} +2 -2
- package/corpus/templates/design/app/components/design/inspector/index.ts +12 -12
- package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +5 -2
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +3 -3
- package/corpus/templates/design/app/components/layout/Layout.tsx +5 -2
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +167 -91
- package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +16 -3
- package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +15 -0
- package/corpus/templates/design/app/global.css +4 -0
- package/corpus/templates/design/app/hooks/use-design-system.ts +4 -1
- package/corpus/templates/design/app/hooks/use-navigation-state.ts +38 -3
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +9 -2
- package/corpus/templates/design/app/i18n/zh-TW.ts +22 -0
- package/corpus/templates/design/app/i18n-data.ts +527 -0
- package/corpus/templates/design/app/lib/design-systems.ts +6 -4
- package/corpus/templates/design/app/lib/design-templates.ts +15 -3
- package/corpus/templates/design/app/pages/DesignEditor.tsx +641 -158
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +42 -34
- package/corpus/templates/design/app/pages/VisualEdit.tsx +100 -0
- package/corpus/templates/design/app/root.tsx +42 -9
- package/corpus/templates/design/app/routes/visual-edit.tsx +7 -0
- package/corpus/templates/design/changelog/2026-06-28-live-cursors-now-keep-names-beside-a-cleaner-pointer-marker.md +1 -1
- package/corpus/templates/design/changelog/2026-06-28-mode-switching-now-lives-in-a-compact-bottom-right-icon-dock.md +1 -1
- package/corpus/templates/design/changelog/2026-06-28-visual-code-design-mode.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-design-generation-prompts-now-show-connect-ai-before-sending.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-design-mode-top-chrome-now-groups-collaborators-preview-shar.md +1 -1
- package/corpus/templates/design/changelog/2026-06-29-fixed-design-editor-exports-and-gradient-edits-so-multi-scre.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-longer-hosted-agent-turns.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-png-export-handles-modern-css-color-functions-more-reliably.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-png-export-now-ignores-duplicate-clicks-while-a-download-is-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-public-visual-edit-and-shared-design-links-now-invite-visito.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-visual-edit-actions-now-reject-missing-design-targets-before.md +6 -0
- package/corpus/templates/design/e2e/README.md +71 -0
- package/corpus/templates/design/e2e/global-setup.ts +157 -0
- package/corpus/templates/design/e2e/helpers.ts +148 -0
- package/corpus/templates/design/netlify.toml +3 -4
- package/corpus/templates/design/package.json +5 -1
- package/corpus/templates/design/playwright.config.ts +51 -0
- package/corpus/templates/design/server/handlers/index-design-system-with-builder.ts +121 -0
- package/corpus/templates/design/server/handlers/uploads.ts +89 -38
- package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +181 -0
- package/corpus/templates/design/server/lib/coding-handoff.ts +33 -4
- package/corpus/templates/design/server/lib/design-export.ts +35 -8
- package/corpus/templates/design/server/plugins/agent-chat.ts +4 -0
- package/corpus/templates/design/server/plugins/auth.ts +10 -1
- package/corpus/templates/design/server/routes/api/index-design-system-with-builder.post.ts +1 -0
- package/corpus/templates/design/shared/api.ts +2 -0
- package/corpus/templates/design/shared/apply-edits.ts +12 -8
- package/corpus/templates/design/shared/canvas-math.ts +19 -1
- package/corpus/templates/design/shared/code-layer.ts +87 -28
- package/corpus/templates/design/shared/generation-session.ts +1 -0
- package/corpus/templates/design/shared/resolve-tweaks.ts +4 -3
- package/corpus/templates/design/shared/shader-presets.ts +10 -0
- package/corpus/templates/design/shared/source-mode.ts +9 -0
- package/corpus/templates/design/vitest.config.ts +2 -1
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +1 -1
- package/corpus/templates/plan/.agents/skills/visual-plan/references/canvas.md +1 -1
- package/corpus/templates/plan/AGENTS.md +1 -1
- package/corpus/templates/plan/actions/create-plan-design.ts +1 -1
- package/corpus/templates/plan/actions/validate-local-plan-source.ts +2 -10
- package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -0
- package/corpus/templates/plan/docs/commenting-ux-plan.md +2 -2
- package/corpus/templates/plan/server/plan-content.ts +1 -1
- package/corpus/templates/plan/server/ui-plan-html.ts +2 -2
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +6 -153
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +53 -38
- package/corpus/templates/slides/app/components/design-system/{fig-import-response.ts → builder-index-response.ts} +9 -6
- package/corpus/templates/slides/app/components/visual-editor/MultiSelectChip.tsx +1 -1
- package/corpus/templates/slides/changelog/2026-06-29-design-system-setup-now-indexes-uploaded-design-files-throug.md +6 -0
- package/corpus/templates/slides/changelog/2026-06-29-longer-hosted-agent-turns.md +6 -0
- package/corpus/templates/slides/netlify.toml +3 -6
- package/corpus/templates/slides/server/handlers/index-design-system-with-builder.ts +116 -0
- package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +179 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +4 -1
- package/corpus/templates/slides/server/routes/api/index-design-system-with-builder.post.ts +1 -0
- package/dist/action.d.ts +15 -0
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +6 -0
- package/dist/action.js.map +1 -1
- package/dist/agent/durable-background.d.ts +9 -7
- package/dist/agent/durable-background.d.ts.map +1 -1
- package/dist/agent/durable-background.js +27 -11
- package/dist/agent/durable-background.js.map +1 -1
- package/dist/agent/production-agent.d.ts +7 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +4 -1
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-loop-with-resume.d.ts +2 -1
- package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
- package/dist/agent/run-loop-with-resume.js +2 -2
- package/dist/agent/run-loop-with-resume.js.map +1 -1
- package/dist/brand-kit/fig/index.d.ts +4 -4
- package/dist/brand-kit/fig/index.d.ts.map +1 -1
- package/dist/brand-kit/fig/index.js +14 -27
- package/dist/brand-kit/fig/index.js.map +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +1 -0
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-config-writers.d.ts +15 -7
- package/dist/cli/mcp-config-writers.d.ts.map +1 -1
- package/dist/cli/mcp-config-writers.js +198 -45
- package/dist/cli/mcp-config-writers.js.map +1 -1
- package/dist/cli/skills.d.ts +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +18 -3
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +11 -1
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat.d.ts.map +1 -1
- package/dist/client/agent-chat.js +15 -2
- package/dist/client/agent-chat.js.map +1 -1
- package/dist/client/composer/PromptComposer.d.ts.map +1 -1
- package/dist/client/composer/PromptComposer.js +35 -1
- package/dist/client/composer/PromptComposer.js.map +1 -1
- package/dist/client/org/OrgSwitcher.js +1 -1
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/sharing/ShareButton.d.ts +1 -1
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +2 -15
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/collab/presence.d.ts +1 -1
- package/dist/collab/presence.js +1 -1
- package/dist/collab/presence.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/mcp/connect-route.d.ts.map +1 -1
- package/dist/mcp/connect-route.js +34 -5
- package/dist/mcp/connect-route.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +8 -8
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/action-discovery.d.ts.map +1 -1
- package/dist/server/action-discovery.js +5 -0
- package/dist/server/action-discovery.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +6 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +12 -3
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/sharing/registry.d.ts.map +1 -1
- package/dist/sharing/registry.js +11 -0
- package/dist/sharing/registry.js.map +1 -1
- package/dist/templates/default/pnpm-workspace.yaml +1 -0
- package/dist/templates/workspace-root/pnpm-workspace.yaml +1 -0
- package/docs/content/locales/ar-SA/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/ar-SA/template-design.mdx +1 -1
- package/docs/content/locales/de-DE/real-time-collaboration.mdx +3 -3
- package/docs/content/locales/de-DE/template-design.mdx +1 -1
- package/docs/content/locales/es-ES/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/es-ES/template-design.mdx +1 -1
- package/docs/content/locales/fr-FR/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/fr-FR/template-design.mdx +1 -1
- package/docs/content/locales/hi-IN/template-design.mdx +1 -1
- package/docs/content/locales/ja-JP/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/ja-JP/template-design.mdx +1 -1
- package/docs/content/locales/ko-KR/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/ko-KR/template-design.mdx +1 -1
- package/docs/content/locales/pt-BR/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/pt-BR/template-design.mdx +1 -1
- package/docs/content/locales/zh-CN/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/zh-CN/template-design.mdx +1 -1
- package/docs/content/locales/zh-TW/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/zh-TW/template-design.mdx +1 -1
- package/docs/content/real-time-collaboration.mdx +2 -2
- package/docs/content/template-design.mdx +1 -1
- package/package.json +3 -7
- package/src/templates/default/pnpm-workspace.yaml +1 -0
- package/src/templates/workspace-root/pnpm-workspace.yaml +1 -0
- package/corpus/core/src/brand-kit/fig/decode.ts +0 -410
- package/corpus/core/src/brand-kit/fig/extract-design-system.ts +0 -947
- package/corpus/core/src/brand-kit/fig/fig-to-html.ts +0 -1906
- package/corpus/templates/design/actions/import-figma.ts +0 -55
- package/corpus/templates/design/changelog/2026-06-28-figma-style-code-design-mode.md +0 -6
- package/corpus/templates/design/server/handlers/import-figma-system.ts +0 -86
- package/corpus/templates/design/server/routes/api/import-figma-system.post.ts +0 -1
- package/corpus/templates/slides/server/handlers/import-figma-system.ts +0 -101
- package/corpus/templates/slides/server/routes/api/import-figma-system.post.ts +0 -1
- package/dist/brand-kit/fig/decode.d.ts +0 -33
- package/dist/brand-kit/fig/decode.d.ts.map +0 -1
- package/dist/brand-kit/fig/decode.js +0 -358
- package/dist/brand-kit/fig/decode.js.map +0 -1
- package/dist/brand-kit/fig/extract-design-system.d.ts +0 -44
- package/dist/brand-kit/fig/extract-design-system.d.ts.map +0 -1
- package/dist/brand-kit/fig/extract-design-system.js +0 -752
- package/dist/brand-kit/fig/extract-design-system.js.map +0 -1
- package/dist/brand-kit/fig/fig-to-html.d.ts +0 -246
- package/dist/brand-kit/fig/fig-to-html.d.ts.map +0 -1
- package/dist/brand-kit/fig/fig-to-html.js +0 -1506
- package/dist/brand-kit/fig/fig-to-html.js.map +0 -1
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { eq } from "drizzle-orm";
|
|
2
|
+
import { nanoid } from "nanoid";
|
|
3
|
+
|
|
4
|
+
import { getDb, schema } from "../db/index.js";
|
|
5
|
+
|
|
6
|
+
type BuilderDesignSystemIndexResult = {
|
|
7
|
+
designSystemId: string;
|
|
8
|
+
jobId: string;
|
|
9
|
+
builderUrl: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export function localBuilderDesignSystemId(
|
|
13
|
+
builderDesignSystemId: string,
|
|
14
|
+
): string {
|
|
15
|
+
const slug = builderDesignSystemId
|
|
16
|
+
.replace(/[^a-zA-Z0-9_-]+/g, "-")
|
|
17
|
+
.replace(/^-+|-+$/g, "")
|
|
18
|
+
.slice(0, 96);
|
|
19
|
+
return `builder-${slug || "design-system"}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function builderProxyData({
|
|
23
|
+
builderDesignSystemId,
|
|
24
|
+
jobId,
|
|
25
|
+
builderUrl,
|
|
26
|
+
projectName,
|
|
27
|
+
description,
|
|
28
|
+
}: {
|
|
29
|
+
builderDesignSystemId: string;
|
|
30
|
+
jobId: string;
|
|
31
|
+
builderUrl: string;
|
|
32
|
+
projectName?: string;
|
|
33
|
+
description?: string;
|
|
34
|
+
}) {
|
|
35
|
+
return JSON.stringify({
|
|
36
|
+
source: "builder",
|
|
37
|
+
builderDesignSystemId,
|
|
38
|
+
builderJobId: jobId,
|
|
39
|
+
builderUrl,
|
|
40
|
+
colors: {
|
|
41
|
+
primary: "var(--primary)",
|
|
42
|
+
secondary: "var(--secondary)",
|
|
43
|
+
accent: "var(--accent)",
|
|
44
|
+
background: "var(--background)",
|
|
45
|
+
surface: "var(--card)",
|
|
46
|
+
text: "var(--foreground)",
|
|
47
|
+
textMuted: "var(--muted-foreground)",
|
|
48
|
+
},
|
|
49
|
+
typography: {
|
|
50
|
+
headingFont: "inherit",
|
|
51
|
+
bodyFont: "inherit",
|
|
52
|
+
headingWeight: "700",
|
|
53
|
+
bodyWeight: "400",
|
|
54
|
+
headingSizes: { h1: "48px", h2: "32px", h3: "24px" },
|
|
55
|
+
},
|
|
56
|
+
spacing: { elementGap: "24px", pagePadding: "48px" },
|
|
57
|
+
borders: { radius: "12px", accentWidth: "1px" },
|
|
58
|
+
logos: [],
|
|
59
|
+
notes: [
|
|
60
|
+
"This is a local proxy for a Builder-indexed design system.",
|
|
61
|
+
`Builder design system id: ${builderDesignSystemId}`,
|
|
62
|
+
`Builder indexing job id: ${jobId}`,
|
|
63
|
+
`Builder URL: ${builderUrl}`,
|
|
64
|
+
projectName ? `Requested name: ${projectName}` : "",
|
|
65
|
+
description ? `Context: ${description}` : "",
|
|
66
|
+
"Use Builder as the source of truth for extracted tokens and guidance.",
|
|
67
|
+
]
|
|
68
|
+
.filter(Boolean)
|
|
69
|
+
.join("\n"),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function builderProxyInstructions({
|
|
74
|
+
builderDesignSystemId,
|
|
75
|
+
jobId,
|
|
76
|
+
builderUrl,
|
|
77
|
+
}: {
|
|
78
|
+
builderDesignSystemId: string;
|
|
79
|
+
jobId: string;
|
|
80
|
+
builderUrl: string;
|
|
81
|
+
}) {
|
|
82
|
+
return [
|
|
83
|
+
"This design system is indexed and owned by Builder.",
|
|
84
|
+
`Builder design system id: ${builderDesignSystemId}`,
|
|
85
|
+
`Builder job id: ${jobId}`,
|
|
86
|
+
`Builder URL: ${builderUrl}`,
|
|
87
|
+
"When generating designs, treat Builder as the source of truth for the final extracted tokens, assets, and guidance.",
|
|
88
|
+
].join("\n");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export async function upsertBuilderProxyDesignSystem({
|
|
92
|
+
result,
|
|
93
|
+
ownerEmail,
|
|
94
|
+
orgId,
|
|
95
|
+
projectName,
|
|
96
|
+
description,
|
|
97
|
+
}: {
|
|
98
|
+
result: BuilderDesignSystemIndexResult;
|
|
99
|
+
ownerEmail: string;
|
|
100
|
+
orgId?: string | null;
|
|
101
|
+
projectName?: string;
|
|
102
|
+
description?: string;
|
|
103
|
+
}) {
|
|
104
|
+
const db = getDb();
|
|
105
|
+
const now = new Date().toISOString();
|
|
106
|
+
const baseLocalDesignSystemId = localBuilderDesignSystemId(
|
|
107
|
+
result.designSystemId,
|
|
108
|
+
);
|
|
109
|
+
const title = projectName?.trim() || "Builder indexed design system";
|
|
110
|
+
const localData = builderProxyData({
|
|
111
|
+
builderDesignSystemId: result.designSystemId,
|
|
112
|
+
jobId: result.jobId,
|
|
113
|
+
builderUrl: result.builderUrl,
|
|
114
|
+
projectName,
|
|
115
|
+
description,
|
|
116
|
+
});
|
|
117
|
+
const customInstructions = builderProxyInstructions({
|
|
118
|
+
builderDesignSystemId: result.designSystemId,
|
|
119
|
+
jobId: result.jobId,
|
|
120
|
+
builderUrl: result.builderUrl,
|
|
121
|
+
});
|
|
122
|
+
const [existing] = await db
|
|
123
|
+
.select({
|
|
124
|
+
id: schema.designSystems.id,
|
|
125
|
+
ownerEmail: schema.designSystems.ownerEmail,
|
|
126
|
+
})
|
|
127
|
+
.from(schema.designSystems)
|
|
128
|
+
.where(eq(schema.designSystems.id, baseLocalDesignSystemId))
|
|
129
|
+
.limit(1);
|
|
130
|
+
const localDesignSystemId =
|
|
131
|
+
existing && existing.ownerEmail !== ownerEmail
|
|
132
|
+
? `${baseLocalDesignSystemId}-${nanoid(8)}`
|
|
133
|
+
: baseLocalDesignSystemId;
|
|
134
|
+
if (existing && existing.ownerEmail === ownerEmail) {
|
|
135
|
+
await db
|
|
136
|
+
.update(schema.designSystems)
|
|
137
|
+
.set({
|
|
138
|
+
title,
|
|
139
|
+
description:
|
|
140
|
+
description ??
|
|
141
|
+
`Builder indexed design system ${result.designSystemId}`,
|
|
142
|
+
data: localData,
|
|
143
|
+
assets: "[]",
|
|
144
|
+
customInstructions,
|
|
145
|
+
updatedAt: now,
|
|
146
|
+
})
|
|
147
|
+
.where(eq(schema.designSystems.id, existing.id));
|
|
148
|
+
} else {
|
|
149
|
+
const [ownedSystem] = await db
|
|
150
|
+
.select({ id: schema.designSystems.id })
|
|
151
|
+
.from(schema.designSystems)
|
|
152
|
+
.where(eq(schema.designSystems.ownerEmail, ownerEmail))
|
|
153
|
+
.limit(1);
|
|
154
|
+
await db.insert(schema.designSystems).values({
|
|
155
|
+
id: localDesignSystemId,
|
|
156
|
+
title,
|
|
157
|
+
description:
|
|
158
|
+
description ?? `Builder indexed design system ${result.designSystemId}`,
|
|
159
|
+
data: localData,
|
|
160
|
+
assets: "[]",
|
|
161
|
+
customInstructions,
|
|
162
|
+
isDefault: !ownedSystem,
|
|
163
|
+
ownerEmail,
|
|
164
|
+
orgId: orgId ?? null,
|
|
165
|
+
createdAt: now,
|
|
166
|
+
updatedAt: now,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
localDesignSystemId,
|
|
172
|
+
instructions: [
|
|
173
|
+
"Builder design-system indexing has started.",
|
|
174
|
+
`Builder design system: ${result.designSystemId}`,
|
|
175
|
+
`Local selectable design system: ${localDesignSystemId}`,
|
|
176
|
+
`Builder job: ${result.jobId}`,
|
|
177
|
+
`Open: ${result.builderUrl}`,
|
|
178
|
+
"Use the local design system id in Design flows; Builder remains the source of truth for the indexed brand kit.",
|
|
179
|
+
].join("\n"),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
@@ -114,7 +114,10 @@ function injectResolvedTokensIntoHtml(
|
|
|
114
114
|
): string {
|
|
115
115
|
const entries = Object.entries(resolvedCssVars);
|
|
116
116
|
if (entries.length === 0) return content;
|
|
117
|
-
if (
|
|
117
|
+
if (
|
|
118
|
+
/data-applied-design-tokens|\/\* applied-design-tokens \*\//.test(content)
|
|
119
|
+
)
|
|
120
|
+
return content;
|
|
118
121
|
|
|
119
122
|
const decls = entries
|
|
120
123
|
.map(([name, value]) => ` ${name}: ${value}; /* applied-design-tokens */`)
|
|
@@ -124,9 +127,35 @@ function injectResolvedTokensIntoHtml(
|
|
|
124
127
|
const rootOpen = content.lastIndexOf(":root");
|
|
125
128
|
if (rootOpen !== -1) {
|
|
126
129
|
const braceOpen = content.indexOf("{", rootOpen);
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
+
if (braceOpen !== -1) {
|
|
131
|
+
// Walk forward with a brace-depth counter so values containing `}`
|
|
132
|
+
// (e.g. url("}"), attr() fallbacks) don't fool us into injecting inside
|
|
133
|
+
// the value rather than at the end of the :root block.
|
|
134
|
+
let depth = 0;
|
|
135
|
+
let braceClose = -1;
|
|
136
|
+
let inSingle = false;
|
|
137
|
+
let inDouble = false;
|
|
138
|
+
for (let i = braceOpen; i < content.length; i++) {
|
|
139
|
+
const ch = content[i];
|
|
140
|
+
if (ch === "'" && !inDouble) {
|
|
141
|
+
inSingle = !inSingle;
|
|
142
|
+
} else if (ch === '"' && !inSingle) {
|
|
143
|
+
inDouble = !inDouble;
|
|
144
|
+
} else if (!inSingle && !inDouble) {
|
|
145
|
+
if (ch === "{") {
|
|
146
|
+
depth++;
|
|
147
|
+
} else if (ch === "}") {
|
|
148
|
+
depth--;
|
|
149
|
+
if (depth === 0) {
|
|
150
|
+
braceClose = i;
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (braceClose !== -1) {
|
|
157
|
+
return `${content.slice(0, braceClose)}\n${decls}\n${content.slice(braceClose)}`;
|
|
158
|
+
}
|
|
130
159
|
}
|
|
131
160
|
}
|
|
132
161
|
|
|
@@ -17,6 +17,12 @@ function escapeHtml(str: string): string {
|
|
|
17
17
|
.replace(/"/g, """);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
function extractRenderableHtml(content: string): string {
|
|
21
|
+
const bodyMatch = content.match(/<body\b[^>]*>([\s\S]*?)<\/body>/i);
|
|
22
|
+
if (bodyMatch) return bodyMatch[1].trim();
|
|
23
|
+
return content;
|
|
24
|
+
}
|
|
25
|
+
|
|
20
26
|
export function safeExportBaseName(title: string | null | undefined): string {
|
|
21
27
|
const safe = (title || "design")
|
|
22
28
|
.replace(/[^a-zA-Z0-9_-]/g, "-")
|
|
@@ -42,7 +48,10 @@ export function buildStandaloneHtml(args: {
|
|
|
42
48
|
const jsxFiles = files.filter((f) => f.fileType === "jsx");
|
|
43
49
|
const indexHtml =
|
|
44
50
|
files.find((f) => f.filename === "index.html") ?? htmlFiles[0];
|
|
45
|
-
const combinedCss = cssFiles
|
|
51
|
+
const combinedCss = cssFiles
|
|
52
|
+
.map((f) => f.content ?? "")
|
|
53
|
+
.join("\n\n")
|
|
54
|
+
.replace(/<\/style/gi, "<\\/style");
|
|
46
55
|
|
|
47
56
|
if (
|
|
48
57
|
indexHtml?.content &&
|
|
@@ -53,7 +62,7 @@ export function buildStandaloneHtml(args: {
|
|
|
53
62
|
// so multi-file designs still ship in one bundle.
|
|
54
63
|
const extraBody = [...htmlFiles, ...jsxFiles]
|
|
55
64
|
.filter((f) => f !== indexHtml)
|
|
56
|
-
.map((f) => f.content ?? "")
|
|
65
|
+
.map((f) => extractRenderableHtml(f.content ?? ""))
|
|
57
66
|
.join("\n\n");
|
|
58
67
|
if (extraBody.trim()) {
|
|
59
68
|
// Inline JS / template literals can contain `</body>` strings, so favor
|
|
@@ -85,7 +94,7 @@ export function buildStandaloneHtml(args: {
|
|
|
85
94
|
}
|
|
86
95
|
|
|
87
96
|
const combinedBody = [...htmlFiles, ...jsxFiles]
|
|
88
|
-
.map((f) => f.content ?? "")
|
|
97
|
+
.map((f) => extractRenderableHtml(f.content ?? ""))
|
|
89
98
|
.join("\n\n");
|
|
90
99
|
|
|
91
100
|
return `<!DOCTYPE html>
|
|
@@ -128,18 +137,36 @@ function normalizeHtmlForSvg(html: string): string {
|
|
|
128
137
|
"&",
|
|
129
138
|
);
|
|
130
139
|
|
|
131
|
-
|
|
132
|
-
|
|
140
|
+
// Wrap <script> and <style> block content in CDATA so that JS/CSS with
|
|
141
|
+
// raw `<`, `>`, or `&&` survives the XML parse required by SVG foreignObject.
|
|
142
|
+
const withCdata = withEscapedBareAmpersands
|
|
143
|
+
.replace(
|
|
144
|
+
/(<script\b[^>]*>)([\s\S]*?)(<\/script>)/gi,
|
|
145
|
+
(_, open: string, content: string, close: string) => {
|
|
146
|
+
if (content.includes("//]]>")) return _;
|
|
147
|
+
return `${open}//<![CDATA[\n${content}\n//]]>${close}`;
|
|
148
|
+
},
|
|
149
|
+
)
|
|
150
|
+
.replace(
|
|
151
|
+
/(<style\b[^>]*>)([\s\S]*?)(<\/style>)/gi,
|
|
152
|
+
(_, open: string, content: string, close: string) => {
|
|
153
|
+
if (content.includes("]]>")) return _;
|
|
154
|
+
return `${open}<![CDATA[\n${content}\n]]>${close}`;
|
|
155
|
+
},
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
if (/<html\b[^>]*\bxmlns=/i.test(withCdata)) {
|
|
159
|
+
return withCdata;
|
|
133
160
|
}
|
|
134
161
|
|
|
135
|
-
if (/<html\b/i.test(
|
|
136
|
-
return
|
|
162
|
+
if (/<html\b/i.test(withCdata)) {
|
|
163
|
+
return withCdata.replace(
|
|
137
164
|
/<html\b/i,
|
|
138
165
|
'<html xmlns="http://www.w3.org/1999/xhtml"',
|
|
139
166
|
);
|
|
140
167
|
}
|
|
141
168
|
|
|
142
|
-
return `<html xmlns="http://www.w3.org/1999/xhtml"><body>${
|
|
169
|
+
return `<html xmlns="http://www.w3.org/1999/xhtml"><body>${withCdata}</body></html>`;
|
|
143
170
|
}
|
|
144
171
|
|
|
145
172
|
export function buildSvgForeignObject(args: {
|
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
import actionsRegistry from "../../.generated/actions-registry.js";
|
|
8
8
|
import "../register-secrets.js";
|
|
9
9
|
|
|
10
|
+
const DESIGN_BACKGROUND_RUN_SOFT_TIMEOUT_MS = 13 * 60_000;
|
|
11
|
+
|
|
10
12
|
const INITIAL_TOOL_NAMES = [
|
|
11
13
|
"view-screen",
|
|
12
14
|
"list-designs",
|
|
@@ -37,6 +39,8 @@ export default createAgentChatPlugin({
|
|
|
37
39
|
// paginate, and reduce provider data through providerFetch() without us
|
|
38
40
|
// hardcoding one action per GitHub endpoint.
|
|
39
41
|
codeExecution: { production: "sandboxed" },
|
|
42
|
+
durableBackgroundRuns: true,
|
|
43
|
+
runSoftTimeoutMs: DESIGN_BACKGROUND_RUN_SOFT_TIMEOUT_MS,
|
|
40
44
|
resolveOrgId: async (event) => (await getOrgContext(event)).orgId,
|
|
41
45
|
systemPrompt: `You are an AI prototyping assistant. You create and edit designs, files, design systems, variants, exports, sharing, and connected repository context through actions and shared application state.
|
|
42
46
|
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { createAuthPlugin } from "@agent-native/core/server";
|
|
2
2
|
|
|
3
3
|
export default createAuthPlugin({
|
|
4
|
+
workspaceAppAudience: "internal",
|
|
5
|
+
// The visual-edit entry route and public design editor links can load without
|
|
6
|
+
// a session. Creating, mutating, generating, and sharing designs still go
|
|
7
|
+
// through authenticated actions.
|
|
8
|
+
workspaceAppPublicPaths: ["/visual-edit", "/design"],
|
|
4
9
|
marketing: {
|
|
5
10
|
appName: "Agent-Native Design",
|
|
6
11
|
tagline:
|
|
@@ -19,5 +24,9 @@ export default createAuthPlugin({
|
|
|
19
24
|
// publicPaths uses prefix matching, so this covers
|
|
20
25
|
// /api/design-handoff/<id>?token=... while keeping every other /api/* and
|
|
21
26
|
// /_agent-native/* route behind auth.
|
|
22
|
-
publicPaths: [
|
|
27
|
+
publicPaths: [
|
|
28
|
+
"/api/design-handoff",
|
|
29
|
+
"/__manifest",
|
|
30
|
+
"/_agent-native/actions/get-design",
|
|
31
|
+
],
|
|
23
32
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { indexDesignSystemWithBuilder as default } from "../../handlers/index-design-system-with-builder";
|
|
@@ -81,6 +81,8 @@ export interface TweakDefinition {
|
|
|
81
81
|
step?: number;
|
|
82
82
|
defaultValue: string | number | boolean;
|
|
83
83
|
cssVar?: string;
|
|
84
|
+
/** CSS unit to append when resolving a numeric slider value, e.g. "px" or "rem". When omitted, "px" is inferred for vars whose name contains "radius" and no unit is added for others. */
|
|
85
|
+
unit?: string;
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
// --- Question Flow ---
|
|
@@ -30,8 +30,9 @@ function escapeRegExp(value: string): string {
|
|
|
30
30
|
|
|
31
31
|
function countOccurrences(haystack: string, needle: string): number {
|
|
32
32
|
if (!needle) return 0;
|
|
33
|
-
// Step by 1 (not by needle length) so self-overlapping matches
|
|
34
|
-
//
|
|
33
|
+
// Step by 1 (not by needle length) so self-overlapping matches are counted.
|
|
34
|
+
// A count > 1 does NOT immediately throw — Strategy 2 runs first and may
|
|
35
|
+
// still resolve a unique non-overlapping match.
|
|
35
36
|
let count = 0;
|
|
36
37
|
let idx = haystack.indexOf(needle);
|
|
37
38
|
while (idx !== -1) {
|
|
@@ -61,11 +62,10 @@ export function applyOneEdit(
|
|
|
61
62
|
// Strategy 1 — exact substring.
|
|
62
63
|
const exact = countOccurrences(content, search);
|
|
63
64
|
if (exact === 1) return content.split(search).join(replace);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
65
|
+
// When exact > 1 (including self-overlapping matches), fall through to
|
|
66
|
+
// Strategy 2 before declaring ambiguity. Strategy 2 uses a non-overlapping
|
|
67
|
+
// regex scan, so a search string that appears self-overlapping under Strategy
|
|
68
|
+
// 1 may still resolve to a single unique whitespace-flexible match.
|
|
69
69
|
|
|
70
70
|
// Strategy 2 — whitespace-flexible.
|
|
71
71
|
const pattern = escapeRegExp(search).replace(/\s+/g, "\\s+");
|
|
@@ -77,8 +77,12 @@ export function applyOneEdit(
|
|
|
77
77
|
return content.replace(re, () => replace);
|
|
78
78
|
}
|
|
79
79
|
if (flexible > 1) {
|
|
80
|
+
const detail =
|
|
81
|
+
exact > 1
|
|
82
|
+
? `${exact} places (exact) and ${flexible} places (whitespace-insensitive)`
|
|
83
|
+
: `${flexible} places (whitespace-insensitive)`;
|
|
80
84
|
throw new Error(
|
|
81
|
-
`Edit ${index + 1}: "search" matched ${
|
|
85
|
+
`Edit ${index + 1}: "search" matched ${detail} — add more surrounding context so it matches exactly one location.`,
|
|
82
86
|
);
|
|
83
87
|
}
|
|
84
88
|
|
|
@@ -346,7 +346,10 @@ export function assignRegions(
|
|
|
346
346
|
const requestedColumns =
|
|
347
347
|
options.columns == null
|
|
348
348
|
? maxColumns
|
|
349
|
-
:
|
|
349
|
+
: Math.min(
|
|
350
|
+
maxColumns,
|
|
351
|
+
getWholeNumberAtLeast(options.columns, maxColumns, 1),
|
|
352
|
+
);
|
|
350
353
|
const columns = Math.min(total, requestedColumns);
|
|
351
354
|
|
|
352
355
|
return Array.from({ length: total }, (_, index) => {
|
|
@@ -563,9 +566,24 @@ export function resizeFrameFromDelta(
|
|
|
563
566
|
}
|
|
564
567
|
}
|
|
565
568
|
|
|
569
|
+
const preClampWidth = width;
|
|
570
|
+
const preClampHeight = height;
|
|
566
571
|
width = Math.max(options.minWidth ?? MIN_CANVAS_FRAME_WIDTH, width);
|
|
567
572
|
height = Math.max(options.minHeight ?? MIN_CANVAS_FRAME_HEIGHT, height);
|
|
568
573
|
|
|
574
|
+
if (options.preserveAspectRatio) {
|
|
575
|
+
const widthClamped = width > preClampWidth;
|
|
576
|
+
const heightClamped = height > preClampHeight;
|
|
577
|
+
if (widthClamped && !heightClamped) {
|
|
578
|
+
height = width / ratio;
|
|
579
|
+
} else if (heightClamped && !widthClamped) {
|
|
580
|
+
width = height * ratio;
|
|
581
|
+
} else if (widthClamped && heightClamped) {
|
|
582
|
+
// Both axes hit their minimum; width wins as the primary authority
|
|
583
|
+
height = width / ratio;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
569
587
|
return {
|
|
570
588
|
...origin,
|
|
571
589
|
x: getResizedAxisStart(
|
|
@@ -557,6 +557,20 @@ const NON_VISUAL_TAGS = new Set([
|
|
|
557
557
|
|
|
558
558
|
const RAW_TEXT_VISUAL_TAGS = new Set(["textarea"]);
|
|
559
559
|
|
|
560
|
+
// HTML5 elements that are implicitly closed when a sibling of the same (or
|
|
561
|
+
// related) type opens, because their closing tags are optional per the spec.
|
|
562
|
+
const IMPLICIT_CLOSE_TAGS: Map<string, Set<string>> = new Map([
|
|
563
|
+
["li", new Set(["li"])],
|
|
564
|
+
["p", new Set(["p"])],
|
|
565
|
+
["td", new Set(["td", "th"])],
|
|
566
|
+
["th", new Set(["td", "th"])],
|
|
567
|
+
["tr", new Set(["tr"])],
|
|
568
|
+
["dt", new Set(["dt", "dd"])],
|
|
569
|
+
["dd", new Set(["dt", "dd"])],
|
|
570
|
+
["option", new Set(["option"])],
|
|
571
|
+
["optgroup", new Set(["optgroup"])],
|
|
572
|
+
]);
|
|
573
|
+
|
|
560
574
|
const DATA_SELECTOR_PRIORITY = [
|
|
561
575
|
"data-agent-native-node-id",
|
|
562
576
|
"data-code-layer-id",
|
|
@@ -1017,15 +1031,36 @@ function parseHtmlElements(html: string): ParsedElement[] {
|
|
|
1017
1031
|
const element = elements[stack[i]];
|
|
1018
1032
|
if (!element) continue;
|
|
1019
1033
|
stack.pop();
|
|
1020
|
-
element.
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1034
|
+
if (element.tag === tag) {
|
|
1035
|
+
element.closeStart = match.index;
|
|
1036
|
+
element.closeEnd = match.index + raw.length;
|
|
1037
|
+
element.contentEnd = match.index;
|
|
1038
|
+
element.end = match.index + raw.length;
|
|
1039
|
+
break;
|
|
1040
|
+
} else {
|
|
1041
|
+
// Implicitly close optional-close-tag elements (e.g. <li>, <p>)
|
|
1042
|
+
// without attributing the parent's close tag to them.
|
|
1043
|
+
element.contentEnd = match.index;
|
|
1044
|
+
element.end = match.index;
|
|
1045
|
+
}
|
|
1025
1046
|
}
|
|
1026
1047
|
continue;
|
|
1027
1048
|
}
|
|
1028
1049
|
|
|
1050
|
+
// Auto-close HTML5 optional-close-tag elements when a sibling of the same
|
|
1051
|
+
// type (or a related type) opens. This mirrors how browsers handle elements
|
|
1052
|
+
// like <li>, <p>, <td>, <th>, <tr>, <dt>, <dd>, <option>, <optgroup>.
|
|
1053
|
+
const stackTopTag =
|
|
1054
|
+
stack.length > 0 ? elements[stack[stack.length - 1]]?.tag : undefined;
|
|
1055
|
+
if (stackTopTag && IMPLICIT_CLOSE_TAGS.get(tag)?.has(stackTopTag)) {
|
|
1056
|
+
const popped = stack.pop()!;
|
|
1057
|
+
const poppedElement = elements[popped];
|
|
1058
|
+
if (poppedElement) {
|
|
1059
|
+
poppedElement.contentEnd = match.index;
|
|
1060
|
+
poppedElement.end = match.index;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1029
1064
|
const parentIndex = stack.length > 0 ? stack[stack.length - 1] : undefined;
|
|
1030
1065
|
const parentKey = `${parentIndex ?? "root"}:${tag}`;
|
|
1031
1066
|
const nthOfType = (sameTypeCounts.get(parentKey) ?? 0) + 1;
|
|
@@ -1140,7 +1175,7 @@ function pathSelector(
|
|
|
1140
1175
|
? undefined
|
|
1141
1176
|
: elements[current.parentIndex];
|
|
1142
1177
|
}
|
|
1143
|
-
return parts.
|
|
1178
|
+
return parts.join(" > ");
|
|
1144
1179
|
}
|
|
1145
1180
|
|
|
1146
1181
|
function primarySelector(
|
|
@@ -1314,24 +1349,32 @@ function layoutFor(
|
|
|
1314
1349
|
style.display ??
|
|
1315
1350
|
(classes.has("flex")
|
|
1316
1351
|
? "flex"
|
|
1317
|
-
: classes.has("
|
|
1318
|
-
? "
|
|
1319
|
-
: classes.has("
|
|
1320
|
-
? "
|
|
1321
|
-
: classes.has("
|
|
1322
|
-
? "
|
|
1323
|
-
: classes.has("
|
|
1324
|
-
? "
|
|
1325
|
-
:
|
|
1352
|
+
: classes.has("inline-flex")
|
|
1353
|
+
? "inline-flex"
|
|
1354
|
+
: classes.has("grid")
|
|
1355
|
+
? "grid"
|
|
1356
|
+
: classes.has("inline-grid")
|
|
1357
|
+
? "inline-grid"
|
|
1358
|
+
: classes.has("hidden")
|
|
1359
|
+
? "none"
|
|
1360
|
+
: classes.has("block")
|
|
1361
|
+
? "block"
|
|
1362
|
+
: classes.has("inline-block")
|
|
1363
|
+
? "inline-block"
|
|
1364
|
+
: undefined);
|
|
1326
1365
|
const parentDisplay =
|
|
1327
1366
|
parentStyle?.display ??
|
|
1328
1367
|
(parentClasses?.has("flex")
|
|
1329
1368
|
? "flex"
|
|
1330
|
-
: parentClasses?.has("
|
|
1331
|
-
? "
|
|
1332
|
-
: parentClasses?.has("
|
|
1333
|
-
? "
|
|
1334
|
-
:
|
|
1369
|
+
: parentClasses?.has("inline-flex")
|
|
1370
|
+
? "inline-flex"
|
|
1371
|
+
: parentClasses?.has("grid")
|
|
1372
|
+
? "grid"
|
|
1373
|
+
: parentClasses?.has("inline-grid")
|
|
1374
|
+
? "inline-grid"
|
|
1375
|
+
: parentClasses?.has("hidden")
|
|
1376
|
+
? "none"
|
|
1377
|
+
: undefined);
|
|
1335
1378
|
const flexDirection =
|
|
1336
1379
|
style["flex-direction"] ??
|
|
1337
1380
|
(classes.has("flex-col")
|
|
@@ -1921,11 +1964,8 @@ function selectorMatches(
|
|
|
1921
1964
|
const selectorHasDirectPath = normalizedSelector.includes(" > ");
|
|
1922
1965
|
if (
|
|
1923
1966
|
selectorHasDirectPath &&
|
|
1924
|
-
normalizedNodeSelectors.some(
|
|
1925
|
-
(
|
|
1926
|
-
candidate.endsWith(` > ${normalizedSelector}`) ||
|
|
1927
|
-
(candidate.includes(" > ") &&
|
|
1928
|
-
normalizedSelector.endsWith(` > ${candidate}`)),
|
|
1967
|
+
normalizedNodeSelectors.some((candidate) =>
|
|
1968
|
+
candidate.endsWith(` > ${normalizedSelector}`),
|
|
1929
1969
|
)
|
|
1930
1970
|
) {
|
|
1931
1971
|
return true;
|
|
@@ -2180,7 +2220,7 @@ function sanitizeTextEditHtml(html: string): string {
|
|
|
2180
2220
|
)
|
|
2181
2221
|
.replace(/\s+on[A-Za-z]+\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/g, "")
|
|
2182
2222
|
.replace(
|
|
2183
|
-
/\s+(href|src|xlink:href)\s*=\s*(["'])\s*javascript:[\s\S]*?\2/gi,
|
|
2223
|
+
/\s+(href|src|xlink:href)\s*=\s*(?:(["'])\s*(?:javascript|vbscript|data):[\s\S]*?\2|(?:javascript|vbscript|data):[^\s>]*)/gi,
|
|
2184
2224
|
"",
|
|
2185
2225
|
);
|
|
2186
2226
|
}
|
|
@@ -2253,6 +2293,7 @@ function applyMoveNodeEdit(
|
|
|
2253
2293
|
function findAfterNode(
|
|
2254
2294
|
projection: CodeLayerProjection,
|
|
2255
2295
|
before: CodeLayerNode,
|
|
2296
|
+
insertAt?: number,
|
|
2256
2297
|
): CodeLayerNode | undefined {
|
|
2257
2298
|
return (
|
|
2258
2299
|
projection.nodes.find((node) => node.id === before.id) ??
|
|
@@ -2260,7 +2301,13 @@ function findAfterNode(
|
|
|
2260
2301
|
(node) =>
|
|
2261
2302
|
node.tag === before.tag &&
|
|
2262
2303
|
node.source?.openStart === before.source?.openStart,
|
|
2263
|
-
)
|
|
2304
|
+
) ??
|
|
2305
|
+
(insertAt !== undefined
|
|
2306
|
+
? projection.nodes.find(
|
|
2307
|
+
(node) =>
|
|
2308
|
+
node.tag === before.tag && node.source?.openStart === insertAt,
|
|
2309
|
+
)
|
|
2310
|
+
: undefined)
|
|
2264
2311
|
);
|
|
2265
2312
|
}
|
|
2266
2313
|
|
|
@@ -2322,6 +2369,7 @@ export function applyVisualEdit(
|
|
|
2322
2369
|
}
|
|
2323
2370
|
|
|
2324
2371
|
let edit: { content: string; capability: EditCapability } | PatchResultStatus;
|
|
2372
|
+
let moveInsertAt: number | undefined;
|
|
2325
2373
|
if (intent.kind === "style") {
|
|
2326
2374
|
edit = applyStyleEdit(html, element, intent);
|
|
2327
2375
|
} else if (intent.kind === "class") {
|
|
@@ -2363,6 +2411,17 @@ export function applyVisualEdit(
|
|
|
2363
2411
|
),
|
|
2364
2412
|
};
|
|
2365
2413
|
}
|
|
2414
|
+
// Compute the expected post-move openStart so findAfterNode can locate the
|
|
2415
|
+
// moved node even when its nodeId changes (position-based id).
|
|
2416
|
+
const rawInsertAt =
|
|
2417
|
+
intent.placement === "before"
|
|
2418
|
+
? anchorElement.start
|
|
2419
|
+
: intent.placement === "after"
|
|
2420
|
+
? anchorElement.end
|
|
2421
|
+
: anchorElement.contentEnd;
|
|
2422
|
+
const removedLength = element.end - element.start;
|
|
2423
|
+
moveInsertAt =
|
|
2424
|
+
element.start < rawInsertAt ? rawInsertAt - removedLength : rawInsertAt;
|
|
2366
2425
|
edit = applyMoveNodeEdit(html, element, anchorElement, intent);
|
|
2367
2426
|
}
|
|
2368
2427
|
|
|
@@ -2389,7 +2448,7 @@ export function applyVisualEdit(
|
|
|
2389
2448
|
}
|
|
2390
2449
|
|
|
2391
2450
|
const nextProjection = buildCodeLayerProjection(edit.content, { source });
|
|
2392
|
-
const afterNode = findAfterNode(nextProjection, beforeNode);
|
|
2451
|
+
const afterNode = findAfterNode(nextProjection, beforeNode, moveInsertAt);
|
|
2393
2452
|
const after = afterNode ? summarizeNode(afterNode) : undefined;
|
|
2394
2453
|
|
|
2395
2454
|
return {
|
|
@@ -24,8 +24,8 @@ export type TweakSelections = Record<string, string | number | boolean>;
|
|
|
24
24
|
* assignments. Rules (must match the editor's historical inline behavior):
|
|
25
25
|
*
|
|
26
26
|
* - booleans -> "1" / "0"
|
|
27
|
-
* - numbers -> `${value}` plus
|
|
28
|
-
* otherwise unitless
|
|
27
|
+
* - numbers -> `${value}` plus `t.unit` when provided, falling back to "px"
|
|
28
|
+
* when the CSS var name contains "radius", otherwise unitless
|
|
29
29
|
* - strings -> the string as-is
|
|
30
30
|
*
|
|
31
31
|
* Tweaks without a `cssVar` are skipped (they don't map to a property).
|
|
@@ -42,7 +42,8 @@ export function resolveTweaksToCssVars(
|
|
|
42
42
|
if (typeof v === "boolean") {
|
|
43
43
|
out[t.cssVar] = v ? "1" : "0";
|
|
44
44
|
} else if (typeof v === "number") {
|
|
45
|
-
const unit =
|
|
45
|
+
const unit =
|
|
46
|
+
t.unit ?? (t.cssVar.toLowerCase().includes("radius") ? "px" : "");
|
|
46
47
|
out[t.cssVar] = `${v}${unit}`;
|
|
47
48
|
} else {
|
|
48
49
|
out[t.cssVar] = String(v);
|