@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
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
getRequestUserEmail,
|
|
4
4
|
getRequestOrgId,
|
|
5
5
|
} from "@agent-native/core/server/request-context";
|
|
6
|
-
import { eq } from "drizzle-orm";
|
|
6
|
+
import { and, eq, isNull } from "drizzle-orm";
|
|
7
7
|
import { nanoid } from "nanoid";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
|
|
@@ -66,12 +66,23 @@ export default defineAction({
|
|
|
66
66
|
if (!ownerEmail) throw new Error("no authenticated user");
|
|
67
67
|
const orgId = getRequestOrgId();
|
|
68
68
|
|
|
69
|
-
// Check only this user's owned systems. Shared systems
|
|
70
|
-
// the first system a user creates from becoming their
|
|
69
|
+
// Check only this user's owned systems within the same org. Shared systems
|
|
70
|
+
// should not prevent the first system a user creates from becoming their
|
|
71
|
+
// default, and systems in other orgs must not suppress the default in this org.
|
|
71
72
|
const existing = await db
|
|
72
73
|
.select({ id: schema.designSystems.id })
|
|
73
74
|
.from(schema.designSystems)
|
|
74
|
-
.where(
|
|
75
|
+
.where(
|
|
76
|
+
orgId
|
|
77
|
+
? and(
|
|
78
|
+
eq(schema.designSystems.ownerEmail, ownerEmail),
|
|
79
|
+
eq(schema.designSystems.orgId, orgId),
|
|
80
|
+
)
|
|
81
|
+
: and(
|
|
82
|
+
eq(schema.designSystems.ownerEmail, ownerEmail),
|
|
83
|
+
isNull(schema.designSystems.orgId),
|
|
84
|
+
),
|
|
85
|
+
)
|
|
75
86
|
.limit(1);
|
|
76
87
|
|
|
77
88
|
const isDefault = existing.length === 0;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import { seedFromText } from "@agent-native/core/collab";
|
|
3
3
|
import { assertAccess } from "@agent-native/core/sharing";
|
|
4
|
-
import { eq } from "drizzle-orm";
|
|
4
|
+
import { and, eq } from "drizzle-orm";
|
|
5
5
|
import { nanoid } from "nanoid";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
|
|
@@ -34,6 +34,25 @@ export default defineAction({
|
|
|
34
34
|
await assertAccess("design", designId, "editor");
|
|
35
35
|
|
|
36
36
|
const db = getDb();
|
|
37
|
+
|
|
38
|
+
// Guard against duplicate (designId, filename) — edit-design uses .limit(1)
|
|
39
|
+
// which is non-deterministic when multiple rows match the same key.
|
|
40
|
+
const [existing] = await db
|
|
41
|
+
.select({ id: schema.designFiles.id })
|
|
42
|
+
.from(schema.designFiles)
|
|
43
|
+
.where(
|
|
44
|
+
and(
|
|
45
|
+
eq(schema.designFiles.designId, designId),
|
|
46
|
+
eq(schema.designFiles.filename, filename),
|
|
47
|
+
),
|
|
48
|
+
)
|
|
49
|
+
.limit(1);
|
|
50
|
+
if (existing) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`File "${filename}" already exists in design ${designId} — use edit-design to modify it`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
37
56
|
const id = nanoid();
|
|
38
57
|
const now = new Date().toISOString();
|
|
39
58
|
|
|
@@ -7,12 +7,12 @@ import { getDb, schema } from "../server/db/index.js";
|
|
|
7
7
|
|
|
8
8
|
export default defineAction({
|
|
9
9
|
description:
|
|
10
|
-
"Delete a design system. Requires
|
|
10
|
+
"Delete a design system. Requires owner access. Designs linked to it are unlinked.",
|
|
11
11
|
schema: z.object({
|
|
12
12
|
id: z.string().min(1).describe("Design system ID to delete"),
|
|
13
13
|
}),
|
|
14
14
|
run: async ({ id }) => {
|
|
15
|
-
await assertAccess("design-system", id, "
|
|
15
|
+
await assertAccess("design-system", id, "owner");
|
|
16
16
|
|
|
17
17
|
const db = getDb();
|
|
18
18
|
|
|
@@ -31,14 +31,45 @@ export default defineAction({
|
|
|
31
31
|
const now = new Date().toISOString();
|
|
32
32
|
const newTitle = title || `Copy of ${source.title}`;
|
|
33
33
|
|
|
34
|
-
//
|
|
34
|
+
// Fetch source files first so we can remap canvasFrames before inserting
|
|
35
|
+
const files = await db
|
|
36
|
+
.select()
|
|
37
|
+
.from(schema.designFiles)
|
|
38
|
+
.where(eq(schema.designFiles.designId, id));
|
|
39
|
+
|
|
40
|
+
// Build old-to-new file ID mapping upfront
|
|
41
|
+
const idMap = new Map<string, string>(
|
|
42
|
+
files.map((file) => [file.id, nanoid()]),
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
// Remap canvasFrames keys in source.data from old IDs to new IDs
|
|
46
|
+
let newData = source.data;
|
|
47
|
+
try {
|
|
48
|
+
const parsed =
|
|
49
|
+
typeof source.data === "string" ? JSON.parse(source.data) : source.data;
|
|
50
|
+
if (parsed && typeof parsed === "object" && parsed.canvasFrames) {
|
|
51
|
+
const remapped: Record<string, unknown> = {};
|
|
52
|
+
for (const [oldId, geometry] of Object.entries(parsed.canvasFrames)) {
|
|
53
|
+
const newFileId = idMap.get(oldId);
|
|
54
|
+
remapped[newFileId ?? oldId] = geometry;
|
|
55
|
+
}
|
|
56
|
+
newData =
|
|
57
|
+
typeof source.data === "string"
|
|
58
|
+
? JSON.stringify({ ...parsed, canvasFrames: remapped })
|
|
59
|
+
: { ...parsed, canvasFrames: remapped };
|
|
60
|
+
}
|
|
61
|
+
} catch {
|
|
62
|
+
// If data is unparseable, fall back to copying verbatim
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Copy the design with remapped canvasFrames
|
|
35
66
|
await db.insert(schema.designs).values({
|
|
36
67
|
id: newId,
|
|
37
68
|
title: newTitle,
|
|
38
69
|
description: source.description,
|
|
39
70
|
projectType: source.projectType,
|
|
40
71
|
designSystemId: source.designSystemId ?? null,
|
|
41
|
-
data:
|
|
72
|
+
data: newData,
|
|
42
73
|
ownerEmail: (() => {
|
|
43
74
|
const e = getRequestUserEmail();
|
|
44
75
|
if (!e) throw new Error("no authenticated user");
|
|
@@ -49,15 +80,10 @@ export default defineAction({
|
|
|
49
80
|
updatedAt: now,
|
|
50
81
|
});
|
|
51
82
|
|
|
52
|
-
// Copy all associated files
|
|
53
|
-
const files = await db
|
|
54
|
-
.select()
|
|
55
|
-
.from(schema.designFiles)
|
|
56
|
-
.where(eq(schema.designFiles.designId, id));
|
|
57
|
-
|
|
83
|
+
// Copy all associated files using the pre-generated IDs
|
|
58
84
|
for (const file of files) {
|
|
59
85
|
await db.insert(schema.designFiles).values({
|
|
60
|
-
id:
|
|
86
|
+
id: idMap.get(file.id)!,
|
|
61
87
|
designId: newId,
|
|
62
88
|
filename: file.filename,
|
|
63
89
|
fileType: file.fileType,
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { defineAction, embedApp } from "@agent-native/core";
|
|
2
|
+
import {
|
|
3
|
+
deleteAppState,
|
|
4
|
+
readAppState,
|
|
5
|
+
writeAppState,
|
|
6
|
+
} from "@agent-native/core/application-state";
|
|
2
7
|
import {
|
|
3
8
|
hasCollabState,
|
|
4
9
|
applyText,
|
|
@@ -18,6 +23,10 @@ import {
|
|
|
18
23
|
mergeCanvasFramePlacements,
|
|
19
24
|
type CanvasFramePlacement,
|
|
20
25
|
} from "../shared/canvas-frames.js";
|
|
26
|
+
import {
|
|
27
|
+
designGenerationSessionKey,
|
|
28
|
+
type DesignGenerationSession,
|
|
29
|
+
} from "../shared/generation-session.js";
|
|
21
30
|
|
|
22
31
|
/** Editor deep link so external agents can surface "Open design". */
|
|
23
32
|
function designDeepLink(designId: string): string {
|
|
@@ -28,6 +37,50 @@ function designDeepLink(designId: string): string {
|
|
|
28
37
|
});
|
|
29
38
|
}
|
|
30
39
|
|
|
40
|
+
function isRenderableDesignFile(file: {
|
|
41
|
+
fileType?: string | null;
|
|
42
|
+
content?: string | null;
|
|
43
|
+
}): boolean {
|
|
44
|
+
const fileType = file.fileType ?? "html";
|
|
45
|
+
return (
|
|
46
|
+
(fileType === "html" || fileType === "jsx") && Boolean(file.content?.trim())
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function updateGenerationSessionForSavedFiles(
|
|
51
|
+
designId: string,
|
|
52
|
+
savedFilenames: string[],
|
|
53
|
+
) {
|
|
54
|
+
const key = designGenerationSessionKey(designId);
|
|
55
|
+
const rawSession = await readAppState(key).catch(() => null);
|
|
56
|
+
if (!rawSession || typeof rawSession !== "object") return;
|
|
57
|
+
const session = rawSession as unknown as DesignGenerationSession;
|
|
58
|
+
if (session.designId !== designId || !Array.isArray(session.frames)) return;
|
|
59
|
+
|
|
60
|
+
const saved = new Set(savedFilenames);
|
|
61
|
+
const frames = session.frames.map((frame) =>
|
|
62
|
+
frame.filename && saved.has(frame.filename)
|
|
63
|
+
? {
|
|
64
|
+
...frame,
|
|
65
|
+
status: "done" as const,
|
|
66
|
+
step: "Saved",
|
|
67
|
+
progress: 1,
|
|
68
|
+
}
|
|
69
|
+
: frame,
|
|
70
|
+
);
|
|
71
|
+
const allDone = frames.every((frame) => frame.status === "done");
|
|
72
|
+
if (allDone) {
|
|
73
|
+
await deleteAppState(key);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
await writeAppState(key, {
|
|
78
|
+
...session,
|
|
79
|
+
status: "generating",
|
|
80
|
+
frames,
|
|
81
|
+
} as unknown as Record<string, unknown>);
|
|
82
|
+
}
|
|
83
|
+
|
|
31
84
|
export default defineAction({
|
|
32
85
|
description:
|
|
33
86
|
"Save generated design content to a design project. " +
|
|
@@ -181,19 +234,6 @@ export default defineAction({
|
|
|
181
234
|
}
|
|
182
235
|
}
|
|
183
236
|
|
|
184
|
-
const hasRenderableFile = files.some((file) => {
|
|
185
|
-
const fileType = file.fileType ?? "html";
|
|
186
|
-
return (
|
|
187
|
-
(fileType === "html" || fileType === "jsx") &&
|
|
188
|
-
file.content.trim().length > 0
|
|
189
|
-
);
|
|
190
|
-
});
|
|
191
|
-
if (!hasRenderableFile) {
|
|
192
|
-
throw new Error(
|
|
193
|
-
"generate-design requires at least one non-empty HTML or JSX file before the design can be reported as ready",
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
237
|
const savedFiles: Array<{
|
|
198
238
|
id: string;
|
|
199
239
|
filename: string;
|
|
@@ -206,6 +246,15 @@ export default defineAction({
|
|
|
206
246
|
.from(schema.designFiles)
|
|
207
247
|
.where(eq(schema.designFiles.designId, designId));
|
|
208
248
|
|
|
249
|
+
const hasRenderableFile =
|
|
250
|
+
files.some(isRenderableDesignFile) ||
|
|
251
|
+
existingFiles.some(isRenderableDesignFile);
|
|
252
|
+
if (!hasRenderableFile) {
|
|
253
|
+
throw new Error(
|
|
254
|
+
"generate-design requires at least one non-empty HTML or JSX file before the design can be reported as ready",
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
209
258
|
const existingByName = new Map(existingFiles.map((f) => [f.filename, f]));
|
|
210
259
|
|
|
211
260
|
for (const file of files) {
|
|
@@ -270,6 +319,19 @@ export default defineAction({
|
|
|
270
319
|
agentLeaveDocument(fileId);
|
|
271
320
|
}
|
|
272
321
|
|
|
322
|
+
// Update the in-memory map so a second entry with the same filename
|
|
323
|
+
// in the same `files` array hits the UPDATE branch instead of
|
|
324
|
+
// inserting a duplicate row.
|
|
325
|
+
existingByName.set(file.filename, {
|
|
326
|
+
id: fileId,
|
|
327
|
+
designId,
|
|
328
|
+
filename: file.filename,
|
|
329
|
+
fileType: file.fileType ?? "html",
|
|
330
|
+
content: file.content,
|
|
331
|
+
createdAt: now,
|
|
332
|
+
updatedAt: now,
|
|
333
|
+
});
|
|
334
|
+
|
|
273
335
|
savedFiles.push({
|
|
274
336
|
id: fileId,
|
|
275
337
|
filename: file.filename,
|
|
@@ -290,31 +352,12 @@ export default defineAction({
|
|
|
290
352
|
// Merge with existing data so tweak definitions survive content updates.
|
|
291
353
|
// The data column is a free-form JSON blob; we own these keys here and
|
|
292
354
|
// leave anything else intact.
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
try {
|
|
300
|
-
const parsed = JSON.parse(existingDesign.data);
|
|
301
|
-
if (parsed && typeof parsed === "object") prevData = parsed;
|
|
302
|
-
} catch {
|
|
303
|
-
// Stale or invalid JSON — start fresh.
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
const mergedData: Record<string, unknown> = {
|
|
307
|
-
...prevData,
|
|
308
|
-
lastPrompt: prompt,
|
|
309
|
-
generatedAt: now,
|
|
310
|
-
fileCount: files.length,
|
|
311
|
-
};
|
|
312
|
-
if (tweaks !== undefined) {
|
|
313
|
-
mergedData.tweaks = tweaks.map((tweak) => ({
|
|
314
|
-
...tweak,
|
|
315
|
-
type: tweak.type === "color-swatches" ? "color-swatch" : tweak.type,
|
|
316
|
-
}));
|
|
317
|
-
}
|
|
355
|
+
//
|
|
356
|
+
// Wrapped in a transaction so that concurrent generate-design calls for the
|
|
357
|
+
// same design (e.g. the parallel fan-out from generate-screens) each read
|
|
358
|
+
// the latest canvasFrames and merge their own placement on top, rather than
|
|
359
|
+
// all reading the same stale snapshot and the last writer silently
|
|
360
|
+
// discarding the others' frame coordinates.
|
|
318
361
|
let placedFrames:
|
|
319
362
|
| Array<{
|
|
320
363
|
fileId: string;
|
|
@@ -322,39 +365,73 @@ export default defineAction({
|
|
|
322
365
|
frame: CanvasFramePlacement;
|
|
323
366
|
}>
|
|
324
367
|
| undefined;
|
|
325
|
-
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
368
|
+
await db.transaction(async (tx) => {
|
|
369
|
+
const [existingDesign] = await tx
|
|
370
|
+
.select({ data: schema.designs.data })
|
|
371
|
+
.from(schema.designs)
|
|
372
|
+
.where(eq(schema.designs.id, designId));
|
|
373
|
+
let prevData: Record<string, unknown> = {};
|
|
374
|
+
if (existingDesign?.data) {
|
|
375
|
+
try {
|
|
376
|
+
const parsed = JSON.parse(existingDesign.data);
|
|
377
|
+
if (parsed && typeof parsed === "object") prevData = parsed;
|
|
378
|
+
} catch {
|
|
379
|
+
// Stale or invalid JSON — start fresh.
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
const mergedData: Record<string, unknown> = {
|
|
383
|
+
...prevData,
|
|
384
|
+
lastPrompt: prompt,
|
|
385
|
+
generatedAt: now,
|
|
386
|
+
fileCount: files.length,
|
|
387
|
+
};
|
|
388
|
+
if (tweaks !== undefined) {
|
|
389
|
+
mergedData.tweaks = tweaks.map((tweak) => ({
|
|
390
|
+
...tweak,
|
|
391
|
+
type: tweak.type === "color-swatches" ? "color-swatch" : tweak.type,
|
|
392
|
+
}));
|
|
393
|
+
}
|
|
394
|
+
if (canvasFrames !== undefined) {
|
|
395
|
+
const savedByFileId = new Map(
|
|
396
|
+
savedFiles.map((file) => [file.id, file]),
|
|
397
|
+
);
|
|
398
|
+
const savedByFilename = new Map(
|
|
399
|
+
savedFiles.map((file) => [file.filename, file]),
|
|
400
|
+
);
|
|
401
|
+
const existingByFileId = new Map(
|
|
402
|
+
existingFiles.map((file) => [file.id, file]),
|
|
403
|
+
);
|
|
404
|
+
const merged = mergeCanvasFramePlacements({
|
|
405
|
+
existing: prevData.canvasFrames,
|
|
406
|
+
placements: canvasFrames,
|
|
407
|
+
resolveFileId: (placement) => {
|
|
408
|
+
if (placement.fileId) {
|
|
409
|
+
return savedByFileId.has(placement.fileId) ||
|
|
410
|
+
existingByFileId.has(placement.fileId)
|
|
411
|
+
? placement.fileId
|
|
412
|
+
: undefined;
|
|
413
|
+
}
|
|
414
|
+
return placement.filename
|
|
415
|
+
? (savedByFilename.get(placement.filename)?.id ??
|
|
416
|
+
existingByName.get(placement.filename)?.id)
|
|
341
417
|
: undefined;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
});
|
|
349
|
-
mergedData.canvasFrames = merged.canvasFrames;
|
|
350
|
-
placedFrames = merged.placedFrames;
|
|
351
|
-
}
|
|
352
|
-
designUpdates.data = JSON.stringify(mergedData);
|
|
418
|
+
},
|
|
419
|
+
});
|
|
420
|
+
mergedData.canvasFrames = merged.canvasFrames;
|
|
421
|
+
placedFrames = merged.placedFrames;
|
|
422
|
+
}
|
|
423
|
+
designUpdates.data = JSON.stringify(mergedData);
|
|
353
424
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
425
|
+
await tx
|
|
426
|
+
.update(schema.designs)
|
|
427
|
+
.set(designUpdates)
|
|
428
|
+
.where(eq(schema.designs.id, designId));
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
await updateGenerationSessionForSavedFiles(
|
|
432
|
+
designId,
|
|
433
|
+
savedFiles.map((file) => file.filename),
|
|
434
|
+
);
|
|
358
435
|
|
|
359
436
|
return {
|
|
360
437
|
designId,
|
|
@@ -42,16 +42,27 @@ function designDeepLink(designId: string): string {
|
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
const requestedScreenSchema = z
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
45
|
+
const requestedScreenSchema = z
|
|
46
|
+
.object({
|
|
47
|
+
frameId: z.string().optional(),
|
|
48
|
+
title: z.string().min(1),
|
|
49
|
+
filename: z
|
|
50
|
+
.string()
|
|
51
|
+
.optional()
|
|
52
|
+
.describe("Target filename for this screen, such as onboarding.html"),
|
|
53
|
+
role: z.enum(["screen", "variant"]).optional().default("screen"),
|
|
54
|
+
variantOf: z.string().optional(),
|
|
55
|
+
})
|
|
56
|
+
.superRefine((screen, ctx) => {
|
|
57
|
+
if (screen.role === "variant" && !screen.variantOf) {
|
|
58
|
+
ctx.addIssue({
|
|
59
|
+
code: z.ZodIssueCode.custom,
|
|
60
|
+
path: ["variantOf"],
|
|
61
|
+
message:
|
|
62
|
+
"variant screens require variantOf to identify the base screen",
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
});
|
|
55
66
|
|
|
56
67
|
export default defineAction({
|
|
57
68
|
description:
|
|
@@ -101,10 +112,39 @@ export default defineAction({
|
|
|
101
112
|
origin: { x: 0, y: 0 },
|
|
102
113
|
columns: screens.length <= 3 ? screens.length : 3,
|
|
103
114
|
});
|
|
115
|
+
|
|
116
|
+
const seenFilenames = new Map<string, number>();
|
|
117
|
+
// Dedupe any filename (explicit or auto-generated) so two screens can never
|
|
118
|
+
// resolve to the same target file — otherwise generate-design silently
|
|
119
|
+
// overwrites the first screen's output with the second's.
|
|
120
|
+
const dedupeFilename = (base: string): string => {
|
|
121
|
+
if (!seenFilenames.has(base)) {
|
|
122
|
+
seenFilenames.set(base, 1);
|
|
123
|
+
return base;
|
|
124
|
+
}
|
|
125
|
+
const count = seenFilenames.get(base)! + 1;
|
|
126
|
+
seenFilenames.set(base, count);
|
|
127
|
+
const dot = base.lastIndexOf(".");
|
|
128
|
+
return dot > 0
|
|
129
|
+
? `${base.slice(0, dot)}-${count}${base.slice(dot)}`
|
|
130
|
+
: `${base}-${count}`;
|
|
131
|
+
};
|
|
132
|
+
const requestedTargets = screens.map((screen, index) => {
|
|
133
|
+
if (screen.filename) return dedupeFilename(screen.filename);
|
|
134
|
+
const slug =
|
|
135
|
+
screen.title
|
|
136
|
+
.toLowerCase()
|
|
137
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
138
|
+
.replace(/^-+|-+$/g, "")
|
|
139
|
+
.slice(0, 48) || `screen-${index + 1}`;
|
|
140
|
+
return dedupeFilename(`${slug}.html`);
|
|
141
|
+
});
|
|
142
|
+
|
|
104
143
|
const frames: DesignGenerationFrame[] = screens.map((screen, index) => {
|
|
105
144
|
const frameId = screen.frameId ?? nanoid();
|
|
106
145
|
return {
|
|
107
146
|
frameId,
|
|
147
|
+
filename: requestedTargets[index],
|
|
108
148
|
agentId: `agent-${frameId}`,
|
|
109
149
|
agentName: AGENT_NAMES[index % AGENT_NAMES.length] ?? "Agent",
|
|
110
150
|
agentColor:
|
|
@@ -142,15 +182,7 @@ export default defineAction({
|
|
|
142
182
|
|
|
143
183
|
const targets = frames.map((frame, index) => {
|
|
144
184
|
const requested = screens[index]!;
|
|
145
|
-
const filename =
|
|
146
|
-
requested.filename ??
|
|
147
|
-
`${
|
|
148
|
-
requested.title
|
|
149
|
-
.toLowerCase()
|
|
150
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
151
|
-
.replace(/^-+|-+$/g, "")
|
|
152
|
-
.slice(0, 48) || `screen-${index + 1}`
|
|
153
|
-
}.html`;
|
|
185
|
+
const filename = requestedTargets[index]!;
|
|
154
186
|
return {
|
|
155
187
|
frameId: frame.frameId,
|
|
156
188
|
title: requested.title,
|
|
@@ -43,7 +43,11 @@ export default defineAction({
|
|
|
43
43
|
run: async ({ designId }) => {
|
|
44
44
|
const access = await resolveAccess("design", designId);
|
|
45
45
|
if (!access) {
|
|
46
|
-
|
|
46
|
+
const err = new Error("Design not found") as Error & {
|
|
47
|
+
statusCode: number;
|
|
48
|
+
};
|
|
49
|
+
err.statusCode = 404;
|
|
50
|
+
throw err;
|
|
47
51
|
}
|
|
48
52
|
const design = access.resource as typeof schema.designs.$inferSelect;
|
|
49
53
|
|
|
@@ -13,6 +13,7 @@ export default defineAction({
|
|
|
13
13
|
id: z.string().describe("Design ID"),
|
|
14
14
|
}),
|
|
15
15
|
readOnly: true,
|
|
16
|
+
requiresAuth: false,
|
|
16
17
|
http: { method: "GET" },
|
|
17
18
|
run: async ({ id }) => {
|
|
18
19
|
const access = await resolveAccess("design", id);
|
|
@@ -39,6 +40,7 @@ export default defineAction({
|
|
|
39
40
|
visibility: row.visibility,
|
|
40
41
|
createdAt: row.createdAt,
|
|
41
42
|
updatedAt: row.updatedAt,
|
|
43
|
+
accessRole: access.role,
|
|
42
44
|
files: files.map((f) => ({
|
|
43
45
|
id: f.id,
|
|
44
46
|
filename: f.filename,
|
|
@@ -12,15 +12,28 @@ export default defineAction({
|
|
|
12
12
|
"has good styling (CSS custom properties, fonts, colors), this extracts those " +
|
|
13
13
|
"into reusable design tokens. Alternatively, import from an existing design system " +
|
|
14
14
|
"for cloning/forking. Returns extracted tokens plus raw CSS for agent refinement.",
|
|
15
|
-
schema: z
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
schema: z
|
|
16
|
+
.object({
|
|
17
|
+
designId: z
|
|
18
|
+
.string()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("Design project ID to extract tokens from"),
|
|
21
|
+
designSystemId: z
|
|
22
|
+
.string()
|
|
23
|
+
.optional()
|
|
24
|
+
.describe(
|
|
25
|
+
"If provided, import from this existing design system instead of extracting from the design project",
|
|
26
|
+
),
|
|
27
|
+
})
|
|
28
|
+
.superRefine((args, ctx) => {
|
|
29
|
+
if (!args.designId && !args.designSystemId) {
|
|
30
|
+
ctx.addIssue({
|
|
31
|
+
code: z.ZodIssueCode.custom,
|
|
32
|
+
path: ["designId"],
|
|
33
|
+
message: "designId or designSystemId is required",
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}),
|
|
24
37
|
readOnly: true,
|
|
25
38
|
http: { method: "GET" },
|
|
26
39
|
run: async ({ designId, designSystemId }) => {
|
|
@@ -55,6 +68,12 @@ export default defineAction({
|
|
|
55
68
|
};
|
|
56
69
|
}
|
|
57
70
|
|
|
71
|
+
if (!designId) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
"designId is required when designSystemId is not provided",
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
58
77
|
// Extract tokens from the design project
|
|
59
78
|
await assertAccess("design", designId, "viewer");
|
|
60
79
|
|
|
@@ -8,6 +8,9 @@ import {
|
|
|
8
8
|
} from "@agent-native/core/server/design-token-utils";
|
|
9
9
|
import { z } from "zod";
|
|
10
10
|
|
|
11
|
+
const DOC_MAX_FILES = 20;
|
|
12
|
+
const DOC_MAX_TEXT_BYTES = 500 * 1024;
|
|
13
|
+
|
|
11
14
|
export default defineAction({
|
|
12
15
|
description:
|
|
13
16
|
"Process uploaded document metadata (DOCX, PPTX, PDF, XLSX) and return " +
|
|
@@ -44,16 +47,29 @@ export default defineAction({
|
|
|
44
47
|
}),
|
|
45
48
|
readOnly: true,
|
|
46
49
|
run: async ({ files }) => {
|
|
47
|
-
const
|
|
50
|
+
const capped = files.slice(0, DOC_MAX_FILES);
|
|
51
|
+
const processedFiles = capped.map((file) => {
|
|
48
52
|
const contentType = classifyFile(file.fileType);
|
|
49
|
-
|
|
53
|
+
|
|
54
|
+
// Truncate textContent before regex scanning to bound CPU/memory usage.
|
|
55
|
+
let text = file.textContent;
|
|
56
|
+
if (text) {
|
|
57
|
+
const encoded = new TextEncoder().encode(text);
|
|
58
|
+
if (encoded.byteLength > DOC_MAX_TEXT_BYTES) {
|
|
59
|
+
text = new TextDecoder().decode(
|
|
60
|
+
encoded.subarray(0, DOC_MAX_TEXT_BYTES),
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const hasText = !!text && text.trim().length > 0;
|
|
50
66
|
|
|
51
67
|
let likelyColors: string[] = [];
|
|
52
68
|
let likelyFonts: string[] = [];
|
|
53
69
|
|
|
54
|
-
if (
|
|
55
|
-
likelyColors = extractDocumentColors(
|
|
56
|
-
likelyFonts = extractDocumentFonts(
|
|
70
|
+
if (text) {
|
|
71
|
+
likelyColors = extractDocumentColors(text);
|
|
72
|
+
likelyFonts = extractDocumentFonts(text);
|
|
57
73
|
}
|
|
58
74
|
|
|
59
75
|
if (file.metadata) {
|
|
@@ -80,9 +96,7 @@ export default defineAction({
|
|
|
80
96
|
likelyColors,
|
|
81
97
|
likelyFonts,
|
|
82
98
|
contentType,
|
|
83
|
-
extractedText:
|
|
84
|
-
? file.textContent.slice(0, 2000)
|
|
85
|
-
: undefined,
|
|
99
|
+
extractedText: text ? text.slice(0, 2000) : undefined,
|
|
86
100
|
suggestions,
|
|
87
101
|
},
|
|
88
102
|
};
|