@agent-native/core 0.137.8 → 0.139.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/agent-native.eject.json +2 -0
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +15 -0
- package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/analytics/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/analytics/AGENTS.md +2 -2
- package/corpus/templates/analytics/actions/get-first-party-analytics-health.ts +65 -0
- package/corpus/templates/analytics/actions/provider-api-catalog.ts +3 -6
- package/corpus/templates/analytics/actions/provider-api-docs.ts +3 -6
- package/corpus/templates/analytics/actions/provider-api-request.ts +3 -6
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +3 -3
- package/corpus/templates/analytics/agent-native.json +12 -0
- package/corpus/templates/analytics/app/i18n-data.ts +162 -0
- package/corpus/templates/analytics/app/pages/DataSources.tsx +126 -1
- package/corpus/templates/analytics/changelog/2026-08-05-analytics-now-flags-neon-pressure-and-guides-high-volume-tra.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-05-first-party-analytics-uses-compact-rollups-for-faster-usage-.md +6 -0
- package/corpus/templates/analytics/server/db/schema.ts +52 -0
- package/corpus/templates/analytics/server/lib/credential-keys.ts +3 -0
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +2 -0
- package/corpus/templates/analytics/server/lib/emails.ts +51 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-health.ts +397 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +182 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +86 -15
- package/corpus/templates/analytics/server/lib/provider-api.ts +20 -1
- package/corpus/templates/analytics/server/lib/replay-storage.ts +1 -1
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -0
- package/corpus/templates/analytics/server/plugins/db.ts +60 -0
- package/corpus/templates/analytics/server/plugins/transactional-emails.ts +5 -0
- package/corpus/templates/assets/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/assets/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/assets/agent-native.json +12 -0
- package/corpus/templates/assets/server/lib/generation.ts +8 -8
- package/corpus/templates/assets/server/lib/storage.ts +1 -1
- package/corpus/templates/assets/server/plugins/onboarding.ts +1 -1
- package/corpus/templates/brain/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/brain/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/brain/agent-native.json +12 -0
- package/corpus/templates/calendar/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/calendar/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/calendar/agent-native.json +12 -0
- package/corpus/templates/calendar/server/lib/booking-emails.ts +154 -70
- package/corpus/templates/calendar/server/lib/emails.ts +167 -0
- package/corpus/templates/calendar/server/lib/event-guest-notifications.ts +64 -28
- package/corpus/templates/calendar/server/plugins/transactional-emails.ts +5 -0
- package/corpus/templates/chat/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/chat/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/chat/AGENTS.md +3 -0
- package/corpus/templates/chat/DESIGN.md +28 -0
- package/corpus/templates/chat/agent-native.json +12 -0
- package/corpus/templates/clips/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/clips/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/clips/actions/cleanup-transcript.ts +2 -2
- package/corpus/templates/clips/actions/delete-recording-permanent.ts +3 -0
- package/corpus/templates/clips/actions/get-playback-position.ts +68 -0
- package/corpus/templates/clips/actions/import-loom-recording.ts +2 -2
- package/corpus/templates/clips/actions/invite-member.ts +39 -15
- package/corpus/templates/clips/actions/save-playback-position.ts +80 -0
- package/corpus/templates/clips/actions/set-thumbnail.ts +1 -1
- package/corpus/templates/clips/agent-native.json +12 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +54 -5
- package/corpus/templates/clips/app/hooks/use-playback-position.ts +188 -0
- package/corpus/templates/clips/app/hooks/use-view-tracking.ts +6 -24
- package/corpus/templates/clips/app/lib/playback-position.ts +99 -0
- package/corpus/templates/clips/app/lib/viewer-session.ts +29 -0
- package/corpus/templates/clips/changelog/2026-08-05-clip-buffering-now-uses-buffering-copy-after-playback.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-05-clips-remembers-your-playback-position-when-you-reopen-a-cli.md +6 -0
- package/corpus/templates/clips/learnings.defaults.md +1 -1
- package/corpus/templates/clips/server/db/schema.ts +18 -0
- package/corpus/templates/clips/server/lib/emails.ts +256 -0
- package/corpus/templates/clips/server/lib/public-agent-context.ts +1 -1
- package/corpus/templates/clips/server/lib/transactional-email-templates.ts +24 -0
- package/corpus/templates/clips/server/lib/video-storage.ts +1 -1
- package/corpus/templates/clips/server/plugins/db.ts +15 -0
- package/corpus/templates/clips/server/plugins/transactional-email-catalog.ts +5 -0
- package/corpus/templates/clips/server/routes/api/media/index.post.ts +1 -1
- package/corpus/templates/content/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +13 -0
- package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/content/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/content/AGENTS.md +1 -0
- package/corpus/templates/content/actions/_content-database-mutation-lock.ts +41 -0
- package/corpus/templates/content/actions/_content-database-row-migration.ts +569 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +82 -36
- package/corpus/templates/content/actions/_database-utils.ts +5 -0
- package/corpus/templates/content/actions/_delete-content-space.ts +25 -11
- package/corpus/templates/content/actions/add-database-item.ts +60 -42
- package/corpus/templates/content/actions/attach-content-database-source.ts +2 -0
- package/corpus/templates/content/actions/configure-document-property.ts +99 -104
- package/corpus/templates/content/actions/delete-content-database.ts +19 -7
- package/corpus/templates/content/actions/delete-document-property.ts +47 -58
- package/corpus/templates/content/actions/delete-document.ts +390 -167
- package/corpus/templates/content/actions/disconnect-content-database-source.ts +41 -24
- package/corpus/templates/content/actions/duplicate-database-item.ts +63 -31
- package/corpus/templates/content/actions/duplicate-database-items.ts +86 -43
- package/corpus/templates/content/actions/duplicate-document-property.ts +37 -14
- package/corpus/templates/content/actions/migrate-content-database-rows.ts +830 -0
- package/corpus/templates/content/actions/move-database-item.ts +14 -0
- package/corpus/templates/content/actions/permanently-delete-document.ts +27 -6
- package/corpus/templates/content/actions/remove-database-items.ts +13 -0
- package/corpus/templates/content/actions/reorder-document-property.ts +45 -46
- package/corpus/templates/content/actions/set-document-property.ts +68 -28
- package/corpus/templates/content/actions/submit-content-database-form.ts +49 -0
- package/corpus/templates/content/actions/transcribe-media.ts +1 -1
- package/corpus/templates/content/agent-native.json +12 -0
- package/corpus/templates/content/app/components/editor/image-upload.ts +2 -2
- package/corpus/templates/content/app/i18n-data.ts +1 -1
- package/corpus/templates/content/changelog/2026-08-01-content-can-reorganize-every-row-in-an-existing-database-as-.md +6 -0
- package/corpus/templates/content/parity/matrix.md +1 -1
- package/corpus/templates/content/parity/matrix.ts +4 -2
- package/corpus/templates/content/server/db/schema.ts +30 -0
- package/corpus/templates/content/server/lib/comment-notifications.ts +57 -26
- package/corpus/templates/content/server/lib/emails.ts +70 -0
- package/corpus/templates/content/server/plugins/db.ts +24 -0
- package/corpus/templates/content/server/plugins/onboarding.ts +2 -2
- package/corpus/templates/content/server/plugins/transactional-emails.ts +5 -0
- package/corpus/templates/crm/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/crm/agent-native.json +12 -0
- package/corpus/templates/design/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/design/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/design/CODE_NATIVE_DESIGN_STUDIO_IMPLEMENTATION_PLAN.md +2 -2
- package/corpus/templates/design/DESIGN-STUDIO-PLAN.md +2 -2
- package/corpus/templates/design/actions/apply-design-token-edit.ts +1 -1
- package/corpus/templates/design/actions/capture-design-state.ts +1 -1
- package/corpus/templates/design/actions/connect-builder-app.ts +2 -2
- package/corpus/templates/design/actions/create-design-branch.ts +1 -1
- package/corpus/templates/design/actions/create-fusion-app.ts +3 -3
- package/corpus/templates/design/actions/deploy-design-preview.ts +1 -1
- package/corpus/templates/design/actions/get-component-details.ts +1 -1
- package/corpus/templates/design/actions/get-design-branch-diff.ts +1 -1
- package/corpus/templates/design/actions/index-components.ts +3 -3
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +1 -1
- package/corpus/templates/design/actions/migrate-inline-design-to-app.ts +3 -3
- package/corpus/templates/design/actions/open-component-source.ts +1 -1
- package/corpus/templates/design/actions/update-design.ts +61 -0
- package/corpus/templates/design/agent-native.json +12 -0
- package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +1 -1
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +1 -1
- package/corpus/templates/design/scripts/qa-figma-stress-import.ts +1 -1
- package/corpus/templates/design/server/lib/figma-node-import.ts +1 -1
- package/corpus/templates/design/shared/design-source-capabilities.ts +25 -9
- package/corpus/templates/dispatch/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/dispatch/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/dispatch/agent-native.json +12 -0
- package/corpus/templates/dispatch/app/routes/transactional-email.$appId.$id.tsx +4 -0
- package/corpus/templates/dispatch/app/routes/transactional-email.tsx +4 -0
- package/corpus/templates/factory/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/factory/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/factory/agent-native.json +12 -0
- package/corpus/templates/forms/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/forms/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/forms/actions/export-responses.ts +1 -1
- package/corpus/templates/forms/agent-native.json +12 -0
- package/corpus/templates/forms/server/lib/emails.ts +52 -0
- package/corpus/templates/forms/server/lib/response-email.ts +2 -0
- package/corpus/templates/forms/server/plugins/transactional-emails.ts +5 -0
- package/corpus/templates/macros/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/macros/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/macros/agent-native.json +12 -0
- package/corpus/templates/mail/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/mail/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/mail/agent-native.json +12 -0
- package/corpus/templates/mail/app/i18n/en-US.ts +1 -1
- package/corpus/templates/mail/server/lib/media-upload.ts +1 -1
- package/corpus/templates/plan/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/plan/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/plan/actions/request-plan-access.ts +33 -12
- package/corpus/templates/plan/agent-native.json +12 -0
- package/corpus/templates/plan/server/lib/comment-notifications.ts +53 -27
- package/corpus/templates/plan/server/lib/emails.ts +67 -0
- package/corpus/templates/plan/server/lib/plan-assets.ts +1 -1
- package/corpus/templates/plan/server/plugins/transactional-emails.ts +5 -0
- package/corpus/templates/slides/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/slides/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/slides/actions/generate-image-api.ts +1 -1
- package/corpus/templates/slides/actions/generate-slides-ai.ts +1 -1
- package/corpus/templates/slides/actions/import-file.ts +2 -2
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +1 -1
- package/corpus/templates/slides/agent-native.json +12 -0
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +1 -1
- package/corpus/templates/slides/app/i18n/en-US.ts +2 -2
- package/corpus/templates/slides/app/lib/deck-sorting.ts +19 -0
- package/corpus/templates/slides/app/lib/image-drop-to-agent.ts +1 -1
- package/corpus/templates/slides/app/pages/Index.tsx +7 -2
- package/corpus/templates/slides/changelog/2026-08-05-decks-are-now-sorted-by-most-recently-updated.md +6 -0
- package/corpus/templates/slides/server/handlers/assets.ts +1 -1
- package/corpus/templates/slides/server/handlers/uploads.ts +1 -1
- package/corpus/templates/slides/server/lib/comment-notifications.ts +44 -21
- package/corpus/templates/slides/server/lib/emails.ts +40 -0
- package/corpus/templates/slides/server/plugins/transactional-emails.ts +5 -0
- package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/tasks/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/tasks/agent-native.json +12 -0
- package/dist/action.d.ts +6 -0
- package/dist/agent/engine/builder-engine.js +2 -2
- package/dist/agent/engine/credential-errors.d.ts +1 -1
- package/dist/agent/engine/credential-errors.js +2 -2
- package/dist/agent/production-agent.js +3 -2
- package/dist/brand-kit/fig/index.js +1 -1
- package/dist/cli/agent.js +45 -3
- package/dist/cli/code-agent-executor.js +2 -1
- package/dist/cli/create.d.ts +9 -1
- package/dist/cli/create.js +94 -1
- package/dist/cli/doctor.d.ts +8 -11
- package/dist/cli/doctor.js +92 -24
- package/dist/cli/index.js +6 -5
- package/dist/client/AgentAskPopover.d.ts +3 -1
- package/dist/client/AgentAskPopover.js +2 -2
- package/dist/client/AgentPanel.js +9 -3
- package/dist/client/AssistantChat.js +54 -33
- package/dist/client/MultiTabAssistantChat.js +1 -1
- package/dist/client/RouteTransitionIndicator.d.ts +7 -0
- package/dist/client/RouteTransitionIndicator.js +31 -0
- package/dist/client/agent-engine-key.js +1 -1
- package/dist/client/app-providers.js +11 -2
- package/dist/client/chat/message-components.js +1 -1
- package/dist/client/chat/run-recovery.js +1 -1
- package/dist/client/chat/tool-call-display.d.ts +3 -1
- package/dist/client/chat/tool-call-display.js +4 -3
- package/dist/client/chat-model-groups.d.ts +6 -0
- package/dist/client/chat-model-groups.js +11 -0
- package/dist/client/error-format.js +1 -1
- package/dist/client/i18n.js +1 -1
- package/dist/client/onboarding/FirstRunOnboarding.d.ts +5 -1
- package/dist/client/onboarding/FirstRunOnboarding.js +29 -13
- package/dist/client/onboarding/first-run-enabled.d.ts +6 -1
- package/dist/client/onboarding/first-run-enabled.js +33 -3
- package/dist/client/onboarding/use-onboarding.js +16 -11
- package/dist/client/resources/mcp-integration-catalog.js +26 -0
- package/dist/client/resources/mcp-integration-logos.js +4 -0
- package/dist/client/route-warmup.js +56 -10
- package/dist/client/settings/AccountSettingsCard.js +78 -3
- package/dist/client/settings/SettingsPanel.js +1 -1
- package/dist/client/settings/VoiceTranscriptionSection.js +2 -2
- package/dist/client/settings/useBuilderStatus.js +1 -1
- package/dist/client/setup-connections/useBuilderConnectCardController.js +1 -1
- package/dist/client/ui/index.d.ts +1 -0
- package/dist/client/ui/index.js +1 -0
- package/dist/client/uploads/upload-editor-image.js +1 -1
- package/dist/client/use-chat-threads.js +3 -0
- package/dist/collab/routes.d.ts +1 -1
- package/dist/config.d.ts +48 -0
- package/dist/config.js +111 -0
- package/dist/db/migrations.js +5 -0
- package/dist/eject/provider-api-definitions.d.ts +1 -1
- package/dist/eject/provider-api-definitions.js +1 -0
- package/dist/eject/remote-mcp-presets.js +1 -0
- package/dist/email-catalog/actions/list-email-activity.d.ts +6 -0
- package/dist/email-catalog/actions/list-email-activity.js +15 -0
- package/dist/email-catalog/actions/list-email-engagement.d.ts +6 -0
- package/dist/email-catalog/actions/list-email-engagement.js +15 -0
- package/dist/email-catalog/actions/list-email-log.d.ts +8 -0
- package/dist/email-catalog/actions/list-email-log.js +22 -0
- package/dist/email-catalog/actions/list-transactional-emails.d.ts +23 -0
- package/dist/email-catalog/actions/list-transactional-emails.js +61 -0
- package/dist/email-catalog/actions/render-transactional-email-preview.d.ts +10 -0
- package/dist/email-catalog/actions/render-transactional-email-preview.js +24 -0
- package/dist/email-catalog/authorize.d.ts +2 -0
- package/dist/email-catalog/authorize.js +10 -0
- package/dist/email-catalog/log.d.ts +57 -0
- package/dist/email-catalog/log.js +117 -0
- package/dist/email-catalog/provider-metrics.d.ts +34 -0
- package/dist/email-catalog/provider-metrics.js +165 -0
- package/dist/email-catalog/registry.d.ts +79 -0
- package/dist/email-catalog/registry.js +71 -0
- package/dist/email-catalog/schema.d.ts +212 -0
- package/dist/email-catalog/schema.js +49 -0
- package/dist/email-catalog/system-emails.d.ts +14 -0
- package/dist/email-catalog/system-emails.js +68 -0
- package/dist/extensions/web-search-tool.js +2 -2
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.js +1 -1
- package/dist/file-upload/registry.js +1 -1
- package/dist/guards/index.d.ts +3 -0
- package/dist/guards/index.js +2 -0
- package/dist/guards/no-empty-migrations.d.ts +14 -0
- package/dist/guards/no-empty-migrations.js +126 -0
- package/dist/index.browser.d.ts +1 -0
- package/dist/index.browser.js +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/localization/default-messages.d.ts +69 -0
- package/dist/localization/default-messages.js +71 -2
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/onboarding/app-profile.js +1 -1
- package/dist/onboarding/plugin.d.ts +2 -0
- package/dist/onboarding/plugin.js +29 -2
- package/dist/org/handlers.js +8 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
- package/dist/provider-api/actions/provider-api.d.ts +13 -13
- package/dist/provider-api/index.d.ts +4 -4
- package/dist/provider-api/index.js +35 -0
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/resources/handlers.js +1 -1
- package/dist/scripts/docs/framework-search.d.ts +9 -0
- package/dist/scripts/docs/framework-search.js +239 -0
- package/dist/scripts/docs/index.js +1 -0
- package/dist/scripts/docs/search.d.ts +10 -0
- package/dist/scripts/docs/search.js +1 -1
- package/dist/scripts/docs/source-search.d.ts +10 -2
- package/dist/scripts/docs/source-search.js +108 -41
- package/dist/search-utils/index.d.ts +11 -0
- package/dist/search-utils/index.js +72 -0
- package/dist/server/action-change.d.ts +6 -0
- package/dist/server/action-change.js +28 -14
- package/dist/server/action-discovery.js +31 -0
- package/dist/server/action-routes.js +1 -0
- package/dist/server/agent-chat/browser-team-tools.js +1 -1
- package/dist/server/agent-chat/script-entries.js +43 -2
- package/dist/server/auth-login-mode.d.ts +8 -0
- package/dist/server/auth-login-mode.js +17 -0
- package/dist/server/auth.js +100 -15
- package/dist/server/better-auth-instance.d.ts +36 -0
- package/dist/server/better-auth-instance.js +42 -5
- package/dist/server/builder-design-systems.js +1 -1
- package/dist/server/core-routes-plugin.js +17 -14
- package/dist/server/credential-provider.js +3 -3
- package/dist/server/email-templates.d.ts +7 -0
- package/dist/server/email-templates.js +24 -0
- package/dist/server/email.d.ts +26 -0
- package/dist/server/email.js +66 -4
- package/dist/server/framework-request-handler.js +6 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/onboarding-html.d.ts +2 -0
- package/dist/server/onboarding-html.js +169 -8
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/realtime-voice.js +1 -1
- package/dist/server/sentry.d.ts +1 -1
- package/dist/server/transcribe-voice.js +3 -3
- package/dist/shared/first-run-onboarding.d.ts +1 -0
- package/dist/shared/first-run-onboarding.js +1 -0
- package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +23 -2
- package/dist/templates/chat/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/dist/templates/chat/AGENTS.md +3 -0
- package/dist/templates/chat/DESIGN.md +28 -0
- package/dist/templates/chat/agent-native.json +12 -0
- package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +23 -2
- package/dist/templates/default/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/dist/templates/default/AGENTS.md +4 -0
- package/dist/templates/default/DESIGN.md +30 -0
- package/dist/templates/default/agent-native.json +9 -0
- package/dist/templates/default/app/i18n/ar-SA.ts +2 -2
- package/dist/templates/default/app/i18n/de-DE.ts +2 -2
- package/dist/templates/default/app/i18n/en-US.ts +2 -2
- package/dist/templates/default/app/i18n/es-ES.ts +2 -2
- package/dist/templates/default/app/i18n/fr-FR.ts +2 -2
- package/dist/templates/default/app/i18n/hi-IN.ts +2 -2
- package/dist/templates/default/app/i18n/ja-JP.ts +2 -2
- package/dist/templates/default/app/i18n/ko-KR.ts +2 -2
- package/dist/templates/default/app/i18n/pt-BR.ts +2 -2
- package/dist/templates/default/app/i18n/zh-CN.ts +2 -2
- package/dist/templates/default/app/i18n/zh-TW.ts +1 -1
- package/dist/templates/default/package.json +1 -0
- package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/dist/templates/headless/agent-native.json +9 -0
- package/dist/templates/headless/package.json +2 -0
- package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +23 -2
- package/dist/templates/workspace-core/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/dist/templates/workspace-core/AGENTS.md +3 -0
- package/dist/templates/workspace-core/DESIGN.md +35 -0
- package/dist/templates/workspace-root/AGENTS.md +3 -0
- package/dist/templates/workspace-root/DESIGN.md +35 -0
- package/dist/templates/workspace-root/agent-native.json +9 -0
- package/dist/templates/workspace-root/package.json +3 -0
- package/dist/transcription/builder-transcription.js +1 -1
- package/dist/user-profile/actions/change-password.d.ts +8 -0
- package/dist/user-profile/actions/change-password.js +24 -0
- package/dist/user-profile/actions/get-auth-methods.d.ts +6 -0
- package/dist/user-profile/actions/get-auth-methods.js +23 -0
- package/dist/user-profile/actions/set-password.d.ts +7 -0
- package/dist/user-profile/actions/set-password.js +23 -0
- package/dist/vite/client.d.ts +8 -1
- package/dist/vite/client.js +63 -12
- package/dist/vite/index.d.ts +1 -0
- package/dist/vite/index.js +1 -0
- package/docs/AGENTS.md +7 -2
- package/docs/SKILL.md +7 -5
- package/docs/content/agent-native-config.mdx +165 -0
- package/docs/content/agent-native-toolkit.mdx +1 -1
- package/docs/content/deployment.mdx +7 -2
- package/docs/content/doctor.mdx +21 -13
- package/docs/content/environment-variables.mdx +158 -0
- package/docs/content/file-uploads.mdx +1 -1
- package/docs/content/getting-started.mdx +1 -1
- package/docs/content/key-concepts.mdx +1 -1
- package/docs/content/multi-app-workspace.mdx +1 -1
- package/docs/content/template-clips-ai-and-editing.mdx +6 -6
- package/docs/content/template-clips-developers.mdx +3 -3
- package/docs/content/toolkit-settings.mdx +1 -1
- package/docs/content/voice-input.mdx +4 -4
- package/package.json +7 -2
- package/src/eject/provider-api-definitions.ts +1 -0
- package/src/eject/remote-mcp-presets.ts +1 -0
- package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +23 -2
- package/src/templates/chat/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/src/templates/chat/AGENTS.md +3 -0
- package/src/templates/chat/DESIGN.md +28 -0
- package/src/templates/chat/agent-native.json +12 -0
- package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/src/templates/default/.agents/skills/frontend-design/SKILL.md +23 -2
- package/src/templates/default/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/src/templates/default/AGENTS.md +4 -0
- package/src/templates/default/DESIGN.md +30 -0
- package/src/templates/default/agent-native.json +9 -0
- package/src/templates/default/app/i18n/ar-SA.ts +2 -2
- package/src/templates/default/app/i18n/de-DE.ts +2 -2
- package/src/templates/default/app/i18n/en-US.ts +2 -2
- package/src/templates/default/app/i18n/es-ES.ts +2 -2
- package/src/templates/default/app/i18n/fr-FR.ts +2 -2
- package/src/templates/default/app/i18n/hi-IN.ts +2 -2
- package/src/templates/default/app/i18n/ja-JP.ts +2 -2
- package/src/templates/default/app/i18n/ko-KR.ts +2 -2
- package/src/templates/default/app/i18n/pt-BR.ts +2 -2
- package/src/templates/default/app/i18n/zh-CN.ts +2 -2
- package/src/templates/default/app/i18n/zh-TW.ts +1 -1
- package/src/templates/default/package.json +1 -0
- package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/src/templates/headless/agent-native.json +9 -0
- package/src/templates/headless/package.json +2 -0
- package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +23 -2
- package/src/templates/workspace-core/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/src/templates/workspace-core/AGENTS.md +3 -0
- package/src/templates/workspace-core/DESIGN.md +35 -0
- package/src/templates/workspace-root/AGENTS.md +3 -0
- package/src/templates/workspace-root/DESIGN.md +35 -0
- package/src/templates/workspace-root/agent-native.json +9 -0
- package/src/templates/workspace-root/package.json +3 -0
|
@@ -11,6 +11,12 @@ import {
|
|
|
11
11
|
DEFAULT_BOOKING_TIMEZONE,
|
|
12
12
|
safeBookingTimeZone,
|
|
13
13
|
} from "./booking-timezone.js";
|
|
14
|
+
import {
|
|
15
|
+
CALENDAR_BOOKING_CANCELLED_EMAIL_ID,
|
|
16
|
+
CALENDAR_BOOKING_CANCELLED_HOST_EMAIL_ID,
|
|
17
|
+
CALENDAR_BOOKING_CONFIRMED_EMAIL_ID,
|
|
18
|
+
CALENDAR_BOOKING_RECEIVED_EMAIL_ID,
|
|
19
|
+
} from "./emails.js";
|
|
14
20
|
|
|
15
21
|
function stripCrlf(value: string | undefined): string {
|
|
16
22
|
return (value ?? "").replace(/[\r\n]+/g, " ").trim();
|
|
@@ -57,6 +63,128 @@ async function sendBestEffort(
|
|
|
57
63
|
}
|
|
58
64
|
}
|
|
59
65
|
|
|
66
|
+
export function renderBookingConfirmedEmail({
|
|
67
|
+
title,
|
|
68
|
+
when,
|
|
69
|
+
host,
|
|
70
|
+
manageUrl,
|
|
71
|
+
meetingLink,
|
|
72
|
+
}: {
|
|
73
|
+
title: string;
|
|
74
|
+
when: string;
|
|
75
|
+
host: string;
|
|
76
|
+
manageUrl: string;
|
|
77
|
+
meetingLink?: string | null;
|
|
78
|
+
}) {
|
|
79
|
+
const paragraphs = [
|
|
80
|
+
`You're booked for ${emailStrong(title)} with ${emailStrong(host)}.`,
|
|
81
|
+
`Time: ${emailStrong(when)}.`,
|
|
82
|
+
];
|
|
83
|
+
if (meetingLink) {
|
|
84
|
+
paragraphs.push(`Meeting link: ${emailLink("Join meeting", meetingLink)}.`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
subject: `Confirmed: ${title}`,
|
|
89
|
+
...renderEmail({
|
|
90
|
+
preheader: `You're booked for ${title} on ${when}.`,
|
|
91
|
+
heading: "Your meeting is booked",
|
|
92
|
+
paragraphs,
|
|
93
|
+
cta: { label: "Manage booking", url: manageUrl },
|
|
94
|
+
footer:
|
|
95
|
+
"Use the manage link if you need to cancel or reschedule this meeting.",
|
|
96
|
+
}),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function renderBookingReceivedEmail({
|
|
101
|
+
title,
|
|
102
|
+
when,
|
|
103
|
+
attendeeName,
|
|
104
|
+
attendee,
|
|
105
|
+
manageUrl,
|
|
106
|
+
meetingLink,
|
|
107
|
+
}: {
|
|
108
|
+
title: string;
|
|
109
|
+
when: string;
|
|
110
|
+
attendeeName: string;
|
|
111
|
+
attendee: string;
|
|
112
|
+
manageUrl: string;
|
|
113
|
+
meetingLink?: string | null;
|
|
114
|
+
}) {
|
|
115
|
+
return {
|
|
116
|
+
subject: `New booking: ${title}`,
|
|
117
|
+
...renderEmail({
|
|
118
|
+
preheader: `${attendeeName} booked ${title} on ${when}.`,
|
|
119
|
+
heading: "New booking",
|
|
120
|
+
paragraphs: [
|
|
121
|
+
`${emailStrong(attendeeName)} booked ${emailStrong(title)}.`,
|
|
122
|
+
`Time: ${emailStrong(when)}.`,
|
|
123
|
+
`Guest: ${emailStrong(attendee)}.`,
|
|
124
|
+
...(meetingLink
|
|
125
|
+
? [`Meeting link: ${emailLink("Join meeting", meetingLink)}.`]
|
|
126
|
+
: []),
|
|
127
|
+
],
|
|
128
|
+
cta: { label: "View booking", url: manageUrl },
|
|
129
|
+
footer: "This booking was created from your calendar booking link.",
|
|
130
|
+
}),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function renderBookingCancelledEmail({
|
|
135
|
+
title,
|
|
136
|
+
when,
|
|
137
|
+
host,
|
|
138
|
+
bookAgainUrl,
|
|
139
|
+
}: {
|
|
140
|
+
title: string;
|
|
141
|
+
when: string;
|
|
142
|
+
host: string;
|
|
143
|
+
bookAgainUrl?: string;
|
|
144
|
+
}) {
|
|
145
|
+
return {
|
|
146
|
+
subject: `Cancelled: ${title}`,
|
|
147
|
+
...renderEmail({
|
|
148
|
+
preheader: `${title} on ${when} was cancelled.`,
|
|
149
|
+
heading: "Your meeting was cancelled",
|
|
150
|
+
paragraphs: [
|
|
151
|
+
`${emailStrong(title)} with ${emailStrong(host || "the host")} has been cancelled.`,
|
|
152
|
+
`Original time: ${emailStrong(when)}.`,
|
|
153
|
+
],
|
|
154
|
+
cta: bookAgainUrl
|
|
155
|
+
? { label: "Book another time", url: bookAgainUrl }
|
|
156
|
+
: undefined,
|
|
157
|
+
footer: "If this was unexpected, contact the meeting host.",
|
|
158
|
+
}),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function renderBookingCancelledHostEmail({
|
|
163
|
+
title,
|
|
164
|
+
when,
|
|
165
|
+
attendeeName,
|
|
166
|
+
attendee,
|
|
167
|
+
}: {
|
|
168
|
+
title: string;
|
|
169
|
+
when: string;
|
|
170
|
+
attendeeName: string;
|
|
171
|
+
attendee: string;
|
|
172
|
+
}) {
|
|
173
|
+
return {
|
|
174
|
+
subject: `Cancelled booking: ${title}`,
|
|
175
|
+
...renderEmail({
|
|
176
|
+
preheader: `${attendeeName}'s booking for ${title} was cancelled.`,
|
|
177
|
+
heading: "Booking cancelled",
|
|
178
|
+
paragraphs: [
|
|
179
|
+
`${emailStrong(attendeeName)}'s booking for ${emailStrong(title)} was cancelled.`,
|
|
180
|
+
`Original time: ${emailStrong(when)}.`,
|
|
181
|
+
`Guest: ${emailStrong(attendee)}.`,
|
|
182
|
+
],
|
|
183
|
+
footer: "No further action is needed.",
|
|
184
|
+
}),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
60
188
|
export async function sendBookingConfirmationEmails({
|
|
61
189
|
booking,
|
|
62
190
|
hostEmail,
|
|
@@ -74,54 +202,31 @@ export async function sendBookingConfirmationEmails({
|
|
|
74
202
|
const attendee = stripCrlf(booking.email);
|
|
75
203
|
const attendeeName = stripCrlf(booking.name) || "there";
|
|
76
204
|
|
|
77
|
-
const attendeeParagraphs = [
|
|
78
|
-
`You're booked for ${emailStrong(title)} with ${emailStrong(host)}.`,
|
|
79
|
-
`Time: ${emailStrong(when)}.`,
|
|
80
|
-
];
|
|
81
|
-
if (booking.meetingLink) {
|
|
82
|
-
attendeeParagraphs.push(
|
|
83
|
-
`Meeting link: ${emailLink("Join meeting", booking.meetingLink)}.`,
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const attendeeEmail = renderEmail({
|
|
88
|
-
preheader: `You're booked for ${title} on ${when}.`,
|
|
89
|
-
heading: "Your meeting is booked",
|
|
90
|
-
paragraphs: attendeeParagraphs,
|
|
91
|
-
cta: { label: "Manage booking", url: manageUrl },
|
|
92
|
-
footer:
|
|
93
|
-
"Use the manage link if you need to cancel or reschedule this meeting.",
|
|
94
|
-
});
|
|
95
|
-
|
|
96
205
|
await sendBestEffort("attendee confirmation", {
|
|
97
206
|
to: attendee,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
207
|
+
...renderBookingConfirmedEmail({
|
|
208
|
+
title,
|
|
209
|
+
when,
|
|
210
|
+
host,
|
|
211
|
+
manageUrl,
|
|
212
|
+
meetingLink: booking.meetingLink,
|
|
213
|
+
}),
|
|
101
214
|
replyTo: host,
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const hostEmailMessage = renderEmail({
|
|
105
|
-
preheader: `${attendeeName} booked ${title} on ${when}.`,
|
|
106
|
-
heading: "New booking",
|
|
107
|
-
paragraphs: [
|
|
108
|
-
`${emailStrong(attendeeName)} booked ${emailStrong(title)}.`,
|
|
109
|
-
`Time: ${emailStrong(when)}.`,
|
|
110
|
-
`Guest: ${emailStrong(attendee)}.`,
|
|
111
|
-
...(booking.meetingLink
|
|
112
|
-
? [`Meeting link: ${emailLink("Join meeting", booking.meetingLink)}.`]
|
|
113
|
-
: []),
|
|
114
|
-
],
|
|
115
|
-
cta: { label: "View booking", url: manageUrl },
|
|
116
|
-
footer: "This booking was created from your calendar booking link.",
|
|
215
|
+
templateId: CALENDAR_BOOKING_CONFIRMED_EMAIL_ID,
|
|
117
216
|
});
|
|
118
217
|
|
|
119
218
|
await sendBestEffort("host notification", {
|
|
120
219
|
to: host,
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
220
|
+
...renderBookingReceivedEmail({
|
|
221
|
+
title,
|
|
222
|
+
when,
|
|
223
|
+
attendeeName,
|
|
224
|
+
attendee,
|
|
225
|
+
manageUrl,
|
|
226
|
+
meetingLink: booking.meetingLink,
|
|
227
|
+
}),
|
|
124
228
|
replyTo: attendee,
|
|
229
|
+
templateId: CALENDAR_BOOKING_RECEIVED_EMAIL_ID,
|
|
125
230
|
});
|
|
126
231
|
}
|
|
127
232
|
|
|
@@ -142,45 +247,24 @@ export async function sendBookingCancellationEmails({
|
|
|
142
247
|
const attendee = stripCrlf(booking.email);
|
|
143
248
|
const attendeeName = stripCrlf(booking.name) || "The guest";
|
|
144
249
|
|
|
145
|
-
const attendeeEmail = renderEmail({
|
|
146
|
-
preheader: `${title} on ${when} was cancelled.`,
|
|
147
|
-
heading: "Your meeting was cancelled",
|
|
148
|
-
paragraphs: [
|
|
149
|
-
`${emailStrong(title)} with ${emailStrong(host || "the host")} has been cancelled.`,
|
|
150
|
-
`Original time: ${emailStrong(when)}.`,
|
|
151
|
-
],
|
|
152
|
-
cta: bookAgainUrl
|
|
153
|
-
? { label: "Book another time", url: bookAgainUrl }
|
|
154
|
-
: undefined,
|
|
155
|
-
footer: "If this was unexpected, contact the meeting host.",
|
|
156
|
-
});
|
|
157
|
-
|
|
158
250
|
await sendBestEffort("attendee cancellation", {
|
|
159
251
|
to: attendee,
|
|
160
|
-
|
|
161
|
-
html: attendeeEmail.html,
|
|
162
|
-
text: attendeeEmail.text,
|
|
252
|
+
...renderBookingCancelledEmail({ title, when, host, bookAgainUrl }),
|
|
163
253
|
replyTo: host || undefined,
|
|
254
|
+
templateId: CALENDAR_BOOKING_CANCELLED_EMAIL_ID,
|
|
164
255
|
});
|
|
165
256
|
|
|
166
257
|
if (!host) return;
|
|
167
258
|
|
|
168
|
-
const hostEmailMessage = renderEmail({
|
|
169
|
-
preheader: `${attendeeName}'s booking for ${title} was cancelled.`,
|
|
170
|
-
heading: "Booking cancelled",
|
|
171
|
-
paragraphs: [
|
|
172
|
-
`${emailStrong(attendeeName)}'s booking for ${emailStrong(title)} was cancelled.`,
|
|
173
|
-
`Original time: ${emailStrong(when)}.`,
|
|
174
|
-
`Guest: ${emailStrong(attendee)}.`,
|
|
175
|
-
],
|
|
176
|
-
footer: "No further action is needed.",
|
|
177
|
-
});
|
|
178
|
-
|
|
179
259
|
await sendBestEffort("host cancellation notification", {
|
|
180
260
|
to: host,
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
261
|
+
...renderBookingCancelledHostEmail({
|
|
262
|
+
title,
|
|
263
|
+
when,
|
|
264
|
+
attendeeName,
|
|
265
|
+
attendee,
|
|
266
|
+
}),
|
|
184
267
|
replyTo: attendee,
|
|
268
|
+
templateId: CALENDAR_BOOKING_CANCELLED_HOST_EMAIL_ID,
|
|
185
269
|
});
|
|
186
270
|
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog entries for the transactional emails Calendar sends.
|
|
3
|
+
*
|
|
4
|
+
* Registered from `server/plugins/transactional-emails.ts` so Dispatch can list
|
|
5
|
+
* and preview them without the app having sent anything yet.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { defineTransactionalEmail } from "@agent-native/core/email-catalog";
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
renderBookingCancelledEmail,
|
|
12
|
+
renderBookingCancelledHostEmail,
|
|
13
|
+
renderBookingConfirmedEmail,
|
|
14
|
+
renderBookingReceivedEmail,
|
|
15
|
+
} from "./booking-emails.js";
|
|
16
|
+
import { renderEventGuestNote } from "./event-guest-notifications.js";
|
|
17
|
+
|
|
18
|
+
/** Obviously-fake sample data — these render in a preview pane, never send. */
|
|
19
|
+
const SAMPLE_TITLE = "Intro call";
|
|
20
|
+
const SAMPLE_WHEN = "Tuesday, March 4, 2025, 10:00 AM - 10:30 AM PST";
|
|
21
|
+
const SAMPLE_HOST = "dana.hill@example.com";
|
|
22
|
+
const SAMPLE_GUEST = "sam.rivera@example.com";
|
|
23
|
+
const SAMPLE_GUEST_NAME = "Sam Rivera";
|
|
24
|
+
const SAMPLE_MANAGE_URL = "https://example.com/book/dana/manage/sample-token";
|
|
25
|
+
const SAMPLE_BOOK_AGAIN_URL = "https://example.com/book/dana/intro-call";
|
|
26
|
+
const SAMPLE_MEETING_LINK = "https://meet.example.com/sample-intro-call";
|
|
27
|
+
|
|
28
|
+
export const CALENDAR_BOOKING_CONFIRMED_EMAIL_ID = "calendar.booking-confirmed";
|
|
29
|
+
export const CALENDAR_BOOKING_RECEIVED_EMAIL_ID = "calendar.booking-received";
|
|
30
|
+
export const CALENDAR_BOOKING_CANCELLED_EMAIL_ID = "calendar.booking-cancelled";
|
|
31
|
+
export const CALENDAR_BOOKING_CANCELLED_HOST_EMAIL_ID =
|
|
32
|
+
"calendar.booking-cancelled-host";
|
|
33
|
+
export const CALENDAR_EVENT_UPDATE_NOTE_EMAIL_ID = "calendar.event-update-note";
|
|
34
|
+
export const CALENDAR_EVENT_CANCELLATION_NOTE_EMAIL_ID =
|
|
35
|
+
"calendar.event-cancellation-note";
|
|
36
|
+
|
|
37
|
+
let registered = false;
|
|
38
|
+
|
|
39
|
+
export function registerCalendarEmails(): void {
|
|
40
|
+
if (registered) return;
|
|
41
|
+
registered = true;
|
|
42
|
+
|
|
43
|
+
defineTransactionalEmail({
|
|
44
|
+
id: CALENDAR_BOOKING_CONFIRMED_EMAIL_ID,
|
|
45
|
+
name: "Booking confirmed (guest)",
|
|
46
|
+
trigger:
|
|
47
|
+
"A guest completes a booking on a public `/book/{username}/{slug}` page and the booking row is created.",
|
|
48
|
+
recipientLabel: "Booking guest",
|
|
49
|
+
recipient:
|
|
50
|
+
"The email address the guest typed into the booking form (`booking.email`).",
|
|
51
|
+
senderLabel: "Default, reply-to host",
|
|
52
|
+
sender:
|
|
53
|
+
"The configured EMAIL_FROM, with reply-to set to the booking link owner's address.",
|
|
54
|
+
preview: () =>
|
|
55
|
+
renderBookingConfirmedEmail({
|
|
56
|
+
title: SAMPLE_TITLE,
|
|
57
|
+
when: SAMPLE_WHEN,
|
|
58
|
+
host: SAMPLE_HOST,
|
|
59
|
+
manageUrl: SAMPLE_MANAGE_URL,
|
|
60
|
+
meetingLink: SAMPLE_MEETING_LINK,
|
|
61
|
+
}),
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
defineTransactionalEmail({
|
|
65
|
+
id: CALENDAR_BOOKING_RECEIVED_EMAIL_ID,
|
|
66
|
+
name: "New booking (host)",
|
|
67
|
+
trigger:
|
|
68
|
+
"Sent alongside the guest confirmation, immediately after a public booking is created.",
|
|
69
|
+
recipientLabel: "Booking link owner",
|
|
70
|
+
recipient:
|
|
71
|
+
"The owner of the booking link, looked up from the link's slug at send time.",
|
|
72
|
+
senderLabel: "Default, reply-to guest",
|
|
73
|
+
sender:
|
|
74
|
+
"The configured EMAIL_FROM, with reply-to set to the guest so the host can reply directly.",
|
|
75
|
+
preview: () =>
|
|
76
|
+
renderBookingReceivedEmail({
|
|
77
|
+
title: SAMPLE_TITLE,
|
|
78
|
+
when: SAMPLE_WHEN,
|
|
79
|
+
attendeeName: SAMPLE_GUEST_NAME,
|
|
80
|
+
attendee: SAMPLE_GUEST,
|
|
81
|
+
manageUrl: SAMPLE_MANAGE_URL,
|
|
82
|
+
meetingLink: SAMPLE_MEETING_LINK,
|
|
83
|
+
}),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
defineTransactionalEmail({
|
|
87
|
+
id: CALENDAR_BOOKING_CANCELLED_EMAIL_ID,
|
|
88
|
+
name: "Booking cancelled (guest)",
|
|
89
|
+
trigger:
|
|
90
|
+
"A booking that was not already cancelled is cancelled, either by the guest through the manage/cancel token link or by someone with access to the booking link.",
|
|
91
|
+
recipientLabel: "Booking guest",
|
|
92
|
+
recipient: "The guest address stored on the booking row.",
|
|
93
|
+
senderLabel: "Default, reply-to host",
|
|
94
|
+
sender:
|
|
95
|
+
"The configured EMAIL_FROM, with reply-to set to the host when a host address could be resolved from the link slug.",
|
|
96
|
+
preview: () =>
|
|
97
|
+
renderBookingCancelledEmail({
|
|
98
|
+
title: SAMPLE_TITLE,
|
|
99
|
+
when: SAMPLE_WHEN,
|
|
100
|
+
host: SAMPLE_HOST,
|
|
101
|
+
bookAgainUrl: SAMPLE_BOOK_AGAIN_URL,
|
|
102
|
+
}),
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
defineTransactionalEmail({
|
|
106
|
+
id: CALENDAR_BOOKING_CANCELLED_HOST_EMAIL_ID,
|
|
107
|
+
name: "Booking cancelled (host)",
|
|
108
|
+
trigger:
|
|
109
|
+
"Sent after the guest cancellation notice, and only when a host address could be resolved from the booking link slug.",
|
|
110
|
+
recipientLabel: "Booking link owner",
|
|
111
|
+
recipient: "The booking link owner's address.",
|
|
112
|
+
senderLabel: "Default, reply-to guest",
|
|
113
|
+
sender:
|
|
114
|
+
"The configured EMAIL_FROM, with reply-to set to the guest who was booked.",
|
|
115
|
+
preview: () =>
|
|
116
|
+
renderBookingCancelledHostEmail({
|
|
117
|
+
title: SAMPLE_TITLE,
|
|
118
|
+
when: SAMPLE_WHEN,
|
|
119
|
+
attendeeName: SAMPLE_GUEST_NAME,
|
|
120
|
+
attendee: SAMPLE_GUEST,
|
|
121
|
+
}),
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
defineTransactionalEmail({
|
|
125
|
+
id: CALENDAR_EVENT_UPDATE_NOTE_EMAIL_ID,
|
|
126
|
+
name: "Event update note",
|
|
127
|
+
trigger:
|
|
128
|
+
"`update-event` runs with a non-empty guest notification message. Google Calendar still sends its own update invite; this carries only the organizer's note.",
|
|
129
|
+
recipientLabel: "Event attendees",
|
|
130
|
+
recipient:
|
|
131
|
+
"Every attendee on the event with a syntactically valid address, excluding the organizer's own `self` attendee row. One email per address.",
|
|
132
|
+
senderLabel: "Default, reply-to organizer",
|
|
133
|
+
sender:
|
|
134
|
+
"The configured EMAIL_FROM, with reply-to set to the organizer running the update.",
|
|
135
|
+
preview: () =>
|
|
136
|
+
renderEventGuestNote({
|
|
137
|
+
title: "Design review",
|
|
138
|
+
organizer: "Dana Hill",
|
|
139
|
+
message: "Moving this an hour later so the whole team can join.",
|
|
140
|
+
when: SAMPLE_WHEN,
|
|
141
|
+
kind: "update",
|
|
142
|
+
htmlLink: "https://calendar.example.com/event/sample",
|
|
143
|
+
}),
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
defineTransactionalEmail({
|
|
147
|
+
id: CALENDAR_EVENT_CANCELLATION_NOTE_EMAIL_ID,
|
|
148
|
+
name: "Event cancellation note",
|
|
149
|
+
trigger:
|
|
150
|
+
"`delete-event` runs with guest notification requested and a non-empty message. Google Calendar sends the cancellation itself; this carries only the organizer's note.",
|
|
151
|
+
recipientLabel: "Event attendees",
|
|
152
|
+
recipient:
|
|
153
|
+
"Every attendee on the deleted event with a syntactically valid address, excluding the organizer's own `self` attendee row. One email per address.",
|
|
154
|
+
senderLabel: "Default, reply-to organizer",
|
|
155
|
+
sender:
|
|
156
|
+
"The configured EMAIL_FROM, with reply-to set to the organizer running the deletion.",
|
|
157
|
+
preview: () =>
|
|
158
|
+
renderEventGuestNote({
|
|
159
|
+
title: "Design review",
|
|
160
|
+
organizer: "Dana Hill",
|
|
161
|
+
message: "Cancelling this week — we will pick it up after the launch.",
|
|
162
|
+
when: SAMPLE_WHEN,
|
|
163
|
+
kind: "cancellation",
|
|
164
|
+
appliesTo: "all events in the series",
|
|
165
|
+
}),
|
|
166
|
+
});
|
|
167
|
+
}
|
|
@@ -6,6 +6,10 @@ import {
|
|
|
6
6
|
} from "@agent-native/core/server";
|
|
7
7
|
|
|
8
8
|
import type { CalendarEvent, DeleteEventScope } from "../../shared/api.js";
|
|
9
|
+
import {
|
|
10
|
+
CALENDAR_EVENT_CANCELLATION_NOTE_EMAIL_ID,
|
|
11
|
+
CALENDAR_EVENT_UPDATE_NOTE_EMAIL_ID,
|
|
12
|
+
} from "./emails.js";
|
|
9
13
|
|
|
10
14
|
export interface GuestNotificationResult {
|
|
11
15
|
requested: boolean;
|
|
@@ -96,6 +100,53 @@ function scopeLabel(scope: DeleteEventScope | undefined): string | undefined {
|
|
|
96
100
|
return "this and following events";
|
|
97
101
|
}
|
|
98
102
|
|
|
103
|
+
export function renderEventGuestNote({
|
|
104
|
+
title,
|
|
105
|
+
organizer,
|
|
106
|
+
message,
|
|
107
|
+
when,
|
|
108
|
+
kind,
|
|
109
|
+
appliesTo,
|
|
110
|
+
htmlLink,
|
|
111
|
+
}: {
|
|
112
|
+
title: string;
|
|
113
|
+
organizer: string;
|
|
114
|
+
message: string;
|
|
115
|
+
when: string;
|
|
116
|
+
kind: GuestNotificationKind;
|
|
117
|
+
appliesTo?: string;
|
|
118
|
+
htmlLink?: string | null;
|
|
119
|
+
}) {
|
|
120
|
+
const heading =
|
|
121
|
+
kind === "cancellation" ? "Event cancellation note" : "Event update note";
|
|
122
|
+
const subjectPrefix =
|
|
123
|
+
kind === "cancellation" ? "Cancellation note" : "Update note";
|
|
124
|
+
const eventAction = kind === "cancellation" ? "cancelling" : "updating";
|
|
125
|
+
const paragraphs = [
|
|
126
|
+
`${emailStrong(organizer)} added this note while ${eventAction} ${emailStrong(title)}.`,
|
|
127
|
+
messageParagraph(message),
|
|
128
|
+
`When: ${emailStrong(when)}.`,
|
|
129
|
+
];
|
|
130
|
+
if (appliesTo) {
|
|
131
|
+
paragraphs.push(`Applies to: ${emailStrong(appliesTo)}.`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
subject: `${subjectPrefix}: ${title}`,
|
|
136
|
+
...renderEmail({
|
|
137
|
+
preheader: `${subjectPrefix}: ${title}`,
|
|
138
|
+
heading,
|
|
139
|
+
paragraphs,
|
|
140
|
+
cta:
|
|
141
|
+
kind === "update" && htmlLink
|
|
142
|
+
? { label: "Open in Google Calendar", url: htmlLink }
|
|
143
|
+
: undefined,
|
|
144
|
+
footer:
|
|
145
|
+
"Google Calendar sends the calendar update separately. This message carries the organizer note.",
|
|
146
|
+
}),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
99
150
|
export async function sendEventGuestNotificationNote({
|
|
100
151
|
event,
|
|
101
152
|
organizerEmail,
|
|
@@ -138,33 +189,14 @@ export async function sendEventGuestNotificationNote({
|
|
|
138
189
|
};
|
|
139
190
|
}
|
|
140
191
|
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
kind
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
`${emailStrong(organizer)} added this note while ${eventAction} ${emailStrong(title)}.`,
|
|
150
|
-
messageParagraph(normalizedMessage),
|
|
151
|
-
`When: ${emailStrong(formatWhen(event))}.`,
|
|
152
|
-
];
|
|
153
|
-
const appliesTo = scopeLabel(scope);
|
|
154
|
-
if (appliesTo) {
|
|
155
|
-
paragraphs.push(`Applies to: ${emailStrong(appliesTo)}.`);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const rendered = renderEmail({
|
|
159
|
-
preheader: `${subjectPrefix}: ${title}`,
|
|
160
|
-
heading,
|
|
161
|
-
paragraphs,
|
|
162
|
-
cta:
|
|
163
|
-
kind === "update" && event.htmlLink
|
|
164
|
-
? { label: "Open in Google Calendar", url: event.htmlLink }
|
|
165
|
-
: undefined,
|
|
166
|
-
footer:
|
|
167
|
-
"Google Calendar sends the calendar update separately. This message carries the organizer note.",
|
|
192
|
+
const rendered = renderEventGuestNote({
|
|
193
|
+
title: stripCrlf(event.title) || "Calendar event",
|
|
194
|
+
organizer: stripCrlf(event.organizer?.displayName) || organizerEmail,
|
|
195
|
+
message: normalizedMessage,
|
|
196
|
+
when: formatWhen(event),
|
|
197
|
+
kind,
|
|
198
|
+
appliesTo: scopeLabel(scope),
|
|
199
|
+
htmlLink: event.htmlLink,
|
|
168
200
|
});
|
|
169
201
|
|
|
170
202
|
let sentCount = 0;
|
|
@@ -174,10 +206,14 @@ export async function sendEventGuestNotificationNote({
|
|
|
174
206
|
try {
|
|
175
207
|
await sendEmail({
|
|
176
208
|
to,
|
|
177
|
-
subject:
|
|
209
|
+
subject: rendered.subject,
|
|
178
210
|
html: rendered.html,
|
|
179
211
|
text: rendered.text,
|
|
180
212
|
replyTo: organizerEmail,
|
|
213
|
+
templateId:
|
|
214
|
+
kind === "cancellation"
|
|
215
|
+
? CALENDAR_EVENT_CANCELLATION_NOTE_EMAIL_ID
|
|
216
|
+
: CALENDAR_EVENT_UPDATE_NOTE_EMAIL_ID,
|
|
181
217
|
});
|
|
182
218
|
sentCount += 1;
|
|
183
219
|
} catch (error) {
|
|
@@ -31,6 +31,26 @@ the framework monorepo checkout.
|
|
|
31
31
|
|
|
32
32
|
From a generated app directory:
|
|
33
33
|
|
|
34
|
+
```bash
|
|
35
|
+
pnpm action framework-search --pattern "defineAction"
|
|
36
|
+
pnpm action framework-search --pattern "templates/*/actions/*.ts" --mode glob --scope source
|
|
37
|
+
pnpm action framework-search --pattern "Agent(?:Panel|Sidebar)" --mode regex --scope source
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Use `framework-search` first when a question may cross the docs and source
|
|
41
|
+
boundary. It searches the version-matched framework docs, runtime-visible
|
|
42
|
+
skills, readable Core or Toolkit package source, and first-party template
|
|
43
|
+
corpus in one bounded read-only call. Use `scope: docs` or `scope: source` to
|
|
44
|
+
narrow it, then use the existing focused readers for the page or file you need.
|
|
45
|
+
|
|
46
|
+
The same tool is available in the headless `pnpm agent` loop and every built-in
|
|
47
|
+
app agent. Its default substring mode is safest for ordinary questions; use
|
|
48
|
+
`glob` for wildcard paths, `sql-like` for `%` and `_` wildcards, and `regex`
|
|
49
|
+
for precise structural matches. Results are bounded, so refine the pattern or
|
|
50
|
+
path instead of treating a truncated result as exhaustive.
|
|
51
|
+
|
|
52
|
+
From a generated app directory, the lower-level readers remain available:
|
|
53
|
+
|
|
34
54
|
```bash
|
|
35
55
|
pnpm action docs-search --query "<feature>"
|
|
36
56
|
pnpm action docs-search --slug <slug>
|
|
@@ -41,9 +61,9 @@ pnpm action source-search --path templates/chat/actions/hello.ts
|
|
|
41
61
|
pnpm action source-search --list
|
|
42
62
|
```
|
|
43
63
|
|
|
44
|
-
The headless `pnpm agent` loop and built-in app agent also expose
|
|
45
|
-
`
|
|
46
|
-
|
|
64
|
+
The headless `pnpm agent` loop and built-in app agent also expose read-only
|
|
65
|
+
`framework-search`, `docs-search`, and `source-search` tools. Use the unified
|
|
66
|
+
tool for discovery, then the focused tools for full page or file reads.
|
|
47
67
|
|
|
48
68
|
If the action runner is unavailable, search the package directly:
|
|
49
69
|
|
|
@@ -65,6 +65,22 @@ Contextual agent UI is not a reason to expose every option at once. Start with
|
|
|
65
65
|
the domain task's primary action, reveal review or configuration only when the
|
|
66
66
|
current state needs it, and let the sidebar carry conversational depth.
|
|
67
67
|
|
|
68
|
+
## Visual Direction And Workspace Variety
|
|
69
|
+
|
|
70
|
+
Shared workspace behavior should be consistent without forcing every app into
|
|
71
|
+
the same visual skin. Keep shell and component tokens semantic, then let each
|
|
72
|
+
app declare a named direction in `DESIGN.md` before styling. A new app should
|
|
73
|
+
choose its palette family and composition from the product context, compare
|
|
74
|
+
nearby apps, and avoid inheriting their accent by default. Use the
|
|
75
|
+
`frontend-design` visual-direction reference for mode, palette, type, density,
|
|
76
|
+
shape, anti-references, and the `distill` / `typeset` / `colorize` / `layout` /
|
|
77
|
+
`polish` / `audit` review vocabulary.
|
|
78
|
+
|
|
79
|
+
Do not make warm beige plus terracotta the workspace fallback. Preserve a
|
|
80
|
+
workspace-level brand when one exists; otherwise keep shared chrome neutral and
|
|
81
|
+
allow app-owned accents to distinguish products while retaining accessible
|
|
82
|
+
semantic states and the shared AgentSidebar contract.
|
|
83
|
+
|
|
68
84
|
## Discover Before Building
|
|
69
85
|
|
|
70
86
|
Before creating an app-local version of repeated workspace or agent UI:
|
|
@@ -34,6 +34,22 @@ Before coding, decide:
|
|
|
34
34
|
|
|
35
35
|
Then implement working code that is cohesive, accessible, responsive, and polished in small details: typography, spacing, copy, motion, empty states, loading states, focus states, and error states.
|
|
36
36
|
|
|
37
|
+
## Visual Direction Contract
|
|
38
|
+
|
|
39
|
+
Before styling a new app or workspace surface, define its product mode,
|
|
40
|
+
audience, visual world, palette family, type treatment, composition, shape
|
|
41
|
+
language, and anti-references in `DESIGN.md`. Read
|
|
42
|
+
`references/visual-direction.md` for the direction families and review
|
|
43
|
+
vocabulary. This is the Impeccable-inspired design contract for Agent-Native
|
|
44
|
+
apps: understand the product, name the mode, deal a few coherent directions,
|
|
45
|
+
commit to one, and audit the result instead of averaging back to a starter.
|
|
46
|
+
|
|
47
|
+
Preserve an existing brand system and component library. When no brand exists,
|
|
48
|
+
choose a deliberate direction based on the domain and compare sibling apps
|
|
49
|
+
before selecting its accent family. Shared behavior and semantic token names
|
|
50
|
+
should stay consistent; palette, density, composition, type contrast, and
|
|
51
|
+
shape language should not be identical by default.
|
|
52
|
+
|
|
37
53
|
## Minimalism And Progressive Disclosure
|
|
38
54
|
|
|
39
55
|
Default to Apple/Linear-level restraint: make the primary workflow obvious, then remove everything that does not help that workflow right now. A polished UI often has fewer visible controls, fewer borders, fewer labels, and fewer explanatory surfaces than the first reasonable implementation.
|
|
@@ -81,13 +97,13 @@ passed this requirement yet.
|
|
|
81
97
|
operational apps, make a clear sans-serif hierarchy the default; reserve a
|
|
82
98
|
serif or editorial face for a deliberate content preview or brand moment,
|
|
83
99
|
not the whole application shell.
|
|
84
|
-
- **Color and theme**: Use semantic tokens and CSS variables. Avoid one-note palettes and default purple/blue gradients unless the brand demands them.
|
|
100
|
+
- **Color and theme**: Use semantic tokens and CSS variables. Avoid one-note palettes, default warm beige/terracotta, and default purple/blue gradients unless the brand demands them. New apps should choose a product-fitting accent family rather than inherit the previous app's color.
|
|
85
101
|
- **Motion**: Prefer purposeful transitions and small state changes. Use CSS transitions/keyframes unless the app already uses a motion library. Never `transition-all` — list the properties that actually change (e.g. `transition-[opacity,transform]`). Use the shared easing tokens defined in `packages/core/src/styles/agent-native.css` instead of hand-typing curves: `var(--ease-drawer)` (260ms, drawers/app chrome), `var(--ease-collapse)` (200ms, expand/collapse), `var(--ease-out-strong)` (snappy entrances) — in Tailwind, `ease-[var(--ease-collapse)]`. Enter/exit with ease-out, never `ease-in`. Overlays that zoom in must set the Radix origin var (e.g. `origin-[--radix-popover-content-transform-origin]`). Animate `transform`/`opacity`, not width/height/padding/box-shadow. Gate looping or large-movement animations with `motion-reduce:`. Command palettes and keyboard-triggered actions get no animation.
|
|
86
102
|
- **Composition**: Match the workflow. Operational apps should be dense and scannable; marketing or portfolio pages can be more immersive.
|
|
87
103
|
- **Visual assets**: Websites, games, and object-focused pages need real or generated media when images help users understand the subject.
|
|
88
104
|
- **Responsive fit**: Text must not overflow buttons, cards, tabs, sidebars, or fixed-format tools. Use stable dimensions for boards, grids, toolbars, and counters.
|
|
89
105
|
|
|
90
|
-
**Beat convergence, not just defaults.** You sample toward the "on-distribution" center, so naming what to avoid is not enough: every "don't" needs a "do", or you converge on the next safe option
|
|
106
|
+
**Beat convergence, not just defaults.** You sample toward the "on-distribution" center, so naming what to avoid is not enough: every "don't" needs a "do", or you converge on the next safe option. Commit to one named direction, pair any reference with the reason it fits, and match implementation effort to the vision. If the brief is open, consider two or three coherent visual worlds, then commit to one instead of averaging them. When building on an existing app, inspect its tokens/type/components first and treat any drift back to a default as a missing token to pin, not something to re-prompt.
|
|
91
107
|
|
|
92
108
|
## Agent-Native UI Rules
|
|
93
109
|
|
|
@@ -164,6 +180,9 @@ as an operator would use it repeatedly:
|
|
|
164
180
|
- For review flows, stack the source/original first and the generated or safe
|
|
165
181
|
result second by default. Use side-by-side comparison only when the content
|
|
166
182
|
is short enough to scan without excessive horizontal reading.
|
|
183
|
+
- Compare the result with sibling apps. Shared toolkit behavior should feel
|
|
184
|
+
consistent, but a repeated palette, hero composition, type pairing, and
|
|
185
|
+
radius language without a product reason is visual drift, not consistency.
|
|
167
186
|
- Check the result at the target desktop width and a narrow width. If the first
|
|
168
187
|
viewport feels like documentation instead of a tool, subtract again.
|
|
169
188
|
|
|
@@ -216,6 +235,8 @@ For substantial frontend work:
|
|
|
216
235
|
5. When registering or changing a company adapter, run
|
|
217
236
|
`@agent-native/toolkit/conformance`, including mixed-overlay focus,
|
|
218
237
|
`portalContainer`, and z-index stacking checks.
|
|
238
|
+
6. For a new app or a visual redesign, review `DESIGN.md` against the rendered
|
|
239
|
+
surface and run the anti-slop audit in `references/visual-direction.md`.
|
|
219
240
|
|
|
220
241
|
## Related Skills
|
|
221
242
|
|