@agent-native/core 0.80.7 → 0.80.9
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 +18 -0
- package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +6 -0
- package/corpus/core/docs/content/locales/de-DE/template-design.mdx +8 -0
- package/corpus/core/docs/content/locales/es-ES/template-design.mdx +10 -2
- package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +10 -2
- package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +7 -0
- package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +7 -0
- package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +7 -0
- package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +9 -2
- package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +6 -0
- package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +6 -0
- package/corpus/core/docs/content/template-design.mdx +9 -2
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/cli/mcp.ts +10 -0
- package/corpus/core/src/cli/skills.ts +58 -12
- package/corpus/core/src/client/AssistantChat.tsx +70 -27
- package/corpus/core/src/client/analytics.ts +3 -1
- package/corpus/core/src/client/error-format.ts +25 -0
- package/corpus/core/src/client/extensions/ExtensionViewer.tsx +13 -11
- package/corpus/core/src/client/guided-questions.tsx +32 -4
- package/corpus/core/src/client/onboarding/OnboardingPanel.tsx +33 -1
- package/corpus/core/src/client/resources/BuiltinCapabilityDetail.tsx +8 -0
- package/corpus/core/src/client/resources/use-builtin-capabilities.ts +4 -2
- package/corpus/core/src/client/session-replay.ts +34 -0
- package/corpus/core/src/client/sharing/ShareButton.tsx +106 -21
- package/corpus/core/src/coding-tools/index.ts +1 -1
- package/corpus/core/src/mcp/index.ts +2 -0
- package/corpus/core/src/mcp/screen-memory-stdio.ts +290 -0
- package/corpus/core/src/mcp-client/builtin-capabilities.ts +13 -1
- package/corpus/core/src/mcp-client/index.ts +9 -0
- package/corpus/core/src/mcp-client/screen-memory-local.ts +461 -0
- package/corpus/core/src/onboarding/types.ts +7 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +25 -0
- package/corpus/core/src/server/agents-bundle.ts +35 -7
- package/corpus/core/src/styles/agent-native.css +5 -0
- package/corpus/core/src/templates/default/app/global.css +35 -35
- package/corpus/templates/analytics/AGENTS.md +6 -0
- package/corpus/templates/analytics/actions/github-repo-files.ts +9 -0
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +4 -4
- package/corpus/templates/analytics/app/global.css +144 -40
- package/corpus/templates/analytics/app/pages/adhoc/explorer/index.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/ChartCard.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +1 -1
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +4 -4
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +9 -9
- package/corpus/templates/analytics/changelog/2026-06-29-agents-can-search-and-read-connected-github-repositories-whe.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-sessions-and-explorer-layouts-adapt-when-the-agent-sidebar-is.md +6 -0
- package/corpus/templates/assets/app/components/layout/Layout.tsx +3 -1
- package/corpus/templates/assets/app/components/library/LibraryPresetGrid.tsx +1 -1
- package/corpus/templates/assets/app/global.css +99 -35
- package/corpus/templates/assets/app/routes/asset.$id.tsx +2 -2
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +4 -4
- package/corpus/templates/assets/app/routes/library.tsx +4 -4
- package/corpus/templates/assets/changelog/2026-06-29-asset-library-and-detail-layouts-adapt-when-the-agent-sidebar.md +6 -0
- package/corpus/templates/brain/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/brain/app/global.css +63 -35
- package/corpus/templates/brain/app/routes/search.tsx +1 -1
- package/corpus/templates/brain/app/routes/settings.tsx +1 -1
- package/corpus/templates/brain/app/routes/sources.tsx +2 -2
- package/corpus/templates/brain/changelog/2026-06-29-search-settings-and-source-layouts-adapt-when-the-agent-sidebar.md +6 -0
- package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +4 -4
- package/corpus/templates/calendar/app/components/calendar/FindTimePanel.tsx +3 -2
- package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +4 -2
- package/corpus/templates/calendar/app/global.css +69 -35
- package/corpus/templates/calendar/changelog/2026-06-29-event-and-find-time-layouts-adapt-when-the-agent-sidebar-is.md +6 -0
- package/corpus/templates/chat/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/chat/app/global.css +35 -35
- package/corpus/templates/chat/changelog/2026-06-29-chat-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
- package/corpus/templates/clips/AGENTS.md +13 -0
- package/corpus/templates/clips/actions/get-screen-memory-status.ts +12 -0
- package/corpus/templates/clips/actions/query-screen-memory-context.ts +29 -0
- package/corpus/templates/clips/actions/view-screen.ts +2 -2
- package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -1
- package/corpus/templates/clips/app/global.css +47 -35
- package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +3 -3
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +45 -18
- package/corpus/templates/clips/changelog/2026-06-29-meeting-detail-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-29-screen-memory-keeps-a-local-rolling-screen-buffer-for-agent-context.md +5 -0
- package/corpus/templates/clips/changelog/2026-06-29-video-chat-is-easier-to-find-on-recording-pages-and-s3-setup.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/styles.css +39 -39
- package/corpus/templates/clips/desktop/src/app.tsx +290 -1
- package/corpus/templates/clips/desktop/src/shared/config.ts +83 -0
- package/corpus/templates/clips/desktop/src/styles.css +67 -52
- package/corpus/templates/clips/desktop/src-tauri/src/config.rs +50 -0
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +17 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +13 -13
- package/corpus/templates/clips/desktop/src-tauri/src/screen_memory.rs +990 -0
- package/corpus/templates/clips/server/plugins/onboarding.ts +2 -0
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +69 -16
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +3 -3
- package/corpus/templates/content/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/content/app/global.css +29 -15
- package/corpus/templates/content/changelog/2026-06-29-database-gallery-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
- package/corpus/templates/content/changelog/2026-06-29-read-only-pages-no-longer-try-to-autosave-or-open-editor-onl.md +6 -0
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +25 -20
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +8 -0
- package/corpus/templates/design/.agents/skills/export-handoff/SKILL.md +8 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +13 -0
- package/corpus/templates/design/AGENTS.md +24 -14
- package/corpus/templates/design/CODE_NATIVE_DESIGN_STUDIO_IMPLEMENTATION_PLAN.md +1054 -0
- package/corpus/templates/design/actions/apply-visual-edit.ts +24 -4
- package/corpus/templates/design/actions/edit-design.ts +6 -3
- package/corpus/templates/design/actions/export-coding-handoff.ts +12 -4
- package/corpus/templates/design/actions/generate-design.ts +6 -21
- package/corpus/templates/design/actions/generate-screens.ts +48 -5
- package/corpus/templates/design/actions/get-design.ts +1 -0
- package/corpus/templates/design/actions/present-design-variants.ts +355 -30
- package/corpus/templates/design/actions/update-design.ts +47 -10
- package/corpus/templates/design/actions/update-file.ts +33 -8
- package/corpus/templates/design/actions/view-screen.ts +89 -31
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +389 -71
- package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +1 -1
- package/corpus/templates/design/app/components/design/EditPanel.tsx +596 -95
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +428 -221
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +1197 -228
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +94 -217
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +28 -14
- package/corpus/templates/design/app/components/design/index.ts +0 -1
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +228 -170
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +140 -13
- package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +39 -8
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +4 -2
- package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +75 -5
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +37 -12
- package/corpus/templates/design/app/components/design/inspector/index.ts +1 -0
- package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +17 -4
- package/corpus/templates/design/app/components/design/types.ts +9 -0
- package/corpus/templates/design/app/components/layout/Layout.tsx +23 -5
- package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +448 -259
- package/corpus/templates/design/app/global.css +77 -49
- package/corpus/templates/design/app/hooks/use-question-flow.ts +2 -2
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +8 -1
- package/corpus/templates/design/app/i18n/zh-TW.ts +4 -0
- package/corpus/templates/design/app/i18n-data.ts +55 -3
- package/corpus/templates/design/app/pages/DesignEditor.tsx +2783 -658
- package/corpus/templates/design/app/root.tsx +1 -1
- package/corpus/templates/design/changelog/2026-06-29-agent-edits-to-a-design-are-no-longer-occasionally-dropped-o.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-box-shadow-and-gradient-colors-keep-named-css-colors-like-re.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-containers-no-longer-block-selecting-nested-elements-and-nor.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-cut-cmd-ctrl-x-now-removes-the-selected-element-to-the-clipb.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-deleting-with-multiple-layers-selected-in-the-layers-panel-n.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-design-agents-now-generate-and-refine-variants-from-stronger.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-design-inspector-controls-now-match-figmas-softer-dark-chrome.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-design-questions-now-appear-as-a-cleaner-canvas-intake-with-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-design-variant-directions-now-appear-as-board-screens-with-chat-buttons.md +5 -0
- package/corpus/templates/design/changelog/2026-06-29-duplicating-a-screen-now-gives-the-copy-its-own-layer-ids-so.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-element-selection-no-longer-snaps-back-to-the-previous-layer.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-frame-resize-measurements-now-stay-beside-the-cursor-while-d.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-hiding-and-re-showing-a-gradient-fill-now-preserves-each-sto.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-inspector-number-fields-have-cleaner-tooltips-and-draggable-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-layer-locking-layer-nesting-generated-question-intake-and-im.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-layer-names-in-the-sidebar-can-scroll-horizontally-instead-o.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-layer-nesting-in-the-sidebar-now-uses-tighter-spacing-so-nam.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-layers-no-longer-repeat-document-wrapper-rows-when-a-screen-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-overview-previews-now-keep-element-hover-and-selection-tied-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-picking-a-design-direction-now-submits-to-the-agent-right-aw.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-pressing-escape-now-cancels-a-stuck-screen-drag-in-the-overv.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-screen-overview-is-easier-to-find-and-named-screens-open-dir.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-screen-overview-only-highlights-screens-when-the-frame-or-ti.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-screen-overview-previews-now-resize-to-match-the-selected-de.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-screen-overview-selection-now-uses-a-pointer-cursor-instead-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-screen-overview-selection-outlines-now-stay-locked-to-the-se.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-screen-overview-zoom-now-reports-real-screen-scale-separatel.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-screen-overview-zooming-feels-smoother-and-selection-outline.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-screen-overview-zooming-now-stays-on-the-overview-canvas-ins.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-selecting-a-nested-layer-from-all-screens-now-keeps-you-in-a.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-share-now-groups-link-sharing-exports-and-agent-handoff.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-style-changes-that-set-several-properties-at-once-fixed-size.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-the-design-editor-loading-skeleton-now-uses-a-softer-charcoa.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-the-device-preview-menu-now-sits-next-to-the-preview-button-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-the-editor-no-longer-crashes-when-a-screen-ends-up-with-dupl.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-the-inspector-stays-read-only-while-an-empty-design-is-still.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-the-missing-design-view-now-matches-the-rest-of-the-editor-c.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-the-pen-tool-icon-and-tool-option-menus-better-match-the-edi.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-typography-controls-now-keep-the-font-name-visible-and-move-.md +6 -0
- package/corpus/templates/design/e2e/README.md +4 -3
- package/corpus/templates/design/e2e/global-setup.ts +24 -23
- package/corpus/templates/design/e2e/helpers.ts +122 -11
- package/corpus/templates/design/playwright.config.ts +19 -4
- package/corpus/templates/design/server/lib/coding-handoff.ts +126 -2
- package/corpus/templates/design/server/plugins/core-routes.ts +1 -2
- package/corpus/templates/design/server/routes/api/design-handoff/[id].zip.get.ts +86 -0
- package/corpus/templates/design/shared/code-layer.ts +125 -22
- package/corpus/templates/design/shared/color-utils.ts +159 -0
- package/corpus/templates/design/shared/generation-session.ts +42 -0
- package/corpus/templates/dispatch/app/global.css +79 -35
- package/corpus/templates/dispatch/app/routes/integrations.tsx +8 -7
- package/corpus/templates/dispatch/changelog/2026-06-29-integration-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
- package/corpus/templates/forms/app/components/layout/Layout.tsx +6 -2
- package/corpus/templates/forms/app/global.css +64 -35
- package/corpus/templates/forms/app/pages/FormsListPage.tsx +2 -2
- package/corpus/templates/forms/app/pages/ResponseInsightsPage.tsx +3 -3
- package/corpus/templates/forms/changelog/2026-06-29-form-list-and-insight-layouts-adapt-when-the-agent-sidebar.md +6 -0
- package/corpus/templates/macros/app/components/layout/AppLayout.tsx +3 -1
- package/corpus/templates/macros/app/global.css +25 -9
- package/corpus/templates/macros/changelog/2026-06-29-macro-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +6 -2
- package/corpus/templates/mail/app/global.css +42 -36
- package/corpus/templates/mail/app/pages/InboxPage.tsx +1 -1
- package/corpus/templates/mail/changelog/2026-06-29-the-contact-panel-now-adapts-to-the-available-mail-pane-width.md +6 -0
- package/corpus/templates/plan/app/components/layout/Layout.tsx +3 -1
- package/corpus/templates/plan/app/components/plan/DocumentArea.tsx +6 -7
- package/corpus/templates/plan/app/global.css +74 -42
- package/corpus/templates/plan/changelog/2026-06-29-plan-document-blocks-adapt-to-the-available-document-width.md +6 -0
- package/corpus/templates/plan/changelog/2026-06-29-plan-titles-and-summaries-can-be-edited-inline-without-focus.md +6 -0
- package/corpus/templates/slides/app/components/layout/Layout.tsx +3 -1
- package/corpus/templates/slides/app/global.css +49 -33
- package/corpus/templates/slides/changelog/2026-06-29-slide-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
- package/corpus/templates/videos/app/components/layout/Layout.tsx +3 -1
- package/corpus/templates/videos/app/global.css +35 -35
- package/corpus/templates/videos/changelog/2026-06-29-video-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
- package/dist/cli/mcp.d.ts.map +1 -1
- package/dist/cli/mcp.js +10 -0
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +58 -12
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +54 -24
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +2 -1
- package/dist/client/analytics.js.map +1 -1
- 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/extensions/ExtensionViewer.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionViewer.js +3 -4
- package/dist/client/extensions/ExtensionViewer.js.map +1 -1
- package/dist/client/guided-questions.d.ts +4 -0
- package/dist/client/guided-questions.d.ts.map +1 -1
- package/dist/client/guided-questions.js +16 -7
- package/dist/client/guided-questions.js.map +1 -1
- package/dist/client/onboarding/OnboardingPanel.js +26 -1
- package/dist/client/onboarding/OnboardingPanel.js.map +1 -1
- package/dist/client/resources/BuiltinCapabilityDetail.d.ts.map +1 -1
- package/dist/client/resources/BuiltinCapabilityDetail.js +1 -1
- package/dist/client/resources/BuiltinCapabilityDetail.js.map +1 -1
- package/dist/client/resources/use-builtin-capabilities.d.ts +1 -1
- package/dist/client/resources/use-builtin-capabilities.d.ts.map +1 -1
- package/dist/client/resources/use-builtin-capabilities.js +2 -1
- package/dist/client/resources/use-builtin-capabilities.js.map +1 -1
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +31 -0
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/sharing/ShareButton.d.ts +14 -0
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +36 -7
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/coding-tools/index.js +1 -1
- package/dist/coding-tools/index.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/mcp/index.d.ts +2 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +1 -0
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/screen-memory-stdio.d.ts +6 -0
- package/dist/mcp/screen-memory-stdio.d.ts.map +1 -0
- package/dist/mcp/screen-memory-stdio.js +213 -0
- package/dist/mcp/screen-memory-stdio.js.map +1 -0
- package/dist/mcp-client/builtin-capabilities.d.ts +1 -1
- package/dist/mcp-client/builtin-capabilities.d.ts.map +1 -1
- package/dist/mcp-client/builtin-capabilities.js +10 -0
- package/dist/mcp-client/builtin-capabilities.js.map +1 -1
- package/dist/mcp-client/index.d.ts +1 -0
- package/dist/mcp-client/index.d.ts.map +1 -1
- package/dist/mcp-client/index.js +1 -0
- package/dist/mcp-client/index.js.map +1 -1
- package/dist/mcp-client/screen-memory-local.d.ts +61 -0
- package/dist/mcp-client/screen-memory-local.d.ts.map +1 -0
- package/dist/mcp-client/screen-memory-local.js +336 -0
- package/dist/mcp-client/screen-memory-local.js.map +1 -0
- package/dist/onboarding/types.d.ts +7 -0
- package/dist/onboarding/types.d.ts.map +1 -1
- package/dist/onboarding/types.js.map +1 -1
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +26 -0
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agents-bundle.d.ts.map +1 -1
- package/dist/server/agents-bundle.js +22 -7
- package/dist/server/agents-bundle.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/styles/agent-native.css +5 -0
- package/dist/templates/default/app/global.css +35 -35
- package/docs/content/locales/ar-SA/template-design.mdx +6 -0
- package/docs/content/locales/de-DE/template-design.mdx +8 -0
- package/docs/content/locales/es-ES/template-design.mdx +10 -2
- package/docs/content/locales/fr-FR/template-design.mdx +10 -2
- package/docs/content/locales/hi-IN/template-design.mdx +7 -0
- package/docs/content/locales/ja-JP/template-design.mdx +7 -0
- package/docs/content/locales/ko-KR/template-design.mdx +7 -0
- package/docs/content/locales/pt-BR/template-design.mdx +9 -2
- package/docs/content/locales/zh-CN/template-design.mdx +6 -0
- package/docs/content/locales/zh-TW/template-design.mdx +6 -0
- package/docs/content/template-design.mdx +9 -2
- package/package.json +1 -1
- package/src/templates/default/app/global.css +35 -35
- package/corpus/templates/design/app/components/design/VariantGrid.tsx +0 -189
- package/corpus/templates/design/app/components/design/VariantHandoffCard.tsx +0 -115
- package/corpus/templates/design/app/hooks/use-variant-flow.ts +0 -258
|
@@ -15,6 +15,12 @@ import { defineConfig, devices } from "@playwright/test";
|
|
|
15
15
|
*/
|
|
16
16
|
const PORT = Number(process.env.E2E_PORT ?? 9333);
|
|
17
17
|
const BASE_URL = process.env.E2E_BASE_URL ?? `http://127.0.0.1:${PORT}`;
|
|
18
|
+
const E2E_DATABASE_URL = `file:${path.join(
|
|
19
|
+
import.meta.dirname,
|
|
20
|
+
"data",
|
|
21
|
+
"e2e.db",
|
|
22
|
+
)}`;
|
|
23
|
+
const BROWSER_CHANNEL = process.env.E2E_BROWSER_CHANNEL;
|
|
18
24
|
|
|
19
25
|
export default defineConfig({
|
|
20
26
|
testDir: "./e2e",
|
|
@@ -33,14 +39,23 @@ export default defineConfig({
|
|
|
33
39
|
actionTimeout: 15_000,
|
|
34
40
|
navigationTimeout: 30_000,
|
|
35
41
|
},
|
|
36
|
-
projects: [
|
|
42
|
+
projects: [
|
|
43
|
+
{
|
|
44
|
+
name: BROWSER_CHANNEL ? `chromium-${BROWSER_CHANNEL}` : "chromium",
|
|
45
|
+
use: {
|
|
46
|
+
...devices["Desktop Chrome"],
|
|
47
|
+
...(BROWSER_CHANNEL ? { channel: BROWSER_CHANNEL } : {}),
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
],
|
|
37
51
|
webServer: process.env.E2E_BASE_URL
|
|
38
52
|
? undefined
|
|
39
53
|
: {
|
|
40
54
|
// APP_NAME + the app-prefixed DESIGN_DATABASE_URL is checked BEFORE the
|
|
41
|
-
// generic DATABASE_URL,
|
|
42
|
-
//
|
|
43
|
-
|
|
55
|
+
// generic DATABASE_URL, but set both to an absolute SQLite URL so a
|
|
56
|
+
// `.env` Postgres URL or a changed command cwd can never override this
|
|
57
|
+
// throwaway local db.
|
|
58
|
+
command: `APP_NAME=design DESIGN_DATABASE_URL=${JSON.stringify(E2E_DATABASE_URL)} DATABASE_URL=${JSON.stringify(E2E_DATABASE_URL)} PORT=${PORT} corepack pnpm dev`,
|
|
44
59
|
url: BASE_URL,
|
|
45
60
|
reuseExistingServer: !process.env.CI,
|
|
46
61
|
// Cold Vite dep-optimization on first boot can exceed two minutes.
|
|
@@ -82,6 +82,23 @@ export function buildRawHandoffUrl({
|
|
|
82
82
|
return normalizedOrigin ? `${normalizedOrigin}${path}` : path;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
export function buildHandoffZipUrl({
|
|
86
|
+
id,
|
|
87
|
+
token,
|
|
88
|
+
origin,
|
|
89
|
+
}: {
|
|
90
|
+
id: string;
|
|
91
|
+
token: string;
|
|
92
|
+
origin?: string | null;
|
|
93
|
+
}): string {
|
|
94
|
+
const params = new URLSearchParams({ token });
|
|
95
|
+
const path = appPath(
|
|
96
|
+
`/api/design-handoff/${encodeURIComponent(id)}.zip?${params.toString()}`,
|
|
97
|
+
);
|
|
98
|
+
const normalizedOrigin = normalizeHandoffOrigin(origin);
|
|
99
|
+
return normalizedOrigin ? `${normalizedOrigin}${path}` : path;
|
|
100
|
+
}
|
|
101
|
+
|
|
85
102
|
function parseDesignData(data?: string | null): Record<string, unknown> {
|
|
86
103
|
if (!data) return {};
|
|
87
104
|
try {
|
|
@@ -301,20 +318,127 @@ export function buildDesignHandoffMarkdown(
|
|
|
301
318
|
return `${lines.join("\n")}\n`;
|
|
302
319
|
}
|
|
303
320
|
|
|
321
|
+
function safeZipBaseName(title?: string | null): string {
|
|
322
|
+
const safe = (title || "design")
|
|
323
|
+
.replace(/[^a-zA-Z0-9_-]/g, "-")
|
|
324
|
+
.replace(/-+/g, "-")
|
|
325
|
+
.replace(/^-|-$/g, "");
|
|
326
|
+
return safe || "design";
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export function buildHandoffZipFilename(title?: string | null): string {
|
|
330
|
+
return `${safeZipBaseName(title)}-agent-handoff.zip`;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function safeZipPath(filename: string, fallback: string): string {
|
|
334
|
+
const normalized = filename
|
|
335
|
+
.replace(/\\/g, "/")
|
|
336
|
+
.split("/")
|
|
337
|
+
.map((part) => part.trim())
|
|
338
|
+
.filter((part) => part && part !== "." && part !== "..")
|
|
339
|
+
.join("/");
|
|
340
|
+
const withoutControlCharacters = normalized.replace(/[\x00-\x1f\x7f]/g, "");
|
|
341
|
+
return withoutControlCharacters || fallback;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function uniqueZipPath(path: string, seen: Set<string>): string {
|
|
345
|
+
if (!seen.has(path)) {
|
|
346
|
+
seen.add(path);
|
|
347
|
+
return path;
|
|
348
|
+
}
|
|
349
|
+
const slash = path.lastIndexOf("/");
|
|
350
|
+
const dir = slash === -1 ? "" : `${path.slice(0, slash + 1)}`;
|
|
351
|
+
const base = slash === -1 ? path : path.slice(slash + 1);
|
|
352
|
+
const dot = base.lastIndexOf(".");
|
|
353
|
+
const name = dot === -1 ? base : base.slice(0, dot);
|
|
354
|
+
const ext = dot === -1 ? "" : base.slice(dot);
|
|
355
|
+
let index = 2;
|
|
356
|
+
while (seen.has(`${dir}${name}-${index}${ext}`)) index += 1;
|
|
357
|
+
const next = `${dir}${name}-${index}${ext}`;
|
|
358
|
+
seen.add(next);
|
|
359
|
+
return next;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export async function buildDesignHandoffZip(
|
|
363
|
+
payload: DesignHandoffPayload,
|
|
364
|
+
): Promise<Uint8Array> {
|
|
365
|
+
const JSZip = (await import("jszip")).default;
|
|
366
|
+
const zip = new JSZip();
|
|
367
|
+
const seenPaths = new Set<string>();
|
|
368
|
+
|
|
369
|
+
const readme = [
|
|
370
|
+
`# ${payload.design.title}`,
|
|
371
|
+
"",
|
|
372
|
+
"This archive contains the source files exported from Agent-Native Design.",
|
|
373
|
+
"Use the files as the source of truth for layout, typography, colors, spacing, copy, and interactions.",
|
|
374
|
+
"",
|
|
375
|
+
`Design ID: ${payload.design.id}`,
|
|
376
|
+
`Exported: ${payload.exportedAt}`,
|
|
377
|
+
payload.design.projectType
|
|
378
|
+
? `Project type: ${payload.design.projectType}`
|
|
379
|
+
: null,
|
|
380
|
+
"",
|
|
381
|
+
"## Files",
|
|
382
|
+
"",
|
|
383
|
+
...payload.files.map((file) => `- ${file.filename} (${file.fileType})`),
|
|
384
|
+
]
|
|
385
|
+
.filter((line): line is string => line !== null)
|
|
386
|
+
.join("\n");
|
|
387
|
+
|
|
388
|
+
zip.file(uniqueZipPath("README.md", seenPaths), readme);
|
|
389
|
+
zip.file(
|
|
390
|
+
uniqueZipPath("design-handoff.json", seenPaths),
|
|
391
|
+
JSON.stringify(
|
|
392
|
+
{
|
|
393
|
+
exportedAt: payload.exportedAt,
|
|
394
|
+
design: payload.design,
|
|
395
|
+
files: payload.files.map((file) => ({
|
|
396
|
+
filename: file.filename,
|
|
397
|
+
fileType: file.fileType,
|
|
398
|
+
})),
|
|
399
|
+
appliedDesignTokens: payload.appliedDesignTokens,
|
|
400
|
+
},
|
|
401
|
+
null,
|
|
402
|
+
2,
|
|
403
|
+
),
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
payload.files.forEach((file, index) => {
|
|
407
|
+
const path = uniqueZipPath(
|
|
408
|
+
safeZipPath(file.filename, `file-${index + 1}.${file.fileType || "txt"}`),
|
|
409
|
+
seenPaths,
|
|
410
|
+
);
|
|
411
|
+
zip.file(path, file.content);
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
return zip.generateAsync({ type: "uint8array" });
|
|
415
|
+
}
|
|
416
|
+
|
|
304
417
|
export function buildCodingHandoffPrompt({
|
|
305
418
|
rawUrl,
|
|
419
|
+
zipUrl,
|
|
306
420
|
title,
|
|
307
421
|
fileCount,
|
|
308
422
|
}: {
|
|
309
423
|
rawUrl: string;
|
|
424
|
+
zipUrl?: string;
|
|
310
425
|
title: string;
|
|
311
426
|
fileCount: number;
|
|
312
427
|
}): string {
|
|
313
|
-
|
|
428
|
+
const lines = [
|
|
314
429
|
`Build this design as production code: ${title}`,
|
|
315
430
|
"",
|
|
316
431
|
`Fetch the raw design bundle here: ${rawUrl}`,
|
|
432
|
+
];
|
|
433
|
+
if (zipUrl) {
|
|
434
|
+
lines.push(
|
|
435
|
+
"",
|
|
436
|
+
`If you prefer files, download the ZIP bundle here: ${zipUrl}`,
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
lines.push(
|
|
317
440
|
"",
|
|
318
441
|
`The bundle contains ${fileCount} file${fileCount === 1 ? "" : "s"} with the exact HTML/CSS/JSX source from the Design app. Use it as the source of truth for layout, typography, colors, spacing, responsive behavior, copy, and interactions. Convert it into the target project stack or Builder.io page/component while preserving the visual intent. If multiple screens are included, implement the primary page first and map the rest to routes, sections, or components as appropriate.`,
|
|
319
|
-
|
|
442
|
+
);
|
|
443
|
+
return lines.join("\n");
|
|
320
444
|
}
|
|
@@ -6,8 +6,7 @@ import { createCoreRoutesPlugin } from "@agent-native/core/server";
|
|
|
6
6
|
// a resolveOpenPath, `/_agent-native/open?app=design&view=editor&designId=…`
|
|
7
7
|
// falls back to `/<view>` = `/editor`, which has no matching route (the
|
|
8
8
|
// editor route is `design.$id.tsx` → `/design/:id`) and 404s — so an
|
|
9
|
-
// "Open in Design" link for a connected
|
|
10
|
-
// opened the design.
|
|
9
|
+
// "Open in Design" link for a connected external agent never opened the design.
|
|
11
10
|
export default createCoreRoutesPlugin({
|
|
12
11
|
resolveOpenPath: ({ view, params }) => {
|
|
13
12
|
if (params.designId) return `/design/${params.designId}`;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { verifyShortLivedToken } from "@agent-native/core/server";
|
|
2
|
+
import { eq } from "drizzle-orm";
|
|
3
|
+
import {
|
|
4
|
+
defineEventHandler,
|
|
5
|
+
getQuery,
|
|
6
|
+
getRouterParam,
|
|
7
|
+
setResponseHeader,
|
|
8
|
+
setResponseStatus,
|
|
9
|
+
type H3Event,
|
|
10
|
+
} from "h3";
|
|
11
|
+
|
|
12
|
+
import { getDb, schema } from "../../../db/index.js";
|
|
13
|
+
import {
|
|
14
|
+
buildDesignHandoffPayload,
|
|
15
|
+
buildDesignHandoffZip,
|
|
16
|
+
buildHandoffZipFilename,
|
|
17
|
+
} from "../../../lib/coding-handoff.js";
|
|
18
|
+
import { buildDesignSnapshot } from "../../../lib/design-snapshot.js";
|
|
19
|
+
|
|
20
|
+
function notFound(event: H3Event) {
|
|
21
|
+
setResponseStatus(event, 404);
|
|
22
|
+
return { error: "Not found" };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function normalizeRouteId(value: string | undefined): string | undefined {
|
|
26
|
+
if (!value) return value;
|
|
27
|
+
return value.endsWith(".zip") ? value.slice(0, -4) : value;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default defineEventHandler(async (event: H3Event) => {
|
|
31
|
+
const id = normalizeRouteId(getRouterParam(event, "id"));
|
|
32
|
+
if (!id) {
|
|
33
|
+
setResponseStatus(event, 400);
|
|
34
|
+
return { error: "Design ID is required" };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const q = getQuery(event) as {
|
|
38
|
+
token?: string;
|
|
39
|
+
t?: string;
|
|
40
|
+
};
|
|
41
|
+
const token =
|
|
42
|
+
typeof q.token === "string" ? q.token : typeof q.t === "string" ? q.t : "";
|
|
43
|
+
|
|
44
|
+
const verified = verifyShortLivedToken(token, id);
|
|
45
|
+
if (!verified.ok) {
|
|
46
|
+
setResponseStatus(event, 403);
|
|
47
|
+
return { error: "Invalid or expired handoff link" };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const db = getDb();
|
|
51
|
+
// guard:allow-unscoped — this unauthenticated endpoint is gated by a signed, expiring handoff token bound to the design id.
|
|
52
|
+
const [design] = await db
|
|
53
|
+
.select()
|
|
54
|
+
.from(schema.designs)
|
|
55
|
+
.where(eq(schema.designs.id, id))
|
|
56
|
+
.limit(1);
|
|
57
|
+
if (!design) return notFound(event);
|
|
58
|
+
|
|
59
|
+
const snapshot = await buildDesignSnapshot(id, design.data);
|
|
60
|
+
if (snapshot.files.length === 0) return notFound(event);
|
|
61
|
+
|
|
62
|
+
const payload = buildDesignHandoffPayload({
|
|
63
|
+
design,
|
|
64
|
+
files: snapshot.files.map((f) => ({
|
|
65
|
+
filename: f.filename,
|
|
66
|
+
fileType: f.fileType,
|
|
67
|
+
content: f.content,
|
|
68
|
+
})),
|
|
69
|
+
resolvedCssVars: snapshot.resolvedCssVars,
|
|
70
|
+
});
|
|
71
|
+
const zip = await buildDesignHandoffZip(payload);
|
|
72
|
+
const filename = buildHandoffZipFilename(design.title);
|
|
73
|
+
|
|
74
|
+
setResponseHeader(event, "Cache-Control", "no-store");
|
|
75
|
+
setResponseHeader(event, "Referrer-Policy", "no-referrer");
|
|
76
|
+
setResponseHeader(event, "X-Content-Type-Options", "nosniff");
|
|
77
|
+
setResponseHeader(event, "Access-Control-Allow-Origin", "*");
|
|
78
|
+
setResponseHeader(event, "Content-Type", "application/zip");
|
|
79
|
+
setResponseHeader(
|
|
80
|
+
event,
|
|
81
|
+
"Content-Disposition",
|
|
82
|
+
`attachment; filename="${filename}"; filename*=UTF-8''${encodeURIComponent(filename)}`,
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
return zip;
|
|
86
|
+
});
|
|
@@ -1485,6 +1485,49 @@ function treeTypeForNode(node: CodeLayerNode): CodeLayerTreeNodeType {
|
|
|
1485
1485
|
return "element";
|
|
1486
1486
|
}
|
|
1487
1487
|
|
|
1488
|
+
function isCollapsibleDocumentShellNode(
|
|
1489
|
+
node: CodeLayerTreeNode,
|
|
1490
|
+
nodesById: Map<string, CodeLayerNode>,
|
|
1491
|
+
): boolean {
|
|
1492
|
+
if (node.tag !== "html" && node.tag !== "body") return false;
|
|
1493
|
+
return nodesById.get(node.id)?.layerNameSource === "tag";
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
function compactCodeLayerTreeNodes(
|
|
1497
|
+
nodes: CodeLayerTreeNode[],
|
|
1498
|
+
nodesById: Map<string, CodeLayerNode>,
|
|
1499
|
+
ancestors: Set<string> = new Set(),
|
|
1500
|
+
): CodeLayerTreeNode[] {
|
|
1501
|
+
const compacted: CodeLayerTreeNode[] = [];
|
|
1502
|
+
const siblingIds = new Set<string>();
|
|
1503
|
+
|
|
1504
|
+
for (const node of nodes) {
|
|
1505
|
+
if (ancestors.has(node.id)) continue;
|
|
1506
|
+
|
|
1507
|
+
const nextAncestors = new Set(ancestors);
|
|
1508
|
+
nextAncestors.add(node.id);
|
|
1509
|
+
const children = compactCodeLayerTreeNodes(
|
|
1510
|
+
node.children,
|
|
1511
|
+
nodesById,
|
|
1512
|
+
nextAncestors,
|
|
1513
|
+
);
|
|
1514
|
+
const compactedNode: CodeLayerTreeNode = { ...node, children };
|
|
1515
|
+
const promotedNodes =
|
|
1516
|
+
isCollapsibleDocumentShellNode(compactedNode, nodesById) &&
|
|
1517
|
+
children.length > 0
|
|
1518
|
+
? children
|
|
1519
|
+
: [compactedNode];
|
|
1520
|
+
|
|
1521
|
+
for (const promotedNode of promotedNodes) {
|
|
1522
|
+
if (siblingIds.has(promotedNode.id)) continue;
|
|
1523
|
+
siblingIds.add(promotedNode.id);
|
|
1524
|
+
compacted.push(promotedNode);
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
return compacted;
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1488
1531
|
function capabilitiesFor(element: ParsedElement): EditCapability[] {
|
|
1489
1532
|
const capabilities: EditCapability[] = [
|
|
1490
1533
|
{
|
|
@@ -1768,26 +1811,36 @@ export function buildCodeLayerTree(
|
|
|
1768
1811
|
});
|
|
1769
1812
|
}
|
|
1770
1813
|
|
|
1814
|
+
const childIdsByParentId = new Map<string, Set<string>>();
|
|
1771
1815
|
for (const node of projection.nodes) {
|
|
1772
1816
|
const parent =
|
|
1773
1817
|
node.parentId && nodesById.has(node.parentId)
|
|
1774
1818
|
? treeById.get(node.parentId)
|
|
1775
1819
|
: undefined;
|
|
1776
1820
|
const treeNode = treeById.get(node.id);
|
|
1777
|
-
if (parent
|
|
1778
|
-
|
|
1821
|
+
if (!parent || !treeNode || parent.id === treeNode.id) continue;
|
|
1822
|
+
const childIds = childIdsByParentId.get(parent.id) ?? new Set<string>();
|
|
1823
|
+
if (childIds.has(treeNode.id)) continue;
|
|
1824
|
+
childIds.add(treeNode.id);
|
|
1825
|
+
childIdsByParentId.set(parent.id, childIds);
|
|
1826
|
+
parent.children.push(treeNode);
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
const roots: CodeLayerTreeNode[] = [];
|
|
1830
|
+
const rootIds = new Set<string>();
|
|
1831
|
+
const appendRoot = (id: string) => {
|
|
1832
|
+
if (rootIds.has(id)) return;
|
|
1833
|
+
const treeNode = treeById.get(id);
|
|
1834
|
+
if (!treeNode) return;
|
|
1835
|
+
rootIds.add(id);
|
|
1836
|
+
roots.push(treeNode);
|
|
1837
|
+
};
|
|
1779
1838
|
|
|
1780
|
-
|
|
1781
|
-
.map((id) => treeById.get(id))
|
|
1782
|
-
.filter((node): node is CodeLayerTreeNode => Boolean(node));
|
|
1783
|
-
const rootIds = new Set(roots.map((node) => node.id));
|
|
1839
|
+
projection.rootNodeIds.forEach(appendRoot);
|
|
1784
1840
|
for (const node of projection.nodes) {
|
|
1785
|
-
if (!node.parentId
|
|
1786
|
-
const treeNode = treeById.get(node.id);
|
|
1787
|
-
if (treeNode) roots.push(treeNode);
|
|
1788
|
-
}
|
|
1841
|
+
if (!node.parentId) appendRoot(node.id);
|
|
1789
1842
|
}
|
|
1790
|
-
return roots;
|
|
1843
|
+
return compactCodeLayerTreeNodes(roots, nodesById);
|
|
1791
1844
|
}
|
|
1792
1845
|
|
|
1793
1846
|
function normalizeSelectorForMatch(selector: string): string {
|
|
@@ -1797,6 +1850,26 @@ function normalizeSelectorForMatch(selector: string): string {
|
|
|
1797
1850
|
.replace(/\s+/g, " ");
|
|
1798
1851
|
}
|
|
1799
1852
|
|
|
1853
|
+
function selectorPartTag(selectorPart: string): string | null {
|
|
1854
|
+
const match = selectorPart.trim().match(/^([A-Za-z][A-Za-z0-9:-]*)/);
|
|
1855
|
+
return match?.[1]?.toLowerCase() ?? null;
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
function isDocumentRootSelectorPart(selectorPart: string): boolean {
|
|
1859
|
+
const tag = selectorPartTag(selectorPart);
|
|
1860
|
+
return tag === "html" || tag === "body";
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
// Removes positional `:nth-of-type(n)` suffixes from a selector. Runtime
|
|
1864
|
+
// bridge selectors fall back to `:nth-of-type` for elements without a durable
|
|
1865
|
+
// id, and that position is computed against the live (possibly Alpine-mutated)
|
|
1866
|
+
// DOM. When the stored source order differs, the positional index no longer
|
|
1867
|
+
// lines up. Dropping the suffix lets resolution fall back to the element's
|
|
1868
|
+
// stable signal (tag, classes, attributes, ancestor path).
|
|
1869
|
+
function stripPositionalNthOfType(selector: string): string {
|
|
1870
|
+
return selector.replace(/:nth-of-type\(\d+\)/g, "");
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1800
1873
|
function lastSelectorPart(selector: string): string {
|
|
1801
1874
|
const parts = normalizeSelectorForMatch(selector).split(" > ");
|
|
1802
1875
|
return parts[parts.length - 1] ?? selector;
|
|
@@ -1926,7 +1999,11 @@ function selectorPathMatchesElement(
|
|
|
1926
1999
|
let current: ParsedElement | undefined = element;
|
|
1927
2000
|
for (let index = parts.length - 1; index >= 0; index -= 1) {
|
|
1928
2001
|
const selectorPart = parts[index];
|
|
1929
|
-
if (!
|
|
2002
|
+
if (!selectorPart) return false;
|
|
2003
|
+
if (!current) {
|
|
2004
|
+
if (isDocumentRootSelectorPart(selectorPart)) continue;
|
|
2005
|
+
return false;
|
|
2006
|
+
}
|
|
1930
2007
|
if (!simpleSelectorMatchesElement(current, selectorPart)) return false;
|
|
1931
2008
|
current =
|
|
1932
2009
|
current.parentIndex === undefined
|
|
@@ -2024,26 +2101,52 @@ function resolveTarget(
|
|
|
2024
2101
|
};
|
|
2025
2102
|
}
|
|
2026
2103
|
|
|
2027
|
-
const
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2104
|
+
const selectorValue = target.selector ?? "";
|
|
2105
|
+
const matchesForSelector = (value: string): CodeLayerNode[] =>
|
|
2106
|
+
projection.nodes.filter((node) =>
|
|
2107
|
+
selectorMatches(
|
|
2108
|
+
node,
|
|
2109
|
+
value,
|
|
2110
|
+
elementByNodeId.get(node.id),
|
|
2111
|
+
elementByIndex,
|
|
2112
|
+
),
|
|
2113
|
+
);
|
|
2114
|
+
|
|
2115
|
+
const matches = matchesForSelector(selectorValue);
|
|
2035
2116
|
if (matches.length === 1 && matches[0]) {
|
|
2036
2117
|
return { status: "resolved", node: matches[0] };
|
|
2037
2118
|
}
|
|
2038
2119
|
if (matches.length > 1) {
|
|
2039
2120
|
return {
|
|
2040
2121
|
status: "conflict",
|
|
2041
|
-
message: `Selector "${
|
|
2122
|
+
message: `Selector "${selectorValue}" matched ${matches.length} code layer nodes.`,
|
|
2042
2123
|
};
|
|
2043
2124
|
}
|
|
2125
|
+
|
|
2126
|
+
// Strict matching found nothing. Runtime selectors anchor unstamped elements
|
|
2127
|
+
// with positional `:nth-of-type(n)` parts, which drift when the live DOM
|
|
2128
|
+
// order differs from the stored source (reordered or runtime-inserted nodes).
|
|
2129
|
+
// Retry once with the positional suffixes dropped so an element that is still
|
|
2130
|
+
// unique by its tag/classes/attributes resolves instead of surfacing a hard
|
|
2131
|
+
// "did not match" error. Genuinely ambiguous results stay a conflict rather
|
|
2132
|
+
// than silently editing the wrong node.
|
|
2133
|
+
const positionTolerantSelector = stripPositionalNthOfType(selectorValue);
|
|
2134
|
+
if (positionTolerantSelector && positionTolerantSelector !== selectorValue) {
|
|
2135
|
+
const tolerantMatches = matchesForSelector(positionTolerantSelector);
|
|
2136
|
+
if (tolerantMatches.length === 1 && tolerantMatches[0]) {
|
|
2137
|
+
return { status: "resolved", node: tolerantMatches[0] };
|
|
2138
|
+
}
|
|
2139
|
+
if (tolerantMatches.length > 1) {
|
|
2140
|
+
return {
|
|
2141
|
+
status: "conflict",
|
|
2142
|
+
message: `Selector "${selectorValue}" matched ${tolerantMatches.length} code layer nodes after ignoring positional :nth-of-type (the element may have been reordered or added at runtime). Re-select the element to refresh its id.`,
|
|
2143
|
+
};
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2044
2147
|
return {
|
|
2045
2148
|
status: "conflict",
|
|
2046
|
-
message: `Selector "${
|
|
2149
|
+
message: `Selector "${selectorValue}" did not match a code layer node.`,
|
|
2047
2150
|
};
|
|
2048
2151
|
}
|
|
2049
2152
|
|
|
@@ -17,6 +17,160 @@ const RGB_PATTERN =
|
|
|
17
17
|
const HSL_PATTERN =
|
|
18
18
|
/^hsla?\(\s*([0-9.]+)(?:deg)?\s*,\s*([0-9.]+)%\s*,\s*([0-9.]+)%(?:\s*,\s*([0-9.]+%?))?\s*\)$/i;
|
|
19
19
|
|
|
20
|
+
// CSS named colors → hex, so detection/round-tripping works for shadows, gradient
|
|
21
|
+
// stops, and the color picker (not just #hex/rgb()/hsl()). `transparent` is handled
|
|
22
|
+
// separately as fully transparent black.
|
|
23
|
+
const NAMED_COLOR_HEX: Record<string, string> = {
|
|
24
|
+
aliceblue: "#f0f8ff",
|
|
25
|
+
antiquewhite: "#faebd7",
|
|
26
|
+
aqua: "#00ffff",
|
|
27
|
+
aquamarine: "#7fffd4",
|
|
28
|
+
azure: "#f0ffff",
|
|
29
|
+
beige: "#f5f5dc",
|
|
30
|
+
bisque: "#ffe4c4",
|
|
31
|
+
black: "#000000",
|
|
32
|
+
blanchedalmond: "#ffebcd",
|
|
33
|
+
blue: "#0000ff",
|
|
34
|
+
blueviolet: "#8a2be2",
|
|
35
|
+
brown: "#a52a2a",
|
|
36
|
+
burlywood: "#deb887",
|
|
37
|
+
cadetblue: "#5f9ea0",
|
|
38
|
+
chartreuse: "#7fff00",
|
|
39
|
+
chocolate: "#d2691e",
|
|
40
|
+
coral: "#ff7f50",
|
|
41
|
+
cornflowerblue: "#6495ed",
|
|
42
|
+
cornsilk: "#fff8dc",
|
|
43
|
+
crimson: "#dc143c",
|
|
44
|
+
cyan: "#00ffff",
|
|
45
|
+
darkblue: "#00008b",
|
|
46
|
+
darkcyan: "#008b8b",
|
|
47
|
+
darkgoldenrod: "#b8860b",
|
|
48
|
+
darkgray: "#a9a9a9",
|
|
49
|
+
darkgreen: "#006400",
|
|
50
|
+
darkgrey: "#a9a9a9",
|
|
51
|
+
darkkhaki: "#bdb76b",
|
|
52
|
+
darkmagenta: "#8b008b",
|
|
53
|
+
darkolivegreen: "#556b2f",
|
|
54
|
+
darkorange: "#ff8c00",
|
|
55
|
+
darkorchid: "#9932cc",
|
|
56
|
+
darkred: "#8b0000",
|
|
57
|
+
darksalmon: "#e9967a",
|
|
58
|
+
darkseagreen: "#8fbc8f",
|
|
59
|
+
darkslateblue: "#483d8b",
|
|
60
|
+
darkslategray: "#2f4f4f",
|
|
61
|
+
darkslategrey: "#2f4f4f",
|
|
62
|
+
darkturquoise: "#00ced1",
|
|
63
|
+
darkviolet: "#9400d3",
|
|
64
|
+
deeppink: "#ff1493",
|
|
65
|
+
deepskyblue: "#00bfff",
|
|
66
|
+
dimgray: "#696969",
|
|
67
|
+
dimgrey: "#696969",
|
|
68
|
+
dodgerblue: "#1e90ff",
|
|
69
|
+
firebrick: "#b22222",
|
|
70
|
+
floralwhite: "#fffaf0",
|
|
71
|
+
forestgreen: "#228b22",
|
|
72
|
+
fuchsia: "#ff00ff",
|
|
73
|
+
gainsboro: "#dcdcdc",
|
|
74
|
+
ghostwhite: "#f8f8ff",
|
|
75
|
+
gold: "#ffd700",
|
|
76
|
+
goldenrod: "#daa520",
|
|
77
|
+
gray: "#808080",
|
|
78
|
+
green: "#008000",
|
|
79
|
+
greenyellow: "#adff2f",
|
|
80
|
+
grey: "#808080",
|
|
81
|
+
honeydew: "#f0fff0",
|
|
82
|
+
hotpink: "#ff69b4",
|
|
83
|
+
indianred: "#cd5c5c",
|
|
84
|
+
indigo: "#4b0082",
|
|
85
|
+
ivory: "#fffff0",
|
|
86
|
+
khaki: "#f0e68c",
|
|
87
|
+
lavender: "#e6e6fa",
|
|
88
|
+
lavenderblush: "#fff0f5",
|
|
89
|
+
lawngreen: "#7cfc00",
|
|
90
|
+
lemonchiffon: "#fffacd",
|
|
91
|
+
lightblue: "#add8e6",
|
|
92
|
+
lightcoral: "#f08080",
|
|
93
|
+
lightcyan: "#e0ffff",
|
|
94
|
+
lightgoldenrodyellow: "#fafad2",
|
|
95
|
+
lightgray: "#d3d3d3",
|
|
96
|
+
lightgreen: "#90ee90",
|
|
97
|
+
lightgrey: "#d3d3d3",
|
|
98
|
+
lightpink: "#ffb6c1",
|
|
99
|
+
lightsalmon: "#ffa07a",
|
|
100
|
+
lightseagreen: "#20b2aa",
|
|
101
|
+
lightskyblue: "#87cefa",
|
|
102
|
+
lightslategray: "#778899",
|
|
103
|
+
lightslategrey: "#778899",
|
|
104
|
+
lightsteelblue: "#b0c4de",
|
|
105
|
+
lightyellow: "#ffffe0",
|
|
106
|
+
lime: "#00ff00",
|
|
107
|
+
limegreen: "#32cd32",
|
|
108
|
+
linen: "#faf0e6",
|
|
109
|
+
magenta: "#ff00ff",
|
|
110
|
+
maroon: "#800000",
|
|
111
|
+
mediumaquamarine: "#66cdaa",
|
|
112
|
+
mediumblue: "#0000cd",
|
|
113
|
+
mediumorchid: "#ba55d3",
|
|
114
|
+
mediumpurple: "#9370db",
|
|
115
|
+
mediumseagreen: "#3cb371",
|
|
116
|
+
mediumslateblue: "#7b68ee",
|
|
117
|
+
mediumspringgreen: "#00fa9a",
|
|
118
|
+
mediumturquoise: "#48d1cc",
|
|
119
|
+
mediumvioletred: "#c71585",
|
|
120
|
+
midnightblue: "#191970",
|
|
121
|
+
mintcream: "#f5fffa",
|
|
122
|
+
mistyrose: "#ffe4e1",
|
|
123
|
+
moccasin: "#ffe4b5",
|
|
124
|
+
navajowhite: "#ffdead",
|
|
125
|
+
navy: "#000080",
|
|
126
|
+
oldlace: "#fdf5e6",
|
|
127
|
+
olive: "#808000",
|
|
128
|
+
olivedrab: "#6b8e23",
|
|
129
|
+
orange: "#ffa500",
|
|
130
|
+
orangered: "#ff4500",
|
|
131
|
+
orchid: "#da70d6",
|
|
132
|
+
palegoldenrod: "#eee8aa",
|
|
133
|
+
palegreen: "#98fb98",
|
|
134
|
+
paleturquoise: "#afeeee",
|
|
135
|
+
palevioletred: "#db7093",
|
|
136
|
+
papayawhip: "#ffefd5",
|
|
137
|
+
peachpuff: "#ffdab9",
|
|
138
|
+
peru: "#cd853f",
|
|
139
|
+
pink: "#ffc0cb",
|
|
140
|
+
plum: "#dda0dd",
|
|
141
|
+
powderblue: "#b0e0e6",
|
|
142
|
+
purple: "#800080",
|
|
143
|
+
rebeccapurple: "#663399",
|
|
144
|
+
red: "#ff0000",
|
|
145
|
+
rosybrown: "#bc8f8f",
|
|
146
|
+
royalblue: "#4169e1",
|
|
147
|
+
saddlebrown: "#8b4513",
|
|
148
|
+
salmon: "#fa8072",
|
|
149
|
+
sandybrown: "#f4a460",
|
|
150
|
+
seagreen: "#2e8b57",
|
|
151
|
+
seashell: "#fff5ee",
|
|
152
|
+
sienna: "#a0522d",
|
|
153
|
+
silver: "#c0c0c0",
|
|
154
|
+
skyblue: "#87ceeb",
|
|
155
|
+
slateblue: "#6a5acd",
|
|
156
|
+
slategray: "#708090",
|
|
157
|
+
slategrey: "#708090",
|
|
158
|
+
snow: "#fffafa",
|
|
159
|
+
springgreen: "#00ff7f",
|
|
160
|
+
steelblue: "#4682b4",
|
|
161
|
+
tan: "#d2b48c",
|
|
162
|
+
teal: "#008080",
|
|
163
|
+
thistle: "#d8bfd8",
|
|
164
|
+
tomato: "#ff6347",
|
|
165
|
+
turquoise: "#40e0d0",
|
|
166
|
+
violet: "#ee82ee",
|
|
167
|
+
wheat: "#f5deb3",
|
|
168
|
+
white: "#ffffff",
|
|
169
|
+
whitesmoke: "#f5f5f5",
|
|
170
|
+
yellow: "#ffff00",
|
|
171
|
+
yellowgreen: "#9acd32",
|
|
172
|
+
};
|
|
173
|
+
|
|
20
174
|
export function parseCssColor(value: string): RgbaColor | null {
|
|
21
175
|
const trimmed = value.trim();
|
|
22
176
|
if (!trimmed) return null;
|
|
@@ -43,6 +197,11 @@ export function parseCssColor(value: string): RgbaColor | null {
|
|
|
43
197
|
});
|
|
44
198
|
}
|
|
45
199
|
|
|
200
|
+
const lower = trimmed.toLowerCase();
|
|
201
|
+
if (lower === "transparent") return { r: 0, g: 0, b: 0, a: 0 };
|
|
202
|
+
const namedHex = NAMED_COLOR_HEX[lower];
|
|
203
|
+
if (namedHex) return hexToRgba(namedHex);
|
|
204
|
+
|
|
46
205
|
return null;
|
|
47
206
|
}
|
|
48
207
|
|