@agent-native/core 0.102.1 → 0.103.0
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 +15 -0
- package/corpus/core/docs/content/local-file-mode.mdx +99 -489
- package/corpus/core/docs/content/locales/ar-SA/local-file-mode.mdx +35 -490
- package/corpus/core/docs/content/locales/ar-SA/template-content.mdx +10 -24
- package/corpus/core/docs/content/locales/de-DE/local-file-mode.mdx +37 -491
- package/corpus/core/docs/content/locales/de-DE/template-content.mdx +10 -24
- package/corpus/core/docs/content/locales/es-ES/local-file-mode.mdx +35 -493
- package/corpus/core/docs/content/locales/es-ES/template-content.mdx +10 -24
- package/corpus/core/docs/content/locales/fr-FR/local-file-mode.mdx +38 -491
- package/corpus/core/docs/content/locales/fr-FR/template-content.mdx +10 -24
- package/corpus/core/docs/content/locales/hi-IN/local-file-mode.mdx +33 -492
- package/corpus/core/docs/content/locales/hi-IN/template-content.mdx +10 -24
- package/corpus/core/docs/content/locales/ja-JP/local-file-mode.mdx +36 -492
- package/corpus/core/docs/content/locales/ja-JP/template-content.mdx +10 -24
- package/corpus/core/docs/content/locales/ko-KR/local-file-mode.mdx +35 -490
- package/corpus/core/docs/content/locales/ko-KR/template-content.mdx +10 -24
- package/corpus/core/docs/content/locales/pt-BR/local-file-mode.mdx +35 -493
- package/corpus/core/docs/content/locales/pt-BR/template-content.mdx +10 -24
- package/corpus/core/docs/content/locales/zh-CN/local-file-mode.mdx +31 -489
- package/corpus/core/docs/content/locales/zh-CN/template-content.mdx +9 -24
- package/corpus/core/docs/content/locales/zh-TW/local-file-mode.mdx +31 -489
- package/corpus/core/docs/content/locales/zh-TW/template-content.mdx +9 -24
- package/corpus/core/docs/content/template-content.mdx +26 -42
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/cli/content-local.ts +86 -18
- package/corpus/core/src/cli/index.ts +2 -2
- package/corpus/core/src/cli/skills-content/content-skill.ts +36 -25
- package/corpus/core/src/cli/skills.ts +47 -13
- package/corpus/core/src/client/AgentPanel.tsx +7 -0
- package/corpus/core/src/client/AssistantChat.tsx +7 -0
- package/corpus/core/src/client/agent-chat-adapter.ts +7 -1
- package/corpus/core/src/client/chat/message-components.tsx +17 -3
- package/corpus/core/src/client/composer/ComposerPlusMenu.tsx +96 -6
- package/corpus/core/src/client/composer/asset-picker-url.ts +80 -0
- package/corpus/core/src/client/error-format.ts +24 -0
- package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +8 -1
- package/corpus/core/src/local-artifacts/index.ts +65 -0
- package/corpus/templates/assets/app/components/library/GenerationPresetsPanel.tsx +325 -0
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +12 -0
- package/corpus/templates/assets/app/i18n/zh-TW.ts +21 -0
- package/corpus/templates/assets/app/i18n-data.ts +215 -0
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +19 -479
- package/corpus/templates/assets/app/routes/brand-kits.$id_.presets.$presetId.tsx +1 -1
- package/corpus/templates/assets/app/routes/brand-kits.$id_.settings.tsx +446 -0
- package/corpus/templates/assets/app/routes/library.tsx +69 -0
- package/corpus/templates/assets/changelog/2026-07-15-fixed-top-level-image-picker-selections-returning-to-the-com.md +6 -0
- package/corpus/templates/clips/actions/disconnect-calendar.ts +57 -9
- package/corpus/templates/clips/actions/generate-workflow.ts +102 -59
- package/corpus/templates/clips/actions/get-recording-player-data.ts +64 -1
- package/corpus/templates/clips/actions/regenerate-summary.ts +7 -0
- package/corpus/templates/clips/actions/regenerate-title.ts +29 -11
- package/corpus/templates/clips/app/components/editor/editor-layout.tsx +34 -13
- package/corpus/templates/clips/app/components/editor/thumbnail-picker.tsx +87 -9
- package/corpus/templates/clips/app/components/editor/trim-handles.tsx +15 -0
- package/corpus/templates/clips/app/components/editor/waveform.tsx +21 -8
- package/corpus/templates/clips/app/components/library/folder-tree.tsx +52 -0
- package/corpus/templates/clips/app/components/player/settings-panel.tsx +116 -58
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +43 -37
- package/corpus/templates/clips/app/components/player/video-player.tsx +50 -2
- package/corpus/templates/clips/app/components/recorder/microphone-visualizer.tsx +22 -3
- package/corpus/templates/clips/app/i18n/ar-SA.ts +5 -2
- package/corpus/templates/clips/app/i18n/de-DE.ts +6 -2
- package/corpus/templates/clips/app/i18n/en-US.ts +5 -2
- package/corpus/templates/clips/app/i18n/es-ES.ts +6 -2
- package/corpus/templates/clips/app/i18n/fr-FR.ts +5 -2
- package/corpus/templates/clips/app/i18n/hi-IN.ts +5 -2
- package/corpus/templates/clips/app/i18n/ja-JP.ts +6 -1
- package/corpus/templates/clips/app/i18n/ko-KR.ts +5 -2
- package/corpus/templates/clips/app/i18n/pt-BR.ts +6 -2
- package/corpus/templates/clips/app/i18n/zh-CN.ts +5 -2
- package/corpus/templates/clips/app/i18n/zh-TW.ts +5 -2
- package/corpus/templates/clips/app/lib/timestamp-mapping.ts +14 -0
- package/corpus/templates/clips/app/routes/_app.library._index.tsx +1 -2
- package/corpus/templates/clips/app/routes/_index.tsx +1 -2
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +98 -32
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +4 -1
- package/corpus/templates/clips/changelog/2026-07-15-ai-workflow-generation-now-stays-visible-avoids-duplicate-re.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-clip-playback-and-cta-controls-remain-interactive-through-ed.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-clip-titles-no-longer-describe-the-product-as-a-loom-alterna.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-description-regeneration-now-opens-the-agent-chat-so-progres.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-direct-recording-urls-now-respect-share-link-and-password-ac.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-disconnecting-a-calendar-now-clears-unrecorded-synced-meetin.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-folders-now-expose-rename-and-delete-actions-directly-in-the.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-recording-pages-now-explain-sign-in-access-and-avoid-showing.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-the-clips-extension-quick-actions-toolbar-can-be-moved-out-o.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-the-editor-now-skips-cut-sections-during-preview-and-keeps-t.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-thumbnail-capture-now-updates-previews-while-scrubbing-and-l.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-windows-permission-links-open-the-matching-settings-page.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/content-script.ts +117 -2
- package/corpus/templates/clips/chrome-extension/src/overlay.ts +27 -0
- package/corpus/templates/clips/desktop/src-tauri/tauri.conf.json +1 -1
- package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +139 -101
- package/corpus/templates/clips/server/lib/recording-page-access.ts +35 -0
- package/corpus/templates/clips/server/lib/share-password.ts +6 -3
- package/corpus/templates/content/.agents/skills/content/SKILL.md +26 -39
- package/corpus/templates/content/AGENTS.md +25 -30
- package/corpus/templates/content/actions/_builder-docs-client.ts +23 -0
- package/corpus/templates/content/actions/_content-database-source-adapters.ts +21 -3
- package/corpus/templates/content/actions/_content-files.ts +338 -0
- package/corpus/templates/content/actions/_content-space-access.ts +135 -0
- package/corpus/templates/content/actions/_content-spaces.ts +640 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +90 -7
- package/corpus/templates/content/actions/_database-utils.ts +7 -1
- package/corpus/templates/content/actions/_local-file-documents.ts +0 -9
- package/corpus/templates/content/actions/_local-folder-source.ts +53 -0
- package/corpus/templates/content/actions/_property-utils.ts +9 -4
- package/corpus/templates/content/actions/add-database-item.ts +108 -65
- package/corpus/templates/content/actions/backfill-content-files.ts +22 -0
- package/corpus/templates/content/actions/connect-local-folder-source.ts +221 -0
- package/corpus/templates/content/actions/create-content-database.ts +129 -3
- package/corpus/templates/content/actions/create-document.ts +65 -55
- package/corpus/templates/content/actions/create-inline-content-database.ts +6 -1
- package/corpus/templates/content/actions/delete-content-database.ts +3 -0
- package/corpus/templates/content/actions/delete-document.ts +7 -11
- package/corpus/templates/content/actions/disconnect-local-folder-source.ts +175 -0
- package/corpus/templates/content/actions/duplicate-database-item.ts +10 -0
- package/corpus/templates/content/actions/duplicate-database-items.ts +13 -0
- package/corpus/templates/content/actions/edit-document.ts +2 -28
- package/corpus/templates/content/actions/ensure-content-spaces.ts +26 -0
- package/corpus/templates/content/actions/export-content-source.ts +47 -9
- package/corpus/templates/content/actions/get-document.ts +0 -14
- package/corpus/templates/content/actions/import-content-source.ts +43 -3
- package/corpus/templates/content/actions/list-content-spaces.ts +103 -0
- package/corpus/templates/content/actions/list-documents.ts +12 -9
- package/corpus/templates/content/actions/move-document.ts +3 -14
- package/corpus/templates/content/actions/pull-document.ts +0 -23
- package/corpus/templates/content/actions/remove-local-file-source.ts +50 -29
- package/corpus/templates/content/actions/resolve-local-folder-conflict.ts +442 -0
- package/corpus/templates/content/actions/reveal-local-source-file.ts +6 -17
- package/corpus/templates/content/actions/search-documents.ts +0 -34
- package/corpus/templates/content/actions/share-local-file-document.ts +25 -1
- package/corpus/templates/content/actions/submit-content-database-form.ts +12 -0
- package/corpus/templates/content/actions/sync-local-folder-source.ts +731 -0
- package/corpus/templates/content/actions/sync-manifest-local-folder-source.ts +123 -0
- package/corpus/templates/content/actions/update-content-database-view.ts +10 -1
- package/corpus/templates/content/actions/update-document.ts +0 -15
- package/corpus/templates/content/actions/view-screen.ts +2 -50
- package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +76 -62
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +70 -22
- package/corpus/templates/content/app/components/editor/database/grouping.ts +2 -1
- package/corpus/templates/content/app/components/editor/database/settings.tsx +23 -20
- package/corpus/templates/content/app/components/editor/database/shared.tsx +2 -0
- package/corpus/templates/content/app/components/editor/database/sidebar.tsx +330 -0
- package/corpus/templates/content/app/components/editor/database/types.ts +1 -0
- package/corpus/templates/content/app/components/editor/database/view-config.ts +3 -1
- package/corpus/templates/content/app/components/layout/Layout.tsx +25 -1
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +209 -113
- package/corpus/templates/content/app/components/sidebar/select-content-space.ts +31 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +16 -0
- package/corpus/templates/content/app/hooks/use-content-spaces.ts +39 -0
- package/corpus/templates/content/app/i18n/zh-TW.ts +11 -0
- package/corpus/templates/content/app/i18n-data.ts +75 -0
- package/corpus/templates/content/app/routes/_app.local-files.tsx +174 -65
- package/corpus/templates/content/changelog/2026-07-16-content-callouts-can-now-be-reviewed-and-published-to-builder.md +6 -0
- package/corpus/templates/content/changelog/2026-07-16-heading-5-and-heading-6-are-available-from-the-editor-slash-.md +6 -0
- package/corpus/templates/content/changelog/2026-07-16-organize-every-workspace-through-a-customizable-files-databa.md +6 -0
- package/corpus/templates/content/parity/matrix.md +2 -1
- package/corpus/templates/content/parity/matrix.ts +37 -1
- package/corpus/templates/content/scripts/dev-database.mjs +7 -5
- package/corpus/templates/content/server/db/schema.ts +113 -40
- package/corpus/templates/content/server/lib/document-context.ts +15 -1
- package/corpus/templates/content/server/lib/notion-sync.ts +6 -0
- package/corpus/templates/content/server/plugins/db.ts +153 -0
- package/corpus/templates/content/shared/api.ts +17 -3
- package/corpus/templates/content/shared/builder-mdx.ts +163 -16
- package/corpus/templates/design/.agents/skills/design-templates/SKILL.md +59 -0
- package/corpus/templates/design/AGENTS.md +6 -1
- package/corpus/templates/design/actions/create-design-from-template.ts +19 -7
- package/corpus/templates/design/actions/list-design-templates.ts +69 -21
- package/corpus/templates/design/actions/navigate.ts +2 -2
- package/corpus/templates/design/actions/view-screen.ts +15 -2
- package/corpus/templates/design/agent-native.app-skill.json +5 -0
- package/corpus/templates/design/app/components/design/design-canvas/external-preview.ts +7 -3
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +281 -56
- package/corpus/templates/design/app/components/templates/TemplatePreview.tsx +14 -2
- package/corpus/templates/design/app/hooks/use-navigation-state.ts +3 -2
- package/corpus/templates/design/app/i18n/zh-TW.ts +3 -3
- package/corpus/templates/design/app/i18n-data.ts +21 -2
- package/corpus/templates/design/app/i18n-template-feature.ts +218 -10
- package/corpus/templates/design/app/pages/Index.tsx +195 -24
- package/corpus/templates/design/app/pages/Templates.tsx +144 -55
- package/corpus/templates/design/app/pages/design-editor/generation-prompt-directives.ts +12 -1
- package/corpus/templates/design/changelog/2026-07-14-templates-now-appear-in-the-new-design-picker-with-previews-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-15-prototype-print-and-download-buttons-now-work-in-preview.md +6 -0
- package/corpus/templates/design/changelog/2026-07-15-templates-now-open-immediately-after-copying-even-while-the-.md +6 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/mail/AGENTS.md +23 -18
- package/corpus/templates/mail/actions/bulk-archive.ts +32 -28
- package/corpus/templates/mail/actions/mark-read.ts +131 -20
- package/corpus/templates/mail/actions/mark-thread-read.ts +1 -1
- package/corpus/templates/mail/actions/move-email.ts +30 -24
- package/corpus/templates/mail/actions/send-email.ts +73 -68
- package/corpus/templates/mail/changelog/2026-07-15-unread-inbox-cleanup-now-completes-reliably.md +6 -0
- package/corpus/templates/mail/server/handlers/emails.ts +218 -209
- package/corpus/templates/mail/server/lib/bulk-mark-read.ts +30 -0
- package/corpus/templates/mail/server/lib/email-state.ts +198 -113
- package/corpus/templates/mail/server/lib/google-auth.ts +218 -25
- package/corpus/templates/mail/server/lib/jobs.ts +69 -74
- package/corpus/templates/mail/server/lib/local-email-store.ts +265 -0
- package/corpus/templates/mail/server/plugins/agent-chat.ts +6 -0
- package/corpus/templates/slides/actions/extract-pdf.ts +1 -1
- package/corpus/templates/slides/actions/import-file.ts +4 -1
- package/corpus/templates/slides/app/components/editor/ImageGenPanel.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/ImageSearchPanel.tsx +9 -12
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +29 -21
- package/corpus/templates/slides/app/i18n/ar-SA.ts +1 -0
- package/corpus/templates/slides/app/i18n/de-DE.ts +1 -0
- package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
- package/corpus/templates/slides/app/i18n/es-ES.ts +1 -0
- package/corpus/templates/slides/app/i18n/fr-FR.ts +1 -0
- package/corpus/templates/slides/app/i18n/hi-IN.ts +1 -0
- package/corpus/templates/slides/app/i18n/ja-JP.ts +1 -0
- package/corpus/templates/slides/app/i18n/ko-KR.ts +1 -0
- package/corpus/templates/slides/app/i18n/pt-BR.ts +1 -0
- package/corpus/templates/slides/app/i18n/zh-CN.ts +1 -0
- package/corpus/templates/slides/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/slides/changelog/2026-07-15-image-search-and-generation-controls-now-use-the-registered-.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-15-pdf-deck-references-can-be-imported-for-slide-inspiration-ag.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-15-stable-style-inspector-dock.md +6 -0
- package/dist/cli/content-local.d.ts +1 -0
- package/dist/cli/content-local.d.ts.map +1 -1
- package/dist/cli/content-local.js +75 -17
- package/dist/cli/content-local.js.map +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/skills-content/content-skill.d.ts +1 -1
- package/dist/cli/skills-content/content-skill.d.ts.map +1 -1
- package/dist/cli/skills-content/content-skill.js +36 -25
- package/dist/cli/skills-content/content-skill.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +47 -14
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +5 -0
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +7 -0
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +8 -1
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +4 -0
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +10 -3
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/composer/ComposerPlusMenu.d.ts.map +1 -1
- package/dist/client/composer/ComposerPlusMenu.js +58 -6
- package/dist/client/composer/ComposerPlusMenu.js.map +1 -1
- package/dist/client/composer/asset-picker-url.d.ts +16 -0
- package/dist/client/composer/asset-picker-url.d.ts.map +1 -0
- package/dist/client/composer/asset-picker-url.js +64 -0
- package/dist/client/composer/asset-picker-url.js.map +1 -0
- package/dist/client/error-format.d.ts.map +1 -1
- package/dist/client/error-format.js +17 -0
- package/dist/client/error-format.js.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.js +6 -1
- package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/local-artifacts/index.d.ts +10 -0
- package/dist/local-artifacts/index.d.ts.map +1 -1
- package/dist/local-artifacts/index.js +39 -0
- package/dist/local-artifacts/index.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/docs/content/local-file-mode.mdx +99 -489
- package/docs/content/locales/ar-SA/local-file-mode.mdx +35 -490
- package/docs/content/locales/ar-SA/template-content.mdx +10 -24
- package/docs/content/locales/de-DE/local-file-mode.mdx +37 -491
- package/docs/content/locales/de-DE/template-content.mdx +10 -24
- package/docs/content/locales/es-ES/local-file-mode.mdx +35 -493
- package/docs/content/locales/es-ES/template-content.mdx +10 -24
- package/docs/content/locales/fr-FR/local-file-mode.mdx +38 -491
- package/docs/content/locales/fr-FR/template-content.mdx +10 -24
- package/docs/content/locales/hi-IN/local-file-mode.mdx +33 -492
- package/docs/content/locales/hi-IN/template-content.mdx +10 -24
- package/docs/content/locales/ja-JP/local-file-mode.mdx +36 -492
- package/docs/content/locales/ja-JP/template-content.mdx +10 -24
- package/docs/content/locales/ko-KR/local-file-mode.mdx +35 -490
- package/docs/content/locales/ko-KR/template-content.mdx +10 -24
- package/docs/content/locales/pt-BR/local-file-mode.mdx +35 -493
- package/docs/content/locales/pt-BR/template-content.mdx +10 -24
- package/docs/content/locales/zh-CN/local-file-mode.mdx +31 -489
- package/docs/content/locales/zh-CN/template-content.mdx +9 -24
- package/docs/content/locales/zh-TW/local-file-mode.mdx +31 -489
- package/docs/content/locales/zh-TW/template-content.mdx +9 -24
- package/docs/content/template-content.mdx +26 -42
- package/package.json +1 -1
- package/corpus/templates/assets/app/components/library/EditLibraryDialog.tsx +0 -126
|
@@ -1850,10 +1850,14 @@ function nodeSlice(body: string, node: MdxNode) {
|
|
|
1850
1850
|
|
|
1851
1851
|
function freshTextBlock(markdown: string): unknown {
|
|
1852
1852
|
const text = markdownToBuilderTextHtml(markdown);
|
|
1853
|
+
return freshTextHtmlBlock(text, markdown);
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
function freshTextHtmlBlock(text: string, stableSource: string): unknown {
|
|
1853
1857
|
return {
|
|
1854
1858
|
"@type": "@builder.io/sdk:Element",
|
|
1855
1859
|
"@version": 2,
|
|
1856
|
-
id: `builder-mdx-${stableHash(
|
|
1860
|
+
id: `builder-mdx-${stableHash(stableSource).slice(0, 16)}`,
|
|
1857
1861
|
component: {
|
|
1858
1862
|
name: "Text",
|
|
1859
1863
|
options: { text },
|
|
@@ -1868,6 +1872,91 @@ function freshTextBlock(markdown: string): unknown {
|
|
|
1868
1872
|
};
|
|
1869
1873
|
}
|
|
1870
1874
|
|
|
1875
|
+
function assertSafeFreshCalloutNode(node: MdxNode) {
|
|
1876
|
+
for (const child of node.children ?? []) {
|
|
1877
|
+
if (
|
|
1878
|
+
child.type === "mdxFlowExpression" ||
|
|
1879
|
+
child.type === "mdxTextExpression" ||
|
|
1880
|
+
child.type === "mdxjsEsm" ||
|
|
1881
|
+
child.type === "mdxJsxFlowElement" ||
|
|
1882
|
+
child.type === "mdxJsxTextElement"
|
|
1883
|
+
) {
|
|
1884
|
+
throw new Error("Unsupported dynamic syntax inside Builder callout.");
|
|
1885
|
+
}
|
|
1886
|
+
assertSafeFreshCalloutNode(child);
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
function findMdxOpeningTagEnd(raw: string) {
|
|
1891
|
+
let quote: '"' | "'" | null = null;
|
|
1892
|
+
let escaped = false;
|
|
1893
|
+
for (let index = 0; index < raw.length; index += 1) {
|
|
1894
|
+
const character = raw[index];
|
|
1895
|
+
if (escaped) {
|
|
1896
|
+
escaped = false;
|
|
1897
|
+
continue;
|
|
1898
|
+
}
|
|
1899
|
+
if (character === "\\" && quote) {
|
|
1900
|
+
escaped = true;
|
|
1901
|
+
continue;
|
|
1902
|
+
}
|
|
1903
|
+
if (quote) {
|
|
1904
|
+
if (character === quote) quote = null;
|
|
1905
|
+
continue;
|
|
1906
|
+
}
|
|
1907
|
+
if (character === '"' || character === "'") {
|
|
1908
|
+
quote = character;
|
|
1909
|
+
continue;
|
|
1910
|
+
}
|
|
1911
|
+
if (character === ">") return index;
|
|
1912
|
+
}
|
|
1913
|
+
return -1;
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
function freshCalloutBlock(
|
|
1917
|
+
node: MdxNode,
|
|
1918
|
+
raw: string,
|
|
1919
|
+
occurrence: number,
|
|
1920
|
+
): unknown {
|
|
1921
|
+
let icon = "💡";
|
|
1922
|
+
for (const attribute of node.attributes ?? []) {
|
|
1923
|
+
if (
|
|
1924
|
+
attribute.type !== "mdxJsxAttribute" ||
|
|
1925
|
+
!attribute.name ||
|
|
1926
|
+
(attribute.value !== null && typeof attribute.value !== "string")
|
|
1927
|
+
) {
|
|
1928
|
+
throw new Error("Builder callout attributes must be literal values.");
|
|
1929
|
+
}
|
|
1930
|
+
if (attribute.name === "icon") {
|
|
1931
|
+
icon = attribute.value || "💡";
|
|
1932
|
+
continue;
|
|
1933
|
+
}
|
|
1934
|
+
if (attribute.name === "color") continue;
|
|
1935
|
+
throw new Error(
|
|
1936
|
+
`Unsupported Builder callout attribute: ${attribute.name}.`,
|
|
1937
|
+
);
|
|
1938
|
+
}
|
|
1939
|
+
assertSafeFreshCalloutNode(node);
|
|
1940
|
+
|
|
1941
|
+
const openingEnd = findMdxOpeningTagEnd(raw);
|
|
1942
|
+
const closingStart = raw.lastIndexOf("</callout>");
|
|
1943
|
+
if (openingEnd < 0 || closingStart < openingEnd) {
|
|
1944
|
+
throw new Error("Builder callout must have an explicit closing tag.");
|
|
1945
|
+
}
|
|
1946
|
+
const markdown = raw
|
|
1947
|
+
.slice(openingEnd + 1, closingStart)
|
|
1948
|
+
.split(/\r?\n/)
|
|
1949
|
+
.map((line) => line.replace(/^(?:\t| {2})/, ""))
|
|
1950
|
+
.join("\n")
|
|
1951
|
+
.trim();
|
|
1952
|
+
const content = markdownToBuilderTextHtml(markdown);
|
|
1953
|
+
const iconHtml = icon ? `<p><strong>${escapeHtml(icon)}</strong></p>` : "";
|
|
1954
|
+
return freshTextHtmlBlock(
|
|
1955
|
+
`<blockquote>${iconHtml}${content}</blockquote>`,
|
|
1956
|
+
`${raw}\n@source:${node.position?.start?.offset ?? occurrence}`,
|
|
1957
|
+
);
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1871
1960
|
const BUILDER_TABLE_TAGS = new Set([
|
|
1872
1961
|
"table",
|
|
1873
1962
|
"colgroup",
|
|
@@ -2510,7 +2599,7 @@ export async function builderMdxBodyToBuilderBlocks(
|
|
|
2510
2599
|
) {
|
|
2511
2600
|
const root = await parseMdxRoot(body);
|
|
2512
2601
|
const blocks: unknown[] = [];
|
|
2513
|
-
for (const child of root.children ?? []) {
|
|
2602
|
+
for (const [childIndex, child] of (root.children ?? []).entries()) {
|
|
2514
2603
|
const raw = nodeSlice(body, child);
|
|
2515
2604
|
if (!raw) continue;
|
|
2516
2605
|
if (
|
|
@@ -2528,6 +2617,10 @@ export async function builderMdxBodyToBuilderBlocks(
|
|
|
2528
2617
|
blocks.push(freshTableBlock(child, raw));
|
|
2529
2618
|
continue;
|
|
2530
2619
|
}
|
|
2620
|
+
if (child.name === "callout") {
|
|
2621
|
+
blocks.push(freshCalloutBlock(child, raw, childIndex));
|
|
2622
|
+
continue;
|
|
2623
|
+
}
|
|
2531
2624
|
const block = await blockFromMdxComponent(raw, sidecars);
|
|
2532
2625
|
if (block) {
|
|
2533
2626
|
blocks.push(block);
|
|
@@ -2775,24 +2868,78 @@ function inlineMarkdownToHtml(value: string) {
|
|
|
2775
2868
|
.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>")
|
|
2776
2869
|
.replace(/_([^_]+)_/g, "<em>$1</em>")
|
|
2777
2870
|
.replace(/`([^`]+)`/g, "<code>$1</code>")
|
|
2778
|
-
.replace(/\[([^\]]+)\]\(([^)]+)\)/g,
|
|
2871
|
+
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_match, label, destination) => {
|
|
2872
|
+
const href = destination.trim();
|
|
2873
|
+
const hasScheme = /^[a-z][a-z\d+.-]*:/i.test(href);
|
|
2874
|
+
const hasSafeScheme = /^(?:https?:\/\/|mailto:|tel:)/i.test(href);
|
|
2875
|
+
const isNetworkPath = /^(?:\/\/|\\\\)/.test(href);
|
|
2876
|
+
const hasControlCharacter = /[\u0000-\u001f\u007f]/.test(href);
|
|
2877
|
+
if (
|
|
2878
|
+
!href ||
|
|
2879
|
+
isNetworkPath ||
|
|
2880
|
+
hasControlCharacter ||
|
|
2881
|
+
(hasScheme && !hasSafeScheme)
|
|
2882
|
+
) {
|
|
2883
|
+
return label;
|
|
2884
|
+
}
|
|
2885
|
+
return `<a href="${href}">${label}</a>`;
|
|
2886
|
+
});
|
|
2887
|
+
}
|
|
2888
|
+
|
|
2889
|
+
type MarkdownListNode = {
|
|
2890
|
+
type: "ul" | "ol";
|
|
2891
|
+
value: string;
|
|
2892
|
+
children: MarkdownListNode[];
|
|
2893
|
+
};
|
|
2894
|
+
|
|
2895
|
+
function renderMarkdownListNodes(nodes: MarkdownListNode[]): string {
|
|
2896
|
+
const html: string[] = [];
|
|
2897
|
+
for (let index = 0; index < nodes.length; ) {
|
|
2898
|
+
const type = nodes[index].type;
|
|
2899
|
+
const items: string[] = [];
|
|
2900
|
+
while (index < nodes.length && nodes[index].type === type) {
|
|
2901
|
+
const node = nodes[index];
|
|
2902
|
+
items.push(
|
|
2903
|
+
`<li>${inlineMarkdownToHtml(node.value)}${renderMarkdownListNodes(node.children)}</li>`,
|
|
2904
|
+
);
|
|
2905
|
+
index += 1;
|
|
2906
|
+
}
|
|
2907
|
+
html.push(`<${type}>${items.join("")}</${type}>`);
|
|
2908
|
+
}
|
|
2909
|
+
return html.join("");
|
|
2779
2910
|
}
|
|
2780
2911
|
|
|
2781
2912
|
export function markdownToBuilderTextHtml(markdown: string) {
|
|
2782
2913
|
const lines = markdown.trim().split(/\r?\n/);
|
|
2783
2914
|
const html: string[] = [];
|
|
2784
|
-
let listItems:
|
|
2785
|
-
let
|
|
2915
|
+
let listItems: MarkdownListNode[] = [];
|
|
2916
|
+
let listStack: Array<{ indent: number; node: MarkdownListNode }> = [];
|
|
2786
2917
|
const flushList = () => {
|
|
2787
|
-
if (!listItems.length
|
|
2788
|
-
html.push(
|
|
2918
|
+
if (!listItems.length) return;
|
|
2919
|
+
html.push(renderMarkdownListNodes(listItems));
|
|
2789
2920
|
listItems = [];
|
|
2790
|
-
|
|
2921
|
+
listStack = [];
|
|
2791
2922
|
};
|
|
2792
|
-
const appendListItem = (
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2923
|
+
const appendListItem = (
|
|
2924
|
+
type: "ul" | "ol",
|
|
2925
|
+
value: string,
|
|
2926
|
+
whitespace: string,
|
|
2927
|
+
) => {
|
|
2928
|
+
const indent = [...whitespace].reduce(
|
|
2929
|
+
(width, character) => width + (character === "\t" ? 2 : 1),
|
|
2930
|
+
0,
|
|
2931
|
+
);
|
|
2932
|
+
while (
|
|
2933
|
+
listStack.length &&
|
|
2934
|
+
listStack[listStack.length - 1].indent >= indent
|
|
2935
|
+
) {
|
|
2936
|
+
listStack.pop();
|
|
2937
|
+
}
|
|
2938
|
+
const node: MarkdownListNode = { type, value, children: [] };
|
|
2939
|
+
const parent = listStack[listStack.length - 1]?.node;
|
|
2940
|
+
if (parent) parent.children.push(node);
|
|
2941
|
+
else listItems.push(node);
|
|
2942
|
+
listStack.push({ indent, node });
|
|
2796
2943
|
};
|
|
2797
2944
|
for (const line of lines) {
|
|
2798
2945
|
const trimmed = line.trim();
|
|
@@ -2815,14 +2962,14 @@ export function markdownToBuilderTextHtml(markdown: string) {
|
|
|
2815
2962
|
);
|
|
2816
2963
|
continue;
|
|
2817
2964
|
}
|
|
2818
|
-
const unorderedList =
|
|
2965
|
+
const unorderedList = line.match(/^(\s*)[-*]\s+(.+)$/);
|
|
2819
2966
|
if (unorderedList) {
|
|
2820
|
-
appendListItem("ul", unorderedList[1]);
|
|
2967
|
+
appendListItem("ul", unorderedList[2], unorderedList[1]);
|
|
2821
2968
|
continue;
|
|
2822
2969
|
}
|
|
2823
|
-
const orderedList =
|
|
2970
|
+
const orderedList = line.match(/^(\s*)\d+\.\s+(.+)$/);
|
|
2824
2971
|
if (orderedList) {
|
|
2825
|
-
appendListItem("ol", orderedList[1]);
|
|
2972
|
+
appendListItem("ol", orderedList[2], orderedList[1]);
|
|
2826
2973
|
continue;
|
|
2827
2974
|
}
|
|
2828
2975
|
flushList();
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: design-templates
|
|
3
|
+
description: >-
|
|
4
|
+
Find, save, copy, and adapt Design templates. Use when the user references a
|
|
5
|
+
template, a prior design, or wants a reusable starting point.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Design Templates
|
|
9
|
+
|
|
10
|
+
## Prerequisites
|
|
11
|
+
|
|
12
|
+
- Read `navigation` or call `view-screen` when the current template or design
|
|
13
|
+
is unclear.
|
|
14
|
+
- Treat built-in and user-created entries as one template concept. Their
|
|
15
|
+
ownership and available share/delete actions differ, but creation uses the
|
|
16
|
+
same action.
|
|
17
|
+
|
|
18
|
+
## Workflow
|
|
19
|
+
|
|
20
|
+
1. **Resolve the starting point.** When the user mentions a template, past
|
|
21
|
+
design, or prior work, call both `list-design-templates` and `list-designs`
|
|
22
|
+
before generating. Match the requested name or id; ask only when multiple
|
|
23
|
+
plausible results remain.
|
|
24
|
+
2. **Save a reusable template.** Call `save-design-as-template` with the source
|
|
25
|
+
`designId`. The action snapshots inline screens, canvas dimensions,
|
|
26
|
+
defaults, linked design system, and locked layers.
|
|
27
|
+
3. **Create from a template.** Call `create-design-from-template` with the
|
|
28
|
+
resolved `templateId`. Pass `designSystemId` only when the user selected an
|
|
29
|
+
override; the action access-checks it and returns the effective linked id.
|
|
30
|
+
4. **Stop after a pure copy.** If there is no prompt and no pending design-system
|
|
31
|
+
adaptation, open the copied design and do not start generation.
|
|
32
|
+
5. **Adapt copied screens.** When the user supplied a prompt or chose a
|
|
33
|
+
different accessible design system, call `get-design-snapshot` exactly once,
|
|
34
|
+
then refine the existing unlocked content with `edit-design`. Never call
|
|
35
|
+
`generate-design`, delete the copied screens, or recreate the template from
|
|
36
|
+
scratch.
|
|
37
|
+
6. **Verify.** Read back the copied design and confirm its screens, canvas
|
|
38
|
+
dimensions, linked design system, and locked-layer boundaries before
|
|
39
|
+
reporting completion.
|
|
40
|
+
|
|
41
|
+
## Locked Layers
|
|
42
|
+
|
|
43
|
+
`data-agent-native-locked="true"` is authoritative. Keep each locked element
|
|
44
|
+
and all descendants byte-for-byte unchanged during adaptation. If the user
|
|
45
|
+
explicitly wants one changed, ask them to unlock it in the Layers panel first.
|
|
46
|
+
|
|
47
|
+
## Ownership
|
|
48
|
+
|
|
49
|
+
- Built-in templates cannot be renamed, shared, or deleted.
|
|
50
|
+
- Owned user templates may be shared with the standard resource sharing UI and
|
|
51
|
+
deleted with `delete-design-template`.
|
|
52
|
+
- Do not model templates as ordinary `designs` rows and do not invent alternate
|
|
53
|
+
template action names.
|
|
54
|
+
|
|
55
|
+
## Related Skills
|
|
56
|
+
|
|
57
|
+
- `design-generation` — creating and refining Design screens.
|
|
58
|
+
- `design-systems` — applying linked systems and tokens.
|
|
59
|
+
- `sharing` — access and sharing rules for user-created templates.
|
|
@@ -133,12 +133,15 @@ patterns live in `.agents/skills/`.
|
|
|
133
133
|
`generate-design` for new files. For broad rewrites of an existing selected
|
|
134
134
|
file, use `edit-design` with `mode: "replace-file"` and the exact `fileId`;
|
|
135
135
|
never resend files you aren't changing.
|
|
136
|
-
-
|
|
136
|
+
- When the user references a template, prior design, or past work, call both
|
|
137
|
+
`list-design-templates` and `list-designs` before generating so the existing
|
|
138
|
+
starting point is resolved instead of recreated. Use
|
|
137
139
|
`save-design-as-template` to snapshot an editable inline design, including
|
|
138
140
|
its screens, canvas dimensions, defaults, and locked layers. Use
|
|
139
141
|
`create-design-from-template` to instantiate a normal design. If the user
|
|
140
142
|
supplies a prompt, call `get-design-snapshot` once and refine the copied
|
|
141
143
|
files with `edit-design`; never regenerate the template from scratch.
|
|
144
|
+
Read the `design-templates` skill for the complete copy/adaptation workflow.
|
|
142
145
|
- Treat `data-agent-native-locked="true"` as an authoritative template
|
|
143
146
|
boundary. Locked backgrounds, logos, and their descendants must remain
|
|
144
147
|
byte-for-byte unchanged during agent edits. The server rejects attempts to
|
|
@@ -465,6 +468,8 @@ and requires Builder connected. See `full-app-build` skill for the full flow.
|
|
|
465
468
|
Read the relevant skill before deeper work:
|
|
466
469
|
|
|
467
470
|
- `design-generation` for creating/editing prototype HTML and variant flows.
|
|
471
|
+
- `design-templates` for resolving, saving, copying, and adapting templates or
|
|
472
|
+
prior Design work without fresh generation.
|
|
468
473
|
- `responsive-breakpoints` for Framer-style breakpoint editing (single DOM,
|
|
469
474
|
cascading width-scoped overrides, the managed breakpoints media block).
|
|
470
475
|
- `design-systems` for tokens, brand extraction, and linked systems.
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
getRequestOrgId,
|
|
5
5
|
getRequestUserEmail,
|
|
6
6
|
} from "@agent-native/core/server/request-context";
|
|
7
|
-
import {
|
|
7
|
+
import { resolveAccess } from "@agent-native/core/sharing";
|
|
8
8
|
import { eq } from "drizzle-orm";
|
|
9
9
|
import { nanoid } from "nanoid";
|
|
10
10
|
import { z } from "zod";
|
|
@@ -31,7 +31,7 @@ export default defineAction({
|
|
|
31
31
|
"Create an editable design from a reusable template. The action copies the template files, exact dimensions, defaults, and locked layers. " +
|
|
32
32
|
"When a prompt is supplied, refine the copied files with get-design-snapshot and edit-design; do not replace the template with generate-design.",
|
|
33
33
|
schema: z.object({
|
|
34
|
-
templateId: z.string().min(1).describe("
|
|
34
|
+
templateId: z.string().min(1).describe("Saved or built-in template ID"),
|
|
35
35
|
title: z.string().trim().min(1).max(120).optional(),
|
|
36
36
|
prompt: z
|
|
37
37
|
.string()
|
|
@@ -124,14 +124,20 @@ export default defineAction({
|
|
|
124
124
|
let linkedDesignSystemId =
|
|
125
125
|
designSystemId === undefined ? templateDesignSystemId : designSystemId;
|
|
126
126
|
if (linkedDesignSystemId) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
const designSystemAccess = await resolveAccess(
|
|
128
|
+
"design-system",
|
|
129
|
+
linkedDesignSystemId,
|
|
130
|
+
);
|
|
131
|
+
if (!designSystemAccess) {
|
|
132
|
+
if (designSystemId !== undefined) {
|
|
131
133
|
throw new Error("Design system not found");
|
|
134
|
+
}
|
|
132
135
|
linkedDesignSystemId = null;
|
|
133
136
|
}
|
|
134
137
|
}
|
|
138
|
+
const designSystemOverridden =
|
|
139
|
+
designSystemId !== undefined && designSystemId !== templateDesignSystemId;
|
|
140
|
+
const adaptationPending = Boolean(prompt);
|
|
135
141
|
|
|
136
142
|
const ownerEmail = getRequestUserEmail();
|
|
137
143
|
if (!ownerEmail) throw new Error("Not authenticated");
|
|
@@ -149,6 +155,9 @@ export default defineAction({
|
|
|
149
155
|
category: templateCategory,
|
|
150
156
|
templateUpdatedAt,
|
|
151
157
|
instantiatedAt: now,
|
|
158
|
+
templateDesignSystemId,
|
|
159
|
+
appliedDesignSystemId: linkedDesignSystemId,
|
|
160
|
+
designSystemOverridden,
|
|
152
161
|
};
|
|
153
162
|
if (prompt) data.templatePrompt = prompt;
|
|
154
163
|
|
|
@@ -190,6 +199,8 @@ export default defineAction({
|
|
|
190
199
|
title: title ?? templateTitle,
|
|
191
200
|
templateId,
|
|
192
201
|
templateTitle,
|
|
202
|
+
designSystemId: linkedDesignSystemId,
|
|
203
|
+
designSystemOverridden,
|
|
193
204
|
fileCount: files.length,
|
|
194
205
|
lockedLayerCount: countLockedLayersAcrossFiles(persistedFiles),
|
|
195
206
|
templateBaselineFiles: persistedFiles.map((file) => ({
|
|
@@ -197,7 +208,8 @@ export default defineAction({
|
|
|
197
208
|
contentHash: sourceContentHash(file.content),
|
|
198
209
|
})),
|
|
199
210
|
promptPending: Boolean(prompt),
|
|
200
|
-
|
|
211
|
+
adaptationPending,
|
|
212
|
+
nextRequiredAction: adaptationPending
|
|
201
213
|
? "Call get-design-snapshot, then refine unlocked content with edit-design. Do not call generate-design."
|
|
202
214
|
: null,
|
|
203
215
|
};
|
|
@@ -15,7 +15,7 @@ const PREVIEW_MAX_BYTES = 50_000;
|
|
|
15
15
|
|
|
16
16
|
export default defineAction({
|
|
17
17
|
description:
|
|
18
|
-
"List reusable Design templates, including built-in
|
|
18
|
+
"List reusable Design templates, including built-in templates plus templates the user can access or publicly discover.",
|
|
19
19
|
schema: z.object({
|
|
20
20
|
category: designTemplateCategorySchema.optional(),
|
|
21
21
|
includePreview: z.enum(["true", "false"]).optional().default("false"),
|
|
@@ -25,10 +25,11 @@ export default defineAction({
|
|
|
25
25
|
run: async ({ category, includePreview }) => {
|
|
26
26
|
const db = getDb();
|
|
27
27
|
const userEmail = getRequestUserEmail();
|
|
28
|
+
const orgId = getRequestOrgId();
|
|
28
29
|
const access = accessFilter(
|
|
29
30
|
schema.designTemplates,
|
|
30
31
|
schema.designTemplateShares,
|
|
31
|
-
{ userEmail, orgId
|
|
32
|
+
{ userEmail, orgId },
|
|
32
33
|
"viewer",
|
|
33
34
|
{ includePublic: true },
|
|
34
35
|
);
|
|
@@ -41,6 +42,7 @@ export default defineAction({
|
|
|
41
42
|
width: schema.designTemplates.width,
|
|
42
43
|
height: schema.designTemplates.height,
|
|
43
44
|
lockedLayerCount: schema.designTemplates.lockedLayerCount,
|
|
45
|
+
designSystemId: schema.designTemplates.designSystemId,
|
|
44
46
|
visibility: schema.designTemplates.visibility,
|
|
45
47
|
ownerEmail: schema.designTemplates.ownerEmail,
|
|
46
48
|
createdAt: schema.designTemplates.createdAt,
|
|
@@ -54,31 +56,68 @@ export default defineAction({
|
|
|
54
56
|
)
|
|
55
57
|
.orderBy(desc(schema.designTemplates.updatedAt));
|
|
56
58
|
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
fileType: schema.designTemplateFiles.fileType,
|
|
64
|
-
content: sql<string>`substr(${schema.designTemplateFiles.content}, 1, ${PREVIEW_MAX_BYTES})`,
|
|
65
|
-
})
|
|
66
|
-
.from(schema.designTemplateFiles)
|
|
67
|
-
.where(
|
|
68
|
-
inArray(
|
|
69
|
-
schema.designTemplateFiles.templateId,
|
|
70
|
-
rows.map((row) => row.id),
|
|
59
|
+
const linkedDesignSystemIds = Array.from(
|
|
60
|
+
new Set(
|
|
61
|
+
rows
|
|
62
|
+
.map((row) => row.designSystemId)
|
|
63
|
+
.filter(
|
|
64
|
+
(id): id is string => typeof id === "string" && id.length > 0,
|
|
71
65
|
),
|
|
72
|
-
|
|
66
|
+
),
|
|
67
|
+
);
|
|
68
|
+
const [files, accessibleDesignSystems] = await Promise.all([
|
|
69
|
+
includePreview === "true" && rows.length > 0
|
|
70
|
+
? db
|
|
71
|
+
.select({
|
|
72
|
+
templateId: schema.designTemplateFiles.templateId,
|
|
73
|
+
filename: schema.designTemplateFiles.filename,
|
|
74
|
+
fileType: schema.designTemplateFiles.fileType,
|
|
75
|
+
content: sql<string>`substr(${schema.designTemplateFiles.content}, 1, ${PREVIEW_MAX_BYTES})`,
|
|
76
|
+
})
|
|
77
|
+
.from(schema.designTemplateFiles)
|
|
78
|
+
.where(
|
|
79
|
+
and(
|
|
80
|
+
inArray(
|
|
81
|
+
schema.designTemplateFiles.templateId,
|
|
82
|
+
rows.map((row) => row.id),
|
|
83
|
+
),
|
|
84
|
+
eq(schema.designTemplateFiles.fileType, "html"),
|
|
85
|
+
),
|
|
86
|
+
)
|
|
87
|
+
: Promise.resolve([]),
|
|
88
|
+
linkedDesignSystemIds.length > 0
|
|
89
|
+
? db
|
|
90
|
+
.select({ id: schema.designSystems.id })
|
|
91
|
+
.from(schema.designSystems)
|
|
92
|
+
.where(
|
|
93
|
+
and(
|
|
94
|
+
inArray(schema.designSystems.id, linkedDesignSystemIds),
|
|
95
|
+
accessFilter(
|
|
96
|
+
schema.designSystems,
|
|
97
|
+
schema.designSystemShares,
|
|
98
|
+
{ userEmail, orgId },
|
|
99
|
+
"viewer",
|
|
100
|
+
{ includePublic: true },
|
|
101
|
+
),
|
|
102
|
+
),
|
|
103
|
+
)
|
|
104
|
+
: Promise.resolve([]),
|
|
105
|
+
]);
|
|
106
|
+
|
|
107
|
+
const previews = new Map<string, string>();
|
|
108
|
+
if (includePreview === "true") {
|
|
73
109
|
for (const file of files) {
|
|
74
|
-
if (!previews.has(file.templateId)
|
|
110
|
+
if (!previews.has(file.templateId)) {
|
|
75
111
|
previews.set(file.templateId, file.content);
|
|
76
112
|
}
|
|
77
|
-
if (file.filename === "index.html"
|
|
113
|
+
if (file.filename === "index.html") {
|
|
78
114
|
previews.set(file.templateId, file.content);
|
|
79
115
|
}
|
|
80
116
|
}
|
|
81
117
|
}
|
|
118
|
+
const accessibleDesignSystemIds = new Set(
|
|
119
|
+
accessibleDesignSystems.map((system) => system.id),
|
|
120
|
+
);
|
|
82
121
|
|
|
83
122
|
const presets = DESIGN_TEMPLATE_PRESETS.filter(
|
|
84
123
|
(preset) => !category || preset.category === category,
|
|
@@ -90,18 +129,25 @@ export default defineAction({
|
|
|
90
129
|
width: preset.width,
|
|
91
130
|
height: preset.height,
|
|
92
131
|
lockedLayerCount: 2,
|
|
132
|
+
designSystemId: null,
|
|
93
133
|
visibility: "public" as const,
|
|
94
134
|
isOwner: false,
|
|
135
|
+
isBuiltIn: true,
|
|
95
136
|
source: "starter" as const,
|
|
96
137
|
createdAt: null,
|
|
97
138
|
updatedAt: null,
|
|
98
139
|
...(includePreview === "true" ? { previewHtml: preset.content } : {}),
|
|
99
140
|
}));
|
|
100
141
|
|
|
101
|
-
const saved = rows.map(({ ownerEmail, ...row }) => ({
|
|
142
|
+
const saved = rows.map(({ ownerEmail, designSystemId, ...row }) => ({
|
|
102
143
|
...row,
|
|
144
|
+
designSystemId:
|
|
145
|
+
designSystemId && accessibleDesignSystemIds.has(designSystemId)
|
|
146
|
+
? designSystemId
|
|
147
|
+
: null,
|
|
103
148
|
isOwner:
|
|
104
149
|
!!userEmail && ownerEmail.toLowerCase() === userEmail.toLowerCase(),
|
|
150
|
+
isBuiltIn: false,
|
|
105
151
|
source: "saved" as const,
|
|
106
152
|
...(includePreview === "true"
|
|
107
153
|
? { previewHtml: previews.get(row.id) ?? null }
|
|
@@ -110,9 +156,11 @@ export default defineAction({
|
|
|
110
156
|
|
|
111
157
|
return {
|
|
112
158
|
count: presets.length + saved.length,
|
|
159
|
+
builtInCount: presets.length,
|
|
160
|
+
userCount: saved.length,
|
|
113
161
|
starterCount: presets.length,
|
|
114
162
|
savedCount: saved.length,
|
|
115
|
-
templates: [...
|
|
163
|
+
templates: [...saved, ...presets],
|
|
116
164
|
};
|
|
117
165
|
},
|
|
118
166
|
});
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* --filename Screen filename to focus in the design editor
|
|
25
25
|
* --tool Design editor tool to activate
|
|
26
26
|
* --designSystemId Design system ID (for design-systems view)
|
|
27
|
-
* --templateId Saved or
|
|
27
|
+
* --templateId Saved or built-in template ID (for templates view)
|
|
28
28
|
* --path URL path to navigate to
|
|
29
29
|
*/
|
|
30
30
|
|
|
@@ -122,7 +122,7 @@ export default defineAction({
|
|
|
122
122
|
templateId: z
|
|
123
123
|
.string()
|
|
124
124
|
.optional()
|
|
125
|
-
.describe("Saved or
|
|
125
|
+
.describe("Saved or built-in template ID for templates view"),
|
|
126
126
|
path: z.string().optional().describe("URL path to navigate to"),
|
|
127
127
|
})
|
|
128
128
|
.superRefine((args, ctx) => {
|
|
@@ -244,7 +244,9 @@ export default defineAction({
|
|
|
244
244
|
width: preset.width,
|
|
245
245
|
height: preset.height,
|
|
246
246
|
lockedLayerCount: 2,
|
|
247
|
-
|
|
247
|
+
designSystemId: null,
|
|
248
|
+
isBuiltIn: true,
|
|
249
|
+
source: "built-in",
|
|
248
250
|
};
|
|
249
251
|
} else {
|
|
250
252
|
const templateAccess = await resolveAccess(
|
|
@@ -253,6 +255,15 @@ export default defineAction({
|
|
|
253
255
|
).catch(() => null);
|
|
254
256
|
if (templateAccess) {
|
|
255
257
|
const template = templateAccess.resource;
|
|
258
|
+
const linkedDesignSystemId =
|
|
259
|
+
typeof template.designSystemId === "string"
|
|
260
|
+
? template.designSystemId
|
|
261
|
+
: null;
|
|
262
|
+
const designSystemAccess = linkedDesignSystemId
|
|
263
|
+
? await resolveAccess("design-system", linkedDesignSystemId).catch(
|
|
264
|
+
() => null,
|
|
265
|
+
)
|
|
266
|
+
: null;
|
|
256
267
|
screen.template = {
|
|
257
268
|
id: templateId,
|
|
258
269
|
title: template.title ?? null,
|
|
@@ -261,8 +272,10 @@ export default defineAction({
|
|
|
261
272
|
width: template.width ?? null,
|
|
262
273
|
height: template.height ?? null,
|
|
263
274
|
lockedLayerCount: template.lockedLayerCount ?? 0,
|
|
275
|
+
designSystemId: designSystemAccess ? linkedDesignSystemId : null,
|
|
264
276
|
visibility: template.visibility ?? "private",
|
|
265
|
-
|
|
277
|
+
isBuiltIn: false,
|
|
278
|
+
source: "user",
|
|
266
279
|
};
|
|
267
280
|
}
|
|
268
281
|
}
|
|
@@ -110,12 +110,16 @@ export function sanitizeLocalhostSourceSnapshotHtml(html: string): string {
|
|
|
110
110
|
);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
// Prototypes are still sandboxed, but user-initiated print/download controls
|
|
114
|
+
// need the browser permissions that make `window.print()` and download links
|
|
115
|
+
// work inside an iframe. Without these tokens the browser silently ignores
|
|
116
|
+
// the common "Download / Print PDF" pattern.
|
|
113
117
|
const EXTERNAL_PREVIEW_IFRAME_SANDBOX =
|
|
114
|
-
"allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-same-origin";
|
|
118
|
+
"allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads allow-modals allow-same-origin";
|
|
115
119
|
const EDITABLE_INLINE_IFRAME_SANDBOX =
|
|
116
|
-
"allow-scripts allow-popups allow-popups-to-escape-sandbox allow-same-origin";
|
|
120
|
+
"allow-scripts allow-popups allow-popups-to-escape-sandbox allow-downloads allow-modals allow-same-origin";
|
|
117
121
|
const READ_ONLY_INLINE_IFRAME_SANDBOX =
|
|
118
|
-
"allow-scripts allow-popups allow-popups-to-escape-sandbox";
|
|
122
|
+
"allow-scripts allow-popups allow-popups-to-escape-sandbox allow-downloads allow-modals";
|
|
119
123
|
|
|
120
124
|
export function getDesignCanvasIframeSandbox(args: {
|
|
121
125
|
externalPreview: boolean;
|