@agent-native/core 0.82.0 → 0.84.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/README.md +2 -2
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +34 -0
- package/corpus/core/README.md +2 -2
- package/corpus/core/docs/content/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/ar-SA/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/ar-SA/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/ar-SA/template-chat.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/de-DE/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/template-chat.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/es-ES/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/template-chat.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/fr-FR/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/template-chat.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/hi-IN/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/template-chat.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/ja-JP/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/template-chat.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/ko-KR/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/template-chat.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/pt-BR/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/template-chat.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-CN/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/template-chat.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-TW/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/template-chat.mdx +1 -1
- package/corpus/core/docs/content/template-chat.mdx +1 -1
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/engine/builtin.ts +1 -1
- package/corpus/core/src/agent/engine/output-tokens.ts +1 -1
- package/corpus/core/src/agent/harness/acp-adapter.ts +28 -4
- package/corpus/core/src/agent/harness/ai-sdk-adapter.ts +3 -0
- package/corpus/core/src/agent/harness/translate.ts +3 -0
- package/corpus/core/src/agent/harness/types.ts +1 -0
- package/corpus/core/src/agent/model-config.ts +34 -13
- package/corpus/core/src/agent/production-agent.ts +87 -10
- package/corpus/core/src/agent/thread-data-builder.ts +29 -4
- package/corpus/core/src/agent/tool-call-journal.ts +109 -48
- package/corpus/core/src/agent/types.ts +6 -1
- package/corpus/core/src/cli/design-connect.ts +106 -0
- package/corpus/core/src/cli/gateway-helpers.ts +17 -0
- package/corpus/core/src/cli/recap.ts +0 -2
- package/corpus/core/src/cli/skills.ts +54 -16
- package/corpus/core/src/cli/workspace-dev.ts +29 -5
- package/corpus/core/src/client/AssistantChat.tsx +89 -42
- package/corpus/core/src/client/CommandMenu.tsx +34 -12
- package/corpus/core/src/client/DefaultSpinner.tsx +8 -1
- package/corpus/core/src/client/chat/message-components.tsx +49 -1
- package/corpus/core/src/client/chat/repo-helpers.ts +71 -0
- package/corpus/core/src/client/chat/run-recovery.tsx +15 -5
- package/corpus/core/src/client/components/ApiKeySettings.tsx +8 -8
- package/corpus/core/src/client/components/CodeRequiredDialog.tsx +26 -15
- package/corpus/core/src/client/components/MissingKeyCard.tsx +13 -6
- package/corpus/core/src/client/composer/TiptapComposer.tsx +4 -3
- package/corpus/core/src/client/extensions/ExtensionsSidebarSection.tsx +0 -1
- package/corpus/core/src/client/guided-questions.tsx +21 -27
- package/corpus/core/src/client/integrations/IntegrationCard.tsx +1 -1
- package/corpus/core/src/client/integrations/IntegrationsPanel.tsx +1 -1
- package/corpus/core/src/client/onboarding/OnboardingBanner.tsx +2 -2
- package/corpus/core/src/client/onboarding/OnboardingPanel.tsx +23 -19
- package/corpus/core/src/client/resources/ResourceEditor.tsx +18 -10
- package/corpus/core/src/client/resources/ResourcesPanel.tsx +5 -1
- package/corpus/core/src/client/settings/SettingsPanel.tsx +8 -3
- package/corpus/core/src/client/settings/useBuilderStatus.ts +8 -41
- package/corpus/core/src/client/useProductionAgent.ts +6 -2
- package/corpus/core/src/deploy/build.ts +1 -1
- package/corpus/core/src/observability/traces.ts +3 -3
- package/corpus/core/src/onboarding/default-steps.ts +1 -1
- package/corpus/core/src/scripts/agent-engines/manage-agent-engine.ts +1 -1
- package/corpus/core/src/scripts/agent-engines/set-agent-engine.ts +1 -1
- package/corpus/core/src/server/agent-chat-plugin.ts +177 -81
- package/corpus/core/src/server/core-routes-plugin.ts +7 -1
- package/corpus/core/src/server/open-route.ts +59 -40
- package/corpus/core/src/shared/reasoning-effort.ts +2 -0
- package/corpus/core/src/sharing/access.ts +22 -2
- package/corpus/core/src/sharing/registry.ts +18 -0
- package/corpus/core/src/styles/agent-native.css +104 -20
- package/corpus/core/src/styles/rich-markdown-editor.css +11 -10
- package/corpus/templates/analytics/actions/hubspot-deals.ts +64 -4
- package/corpus/templates/analytics/app/components/dashboard/CumulativeNetChart.tsx +10 -10
- package/corpus/templates/analytics/app/components/dashboard/RevenueChart.tsx +10 -10
- package/corpus/templates/analytics/app/components/dashboard/RevenueComparisonChart.tsx +6 -5
- package/corpus/templates/analytics/app/components/dashboard/TimeSeriesChart.tsx +9 -9
- package/corpus/templates/analytics/app/global.css +4 -0
- package/corpus/templates/analytics/app/lib/chart-theme.ts +13 -0
- package/corpus/templates/analytics/app/pages/adhoc/_shared/KpiChart.tsx +22 -24
- package/corpus/templates/analytics/changelog/2026-06-30-dashboard-charts-now-use-theme-aware-tooltip-and-grid-colors.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-30-fixed-ask-composer-spacing-so-the-chat-field-has-a-comfortab.md +6 -0
- package/corpus/templates/calendar/AGENTS.md +4 -0
- package/corpus/templates/calendar/actions/connect-google-calendar.ts +80 -0
- package/corpus/templates/calendar/changelog/2026-06-30-calendar-now-gives-the-agent-a-safe-google-connection-link-i.md +6 -0
- package/corpus/templates/calendar/server/plugins/agent-chat.ts +4 -0
- package/corpus/templates/content/.env.local.example +6 -0
- package/corpus/templates/content/AGENTS.md +10 -1
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +14 -1
- package/corpus/templates/content/actions/_builder-cms-source-adapter.ts +43 -0
- package/corpus/templates/content/actions/_builder-cms-write-adapter.ts +79 -7
- package/corpus/templates/content/actions/_database-source-utils.ts +987 -22
- package/corpus/templates/content/actions/_database-utils.ts +41 -0
- package/corpus/templates/content/actions/_local-file-documents.ts +74 -1
- package/corpus/templates/content/actions/attach-content-database-source.ts +33 -8
- package/corpus/templates/content/actions/change-content-database-source-role.ts +14 -0
- package/corpus/templates/content/actions/disconnect-content-database-source.ts +3 -0
- package/corpus/templates/content/actions/execute-builder-source-execution.ts +71 -3
- package/corpus/templates/content/actions/list-content-databases.ts +41 -33
- package/corpus/templates/content/actions/process-builder-body-hydration.ts +47 -0
- package/corpus/templates/content/actions/update-document.ts +93 -0
- package/corpus/templates/content/app/blocks/SourceComponentBlock.tsx +277 -0
- package/corpus/templates/content/app/blocks/contentBlockRegistry.tsx +2 -0
- package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +5 -5
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +45 -4
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +5 -1
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +92 -0
- package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +5 -3
- package/corpus/templates/content/app/components/editor/extensions/registryBlocks.ts +41 -0
- package/corpus/templates/content/app/components/editor/registrySlashItems.ts +4 -0
- package/corpus/templates/content/app/global.css +16 -8
- package/corpus/templates/content/app/hooks/use-content-database.ts +24 -0
- package/corpus/templates/content/app/i18n/zh-TW.ts +24 -0
- package/corpus/templates/content/app/i18n-data.ts +212 -0
- package/corpus/templates/content/app/lib/content-command-search.ts +64 -0
- package/corpus/templates/content/app/root.tsx +236 -8
- package/corpus/templates/content/changelog/2026-06-29-builder-cms-sources-now-sync-article-bodies-through-content.md +6 -0
- package/corpus/templates/content/changelog/2026-06-30-builder-article-media-now-render-as-images-and-embeds-when-r.md +6 -0
- package/corpus/templates/content/changelog/2026-06-30-builder-source-components-now-render-as-preserved-preview-bl.md +6 -0
- package/corpus/templates/content/changelog/2026-06-30-cmd-k-search-now-opens-from-the-editor-and-finds-real-content.md +6 -0
- package/corpus/templates/content/changelog/2026-06-30-editor-floating-toolbars-now-use-theme-aware-colors-in-light.md +6 -0
- package/corpus/templates/content/package.json +3 -1
- package/corpus/templates/content/scripts/check-native-deps.mjs +57 -0
- package/corpus/templates/content/scripts/dev-database.mjs +83 -0
- package/corpus/templates/content/scripts/seed-demo-user.mjs +107 -0
- package/corpus/templates/content/server/db/schema.ts +27 -0
- package/corpus/templates/content/server/plugins/db.ts +33 -0
- package/corpus/templates/content/shared/api.ts +45 -0
- package/corpus/templates/content/shared/builder-mdx.ts +905 -5
- package/corpus/templates/content/shared/nfm-registry.ts +2 -0
- package/corpus/templates/content/shared/source-component-block.ts +141 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +6 -1
- package/corpus/templates/design/actions/add-localhost-screens.ts +63 -8
- package/corpus/templates/design/actions/apply-motion-edit.ts +12 -46
- package/corpus/templates/design/actions/list-design-native-assets.ts +2 -1
- package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +49 -1
- package/corpus/templates/design/actions/navigate.ts +3 -12
- package/corpus/templates/design/actions/open-visual-edit.ts +341 -0
- package/corpus/templates/design/actions/view-screen.ts +1 -1
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +1 -1
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +350 -15
- package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +71 -91
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +25 -27
- package/corpus/templates/design/app/components/design/DeviceFrame.tsx +1 -1
- package/corpus/templates/design/app/components/design/DrawOverlay.tsx +2 -2
- package/corpus/templates/design/app/components/design/EditPanel.tsx +1111 -570
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +162 -32
- package/corpus/templates/design/app/components/design/MotionDock.tsx +268 -240
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +1193 -207
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +1 -1
- package/corpus/templates/design/app/components/design/ReviewPanel.tsx +81 -102
- package/corpus/templates/design/app/components/design/StatesPanel.tsx +6 -6
- package/corpus/templates/design/app/components/design/TokensPanel.tsx +11 -11
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +9 -7
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +1225 -154
- package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +130 -37
- package/corpus/templates/design/app/components/design/canvas-primitive-style.ts +24 -11
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +184 -162
- package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +137 -79
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +13 -13
- package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +8 -8
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +2 -2
- package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +4 -4
- package/corpus/templates/design/app/components/design/inspector/InspectorAiActions.tsx +3 -3
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +13 -7
- package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +14 -11
- package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +4 -4
- package/corpus/templates/design/app/components/design/inspector/index.ts +2 -0
- package/corpus/templates/design/app/components/design/types.ts +19 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +61 -78
- package/corpus/templates/design/app/components/layout/Header.tsx +0 -1
- package/corpus/templates/design/app/components/layout/Layout.tsx +3 -2
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +0 -2
- package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +5 -4
- package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +1 -1
- package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +2 -2
- package/corpus/templates/design/app/global.css +56 -0
- package/corpus/templates/design/app/hooks/use-agent-generating.ts +4 -5
- package/corpus/templates/design/app/hooks/use-navigation-state.ts +6 -7
- package/corpus/templates/design/app/hooks/use-question-flow.ts +3 -2
- package/corpus/templates/design/app/hooks/useAgentEditRequest.ts +6 -4
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +6 -3
- package/corpus/templates/design/app/i18n/zh-TW.ts +5 -14
- package/corpus/templates/design/app/i18n-data.ts +63 -188
- package/corpus/templates/design/app/lib/agent-chat.ts +13 -0
- package/corpus/templates/design/app/pages/DesignEditor.tsx +1755 -401
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +9 -5
- package/corpus/templates/design/app/pages/DesignSystems.tsx +2 -2
- package/corpus/templates/design/app/pages/Index.tsx +49 -26
- package/corpus/templates/design/app/pages/NotFound.tsx +25 -8
- package/corpus/templates/design/app/pages/VisualEdit.tsx +17 -5
- package/corpus/templates/design/app/routes/examples.tsx +1 -7
- package/corpus/templates/design/app/routes/templates.tsx +7 -4
- package/corpus/templates/design/changelog/2026-06-30-board-shapes-and-auto-layout-controls-are-clearer.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-canvas-editing-now-keeps-undo-redo-and-cross-screen-layer-mo.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-component-selections-now-use-purple-component-chrome-and-sho.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-constraints-now-stay-tucked-into-a-compact-inspector-preview.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-creating-a-component-now-opens-in-a-compact-inspector-popove.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-cards-no-longer-show-legacy-project-type-badges.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-chat-now-keeps-new-turns-in-the-visible-design-agent-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-editor-panels-now-keep-their-compact-text-sizing-cons.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-no-longer-shows-the-connected-local-code-warning-bann.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-now-opens-to-the-files-panel-unless-a-generation-is-a.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-opens-with-a-cleaner-empty-canvas-and-loading-preview.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-tools-use-simpler-less-decorative-icons.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-dragging-absolute-elements-no-longer-shows-coordinate-labels.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-fixed-all-screens-opening-too-zoomed-in-by-default.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-fixed-the-public-design-assets-sidebar-so-native-components-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-fixed-the-screen-overview-board-so-empty-board-space-no-long.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-full-view-screens-can-now-scroll-while-remaining-editable.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-inspector-element-headers-show-the-selected-html-tag-and-the.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-inspector-inputs-stay-compact-across-desktop-breakpoints.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-layers-can-be-multi-selected-from-the-canvas-and-edited-toge.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-local-visual-edit-links-can-edit-localhost-frames-without-si.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-localhost-visual-edit-frames-can-now-be-selected-and-edited.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-marquee-selection-now-works-inside-screens-multi-selected-la.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-motion-is-now-available-from-the-persistent-left-rail-and-th.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-motion-timeline-collapse-and-reopen-animations-feel-smoother.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-multi-select-outlines-now-stay-consistent-across-all-screens.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-new-board-shapes-now-start-with-neutral-gray-styling.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-new-designs-open-into-a-steadier-loading-state-before-the-ed.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-new-designs-show-a-loading-state-during-handoff-and-keep-edi.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-public-visual-edit-design-links-now-open-directly-instead-of.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-removed-the-confusing-states-section-from-the-design-editor-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-removed-the-templates-gallery-from-design-navigation.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-share-stays-visible-as-soon-as-editable-designs-load.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-signed-out-save-and-share-controls-use-simpler-labels-and-op.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-text-added-on-the-canvas-now-focuses-cleanly-with-the-right-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-design-editor-loading-skeleton-is-simpler-and-its-bottom.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-design-editor-loading-skeleton-now-follows-the-current-t.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-design-inspector-no-longer-shows-child-layout-controls-o.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-design-inspector-no-longer-shows-the-ask-ai-section-abov.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-design-review-panel-no-longer-shows-a-separate-inline-au.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-empty-designs-page-now-focuses-on-a-single-primary-new-d.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-layers-panel-header-stays-as-layers-while-multiple-items.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-missing-design-screen-now-uses-a-neutral-back-button.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-motion-timeline-now-closes-without-squeezing-the-canvas-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-new-design-connect-ai-setup-now-lines-up-with-the-compos.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-screen-overview-board-now-blends-into-the-canvas-and-new.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-top-level-canvas-drops-now-show-screen-guides.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-top-level-canvas-layers-now-keep-a-transparent-backdrop-and-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-top-level-canvas-layers-now-select-reliably-from-all-screens.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-visual-edit-can-open-and-refresh-localhost-screens-in-one-au.md +6 -0
- package/corpus/templates/design/e2e/helpers.ts +15 -4
- package/corpus/templates/design/server/db/index.ts +52 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +5 -0
- package/corpus/templates/design/server/plugins/auth.ts +1 -0
- package/corpus/templates/design/server/plugins/core-routes.ts +4 -0
- package/corpus/templates/design/shared/board-file.ts +380 -5
- package/corpus/templates/design/shared/board-objects.ts +2 -2
- package/corpus/templates/design/shared/code-layer.ts +50 -6
- package/corpus/templates/design/shared/motion-compiler.ts +27 -0
- package/corpus/templates/macros/app/components/DailyProgress.tsx +41 -37
- package/corpus/templates/macros/app/components/ExerciseCard.tsx +2 -2
- package/corpus/templates/macros/app/components/MealCard.tsx +2 -2
- package/corpus/templates/macros/app/components/VoiceDictation.tsx +1 -1
- package/corpus/templates/macros/app/components/WeeklyCaloriesChart.tsx +1 -1
- package/corpus/templates/macros/app/components/WeightCard.tsx +2 -2
- package/corpus/templates/macros/app/components/WeightTracker.tsx +1 -1
- package/corpus/templates/macros/app/components/layout/AppLayout.tsx +1 -1
- package/corpus/templates/macros/app/routes/_index.tsx +5 -5
- package/corpus/templates/macros/app/routes/analytics.tsx +1 -1
- package/corpus/templates/macros/changelog/2026-06-30-dashboard-loading-and-chart-surfaces-now-use-theme-aware-col.md +6 -0
- package/corpus/templates/mail/app/components/email/ComposeBubbleToolbar.tsx +14 -11
- package/corpus/templates/mail/app/global.css +3 -2
- package/corpus/templates/mail/changelog/2026-06-30-compose-floating-toolbars-now-use-theme-aware-colors-in-ligh.md +6 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +2 -2
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +3 -3
- package/corpus/templates/slides/app/global.css +10 -0
- package/corpus/templates/slides/app/pages/Index.tsx +55 -51
- package/corpus/templates/slides/changelog/2026-06-30-deck-thumbnails-collapse-cleanly-to-one-column-when-the-chat.md +6 -0
- package/dist/agent/engine/anthropic-engine.d.ts +2 -2
- package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
- package/dist/agent/engine/builder-engine.d.ts +2 -2
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builtin.js +1 -1
- package/dist/agent/engine/builtin.js.map +1 -1
- package/dist/agent/engine/output-tokens.js +1 -1
- package/dist/agent/engine/output-tokens.js.map +1 -1
- package/dist/agent/harness/acp-adapter.d.ts +4 -1
- package/dist/agent/harness/acp-adapter.d.ts.map +1 -1
- package/dist/agent/harness/acp-adapter.js +19 -2
- package/dist/agent/harness/acp-adapter.js.map +1 -1
- package/dist/agent/harness/ai-sdk-adapter.d.ts.map +1 -1
- package/dist/agent/harness/ai-sdk-adapter.js +3 -0
- package/dist/agent/harness/ai-sdk-adapter.js.map +1 -1
- package/dist/agent/harness/translate.d.ts.map +1 -1
- package/dist/agent/harness/translate.js +3 -0
- package/dist/agent/harness/translate.js.map +1 -1
- package/dist/agent/harness/types.d.ts +1 -0
- package/dist/agent/harness/types.d.ts.map +1 -1
- package/dist/agent/harness/types.js.map +1 -1
- package/dist/agent/model-config.d.ts +21 -20
- package/dist/agent/model-config.d.ts.map +1 -1
- package/dist/agent/model-config.js +31 -13
- package/dist/agent/model-config.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +85 -10
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +27 -6
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/agent/tool-call-journal.d.ts +11 -9
- package/dist/agent/tool-call-journal.d.ts.map +1 -1
- package/dist/agent/tool-call-journal.js +92 -40
- package/dist/agent/tool-call-journal.js.map +1 -1
- package/dist/agent/types.d.ts +5 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +84 -0
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/gateway-helpers.d.ts +4 -0
- package/dist/cli/gateway-helpers.d.ts.map +1 -1
- package/dist/cli/gateway-helpers.js +9 -0
- package/dist/cli/gateway-helpers.js.map +1 -1
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +0 -2
- package/dist/cli/recap.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +54 -16
- package/dist/cli/skills.js.map +1 -1
- package/dist/cli/workspace-dev.d.ts.map +1 -1
- package/dist/cli/workspace-dev.js +33 -6
- package/dist/cli/workspace-dev.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +72 -26
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/CommandMenu.d.ts +6 -2
- package/dist/client/CommandMenu.d.ts.map +1 -1
- package/dist/client/CommandMenu.js +25 -14
- package/dist/client/CommandMenu.js.map +1 -1
- package/dist/client/DefaultSpinner.d.ts.map +1 -1
- package/dist/client/DefaultSpinner.js +8 -1
- package/dist/client/DefaultSpinner.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +7 -1
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +37 -1
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/repo-helpers.d.ts +1 -0
- package/dist/client/chat/repo-helpers.d.ts.map +1 -1
- package/dist/client/chat/repo-helpers.js +59 -0
- package/dist/client/chat/repo-helpers.js.map +1 -1
- package/dist/client/chat/run-recovery.d.ts.map +1 -1
- package/dist/client/chat/run-recovery.js +4 -4
- package/dist/client/chat/run-recovery.js.map +1 -1
- package/dist/client/components/ApiKeySettings.js +8 -8
- package/dist/client/components/ApiKeySettings.js.map +1 -1
- package/dist/client/components/CodeRequiredDialog.d.ts.map +1 -1
- package/dist/client/components/CodeRequiredDialog.js +24 -15
- package/dist/client/components/CodeRequiredDialog.js.map +1 -1
- package/dist/client/components/MissingKeyCard.d.ts.map +1 -1
- package/dist/client/components/MissingKeyCard.js +11 -6
- package/dist/client/components/MissingKeyCard.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +4 -3
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.js +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
- package/dist/client/guided-questions.d.ts.map +1 -1
- package/dist/client/guided-questions.js +6 -6
- package/dist/client/guided-questions.js.map +1 -1
- package/dist/client/integrations/IntegrationCard.js +1 -1
- package/dist/client/integrations/IntegrationCard.js.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.js +1 -1
- package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
- package/dist/client/onboarding/OnboardingBanner.js +2 -2
- package/dist/client/onboarding/OnboardingBanner.js.map +1 -1
- package/dist/client/onboarding/OnboardingPanel.js +23 -19
- package/dist/client/onboarding/OnboardingPanel.js.map +1 -1
- package/dist/client/resources/ResourceEditor.d.ts.map +1 -1
- package/dist/client/resources/ResourceEditor.js +13 -10
- package/dist/client/resources/ResourceEditor.js.map +1 -1
- package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
- package/dist/client/resources/ResourcesPanel.js +2 -1
- package/dist/client/resources/ResourcesPanel.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +8 -3
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js +6 -38
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/client/useProductionAgent.d.ts +2 -1
- package/dist/client/useProductionAgent.d.ts.map +1 -1
- package/dist/client/useProductionAgent.js.map +1 -1
- package/dist/deploy/build.js +1 -1
- package/dist/deploy/build.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +3 -3
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js.map +1 -1
- package/dist/onboarding/default-steps.js +1 -1
- package/dist/onboarding/default-steps.js.map +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.js +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.js.map +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.js +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +3 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +134 -72
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/core-routes-plugin.d.ts +3 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +4 -1
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/open-route.d.ts +9 -0
- package/dist/server/open-route.d.ts.map +1 -1
- package/dist/server/open-route.js +48 -38
- package/dist/server/open-route.js.map +1 -1
- package/dist/shared/reasoning-effort.js +3 -0
- package/dist/shared/reasoning-effort.js.map +1 -1
- package/dist/sharing/access.d.ts.map +1 -1
- package/dist/sharing/access.js +18 -2
- package/dist/sharing/access.js.map +1 -1
- package/dist/sharing/registry.d.ts +10 -0
- package/dist/sharing/registry.d.ts.map +1 -1
- package/dist/sharing/registry.js.map +1 -1
- package/dist/styles/agent-native.css +104 -20
- package/dist/styles/rich-markdown-editor.css +11 -10
- package/docs/content/cloneable-saas.mdx +2 -2
- package/docs/content/faq.mdx +1 -1
- package/docs/content/locales/ar-SA/cloneable-saas.mdx +2 -2
- package/docs/content/locales/ar-SA/faq.mdx +1 -1
- package/docs/content/locales/ar-SA/template-chat.mdx +1 -1
- package/docs/content/locales/de-DE/cloneable-saas.mdx +2 -2
- package/docs/content/locales/de-DE/faq.mdx +1 -1
- package/docs/content/locales/de-DE/template-chat.mdx +1 -1
- package/docs/content/locales/es-ES/cloneable-saas.mdx +2 -2
- package/docs/content/locales/es-ES/faq.mdx +1 -1
- package/docs/content/locales/es-ES/template-chat.mdx +1 -1
- package/docs/content/locales/fr-FR/cloneable-saas.mdx +2 -2
- package/docs/content/locales/fr-FR/faq.mdx +1 -1
- package/docs/content/locales/fr-FR/template-chat.mdx +1 -1
- package/docs/content/locales/hi-IN/cloneable-saas.mdx +2 -2
- package/docs/content/locales/hi-IN/faq.mdx +1 -1
- package/docs/content/locales/hi-IN/template-chat.mdx +1 -1
- package/docs/content/locales/ja-JP/cloneable-saas.mdx +2 -2
- package/docs/content/locales/ja-JP/faq.mdx +1 -1
- package/docs/content/locales/ja-JP/template-chat.mdx +1 -1
- package/docs/content/locales/ko-KR/cloneable-saas.mdx +2 -2
- package/docs/content/locales/ko-KR/faq.mdx +1 -1
- package/docs/content/locales/ko-KR/template-chat.mdx +1 -1
- package/docs/content/locales/pt-BR/cloneable-saas.mdx +2 -2
- package/docs/content/locales/pt-BR/faq.mdx +1 -1
- package/docs/content/locales/pt-BR/template-chat.mdx +1 -1
- package/docs/content/locales/zh-CN/cloneable-saas.mdx +2 -2
- package/docs/content/locales/zh-CN/faq.mdx +1 -1
- package/docs/content/locales/zh-CN/template-chat.mdx +1 -1
- package/docs/content/locales/zh-TW/cloneable-saas.mdx +2 -2
- package/docs/content/locales/zh-TW/faq.mdx +1 -1
- package/docs/content/locales/zh-TW/template-chat.mdx +1 -1
- package/docs/content/template-chat.mdx +1 -1
- package/package.json +1 -1
- package/corpus/templates/design/app/components/design/LocalSourceEditBanner.tsx +0 -157
- package/corpus/templates/design/app/lib/design-templates.ts +0 -1305
- package/corpus/templates/design/app/pages/Templates.tsx +0 -279
|
@@ -174,10 +174,21 @@ async function waitForDesignBridgeReady(page: Page): Promise<void> {
|
|
|
174
174
|
// Wait for the iframe bridge to stamp at least one selectable node.
|
|
175
175
|
await expect
|
|
176
176
|
.poll(
|
|
177
|
-
async () =>
|
|
178
|
-
|
|
179
|
-
.locator(
|
|
180
|
-
.
|
|
177
|
+
async () => {
|
|
178
|
+
const previewIframes = await page
|
|
179
|
+
.locator(DESIGN_PREVIEW_IFRAME_SELECTOR)
|
|
180
|
+
.elementHandles();
|
|
181
|
+
let selectableNodeCount = 0;
|
|
182
|
+
for (const iframe of previewIframes) {
|
|
183
|
+
const frame = await iframe.contentFrame();
|
|
184
|
+
if (!frame) continue;
|
|
185
|
+
selectableNodeCount += await frame
|
|
186
|
+
.locator("[data-agent-native-node-id], h1, h2, p, button")
|
|
187
|
+
.count()
|
|
188
|
+
.catch(() => 0);
|
|
189
|
+
}
|
|
190
|
+
return selectableNodeCount;
|
|
191
|
+
},
|
|
181
192
|
{ timeout: 20_000 },
|
|
182
193
|
)
|
|
183
194
|
.toBeGreaterThan(0);
|
|
@@ -6,6 +6,56 @@ import * as schema from "./schema.js";
|
|
|
6
6
|
export const getDb = createGetDb(schema);
|
|
7
7
|
export { schema };
|
|
8
8
|
|
|
9
|
+
function isLocalDevRuntime(): boolean {
|
|
10
|
+
return (
|
|
11
|
+
process.env.NODE_ENV !== "production" &&
|
|
12
|
+
!process.env.NETLIFY &&
|
|
13
|
+
!process.env.VERCEL &&
|
|
14
|
+
!process.env.AWS_LAMBDA_FUNCTION_NAME &&
|
|
15
|
+
!process.env.CF_PAGES
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function isLoopbackHttpUrl(value: unknown): boolean {
|
|
20
|
+
if (typeof value !== "string" || !value.trim()) return false;
|
|
21
|
+
try {
|
|
22
|
+
const url = new URL(value);
|
|
23
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return false;
|
|
24
|
+
const host = url.hostname.toLowerCase();
|
|
25
|
+
return (
|
|
26
|
+
host === "localhost" ||
|
|
27
|
+
host === "::1" ||
|
|
28
|
+
host === "[::1]" ||
|
|
29
|
+
/^127(?:\.\d{1,3}){3}$/.test(host)
|
|
30
|
+
);
|
|
31
|
+
} catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function isLoopbackLocalhostDesign(design: any): boolean {
|
|
37
|
+
if (!isLocalDevRuntime()) return false;
|
|
38
|
+
let data: any;
|
|
39
|
+
try {
|
|
40
|
+
data = typeof design?.data === "string" ? JSON.parse(design.data) : null;
|
|
41
|
+
} catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
if (!data || data.sourceMode !== "localhost") return false;
|
|
45
|
+
|
|
46
|
+
const metadataEntries = Object.values(
|
|
47
|
+
data.localhostScreens ?? data.screenMetadata ?? {},
|
|
48
|
+
) as any[];
|
|
49
|
+
if (metadataEntries.length === 0) return false;
|
|
50
|
+
|
|
51
|
+
return metadataEntries.every((entry) => {
|
|
52
|
+
if (!entry || entry.sourceType !== "localhost") return false;
|
|
53
|
+
const previewUrl = entry.previewUrl ?? entry.url;
|
|
54
|
+
if (!isLoopbackHttpUrl(previewUrl)) return false;
|
|
55
|
+
return !entry.bridgeUrl || isLoopbackHttpUrl(entry.bridgeUrl);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
9
59
|
registerShareableResource({
|
|
10
60
|
type: "design",
|
|
11
61
|
resourceTable: schema.designs,
|
|
@@ -14,6 +64,8 @@ registerShareableResource({
|
|
|
14
64
|
titleColumn: "title",
|
|
15
65
|
getResourcePath: (design) => `/design/${design.id}`,
|
|
16
66
|
getDb,
|
|
67
|
+
publicAccessRole: (design) =>
|
|
68
|
+
isLoopbackLocalhostDesign(design) ? "editor" : "viewer",
|
|
17
69
|
});
|
|
18
70
|
|
|
19
71
|
registerShareableResource({
|
|
@@ -15,6 +15,9 @@ const INITIAL_TOOL_NAMES = [
|
|
|
15
15
|
"get-design",
|
|
16
16
|
"get-design-snapshot",
|
|
17
17
|
"create-design",
|
|
18
|
+
"open-visual-edit",
|
|
19
|
+
"add-localhost-screens",
|
|
20
|
+
"list-localhost-connections",
|
|
18
21
|
"edit-design",
|
|
19
22
|
"generate-design",
|
|
20
23
|
"present-design-variants",
|
|
@@ -46,6 +49,8 @@ export default createAgentChatPlugin({
|
|
|
46
49
|
|
|
47
50
|
When the user asks you to refine an existing design, call view-screen if the open design is unclear, then read the live current file with get-design-snapshot before editing. For small localized changes, call edit-design with exact search/replace edits. For broad copy-only changes such as translating all visible text, call edit-design in replace-file mode with the complete updated file content from the snapshot so the HTML structure, scripts, styles, and tweaks are preserved without dozens of fragile search blocks. Do not claim the design is updated until the mutating action succeeds.
|
|
48
51
|
|
|
52
|
+
When the user asks to visually inspect or edit a running local app, use open-visual-edit. It registers the localhost bridge, creates or reuses the Design project, places URL-backed iframe screens, stores the active visual-edit context, and navigates to overview mode in one authenticated step. For follow-ups like adding a mobile viewport or another route state, reuse the current designId and connectionId and call open-visual-edit or add-localhost-screens with explicit routes/paths and viewport sizes.
|
|
53
|
+
|
|
49
54
|
Provider-specific Design actions are shortcuts, not limits. If a first-class action cannot express the exact GitHub endpoint, repository tree query, code search, issue or pull request query, request body, pagination mode, payload shape, metadata field, or API version needed, call provider-api-catalog and provider-api-docs as needed, then call provider-api-request against the real GitHub API. Use the raw provider API escape hatch instead of weakening the answer or claiming Design cannot do something the underlying GitHub API can do.
|
|
50
55
|
|
|
51
56
|
Design's GitHub provider API uses the saved GITHUB_TOKEN secret when present. Never ask the user to paste tokens into chat. For large GitHub search results or repository scans, pass stageAs and pagination options to provider-api-request, then use query-staged-dataset to count, filter, group, or project the staged rows.
|
|
@@ -21,6 +21,9 @@ import type { BoardObjectEntry } from "./board-objects.js";
|
|
|
21
21
|
/** Reserved filename for the board overlay file. */
|
|
22
22
|
export const BOARD_FILENAME = "__board__.html";
|
|
23
23
|
|
|
24
|
+
const DEFAULT_SHAPE_FILL = "rgb(218 218 218)";
|
|
25
|
+
const DEFAULT_SHAPE_STROKE = "rgb(168 168 168)";
|
|
26
|
+
|
|
24
27
|
// ---------------------------------------------------------------------------
|
|
25
28
|
// isBoardFile
|
|
26
29
|
// ---------------------------------------------------------------------------
|
|
@@ -54,7 +57,8 @@ export function emptyBoardHtml(): string {
|
|
|
54
57
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
55
58
|
<style>
|
|
56
59
|
*, *::before, *::after { box-sizing: border-box; }
|
|
57
|
-
body {
|
|
60
|
+
html, body { background: transparent; }
|
|
61
|
+
body { margin: 0; position: relative; overflow: visible; }
|
|
58
62
|
</style>
|
|
59
63
|
</head>
|
|
60
64
|
<body>
|
|
@@ -153,10 +157,10 @@ export function boardObjectEntryToHtmlFragment(
|
|
|
153
157
|
|
|
154
158
|
// Ellipse kind uses a <div> with border-radius.
|
|
155
159
|
if (kind === "ellipse") {
|
|
156
|
-
const bgColor = fill ??
|
|
160
|
+
const bgColor = fill ?? DEFAULT_SHAPE_FILL;
|
|
157
161
|
const borderStyle = stroke
|
|
158
162
|
? `border:${strokeWidth ?? 1}px solid ${stroke};`
|
|
159
|
-
:
|
|
163
|
+
: `border:1px solid ${DEFAULT_SHAPE_STROKE};`;
|
|
160
164
|
const style = `${baseStyle};background:${bgColor};border-radius:50%;${borderStyle}`;
|
|
161
165
|
return `<div style="${style}" ${dataAttrs}></div>`;
|
|
162
166
|
}
|
|
@@ -170,10 +174,12 @@ export function boardObjectEntryToHtmlFragment(
|
|
|
170
174
|
|
|
171
175
|
// Frame / rectangle / polygon / star / default — basic colored <div>.
|
|
172
176
|
const bgColor =
|
|
173
|
-
fill ?? (kind === "frame" ? "transparent" :
|
|
177
|
+
fill ?? (kind === "frame" ? "transparent" : DEFAULT_SHAPE_FILL);
|
|
174
178
|
const borderStyle = stroke
|
|
175
179
|
? `border:${strokeWidth ?? 1}px solid ${stroke};`
|
|
176
|
-
: ""
|
|
180
|
+
: kind === "frame"
|
|
181
|
+
? ""
|
|
182
|
+
: `border:1px solid ${DEFAULT_SHAPE_STROKE};`;
|
|
177
183
|
const style = `${baseStyle};background:${bgColor};${borderStyle}`;
|
|
178
184
|
|
|
179
185
|
if (kind === "frame") {
|
|
@@ -212,6 +218,375 @@ function kindToLayerName(kind: BoardObjectEntry["kind"]): string {
|
|
|
212
218
|
}
|
|
213
219
|
}
|
|
214
220
|
|
|
221
|
+
// ---------------------------------------------------------------------------
|
|
222
|
+
// backfillBoardPrimitiveMarkers
|
|
223
|
+
// ---------------------------------------------------------------------------
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Adds `data-an-primitive="<kind>"` to board primitive elements that are
|
|
227
|
+
* missing the marker.
|
|
228
|
+
*
|
|
229
|
+
* ## Scope
|
|
230
|
+
*
|
|
231
|
+
* Only elements that look like top-level board primitives are touched:
|
|
232
|
+
* - Must be a direct `<body>` child (depth-1 element)
|
|
233
|
+
* - Must carry `data-agent-native-node-id` (the bridge id stamp)
|
|
234
|
+
* - Must NOT already have `data-an-primitive`
|
|
235
|
+
*
|
|
236
|
+
* ## Kind inference (conservative)
|
|
237
|
+
*
|
|
238
|
+
* | Condition | Inferred kind |
|
|
239
|
+
* |--------------------------------------------------------|---------------|
|
|
240
|
+
* | `<svg>` whose path carries `marker-end` | `"arrow"` |
|
|
241
|
+
* | `<svg>` containing a `<polygon>` | `"polygon"` |
|
|
242
|
+
* | `<svg>` containing exactly one `<path>` and no other shape | `"path"` |
|
|
243
|
+
* | `<svg>` with no reliable vector signal | *(skip — left unmarked, still classifies as a generic shape via tag)* |
|
|
244
|
+
* | Inline style contains `border-radius:50%` | `"ellipse"` |
|
|
245
|
+
* | Inline style contains `background:transparent` or no background, but has `data-agent-native-layer-name` starting with "Frame" | `"frame"` |
|
|
246
|
+
* | Element has non-empty text content and no background color in style | `"text"` |
|
|
247
|
+
* | Otherwise | `"rectangle"` |
|
|
248
|
+
*
|
|
249
|
+
* The function is:
|
|
250
|
+
* - **Pure** — returns a new string, never mutates.
|
|
251
|
+
* - **Additive** — only inserts `data-an-primitive`; never alters geometry,
|
|
252
|
+
* structure, or any other attributes.
|
|
253
|
+
* - **Idempotent** — if the marker is already present on an element, that
|
|
254
|
+
* element is skipped.
|
|
255
|
+
*
|
|
256
|
+
* The implementation uses string-level parsing to remain dependency-free
|
|
257
|
+
* (no DOM parser, no JSDOM). It is intentionally conservative: when in doubt,
|
|
258
|
+
* an element is left as-is rather than mis-classified.
|
|
259
|
+
*/
|
|
260
|
+
export function backfillBoardPrimitiveMarkers(html: string): string {
|
|
261
|
+
// Quick exit: if every node-id-bearing element already has the marker we
|
|
262
|
+
// have nothing to do.
|
|
263
|
+
if (!html.includes("data-agent-native-node-id=")) return html;
|
|
264
|
+
|
|
265
|
+
// We need to find direct <body> children only. We walk the raw HTML string
|
|
266
|
+
// looking for the opening of the <body> element, then iterate sibling-level
|
|
267
|
+
// opening tags until </body>.
|
|
268
|
+
|
|
269
|
+
const bodyStart = html.indexOf("<body");
|
|
270
|
+
if (bodyStart === -1) return html;
|
|
271
|
+
const bodyTagEnd = html.indexOf(">", bodyStart);
|
|
272
|
+
if (bodyTagEnd === -1) return html;
|
|
273
|
+
|
|
274
|
+
const bodyClose = html.lastIndexOf("</body>");
|
|
275
|
+
if (bodyClose === -1) return html;
|
|
276
|
+
|
|
277
|
+
// The direct-child region.
|
|
278
|
+
const before = html.slice(0, bodyTagEnd + 1);
|
|
279
|
+
const children = html.slice(bodyTagEnd + 1, bodyClose);
|
|
280
|
+
const after = html.slice(bodyClose);
|
|
281
|
+
|
|
282
|
+
const patched = _patchDirectChildren(children);
|
|
283
|
+
if (patched === children) return html; // nothing changed
|
|
284
|
+
return before + patched + after;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Walk the HTML fragment that represents the direct children of <body> and
|
|
289
|
+
* insert `data-an-primitive` on qualifying elements that lack it.
|
|
290
|
+
*
|
|
291
|
+
* We do NOT recurse into children — only sibling-level (depth-1) tags are
|
|
292
|
+
* touched.
|
|
293
|
+
*/
|
|
294
|
+
function _patchDirectChildren(fragment: string): string {
|
|
295
|
+
let result = "";
|
|
296
|
+
let pos = 0;
|
|
297
|
+
|
|
298
|
+
while (pos < fragment.length) {
|
|
299
|
+
// Find the next '<'.
|
|
300
|
+
const tagStart = fragment.indexOf("<", pos);
|
|
301
|
+
if (tagStart === -1) {
|
|
302
|
+
result += fragment.slice(pos);
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Copy any text / whitespace before this tag verbatim.
|
|
307
|
+
result += fragment.slice(pos, tagStart);
|
|
308
|
+
pos = tagStart;
|
|
309
|
+
|
|
310
|
+
// Peek: is this a comment, closing tag, or doctype? Copy verbatim.
|
|
311
|
+
const rest = fragment.slice(pos);
|
|
312
|
+
if (
|
|
313
|
+
rest.startsWith("<!--") ||
|
|
314
|
+
rest.startsWith("</") ||
|
|
315
|
+
rest.startsWith("<!") ||
|
|
316
|
+
rest.startsWith("<?")
|
|
317
|
+
) {
|
|
318
|
+
const end = fragment.indexOf(">", pos);
|
|
319
|
+
if (end === -1) {
|
|
320
|
+
result += fragment.slice(pos);
|
|
321
|
+
pos = fragment.length;
|
|
322
|
+
} else {
|
|
323
|
+
result += fragment.slice(pos, end + 1);
|
|
324
|
+
pos = end + 1;
|
|
325
|
+
}
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Find the end of this opening tag (handling quoted attributes).
|
|
330
|
+
const tagEnd = _findTagEnd(fragment, pos);
|
|
331
|
+
if (tagEnd === -1) {
|
|
332
|
+
// Malformed — copy rest verbatim.
|
|
333
|
+
result += fragment.slice(pos);
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const openTag = fragment.slice(pos, tagEnd + 1);
|
|
338
|
+
|
|
339
|
+
// Skip the tag body + nested content and get to the matching close tag so
|
|
340
|
+
// we can copy the whole element and move past it.
|
|
341
|
+
// We need the tag name first.
|
|
342
|
+
const tagNameMatch = openTag.match(/^<([a-zA-Z][a-zA-Z0-9-]*)/);
|
|
343
|
+
if (!tagNameMatch) {
|
|
344
|
+
// Not an element tag — copy verbatim and advance.
|
|
345
|
+
result += openTag;
|
|
346
|
+
pos = tagEnd + 1;
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
const tagName = tagNameMatch[1].toLowerCase();
|
|
350
|
+
|
|
351
|
+
// SVG elements: vector primitives (line/path/arrow/polygon/star) render as
|
|
352
|
+
// <svg>. When the marker is missing we conservatively infer the kind from
|
|
353
|
+
// the SVG's inner geometry so the layers panel shows the right vector icon
|
|
354
|
+
// instead of the generic shape glyph. Geometry is never altered — only the
|
|
355
|
+
// marker attribute is inserted on the opening <svg> tag.
|
|
356
|
+
if (tagName === "svg") {
|
|
357
|
+
const closeTag = `</svg>`;
|
|
358
|
+
const closeIdx = fragment.indexOf(closeTag, tagEnd + 1);
|
|
359
|
+
if (closeIdx === -1) {
|
|
360
|
+
result += fragment.slice(pos);
|
|
361
|
+
pos = fragment.length;
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
const inner = fragment.slice(tagEnd + 1, closeIdx);
|
|
365
|
+
const shouldPatchSvg =
|
|
366
|
+
openTag.includes("data-agent-native-node-id=") &&
|
|
367
|
+
!openTag.includes("data-an-primitive=");
|
|
368
|
+
let patchedSvgOpenTag = openTag;
|
|
369
|
+
if (shouldPatchSvg) {
|
|
370
|
+
const kind = _inferSvgPrimitiveKind(inner);
|
|
371
|
+
if (kind) {
|
|
372
|
+
patchedSvgOpenTag = openTag.replace(
|
|
373
|
+
/(\s*\/?>)$/,
|
|
374
|
+
` data-an-primitive="${kind}"$1`,
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
result += patchedSvgOpenTag + inner + closeTag;
|
|
379
|
+
pos = closeIdx + closeTag.length;
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// For all other elements: decide whether to patch.
|
|
384
|
+
const shouldPatch =
|
|
385
|
+
openTag.includes("data-agent-native-node-id=") &&
|
|
386
|
+
!openTag.includes("data-an-primitive=");
|
|
387
|
+
|
|
388
|
+
let patchedOpenTag = openTag;
|
|
389
|
+
if (shouldPatch) {
|
|
390
|
+
const kind = _inferPrimitiveKind(openTag);
|
|
391
|
+
// Insert marker just before the closing `>` or `/>` of the opening tag.
|
|
392
|
+
patchedOpenTag = openTag.replace(
|
|
393
|
+
/(\s*\/?>)$/,
|
|
394
|
+
` data-an-primitive="${kind}"$1`,
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Find the matching close tag (skip self-closing tags).
|
|
399
|
+
const isSelfClosing = openTag.endsWith("/>") || VOID_ELEMENTS.has(tagName);
|
|
400
|
+
if (isSelfClosing) {
|
|
401
|
+
result += patchedOpenTag;
|
|
402
|
+
pos = tagEnd + 1;
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const closeTag = `</${tagName}>`;
|
|
407
|
+
const closeIdx = _findMatchingClose(fragment, tagEnd + 1, tagName);
|
|
408
|
+
if (closeIdx === -1) {
|
|
409
|
+
// Unmatched open tag — copy rest verbatim.
|
|
410
|
+
result += patchedOpenTag + fragment.slice(tagEnd + 1);
|
|
411
|
+
pos = fragment.length;
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const innerContent = fragment.slice(tagEnd + 1, closeIdx);
|
|
416
|
+
result += patchedOpenTag + innerContent + closeTag;
|
|
417
|
+
pos = closeIdx + closeTag.length;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return result;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/** Void elements that have no closing tag. */
|
|
424
|
+
const VOID_ELEMENTS = new Set([
|
|
425
|
+
"area",
|
|
426
|
+
"base",
|
|
427
|
+
"br",
|
|
428
|
+
"col",
|
|
429
|
+
"embed",
|
|
430
|
+
"hr",
|
|
431
|
+
"img",
|
|
432
|
+
"input",
|
|
433
|
+
"link",
|
|
434
|
+
"meta",
|
|
435
|
+
"param",
|
|
436
|
+
"source",
|
|
437
|
+
"track",
|
|
438
|
+
"wbr",
|
|
439
|
+
]);
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Find the index of the `>` that closes the opening tag starting at `start`
|
|
443
|
+
* in `html`, skipping over quoted attribute values.
|
|
444
|
+
*/
|
|
445
|
+
function _findTagEnd(html: string, start: number): number {
|
|
446
|
+
let i = start + 1; // Skip '<'
|
|
447
|
+
while (i < html.length) {
|
|
448
|
+
const ch = html[i];
|
|
449
|
+
if (ch === ">") return i;
|
|
450
|
+
if (ch === '"' || ch === "'") {
|
|
451
|
+
// Skip quoted attribute value.
|
|
452
|
+
const quote = ch;
|
|
453
|
+
i++;
|
|
454
|
+
while (i < html.length && html[i] !== quote) i++;
|
|
455
|
+
if (i < html.length) i++; // skip closing quote
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
i++;
|
|
459
|
+
}
|
|
460
|
+
return -1;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Find the index of the matching `</tagName>` for an element whose opening tag
|
|
465
|
+
* ended at `afterOpen`. Handles nesting by counting open/close pairs.
|
|
466
|
+
*/
|
|
467
|
+
function _findMatchingClose(
|
|
468
|
+
html: string,
|
|
469
|
+
afterOpen: number,
|
|
470
|
+
tagName: string,
|
|
471
|
+
): number {
|
|
472
|
+
const openRe = new RegExp(`<${tagName}[\\s/>]`, "gi");
|
|
473
|
+
const closeTag = `</${tagName}>`;
|
|
474
|
+
let depth = 1;
|
|
475
|
+
let pos = afterOpen;
|
|
476
|
+
|
|
477
|
+
while (pos < html.length && depth > 0) {
|
|
478
|
+
// Find the next candidate: open or close tag.
|
|
479
|
+
openRe.lastIndex = pos;
|
|
480
|
+
const nextOpen = openRe.exec(html);
|
|
481
|
+
const nextClose = html.indexOf(closeTag, pos);
|
|
482
|
+
|
|
483
|
+
if (nextClose === -1) return -1; // unmatched
|
|
484
|
+
|
|
485
|
+
if (nextOpen && nextOpen.index < nextClose) {
|
|
486
|
+
depth++;
|
|
487
|
+
pos = nextOpen.index + nextOpen[0].length;
|
|
488
|
+
} else {
|
|
489
|
+
depth--;
|
|
490
|
+
if (depth === 0) return nextClose;
|
|
491
|
+
pos = nextClose + closeTag.length;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
return -1;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Infer the `data-an-primitive` kind value for a board element whose opening
|
|
499
|
+
* tag is `openTag` and which is known to lack the marker.
|
|
500
|
+
*
|
|
501
|
+
* Inference is conservative — only clear signals produce a non-"rectangle"
|
|
502
|
+
* kind.
|
|
503
|
+
*/
|
|
504
|
+
function _inferPrimitiveKind(openTag: string): string {
|
|
505
|
+
// Extract the inline style value (first style="..." attribute).
|
|
506
|
+
const styleMatch = openTag.match(/\bstyle="([^"]*)"/i);
|
|
507
|
+
const style = styleMatch ? styleMatch[1] : "";
|
|
508
|
+
|
|
509
|
+
// Ellipse: CSS border-radius:50% (or border-radius: 50%).
|
|
510
|
+
if (/border-radius\s*:\s*50%/.test(style)) {
|
|
511
|
+
return "ellipse";
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// Frame: transparent background.
|
|
515
|
+
if (/background\s*:\s*transparent/.test(style)) {
|
|
516
|
+
return "frame";
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Extract the layer name for additional hints.
|
|
520
|
+
const layerNameMatch = openTag.match(
|
|
521
|
+
/\bdata-agent-native-layer-name="([^"]*)"/i,
|
|
522
|
+
);
|
|
523
|
+
const layerName = layerNameMatch ? layerNameMatch[1] : "";
|
|
524
|
+
|
|
525
|
+
// Frame: layer name starts with "Frame".
|
|
526
|
+
if (/^frame/i.test(layerName)) {
|
|
527
|
+
return "frame";
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Text: the element has no background-color-like value in the style, yet has
|
|
531
|
+
// a color property — we detect this via the presence of "color:" without a
|
|
532
|
+
// "background:" in the style. Also check for the white-space:pre-wrap
|
|
533
|
+
// pattern that text nodes emit.
|
|
534
|
+
if (
|
|
535
|
+
/white-space\s*:\s*pre-wrap/.test(style) ||
|
|
536
|
+
(/\bcolor\s*:/.test(style) && !/\bbackground\s*:/.test(style))
|
|
537
|
+
) {
|
|
538
|
+
return "text";
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// Default: rectangle.
|
|
542
|
+
return "rectangle";
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Infer the `data-an-primitive` kind value for a marker-less board `<svg>`
|
|
547
|
+
* primitive from its inner geometry. Returns `null` when no reliable signal
|
|
548
|
+
* is present, in which case the SVG is left unmarked (it still classifies as a
|
|
549
|
+
* generic shape via tag heuristics) rather than mis-classified.
|
|
550
|
+
*
|
|
551
|
+
* Conservative signals (in priority order):
|
|
552
|
+
* - The path carries `marker-end` (the arrowhead reference) → `"arrow"`
|
|
553
|
+
* - The SVG contains a `<polygon>` element → `"polygon"`
|
|
554
|
+
* - The SVG contains exactly a single `<path>` and nothing
|
|
555
|
+
* else shape-like → `"path"`
|
|
556
|
+
*
|
|
557
|
+
* Geometry (points, path data, polygon points) is never inspected for sizing
|
|
558
|
+
* and never altered — only the presence/type of child elements is consulted.
|
|
559
|
+
*/
|
|
560
|
+
function _inferSvgPrimitiveKind(inner: string): string | null {
|
|
561
|
+
// Arrow: a path with a marker-end reference (the arrowhead). The arrowhead
|
|
562
|
+
// marker itself lives in <defs> as a separate path, so detect the consuming
|
|
563
|
+
// `marker-end="url(...)"` attribute rather than the marker definition.
|
|
564
|
+
if (/marker-end\s*=/.test(inner)) {
|
|
565
|
+
return "arrow";
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// Polygon / star: rendered with a <polygon> element. Both kinds use the same
|
|
569
|
+
// SVG element, so we conservatively report "polygon" (star geometry is a
|
|
570
|
+
// polygon at the markup level and cannot be distinguished without sizing).
|
|
571
|
+
if (/<polygon\b/i.test(inner)) {
|
|
572
|
+
return "polygon";
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// Pen-tool vector: a single <path> and no other shape elements.
|
|
576
|
+
const pathCount = (inner.match(/<path\b/gi) ?? []).length;
|
|
577
|
+
const hasOtherShape = /<(rect|circle|ellipse|line|polyline)\b/i.test(inner);
|
|
578
|
+
if (pathCount === 1 && !hasOtherShape) {
|
|
579
|
+
return "path";
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// No reliable signal — leave unmarked.
|
|
583
|
+
return null;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// ---------------------------------------------------------------------------
|
|
587
|
+
// Private helpers
|
|
588
|
+
// ---------------------------------------------------------------------------
|
|
589
|
+
|
|
215
590
|
function escapeAttr(value: string): string {
|
|
216
591
|
return value
|
|
217
592
|
.replace(/&/g, "&")
|