@agent-native/core 0.122.3 → 0.123.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +544 -0
- package/corpus/core/docs/content/actions.mdx +33 -20
- package/corpus/core/docs/content/agent-mentions.mdx +30 -19
- package/corpus/core/docs/content/agent-native-toolkit.mdx +8 -6
- package/corpus/core/docs/content/agent-resources.mdx +11 -0
- package/corpus/core/docs/content/agent-surfaces.mdx +41 -30
- package/corpus/core/docs/content/audit-log.mdx +78 -0
- package/corpus/core/docs/content/authentication.mdx +7 -5
- package/corpus/core/docs/content/automations.mdx +15 -9
- package/corpus/core/docs/content/client.mdx +11 -11
- package/corpus/core/docs/content/cloneable-saas.mdx +7 -1
- package/corpus/core/docs/content/code-agents-ui.mdx +9 -1
- package/corpus/core/docs/content/components.mdx +7 -0
- package/corpus/core/docs/content/context-awareness.mdx +1 -0
- package/corpus/core/docs/content/creating-templates.mdx +9 -1
- package/corpus/core/docs/content/custom-design-system.mdx +8 -0
- package/corpus/core/docs/content/data-programs.mdx +6 -0
- package/corpus/core/docs/content/deployment.mdx +2 -0
- package/corpus/core/docs/content/doctor.mdx +5 -3
- package/corpus/core/docs/content/extensions.mdx +26 -0
- package/corpus/core/docs/content/external-agents-catalog.mdx +533 -0
- package/corpus/core/docs/content/external-agents.mdx +20 -514
- package/corpus/core/docs/content/faq.mdx +2 -2
- package/corpus/core/docs/content/file-uploads.mdx +44 -0
- package/corpus/core/docs/content/frames.mdx +2 -2
- package/corpus/core/docs/content/generative-ui.mdx +8 -0
- package/corpus/core/docs/content/getting-started.mdx +45 -17
- package/corpus/core/docs/content/human-approval.mdx +9 -0
- package/corpus/core/docs/content/integrations.mdx +4 -3
- package/corpus/core/docs/content/internationalization.mdx +4 -11
- package/corpus/core/docs/content/key-concepts.mdx +1 -1
- package/corpus/core/docs/content/local-file-mode.mdx +5 -0
- package/corpus/core/docs/content/mcp-apps.mdx +2 -1
- package/corpus/core/docs/content/mcp-clients.mdx +32 -1
- package/corpus/core/docs/content/mcp-protocol.mdx +4 -3
- package/corpus/core/docs/content/messaging-internals.mdx +328 -0
- package/corpus/core/docs/content/messaging-recipes.mdx +194 -0
- package/corpus/core/docs/content/messaging.mdx +9 -307
- package/corpus/core/docs/content/multi-app-workspace.mdx +1 -1
- package/corpus/core/docs/content/multi-tenancy.mdx +1 -0
- package/corpus/core/docs/content/native-chat-ui.mdx +8 -0
- package/corpus/core/docs/content/notifications.mdx +18 -20
- package/corpus/core/docs/content/observability.mdx +1 -0
- package/corpus/core/docs/content/onboarding.mdx +20 -6
- package/corpus/core/docs/content/organizations-teams-permissions.mdx +99 -124
- package/corpus/core/docs/content/package-lifecycle.mdx +19 -7
- package/corpus/core/docs/content/progress.mdx +11 -0
- package/corpus/core/docs/content/real-time-collaboration.mdx +44 -3
- package/corpus/core/docs/content/recurring-jobs.mdx +14 -1
- package/corpus/core/docs/content/security.mdx +5 -2
- package/corpus/core/docs/content/server.mdx +2 -1
- package/corpus/core/docs/content/sharing.mdx +22 -3
- package/corpus/core/docs/content/skills-guide.mdx +62 -19
- package/corpus/core/docs/content/syncing-template-changes.mdx +9 -0
- package/corpus/core/docs/content/template-analytics-connectors.mdx +75 -0
- package/corpus/core/docs/content/template-analytics-dashboards.mdx +106 -0
- package/corpus/core/docs/content/template-analytics-developers.mdx +287 -0
- package/corpus/core/docs/content/template-analytics-monitoring-and-sessions.mdx +109 -0
- package/corpus/core/docs/content/template-analytics.mdx +21 -263
- package/corpus/core/docs/content/template-assets-developers.mdx +456 -0
- package/corpus/core/docs/content/template-assets-generation.mdx +147 -0
- package/corpus/core/docs/content/template-assets-integrations.mdx +319 -0
- package/corpus/core/docs/content/template-assets-presets.mdx +185 -0
- package/corpus/core/docs/content/template-assets.mdx +12 -562
- package/corpus/core/docs/content/template-brain-agent.mdx +103 -0
- package/corpus/core/docs/content/template-brain-developers.mdx +379 -0
- package/corpus/core/docs/content/template-brain-knowledge.mdx +50 -0
- package/corpus/core/docs/content/template-brain-sources.mdx +163 -0
- package/corpus/core/docs/content/template-brain.mdx +30 -390
- package/corpus/core/docs/content/template-calendar-agent.mdx +133 -0
- package/corpus/core/docs/content/template-calendar-booking-links.mdx +73 -0
- package/corpus/core/docs/content/template-calendar-developers.mdx +366 -0
- package/corpus/core/docs/content/template-calendar-scheduling.mdx +128 -0
- package/corpus/core/docs/content/template-calendar.mdx +13 -260
- package/corpus/core/docs/content/template-chat-developers.mdx +88 -0
- package/corpus/core/docs/content/template-chat-first-edits.mdx +145 -0
- package/corpus/core/docs/content/template-chat.mdx +12 -77
- package/corpus/core/docs/content/template-clips-ai-and-editing.mdx +114 -0
- package/corpus/core/docs/content/template-clips-capture-everywhere.mdx +120 -0
- package/corpus/core/docs/content/template-clips-developers.mdx +373 -0
- package/corpus/core/docs/content/template-clips-sharing-and-teams.mdx +182 -0
- package/corpus/core/docs/content/template-clips.mdx +19 -508
- package/corpus/core/docs/content/template-content-databases.mdx +406 -0
- package/corpus/core/docs/content/template-content-developers.mdx +364 -0
- package/corpus/core/docs/content/template-content-editing.mdx +60 -0
- package/corpus/core/docs/content/template-content-sync.mdx +149 -0
- package/corpus/core/docs/content/template-content.mdx +21 -561
- package/corpus/core/docs/content/template-design-brand-and-figma.mdx +150 -0
- package/corpus/core/docs/content/template-design-collaboration-and-full-apps.mdx +125 -0
- package/corpus/core/docs/content/template-design-developers.mdx +358 -0
- package/corpus/core/docs/content/template-design-quality-and-components.mdx +95 -0
- package/corpus/core/docs/content/template-design.mdx +20 -344
- package/corpus/core/docs/content/template-dispatch-developers.mdx +121 -0
- package/corpus/core/docs/content/template-dispatch-messaging-routing.mdx +114 -0
- package/corpus/core/docs/content/template-dispatch-operations.mdx +160 -0
- package/corpus/core/docs/content/template-dispatch-vault-integrations.mdx +316 -0
- package/corpus/core/docs/content/template-dispatch.mdx +24 -283
- package/corpus/core/docs/content/template-forms-building-publishing.mdx +135 -0
- package/corpus/core/docs/content/template-forms-developers.mdx +195 -0
- package/corpus/core/docs/content/template-forms-responses.mdx +120 -0
- package/corpus/core/docs/content/template-forms.mdx +21 -230
- package/corpus/core/docs/content/template-mail-agent.mdx +114 -0
- package/corpus/core/docs/content/template-mail-developers.mdx +356 -0
- package/corpus/core/docs/content/template-mail-drafts-and-queue.mdx +103 -0
- package/corpus/core/docs/content/template-mail-inbox.mdx +118 -0
- package/corpus/core/docs/content/template-mail.mdx +23 -274
- package/corpus/core/docs/content/template-plan-automations.mdx +213 -0
- package/corpus/core/docs/content/template-plan-developers.mdx +703 -0
- package/corpus/core/docs/content/template-plan-local-and-desktop.mdx +236 -0
- package/corpus/core/docs/content/template-plan-review-workflow.mdx +180 -0
- package/corpus/core/docs/content/template-plan.mdx +60 -910
- package/corpus/core/docs/content/template-slides-agent.mdx +102 -0
- package/corpus/core/docs/content/template-slides-design-and-media.mdx +94 -0
- package/corpus/core/docs/content/template-slides-developers.mdx +488 -0
- package/corpus/core/docs/content/template-slides-editing.mdx +56 -0
- package/corpus/core/docs/content/template-slides.mdx +20 -362
- package/corpus/core/docs/content/toolkit-capability-packages.mdx +38 -13
- package/corpus/core/docs/content/toolkit-context-knowledge.mdx +49 -9
- package/corpus/core/docs/content/toolkit-editors-canvases.mdx +72 -10
- package/corpus/core/docs/content/toolkit-resources.mdx +16 -0
- package/corpus/core/docs/content/toolkit-settings.mdx +3 -3
- package/corpus/core/docs/content/toolkit-sharing.mdx +5 -7
- package/corpus/core/docs/content/using-your-agent.mdx +25 -2
- package/corpus/core/docs/content/voice-input.mdx +11 -7
- package/corpus/core/docs/content/what-is-agent-native.mdx +1 -0
- package/corpus/core/docs/content/workspace-connections.mdx +21 -11
- package/corpus/core/docs/content/workspace-management.mdx +1 -1
- package/corpus/core/package.json +1 -3
- package/corpus/core/src/a2a/client.ts +4 -2
- package/corpus/core/src/agent/action-warnings.ts +103 -0
- package/corpus/core/src/agent/durable-background.ts +42 -5
- package/corpus/core/src/agent/engine/ai-sdk-engine.ts +58 -6
- package/corpus/core/src/agent/engine/anthropic-engine.ts +51 -8
- package/corpus/core/src/agent/engine/builder-engine.ts +56 -18
- package/corpus/core/src/agent/engine/continuation-dispatch-retry.ts +10 -9
- package/corpus/core/src/agent/engine/credential-errors.ts +11 -0
- package/corpus/core/src/agent/engine/error-detail.ts +39 -0
- package/corpus/core/src/agent/engine/prompt-cache.ts +44 -0
- package/corpus/core/src/agent/engine/registry.ts +22 -30
- package/corpus/core/src/agent/engine/tool-call-journal-seed.ts +2 -1
- package/corpus/core/src/agent/engine/translate-anthropic.ts +99 -0
- package/corpus/core/src/agent/loop-settings.ts +94 -7
- package/corpus/core/src/agent/production-agent.ts +667 -157
- package/corpus/core/src/agent/run-loop-with-resume.ts +27 -1
- package/corpus/core/src/agent/run-manager.ts +229 -39
- package/corpus/core/src/agent/run-store.ts +397 -64
- package/corpus/core/src/agent/thread-data-builder.ts +5 -1
- package/corpus/core/src/agent/types.ts +23 -6
- package/corpus/core/src/application-state/script-helpers.ts +5 -2
- package/corpus/core/src/cli/agents.ts +69 -1
- package/corpus/core/src/cli/app-skill.ts +1 -1
- package/corpus/core/src/cli/code-agent-executor.ts +7 -3
- package/corpus/core/src/cli/design-connect.ts +82 -8
- package/corpus/core/src/cli/index.ts +2 -1
- package/corpus/core/src/cli/mcp.ts +13 -3
- package/corpus/core/src/cli/skills-content/design-visual-edit-skill.ts +169 -24
- package/corpus/core/src/cli/skills-content/rewind-skill.ts +36 -4
- package/corpus/core/src/cli/skills.ts +250 -37
- package/corpus/core/src/cli/telemetry-routing.ts +57 -0
- package/corpus/core/src/cli/telemetry.ts +3 -3
- package/corpus/core/src/client/AssistantChat.tsx +623 -607
- package/corpus/core/src/client/agent-chat-adapter.ts +176 -29
- package/corpus/core/src/client/chat/message-components.tsx +13 -0
- package/corpus/core/src/client/embed-auth.ts +3 -1
- package/corpus/core/src/client/integrations/IntegrationCard.tsx +41 -24
- package/corpus/core/src/client/integrations/IntegrationsPanel.tsx +37 -21
- package/corpus/core/src/client/integrations/webhook-url.ts +29 -0
- package/corpus/core/src/client/org/OrgSwitcher.tsx +41 -27
- package/corpus/core/src/client/org/RequireActiveOrg.tsx +7 -0
- package/corpus/core/src/client/org/TeamPage.tsx +144 -14
- package/corpus/core/src/client/org/hooks.ts +27 -0
- package/corpus/core/src/client/org/index.ts +2 -0
- package/corpus/core/src/client/require-session.tsx +40 -29
- package/corpus/core/src/client/session-replay.ts +1 -1
- package/corpus/core/src/client/settings/DemoModeSection.tsx +0 -5
- package/corpus/core/src/client/settings/SecretsSection.tsx +47 -42
- package/corpus/core/src/client/settings/VoiceTranscriptionSection.tsx +0 -5
- package/corpus/core/src/client/sse-event-processor.ts +83 -8
- package/corpus/core/src/client/use-action.ts +22 -13
- package/corpus/core/src/client/use-agent-engine-configured.ts +36 -4
- package/corpus/core/src/client/use-db-sync.ts +21 -1
- package/corpus/core/src/credentials/index.ts +124 -2
- package/corpus/core/src/deploy/build.ts +93 -30
- package/corpus/core/src/deploy/workspace-deploy.ts +21 -16
- package/corpus/core/src/guards/no-localhost-fallback.ts +76 -14
- package/corpus/core/src/integrations/google-docs-poller.ts +19 -12
- package/corpus/core/src/integrations/webhook-handler.ts +56 -33
- package/corpus/core/src/jobs/scheduler.ts +57 -23
- package/corpus/core/src/localization/default-messages.ts +23 -1
- package/corpus/core/src/mcp/screen-memory-stdio.ts +21 -2
- package/corpus/core/src/observability/evals.ts +7 -8
- package/corpus/core/src/observability/traces.ts +2 -0
- package/corpus/core/src/org/accept-pending.ts +2 -2
- package/corpus/core/src/org/active-org.ts +73 -0
- package/corpus/core/src/org/auto-join-domain.ts +7 -2
- package/corpus/core/src/org/context.ts +169 -66
- package/corpus/core/src/org/handlers.ts +148 -10
- package/corpus/core/src/org/plugin.ts +8 -1
- package/corpus/core/src/org/types.ts +6 -1
- package/corpus/core/src/provider-api/index.ts +6 -1
- package/corpus/core/src/resources/handlers.ts +2 -6
- package/corpus/core/src/resources/script-helpers.ts +2 -1
- package/corpus/core/src/scripts/chat/search-chats.ts +5 -2
- package/corpus/core/src/scripts/describe-workspace-apps.ts +59 -0
- package/corpus/core/src/scripts/resources/delete-memory.ts +5 -2
- package/corpus/core/src/scripts/resources/delete.ts +5 -2
- package/corpus/core/src/scripts/resources/effective.ts +5 -2
- package/corpus/core/src/scripts/resources/list.ts +5 -2
- package/corpus/core/src/scripts/resources/read.ts +5 -2
- package/corpus/core/src/scripts/resources/save-memory.ts +5 -2
- package/corpus/core/src/scripts/resources/write.ts +5 -2
- package/corpus/core/src/server/agent-capabilities.ts +147 -0
- package/corpus/core/src/server/agent-chat/framework-prompts.ts +11 -13
- package/corpus/core/src/server/agent-chat/prompt-resources.ts +183 -57
- package/corpus/core/src/server/agent-chat/script-entries.ts +20 -7
- package/corpus/core/src/server/agent-chat-plugin.ts +27 -0
- package/corpus/core/src/server/auth.ts +38 -32
- package/corpus/core/src/server/core-routes-plugin.ts +229 -179
- package/corpus/core/src/server/credential-provider.ts +196 -44
- package/corpus/core/src/server/embed-session.ts +10 -0
- package/corpus/core/src/server/framework-request-handler.ts +43 -0
- package/corpus/core/src/server/google-auth-plugin.ts +13 -450
- package/corpus/core/src/server/index.ts +4 -1
- package/corpus/core/src/server/onboarding-html.ts +20 -56
- package/corpus/core/src/server/open-route.ts +6 -1
- package/corpus/core/src/server/poll.ts +1 -1
- package/corpus/core/src/server/prompts/framework-core-compact.ts +5 -5
- package/corpus/core/src/server/prompts/framework-core.ts +7 -9
- package/corpus/core/src/server/prompts/shared-rules.ts +20 -9
- package/corpus/core/src/server/request-context.ts +58 -2
- package/corpus/core/src/server/scoped-key-storage.ts +1 -1
- package/corpus/core/src/settings/org-settings.ts +9 -0
- package/corpus/core/src/settings/store.ts +29 -0
- package/corpus/core/src/shared/index.ts +13 -0
- package/corpus/core/src/shared/sign-in-journey.ts +331 -0
- package/corpus/core/src/styles/agent-native.css +8 -0
- package/corpus/core/src/templates/chat/.agents/skills/actions/SKILL.md +19 -1
- package/corpus/core/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +2 -0
- package/corpus/core/src/templates/chat/.agents/skills/frontend-design/SKILL.md +20 -6
- package/corpus/core/src/templates/chat/.agents/skills/security/SKILL.md +2 -0
- package/corpus/core/src/templates/chat/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/corpus/core/src/templates/chat/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/corpus/core/src/templates/chat/AGENTS.md +8 -0
- package/corpus/core/src/templates/chat/app/entry.client.tsx +3 -0
- package/corpus/core/src/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/core/src/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/core/src/templates/chat/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
- package/corpus/core/src/templates/default/.agents/skills/actions/SKILL.md +19 -1
- package/corpus/core/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +2 -0
- package/corpus/core/src/templates/default/.agents/skills/frontend-design/SKILL.md +20 -6
- package/corpus/core/src/templates/default/.agents/skills/security/SKILL.md +2 -0
- package/corpus/core/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/corpus/core/src/templates/default/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/corpus/core/src/templates/default/AGENTS.md +68 -195
- package/corpus/core/src/templates/default/app/entry.client.tsx +3 -0
- package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +8 -0
- package/corpus/core/src/templates/default/app/i18n/de-DE.ts +8 -0
- package/corpus/core/src/templates/default/app/i18n/en-US.ts +8 -0
- package/corpus/core/src/templates/default/app/i18n/es-ES.ts +8 -0
- package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +8 -0
- package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +8 -0
- package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +8 -0
- package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +8 -0
- package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +8 -0
- package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +8 -0
- package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +8 -0
- package/corpus/core/src/templates/headless/.agents/skills/actions/SKILL.md +19 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/actions/SKILL.md +19 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +2 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +100 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +2 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +28 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +14 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +20 -6
- package/corpus/core/src/templates/workspace-core/.agents/skills/qa/SKILL.md +6 -3
- package/corpus/core/src/templates/workspace-core/.agents/skills/security/SKILL.md +2 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/corpus/core/src/templates/workspace-core/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/corpus/core/src/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +91 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +60 -0
- package/corpus/core/src/templates/workspace-core/AGENTS.md +62 -124
- package/corpus/core/src/templates/workspace-root/AGENTS.md +6 -1
- package/corpus/core/src/triggers/dispatcher.ts +28 -17
- package/corpus/core/src/vite/client.ts +20 -8
- package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +19 -1
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +41 -1
- package/corpus/templates/analytics/.agents/skills/dashboard-ops/SKILL.md +50 -22
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +1 -1
- package/corpus/templates/analytics/.agents/skills/data-querying/references/inline-chart-embeds.md +8 -0
- package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +20 -6
- package/corpus/templates/analytics/.agents/skills/security/SKILL.md +2 -0
- package/corpus/templates/analytics/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/corpus/templates/analytics/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/corpus/templates/analytics/.agents/skills/sharing/SKILL.md +228 -0
- package/corpus/templates/analytics/.builder/skills/charts/SKILL.md +2 -2
- package/corpus/templates/analytics/actions/delete-dashboard-view.ts +24 -0
- package/corpus/templates/analytics/actions/delete-user-pref.ts +22 -0
- package/corpus/templates/analytics/actions/generate-chart.ts +8 -245
- package/corpus/templates/analytics/actions/get-theme.ts +27 -0
- package/corpus/templates/analytics/actions/get-user-pref.ts +22 -0
- package/corpus/templates/analytics/actions/list-dashboard-views.ts +25 -0
- package/corpus/templates/analytics/actions/save-dashboard-view.ts +33 -0
- package/corpus/templates/analytics/actions/set-theme.ts +22 -0
- package/corpus/templates/analytics/actions/set-user-pref.ts +24 -0
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +134 -27
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +2 -9
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +0 -17
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +10 -5
- package/corpus/templates/analytics/app/hooks/use-dashboard-views.ts +22 -52
- package/corpus/templates/analytics/app/hooks/use-user-pref.ts +21 -31
- package/corpus/templates/analytics/app/i18n-data.ts +10 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +2 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dual-axis.ts +73 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +8 -27
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/report-panel-window.ts +0 -57
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +8 -0
- package/corpus/templates/analytics/app/root.tsx +0 -28
- package/corpus/templates/analytics/changelog/2026-07-26-error-issues-now-group-by-message-as-well-as-stack-frame-and.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-26-line-area-and-bar-dashboard-panels-can-plot-series-on-a-seco.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-26-scheduled-dashboard-email-reports-now-arrive-complete-and-re.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-26-session-replays-now-detect-rage-clicks-so-the-rage-click-fil.md +6 -0
- package/corpus/templates/analytics/docs/error-capture.md +8 -4
- package/corpus/templates/analytics/package.json +1 -2
- package/corpus/templates/analytics/scripts/preview-dashboard-report.ts +221 -0
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +39 -32
- package/corpus/templates/analytics/server/lib/dashboard-report-render.ts +1168 -0
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +111 -1358
- package/corpus/templates/analytics/server/lib/error-capture.ts +32 -15
- package/corpus/templates/analytics/server/lib/report-chart-svg.ts +901 -0
- package/corpus/templates/analytics/server/lib/session-replay.ts +77 -1
- package/corpus/templates/analytics/shared/dashboard-report-timeouts.ts +3 -4
- package/corpus/templates/assets/.agents/skills/a2a-assets/SKILL.md +28 -0
- package/corpus/templates/assets/.agents/skills/actions/SKILL.md +19 -1
- package/corpus/templates/assets/.agents/skills/assets-navigation/SKILL.md +46 -0
- package/corpus/templates/assets/.agents/skills/creative-context/SKILL.md +12 -0
- package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +20 -6
- package/corpus/templates/assets/.agents/skills/image-generation/SKILL.md +28 -0
- package/corpus/templates/assets/.agents/skills/library-management/SKILL.md +9 -0
- package/corpus/templates/assets/.agents/skills/logo-composite/SKILL.md +11 -0
- package/corpus/templates/assets/.agents/skills/security/SKILL.md +2 -0
- package/corpus/templates/assets/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/corpus/templates/assets/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/corpus/templates/assets/.agents/skills/sharing/SKILL.md +228 -0
- package/corpus/templates/assets/AGENTS.md +58 -125
- package/corpus/templates/assets/actions/variant-slots.ts +8 -4
- package/corpus/templates/assets/app/entry.client.tsx +3 -0
- package/corpus/templates/assets/package.json +0 -2
- package/corpus/templates/brain/.agents/skills/actions/SKILL.md +19 -1
- package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +2 -0
- package/corpus/templates/brain/.agents/skills/brain/SKILL.md +78 -4
- package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +20 -6
- package/corpus/templates/brain/.agents/skills/ingestion-and-connectors/SKILL.md +15 -3
- package/corpus/templates/brain/.agents/skills/security/SKILL.md +2 -0
- package/corpus/templates/brain/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/corpus/templates/brain/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/corpus/templates/brain/.agents/skills/sharing/SKILL.md +228 -0
- package/corpus/templates/brain/.agents/skills/storing-data/SKILL.md +178 -0
- package/corpus/templates/brain/AGENTS.md +73 -119
- package/corpus/templates/brain/app/entry.client.tsx +3 -0
- package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +19 -1
- package/corpus/templates/calendar/.agents/skills/event-management/SKILL.md +56 -3
- package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +20 -6
- package/corpus/templates/calendar/.agents/skills/security/SKILL.md +2 -0
- package/corpus/templates/calendar/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/corpus/templates/calendar/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/corpus/templates/calendar/.agents/skills/sharing/SKILL.md +228 -0
- package/corpus/templates/calendar/AGENTS.md +22 -45
- package/corpus/templates/calendar/app/entry.client.tsx +3 -0
- package/corpus/templates/calendar/server/handlers/events.ts +0 -364
- package/corpus/templates/chat/.agents/skills/actions/SKILL.md +19 -1
- package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +2 -0
- package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +20 -6
- package/corpus/templates/chat/.agents/skills/security/SKILL.md +2 -0
- package/corpus/templates/chat/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/corpus/templates/chat/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/corpus/templates/chat/.agents/skills/sharing/SKILL.md +228 -0
- package/corpus/templates/chat/.agents/skills/storing-data/SKILL.md +178 -0
- package/corpus/templates/chat/AGENTS.md +8 -0
- package/corpus/templates/chat/app/entry.client.tsx +3 -0
- package/corpus/templates/clips/.agents/skills/actions/SKILL.md +19 -1
- package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +42 -0
- package/corpus/templates/clips/.agents/skills/brain-export/SKILL.md +59 -0
- package/corpus/templates/clips/.agents/skills/bug-reports/SKILL.md +37 -0
- package/corpus/templates/clips/.agents/skills/crm-call-evidence/SKILL.md +41 -0
- package/corpus/templates/clips/.agents/skills/dictate/SKILL.md +4 -0
- package/corpus/templates/clips/.agents/skills/external-integrations/SKILL.md +45 -0
- package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +20 -6
- package/corpus/templates/clips/.agents/skills/meetings/SKILL.md +9 -0
- package/corpus/templates/clips/.agents/skills/recording/SKILL.md +45 -0
- package/corpus/templates/clips/.agents/skills/screen-memory/SKILL.md +43 -0
- package/corpus/templates/clips/.agents/skills/security/SKILL.md +2 -0
- package/corpus/templates/clips/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/corpus/templates/clips/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +38 -1
- package/corpus/templates/clips/AGENTS.md +82 -224
- package/corpus/templates/clips/actions/create-recording.ts +4 -0
- package/corpus/templates/clips/app/components/player/sign-in-prompt-dialog.tsx +6 -10
- package/corpus/templates/clips/app/routes/invite.$token.tsx +6 -5
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +4 -5
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +8 -8
- package/corpus/templates/clips/changelog/2026-07-26-long-agent-chat-turns-now-finish-instead-of-stopping-partway.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-26-recordings-no-longer-get-stuck-on-uploading-uploads-now-hold.md +6 -0
- package/corpus/templates/clips/server/db/schema.ts +3 -0
- package/corpus/templates/clips/server/jobs/brain-export.ts +4 -0
- package/corpus/templates/clips/server/lib/recording-upload-state.ts +0 -52
- package/corpus/templates/clips/server/lib/upload-lease.ts +241 -0
- package/corpus/templates/clips/server/plugins/agent-chat.ts +4 -0
- package/corpus/templates/clips/server/plugins/db.ts +18 -347
- package/corpus/templates/clips/server/routes/api/clips/brain-export/run.post.ts +7 -1
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +123 -126
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/reset-chunks.post.ts +4 -0
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/resume.get.ts +118 -0
- package/corpus/templates/clips/server/routes/api/uploads/reap.post.ts +69 -0
- package/corpus/templates/content/.agents/skills/actions/SKILL.md +19 -1
- package/corpus/templates/content/.agents/skills/content/SKILL.md +4 -0
- package/corpus/templates/content/.agents/skills/creative-context/SKILL.md +8 -0
- package/corpus/templates/content/.agents/skills/document-editing/SKILL.md +55 -0
- package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +20 -6
- package/corpus/templates/content/.agents/skills/notion-integration/SKILL.md +12 -1
- package/corpus/templates/content/.agents/skills/security/SKILL.md +2 -0
- package/corpus/templates/content/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/corpus/templates/content/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/corpus/templates/content/.agents/skills/sharing/SKILL.md +228 -0
- package/corpus/templates/content/AGENTS.md +63 -131
- package/corpus/templates/content/app/routes/_app.tsx +4 -4
- package/corpus/templates/content/server/routes/api/notion/callback.get.ts +6 -24
- package/corpus/templates/design/.agents/skills/actions/SKILL.md +19 -1
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +16 -0
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +15 -0
- package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +20 -6
- package/corpus/templates/design/.agents/skills/full-app-build/SKILL.md +12 -0
- package/corpus/templates/design/.agents/skills/security/SKILL.md +2 -0
- package/corpus/templates/design/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/corpus/templates/design/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/corpus/templates/design/.agents/skills/sharing/SKILL.md +228 -0
- package/corpus/templates/design/.agents/skills/storing-data/SKILL.md +178 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +201 -102
- package/corpus/templates/design/AGENTS.md +58 -71
- package/corpus/templates/design/actions/open-visual-edit.ts +111 -2
- package/corpus/templates/design/app/components/design/AddLocalhostScreenDialog.tsx +236 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +1 -1
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +2 -2
- package/corpus/templates/design/app/entry.client.tsx +3 -0
- package/corpus/templates/design/app/i18n-data.ts +180 -0
- package/corpus/templates/design/app/pages/Present.tsx +6 -9
- package/corpus/templates/design/app/pages/VisualEdit.tsx +4 -7
- package/corpus/templates/design/app/pages/design-editor/design-data-geometry-utils.ts +20 -0
- package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +19 -1
- package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +20 -6
- package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +2 -0
- package/corpus/templates/dispatch/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/corpus/templates/dispatch/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/corpus/templates/dispatch/.agents/skills/sharing/SKILL.md +228 -0
- package/corpus/templates/dispatch/.agents/skills/storing-data/SKILL.md +178 -0
- package/corpus/templates/dispatch/app/entry.client.tsx +3 -0
- package/corpus/templates/dispatch/server/plugins/identity-sso.ts +27 -16
- package/corpus/templates/forms/.agents/skills/actions/SKILL.md +19 -1
- package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +20 -6
- package/corpus/templates/forms/.agents/skills/security/SKILL.md +2 -0
- package/corpus/templates/forms/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/corpus/templates/forms/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/corpus/templates/forms/.agents/skills/sharing/SKILL.md +228 -0
- package/corpus/templates/forms/DEVELOPING.md +1 -1
- package/corpus/templates/forms/app/entry.client.tsx +3 -0
- package/corpus/templates/forms/app/pages/FormsListPage.tsx +3 -5
- package/corpus/templates/forms/app/routes/_app.tsx +4 -4
- package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +20 -6
- package/corpus/templates/macros/.agents/skills/security/SKILL.md +2 -0
- package/corpus/templates/macros/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/corpus/templates/macros/.agents/skills/sharing/SKILL.md +228 -0
- package/corpus/templates/macros/.agents/skills/storing-data/SKILL.md +178 -0
- package/corpus/templates/macros/app/entry.client.tsx +3 -0
- package/corpus/templates/mail/.agents/skills/actions/SKILL.md +19 -1
- package/corpus/templates/mail/.agents/skills/contacts-and-crm/SKILL.md +10 -0
- package/corpus/templates/mail/.agents/skills/draft-queue/SKILL.md +3 -0
- package/corpus/templates/mail/.agents/skills/email-drafts/SKILL.md +26 -2
- package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +20 -6
- package/corpus/templates/mail/.agents/skills/inbox-automations/SKILL.md +37 -0
- package/corpus/templates/mail/.agents/skills/inbox-reads-and-triage/SKILL.md +58 -0
- package/corpus/templates/mail/.agents/skills/mail-backends/SKILL.md +33 -0
- package/corpus/templates/mail/.agents/skills/provider-api-scans/SKILL.md +39 -0
- package/corpus/templates/mail/.agents/skills/security/SKILL.md +2 -0
- package/corpus/templates/mail/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/corpus/templates/mail/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/corpus/templates/mail/.agents/skills/sharing/SKILL.md +228 -0
- package/corpus/templates/mail/AGENTS.md +74 -143
- package/corpus/templates/mail/actions/create-alias.ts +36 -0
- package/corpus/templates/mail/actions/create-automation.ts +28 -0
- package/corpus/templates/mail/actions/create-scheduled-job.ts +45 -0
- package/corpus/templates/mail/actions/delete-alias.ts +26 -0
- package/corpus/templates/mail/actions/delete-automation.ts +21 -0
- package/corpus/templates/mail/actions/get-automation-settings.ts +32 -0
- package/corpus/templates/mail/actions/get-mail-preferences.ts +18 -0
- package/corpus/templates/mail/actions/list-aliases.ts +17 -0
- package/corpus/templates/mail/actions/list-automations.ts +18 -0
- package/corpus/templates/mail/actions/list-scheduled-jobs.ts +18 -0
- package/corpus/templates/mail/actions/update-alias.ts +37 -0
- package/corpus/templates/mail/actions/update-automation-settings.ts +33 -0
- package/corpus/templates/mail/actions/update-automation.ts +33 -0
- package/corpus/templates/mail/actions/update-mail-preferences.ts +68 -0
- package/corpus/templates/mail/actions/update-scheduled-job.ts +25 -0
- package/corpus/templates/mail/app/entry.client.tsx +3 -0
- package/corpus/templates/mail/app/hooks/use-aliases.ts +6 -36
- package/corpus/templates/mail/app/hooks/use-automations.ts +9 -16
- package/corpus/templates/mail/app/hooks/use-emails.ts +6 -5
- package/corpus/templates/mail/app/hooks/use-scheduled-jobs.ts +12 -15
- package/corpus/templates/mail/app/pages/SettingsPage.tsx +15 -9
- package/corpus/templates/mail/server/handlers/automations.ts +5 -142
- package/corpus/templates/mail/server/handlers/emails.ts +1 -56
- package/corpus/templates/mail/server/handlers/scheduled-jobs.ts +0 -134
- package/corpus/templates/mail/server/lib/aliases.ts +18 -0
- package/corpus/templates/mail/server/lib/automations.ts +104 -0
- package/corpus/templates/mail/server/lib/jobs.ts +34 -0
- package/corpus/templates/mail/server/lib/mail-settings.ts +43 -0
- package/corpus/templates/mail/shared/automation-schema.ts +10 -0
- package/corpus/templates/plan/.agents/skills/actions/SKILL.md +19 -1
- package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +2 -0
- package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +20 -6
- package/corpus/templates/plan/.agents/skills/plan-authoring-flow/SKILL.md +98 -0
- package/corpus/templates/plan/.agents/skills/plan-browser-editing/SKILL.md +42 -0
- package/corpus/templates/plan/.agents/skills/plan-comments-and-feedback/SKILL.md +68 -0
- package/corpus/templates/plan/.agents/skills/plan-events/SKILL.md +22 -0
- package/corpus/templates/plan/.agents/skills/plan-hosted-writes/SKILL.md +42 -0
- package/corpus/templates/plan/.agents/skills/plan-local-codebase-chat/SKILL.md +38 -0
- package/corpus/templates/plan/.agents/skills/plan-review-recaps/SKILL.md +25 -0
- package/corpus/templates/plan/.agents/skills/plan-source-sync/SKILL.md +68 -0
- package/corpus/templates/plan/.agents/skills/plan-version-history/SKILL.md +25 -0
- package/corpus/templates/plan/.agents/skills/security/SKILL.md +2 -0
- package/corpus/templates/plan/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/corpus/templates/plan/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/corpus/templates/plan/.agents/skills/sharing/SKILL.md +228 -0
- package/corpus/templates/plan/.agents/skills/storing-data/SKILL.md +178 -0
- package/corpus/templates/plan/AGENTS.md +64 -296
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +9 -8
- package/corpus/templates/plan/app/pages/PlansPage.tsx +5 -10
- package/corpus/templates/slides/.agents/skills/actions/SKILL.md +19 -1
- package/corpus/templates/slides/.agents/skills/deck-management/SKILL.md +7 -7
- package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +20 -6
- package/corpus/templates/slides/.agents/skills/security/SKILL.md +2 -0
- package/corpus/templates/slides/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/corpus/templates/slides/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/corpus/templates/slides/.agents/skills/sharing/SKILL.md +228 -0
- package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +3 -2
- package/corpus/templates/slides/.agents/skills/storing-data/SKILL.md +178 -0
- package/corpus/templates/slides/DEVELOPING.md +3 -3
- package/corpus/templates/slides/actions/_deck-write.ts +52 -0
- package/corpus/templates/slides/actions/add-deck.ts +73 -0
- package/corpus/templates/slides/actions/delete-deck.ts +60 -0
- package/corpus/templates/slides/actions/get-deck.ts +3 -1
- package/corpus/templates/slides/actions/save-deck.ts +144 -0
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +27 -20
- package/corpus/templates/slides/app/context/DeckContext.tsx +173 -100
- package/corpus/templates/slides/app/pages/Index.tsx +3 -6
- package/corpus/templates/slides/app/routes/slide.tsx +16 -12
- package/corpus/templates/slides/changelog/2026-07-26-a-newly-created-deck-now-appears-in-the-deck-list-right-away.md +6 -0
- package/corpus/templates/slides/server/handlers/decks.ts +2 -378
- package/corpus/templates/tasks/.agents/skills/action-reference/SKILL.md +47 -0
- package/corpus/templates/tasks/.agents/skills/actions/SKILL.md +19 -1
- package/corpus/templates/tasks/.agents/skills/adding-a-feature/SKILL.md +2 -0
- package/corpus/templates/tasks/.agents/skills/change-summary/SKILL.md +19 -1
- package/corpus/templates/tasks/.agents/skills/custom-fields/SKILL.md +63 -0
- package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +20 -6
- package/corpus/templates/tasks/.agents/skills/security/SKILL.md +2 -0
- package/corpus/templates/tasks/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/corpus/templates/tasks/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/corpus/templates/tasks/.agents/skills/sharing/SKILL.md +228 -0
- package/corpus/templates/tasks/.agents/skills/store-conventions/SKILL.md +45 -0
- package/corpus/templates/tasks/.agents/skills/storing-data/SKILL.md +178 -0
- package/corpus/templates/tasks/.agents/skills/task-inbox-workflow/SKILL.md +66 -0
- package/corpus/templates/tasks/AGENTS.md +48 -113
- package/corpus/templates/tasks/app/entry.client.tsx +3 -0
- package/corpus/toolkit/CHANGELOG.md +12 -0
- package/corpus/toolkit/package.json +1 -1
- package/corpus/toolkit/src/composer/PromptComposer.tsx +23 -20
- package/dist/a2a/client.d.ts +3 -1
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +4 -2
- package/dist/a2a/client.js.map +1 -1
- package/dist/agent/action-warnings.d.ts +27 -0
- package/dist/agent/action-warnings.d.ts.map +1 -0
- package/dist/agent/action-warnings.js +73 -0
- package/dist/agent/action-warnings.js.map +1 -0
- package/dist/agent/durable-background.d.ts +8 -0
- package/dist/agent/durable-background.d.ts.map +1 -1
- package/dist/agent/durable-background.js +37 -5
- package/dist/agent/durable-background.js.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.js +47 -6
- package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
- package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
- package/dist/agent/engine/anthropic-engine.js +41 -9
- package/dist/agent/engine/anthropic-engine.js.map +1 -1
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builder-engine.js +46 -19
- package/dist/agent/engine/builder-engine.js.map +1 -1
- package/dist/agent/engine/continuation-dispatch-retry.d.ts.map +1 -1
- package/dist/agent/engine/continuation-dispatch-retry.js +11 -9
- package/dist/agent/engine/continuation-dispatch-retry.js.map +1 -1
- package/dist/agent/engine/credential-errors.d.ts +6 -0
- package/dist/agent/engine/credential-errors.d.ts.map +1 -1
- package/dist/agent/engine/credential-errors.js +10 -0
- package/dist/agent/engine/credential-errors.js.map +1 -1
- package/dist/agent/engine/error-detail.d.ts +2 -0
- package/dist/agent/engine/error-detail.d.ts.map +1 -0
- package/dist/agent/engine/error-detail.js +37 -0
- package/dist/agent/engine/error-detail.js.map +1 -0
- package/dist/agent/engine/prompt-cache.d.ts +34 -0
- package/dist/agent/engine/prompt-cache.d.ts.map +1 -0
- package/dist/agent/engine/prompt-cache.js +39 -0
- package/dist/agent/engine/prompt-cache.js.map +1 -0
- package/dist/agent/engine/registry.d.ts.map +1 -1
- package/dist/agent/engine/registry.js +23 -33
- package/dist/agent/engine/registry.js.map +1 -1
- package/dist/agent/engine/tool-call-journal-seed.d.ts +1 -1
- package/dist/agent/engine/tool-call-journal-seed.d.ts.map +1 -1
- package/dist/agent/engine/tool-call-journal-seed.js +2 -2
- package/dist/agent/engine/tool-call-journal-seed.js.map +1 -1
- package/dist/agent/engine/translate-anthropic.d.ts +28 -0
- package/dist/agent/engine/translate-anthropic.d.ts.map +1 -1
- package/dist/agent/engine/translate-anthropic.js +75 -0
- package/dist/agent/engine/translate-anthropic.js.map +1 -1
- package/dist/agent/loop-settings.d.ts +35 -2
- package/dist/agent/loop-settings.d.ts.map +1 -1
- package/dist/agent/loop-settings.js +71 -8
- package/dist/agent/loop-settings.js.map +1 -1
- package/dist/agent/production-agent.d.ts +105 -20
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +516 -123
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
- package/dist/agent/run-loop-with-resume.js +24 -2
- package/dist/agent/run-loop-with-resume.js.map +1 -1
- package/dist/agent/run-manager.d.ts +52 -9
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +191 -36
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +87 -14
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +331 -59
- package/dist/agent/run-store.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +6 -1
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/agent/types.d.ts +18 -6
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js +9 -5
- package/dist/agent/types.js.map +1 -1
- package/dist/application-state/script-helpers.d.ts.map +1 -1
- package/dist/application-state/script-helpers.js +2 -2
- package/dist/application-state/script-helpers.js.map +1 -1
- package/dist/cli/agents.d.ts +2 -0
- package/dist/cli/agents.d.ts.map +1 -1
- package/dist/cli/agents.js +48 -1
- package/dist/cli/agents.js.map +1 -1
- package/dist/cli/app-skill.js +1 -1
- package/dist/cli/app-skill.js.map +1 -1
- package/dist/cli/code-agent-executor.d.ts.map +1 -1
- package/dist/cli/code-agent-executor.js +3 -3
- package/dist/cli/code-agent-executor.js.map +1 -1
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +73 -8
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/index.js +3 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp.d.ts.map +1 -1
- package/dist/cli/mcp.js +12 -3
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.d.ts.map +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.js +169 -24
- package/dist/cli/skills-content/design-visual-edit-skill.js.map +1 -1
- package/dist/cli/skills-content/rewind-skill.d.ts +1 -1
- package/dist/cli/skills-content/rewind-skill.d.ts.map +1 -1
- package/dist/cli/skills-content/rewind-skill.js +36 -4
- package/dist/cli/skills-content/rewind-skill.js.map +1 -1
- package/dist/cli/skills.d.ts +2 -0
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +191 -40
- package/dist/cli/skills.js.map +1 -1
- package/dist/cli/telemetry-routing.d.ts +2 -0
- package/dist/cli/telemetry-routing.d.ts.map +1 -0
- package/dist/cli/telemetry-routing.js +54 -0
- package/dist/cli/telemetry-routing.js.map +1 -0
- package/dist/cli/telemetry.js +3 -3
- package/dist/cli/telemetry.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +135 -125
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts +17 -0
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +141 -31
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +9 -1
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +12 -1
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/embed-auth.d.ts.map +1 -1
- package/dist/client/embed-auth.js +3 -1
- package/dist/client/embed-auth.js.map +1 -1
- package/dist/client/integrations/IntegrationCard.d.ts.map +1 -1
- package/dist/client/integrations/IntegrationCard.js +9 -4
- package/dist/client/integrations/IntegrationCard.js.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.d.ts.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.js +13 -7
- package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
- package/dist/client/integrations/webhook-url.d.ts +7 -0
- package/dist/client/integrations/webhook-url.d.ts.map +1 -0
- package/dist/client/integrations/webhook-url.js +32 -0
- package/dist/client/integrations/webhook-url.js.map +1 -0
- package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
- package/dist/client/org/OrgSwitcher.js +13 -11
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/org/RequireActiveOrg.d.ts.map +1 -1
- package/dist/client/org/RequireActiveOrg.js +2 -2
- package/dist/client/org/RequireActiveOrg.js.map +1 -1
- package/dist/client/org/TeamPage.d.ts.map +1 -1
- package/dist/client/org/TeamPage.js +52 -13
- package/dist/client/org/TeamPage.js.map +1 -1
- package/dist/client/org/hooks.d.ts +9 -0
- package/dist/client/org/hooks.d.ts.map +1 -1
- package/dist/client/org/hooks.js +24 -0
- package/dist/client/org/hooks.js.map +1 -1
- package/dist/client/org/index.d.ts +1 -1
- package/dist/client/org/index.d.ts.map +1 -1
- package/dist/client/org/index.js +1 -1
- package/dist/client/org/index.js.map +1 -1
- package/dist/client/require-session.d.ts +12 -17
- package/dist/client/require-session.d.ts.map +1 -1
- package/dist/client/require-session.js +36 -23
- package/dist/client/require-session.js.map +1 -1
- package/dist/client/session-replay.js +1 -1
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/settings/DemoModeSection.d.ts +0 -1
- package/dist/client/settings/DemoModeSection.d.ts.map +1 -1
- package/dist/client/settings/DemoModeSection.js +0 -4
- package/dist/client/settings/DemoModeSection.js.map +1 -1
- package/dist/client/settings/SecretsSection.d.ts.map +1 -1
- package/dist/client/settings/SecretsSection.js +12 -8
- package/dist/client/settings/SecretsSection.js.map +1 -1
- package/dist/client/settings/VoiceTranscriptionSection.d.ts +0 -1
- package/dist/client/settings/VoiceTranscriptionSection.d.ts.map +1 -1
- package/dist/client/settings/VoiceTranscriptionSection.js +1 -4
- package/dist/client/settings/VoiceTranscriptionSection.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +33 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +83 -8
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +23 -14
- package/dist/client/use-action.js.map +1 -1
- package/dist/client/use-agent-engine-configured.d.ts +9 -3
- package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
- package/dist/client/use-agent-engine-configured.js +30 -3
- package/dist/client/use-agent-engine-configured.js.map +1 -1
- package/dist/client/use-db-sync.d.ts +3 -0
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +18 -1
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/credentials/index.d.ts +29 -1
- package/dist/credentials/index.d.ts.map +1 -1
- package/dist/credentials/index.js +111 -2
- package/dist/credentials/index.js.map +1 -1
- package/dist/deploy/build.d.ts +14 -3
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +81 -24
- package/dist/deploy/build.js.map +1 -1
- package/dist/deploy/workspace-deploy.d.ts +15 -0
- package/dist/deploy/workspace-deploy.d.ts.map +1 -1
- package/dist/deploy/workspace-deploy.js +19 -18
- package/dist/deploy/workspace-deploy.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +3 -3
- package/dist/guards/no-localhost-fallback.d.ts +7 -0
- package/dist/guards/no-localhost-fallback.d.ts.map +1 -1
- package/dist/guards/no-localhost-fallback.js +75 -16
- package/dist/guards/no-localhost-fallback.js.map +1 -1
- package/dist/integrations/google-docs-poller.d.ts.map +1 -1
- package/dist/integrations/google-docs-poller.js +8 -3
- package/dist/integrations/google-docs-poller.js.map +1 -1
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +22 -4
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/jobs/scheduler.d.ts +17 -0
- package/dist/jobs/scheduler.d.ts.map +1 -1
- package/dist/jobs/scheduler.js +60 -33
- package/dist/jobs/scheduler.js.map +1 -1
- package/dist/localization/default-messages.d.ts +17 -1
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +17 -1
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/mcp/screen-memory-stdio.d.ts +2 -0
- package/dist/mcp/screen-memory-stdio.d.ts.map +1 -1
- package/dist/mcp/screen-memory-stdio.js +12 -2
- package/dist/mcp/screen-memory-stdio.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/evals.d.ts.map +1 -1
- package/dist/observability/evals.js +7 -10
- package/dist/observability/evals.js.map +1 -1
- package/dist/observability/traces.d.ts +2 -0
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js.map +1 -1
- package/dist/org/accept-pending.js +2 -2
- package/dist/org/accept-pending.js.map +1 -1
- package/dist/org/active-org.d.ts +16 -0
- package/dist/org/active-org.d.ts.map +1 -0
- package/dist/org/active-org.js +57 -0
- package/dist/org/active-org.js.map +1 -0
- package/dist/org/auto-join-domain.d.ts.map +1 -1
- package/dist/org/auto-join-domain.js +3 -2
- package/dist/org/auto-join-domain.js.map +1 -1
- package/dist/org/context.d.ts +19 -1
- package/dist/org/context.d.ts.map +1 -1
- package/dist/org/context.js +159 -71
- package/dist/org/context.js.map +1 -1
- package/dist/org/handlers.d.ts +24 -1
- package/dist/org/handlers.d.ts.map +1 -1
- package/dist/org/handlers.js +129 -10
- package/dist/org/handlers.js.map +1 -1
- package/dist/org/plugin.d.ts +2 -0
- package/dist/org/plugin.d.ts.map +1 -1
- package/dist/org/plugin.js +9 -2
- package/dist/org/plugin.js.map +1 -1
- package/dist/org/types.d.ts +6 -1
- package/dist/org/types.d.ts.map +1 -1
- package/dist/org/types.js.map +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +9 -9
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +3 -2
- package/dist/provider-api/index.js.map +1 -1
- package/dist/resources/handlers.d.ts.map +1 -1
- package/dist/resources/handlers.js +2 -7
- package/dist/resources/handlers.js.map +1 -1
- package/dist/resources/script-helpers.d.ts.map +1 -1
- package/dist/resources/script-helpers.js +2 -2
- package/dist/resources/script-helpers.js.map +1 -1
- package/dist/scripts/chat/search-chats.d.ts.map +1 -1
- package/dist/scripts/chat/search-chats.js +2 -2
- package/dist/scripts/chat/search-chats.js.map +1 -1
- package/dist/scripts/describe-workspace-apps.d.ts +4 -0
- package/dist/scripts/describe-workspace-apps.d.ts.map +1 -0
- package/dist/scripts/describe-workspace-apps.js +34 -0
- package/dist/scripts/describe-workspace-apps.js.map +1 -0
- package/dist/scripts/resources/delete-memory.d.ts.map +1 -1
- package/dist/scripts/resources/delete-memory.js +2 -2
- package/dist/scripts/resources/delete-memory.js.map +1 -1
- package/dist/scripts/resources/delete.d.ts.map +1 -1
- package/dist/scripts/resources/delete.js +2 -2
- package/dist/scripts/resources/delete.js.map +1 -1
- package/dist/scripts/resources/effective.d.ts.map +1 -1
- package/dist/scripts/resources/effective.js +2 -2
- package/dist/scripts/resources/effective.js.map +1 -1
- package/dist/scripts/resources/list.d.ts.map +1 -1
- package/dist/scripts/resources/list.js +2 -2
- package/dist/scripts/resources/list.js.map +1 -1
- package/dist/scripts/resources/read.d.ts.map +1 -1
- package/dist/scripts/resources/read.js +2 -2
- package/dist/scripts/resources/read.js.map +1 -1
- package/dist/scripts/resources/save-memory.d.ts.map +1 -1
- package/dist/scripts/resources/save-memory.js +2 -2
- package/dist/scripts/resources/save-memory.js.map +1 -1
- package/dist/scripts/resources/write.d.ts.map +1 -1
- package/dist/scripts/resources/write.js +2 -2
- package/dist/scripts/resources/write.js.map +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-capabilities.d.ts +21 -0
- package/dist/server/agent-capabilities.d.ts.map +1 -0
- package/dist/server/agent-capabilities.js +106 -0
- package/dist/server/agent-capabilities.js.map +1 -0
- package/dist/server/agent-chat/framework-prompts.d.ts.map +1 -1
- package/dist/server/agent-chat/framework-prompts.js +11 -13
- package/dist/server/agent-chat/framework-prompts.js.map +1 -1
- package/dist/server/agent-chat/prompt-resources.d.ts +32 -0
- package/dist/server/agent-chat/prompt-resources.d.ts.map +1 -1
- package/dist/server/agent-chat/prompt-resources.js +117 -56
- package/dist/server/agent-chat/prompt-resources.js.map +1 -1
- package/dist/server/agent-chat/script-entries.d.ts.map +1 -1
- package/dist/server/agent-chat/script-entries.js +18 -8
- package/dist/server/agent-chat/script-entries.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +27 -1
- 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/auth.d.ts +9 -9
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +32 -33
- package/dist/server/auth.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +45 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +162 -139
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts +35 -2
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +155 -40
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/server/embed-session.d.ts.map +1 -1
- package/dist/server/embed-session.js +10 -0
- package/dist/server/embed-session.js.map +1 -1
- package/dist/server/framework-request-handler.d.ts.map +1 -1
- package/dist/server/framework-request-handler.js +38 -0
- package/dist/server/framework-request-handler.js.map +1 -1
- package/dist/server/google-auth-plugin.d.ts.map +1 -1
- package/dist/server/google-auth-plugin.js +12 -444
- package/dist/server/google-auth-plugin.js.map +1 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -2
- package/dist/server/index.js.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +20 -56
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/server/open-route.d.ts.map +1 -1
- package/dist/server/open-route.js +6 -1
- package/dist/server/open-route.js.map +1 -1
- package/dist/server/poll.js +1 -1
- package/dist/server/poll.js.map +1 -1
- package/dist/server/prompts/framework-core-compact.d.ts.map +1 -1
- package/dist/server/prompts/framework-core-compact.js +5 -6
- package/dist/server/prompts/framework-core-compact.js.map +1 -1
- package/dist/server/prompts/framework-core.d.ts.map +1 -1
- package/dist/server/prompts/framework-core.js +7 -10
- package/dist/server/prompts/framework-core.js.map +1 -1
- package/dist/server/prompts/shared-rules.d.ts +20 -2
- package/dist/server/prompts/shared-rules.d.ts.map +1 -1
- package/dist/server/prompts/shared-rules.js +20 -10
- package/dist/server/prompts/shared-rules.js.map +1 -1
- package/dist/server/request-context.d.ts +26 -1
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/request-context.js +52 -2
- package/dist/server/request-context.js.map +1 -1
- package/dist/server/scoped-key-storage.js +1 -1
- package/dist/server/scoped-key-storage.js.map +1 -1
- package/dist/settings/org-settings.d.ts +2 -0
- package/dist/settings/org-settings.d.ts.map +1 -1
- package/dist/settings/org-settings.js +5 -1
- package/dist/settings/org-settings.js.map +1 -1
- package/dist/settings/store.d.ts +6 -0
- package/dist/settings/store.d.ts.map +1 -1
- package/dist/settings/store.js +25 -0
- package/dist/settings/store.js.map +1 -1
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +1 -0
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/sign-in-journey.d.ts +102 -0
- package/dist/shared/sign-in-journey.d.ts.map +1 -0
- package/dist/shared/sign-in-journey.js +269 -0
- package/dist/shared/sign-in-journey.js.map +1 -0
- package/dist/styles/agent-native.css +8 -0
- package/dist/templates/chat/.agents/skills/actions/SKILL.md +19 -1
- package/dist/templates/chat/.agents/skills/adding-a-feature/SKILL.md +2 -0
- package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +20 -6
- package/dist/templates/chat/.agents/skills/security/SKILL.md +2 -0
- package/dist/templates/chat/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/dist/templates/chat/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/dist/templates/chat/.agents/skills/sharing/SKILL.md +228 -0
- package/dist/templates/chat/.agents/skills/storing-data/SKILL.md +178 -0
- package/dist/templates/chat/AGENTS.md +8 -0
- package/dist/templates/chat/app/entry.client.tsx +3 -0
- package/dist/templates/default/.agents/skills/actions/SKILL.md +19 -1
- package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +2 -0
- package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +20 -6
- package/dist/templates/default/.agents/skills/security/SKILL.md +2 -0
- package/dist/templates/default/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/dist/templates/default/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/dist/templates/default/AGENTS.md +68 -195
- package/dist/templates/default/app/entry.client.tsx +3 -0
- package/dist/templates/default/app/i18n/ar-SA.ts +8 -0
- package/dist/templates/default/app/i18n/de-DE.ts +8 -0
- package/dist/templates/default/app/i18n/en-US.ts +8 -0
- package/dist/templates/default/app/i18n/es-ES.ts +8 -0
- package/dist/templates/default/app/i18n/fr-FR.ts +8 -0
- package/dist/templates/default/app/i18n/hi-IN.ts +8 -0
- package/dist/templates/default/app/i18n/ja-JP.ts +8 -0
- package/dist/templates/default/app/i18n/ko-KR.ts +8 -0
- package/dist/templates/default/app/i18n/pt-BR.ts +8 -0
- package/dist/templates/default/app/i18n/zh-CN.ts +8 -0
- package/dist/templates/default/app/i18n/zh-TW.ts +8 -0
- package/dist/templates/headless/.agents/skills/actions/SKILL.md +19 -1
- package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +19 -1
- package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +2 -0
- package/dist/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +100 -0
- package/dist/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +2 -1
- package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +28 -0
- package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +14 -1
- package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +20 -6
- package/dist/templates/workspace-core/.agents/skills/qa/SKILL.md +6 -3
- package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +2 -0
- package/dist/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/dist/templates/workspace-core/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/dist/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +91 -0
- package/dist/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +60 -0
- package/dist/templates/workspace-core/AGENTS.md +62 -124
- package/dist/templates/workspace-root/AGENTS.md +6 -1
- package/dist/triggers/dispatcher.d.ts.map +1 -1
- package/dist/triggers/dispatcher.js +10 -3
- package/dist/triggers/dispatcher.js.map +1 -1
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +18 -8
- package/dist/vite/client.js.map +1 -1
- package/docs/content/actions.mdx +33 -20
- package/docs/content/agent-mentions.mdx +30 -19
- package/docs/content/agent-native-toolkit.mdx +8 -6
- package/docs/content/agent-resources.mdx +11 -0
- package/docs/content/agent-surfaces.mdx +41 -30
- package/docs/content/audit-log.mdx +78 -0
- package/docs/content/authentication.mdx +7 -5
- package/docs/content/automations.mdx +15 -9
- package/docs/content/client.mdx +11 -11
- package/docs/content/cloneable-saas.mdx +7 -1
- package/docs/content/code-agents-ui.mdx +9 -1
- package/docs/content/components.mdx +7 -0
- package/docs/content/context-awareness.mdx +1 -0
- package/docs/content/creating-templates.mdx +9 -1
- package/docs/content/custom-design-system.mdx +8 -0
- package/docs/content/data-programs.mdx +6 -0
- package/docs/content/deployment.mdx +2 -0
- package/docs/content/doctor.mdx +5 -3
- package/docs/content/extensions.mdx +26 -0
- package/docs/content/external-agents-catalog.mdx +533 -0
- package/docs/content/external-agents.mdx +20 -514
- package/docs/content/faq.mdx +2 -2
- package/docs/content/file-uploads.mdx +44 -0
- package/docs/content/frames.mdx +2 -2
- package/docs/content/generative-ui.mdx +8 -0
- package/docs/content/getting-started.mdx +45 -17
- package/docs/content/human-approval.mdx +9 -0
- package/docs/content/integrations.mdx +4 -3
- package/docs/content/internationalization.mdx +4 -11
- package/docs/content/key-concepts.mdx +1 -1
- package/docs/content/local-file-mode.mdx +5 -0
- package/docs/content/mcp-apps.mdx +2 -1
- package/docs/content/mcp-clients.mdx +32 -1
- package/docs/content/mcp-protocol.mdx +4 -3
- package/docs/content/messaging-internals.mdx +328 -0
- package/docs/content/messaging-recipes.mdx +194 -0
- package/docs/content/messaging.mdx +9 -307
- package/docs/content/multi-app-workspace.mdx +1 -1
- package/docs/content/multi-tenancy.mdx +1 -0
- package/docs/content/native-chat-ui.mdx +8 -0
- package/docs/content/notifications.mdx +18 -20
- package/docs/content/observability.mdx +1 -0
- package/docs/content/onboarding.mdx +20 -6
- package/docs/content/organizations-teams-permissions.mdx +99 -124
- package/docs/content/package-lifecycle.mdx +19 -7
- package/docs/content/progress.mdx +11 -0
- package/docs/content/real-time-collaboration.mdx +44 -3
- package/docs/content/recurring-jobs.mdx +14 -1
- package/docs/content/security.mdx +5 -2
- package/docs/content/server.mdx +2 -1
- package/docs/content/sharing.mdx +22 -3
- package/docs/content/skills-guide.mdx +62 -19
- package/docs/content/syncing-template-changes.mdx +9 -0
- package/docs/content/template-analytics-connectors.mdx +75 -0
- package/docs/content/template-analytics-dashboards.mdx +106 -0
- package/docs/content/template-analytics-developers.mdx +287 -0
- package/docs/content/template-analytics-monitoring-and-sessions.mdx +109 -0
- package/docs/content/template-analytics.mdx +21 -263
- package/docs/content/template-assets-developers.mdx +456 -0
- package/docs/content/template-assets-generation.mdx +147 -0
- package/docs/content/template-assets-integrations.mdx +319 -0
- package/docs/content/template-assets-presets.mdx +185 -0
- package/docs/content/template-assets.mdx +12 -562
- package/docs/content/template-brain-agent.mdx +103 -0
- package/docs/content/template-brain-developers.mdx +379 -0
- package/docs/content/template-brain-knowledge.mdx +50 -0
- package/docs/content/template-brain-sources.mdx +163 -0
- package/docs/content/template-brain.mdx +30 -390
- package/docs/content/template-calendar-agent.mdx +133 -0
- package/docs/content/template-calendar-booking-links.mdx +73 -0
- package/docs/content/template-calendar-developers.mdx +366 -0
- package/docs/content/template-calendar-scheduling.mdx +128 -0
- package/docs/content/template-calendar.mdx +13 -260
- package/docs/content/template-chat-developers.mdx +88 -0
- package/docs/content/template-chat-first-edits.mdx +145 -0
- package/docs/content/template-chat.mdx +12 -77
- package/docs/content/template-clips-ai-and-editing.mdx +114 -0
- package/docs/content/template-clips-capture-everywhere.mdx +120 -0
- package/docs/content/template-clips-developers.mdx +373 -0
- package/docs/content/template-clips-sharing-and-teams.mdx +182 -0
- package/docs/content/template-clips.mdx +19 -508
- package/docs/content/template-content-databases.mdx +406 -0
- package/docs/content/template-content-developers.mdx +364 -0
- package/docs/content/template-content-editing.mdx +60 -0
- package/docs/content/template-content-sync.mdx +149 -0
- package/docs/content/template-content.mdx +21 -561
- package/docs/content/template-design-brand-and-figma.mdx +150 -0
- package/docs/content/template-design-collaboration-and-full-apps.mdx +125 -0
- package/docs/content/template-design-developers.mdx +358 -0
- package/docs/content/template-design-quality-and-components.mdx +95 -0
- package/docs/content/template-design.mdx +20 -344
- package/docs/content/template-dispatch-developers.mdx +121 -0
- package/docs/content/template-dispatch-messaging-routing.mdx +114 -0
- package/docs/content/template-dispatch-operations.mdx +160 -0
- package/docs/content/template-dispatch-vault-integrations.mdx +316 -0
- package/docs/content/template-dispatch.mdx +24 -283
- package/docs/content/template-forms-building-publishing.mdx +135 -0
- package/docs/content/template-forms-developers.mdx +195 -0
- package/docs/content/template-forms-responses.mdx +120 -0
- package/docs/content/template-forms.mdx +21 -230
- package/docs/content/template-mail-agent.mdx +114 -0
- package/docs/content/template-mail-developers.mdx +356 -0
- package/docs/content/template-mail-drafts-and-queue.mdx +103 -0
- package/docs/content/template-mail-inbox.mdx +118 -0
- package/docs/content/template-mail.mdx +23 -274
- package/docs/content/template-plan-automations.mdx +213 -0
- package/docs/content/template-plan-developers.mdx +703 -0
- package/docs/content/template-plan-local-and-desktop.mdx +236 -0
- package/docs/content/template-plan-review-workflow.mdx +180 -0
- package/docs/content/template-plan.mdx +60 -910
- package/docs/content/template-slides-agent.mdx +102 -0
- package/docs/content/template-slides-design-and-media.mdx +94 -0
- package/docs/content/template-slides-developers.mdx +488 -0
- package/docs/content/template-slides-editing.mdx +56 -0
- package/docs/content/template-slides.mdx +20 -362
- package/docs/content/toolkit-capability-packages.mdx +38 -13
- package/docs/content/toolkit-context-knowledge.mdx +49 -9
- package/docs/content/toolkit-editors-canvases.mdx +72 -10
- package/docs/content/toolkit-resources.mdx +16 -0
- package/docs/content/toolkit-settings.mdx +3 -3
- package/docs/content/toolkit-sharing.mdx +5 -7
- package/docs/content/using-your-agent.mdx +25 -2
- package/docs/content/voice-input.mdx +11 -7
- package/docs/content/what-is-agent-native.mdx +1 -0
- package/docs/content/workspace-connections.mdx +21 -11
- package/docs/content/workspace-management.mdx +1 -1
- package/package.json +2 -4
- package/src/a2a/client.ts +4 -2
- package/src/agent/action-warnings.ts +103 -0
- package/src/agent/durable-background.ts +42 -5
- package/src/agent/engine/ai-sdk-engine.ts +58 -6
- package/src/agent/engine/anthropic-engine.ts +51 -8
- package/src/agent/engine/builder-engine.ts +56 -18
- package/src/agent/engine/continuation-dispatch-retry.ts +10 -9
- package/src/agent/engine/credential-errors.ts +11 -0
- package/src/agent/engine/error-detail.ts +39 -0
- package/src/agent/engine/prompt-cache.ts +44 -0
- package/src/agent/engine/registry.ts +22 -30
- package/src/agent/engine/tool-call-journal-seed.ts +2 -1
- package/src/agent/engine/translate-anthropic.ts +99 -0
- package/src/agent/loop-settings.ts +94 -7
- package/src/agent/production-agent.ts +667 -157
- package/src/agent/run-loop-with-resume.ts +27 -1
- package/src/agent/run-manager.ts +229 -39
- package/src/agent/run-store.ts +397 -64
- package/src/agent/thread-data-builder.ts +5 -1
- package/src/agent/types.ts +23 -6
- package/src/application-state/script-helpers.ts +5 -2
- package/src/cli/agents.ts +69 -1
- package/src/cli/app-skill.ts +1 -1
- package/src/cli/code-agent-executor.ts +7 -3
- package/src/cli/design-connect.ts +82 -8
- package/src/cli/index.ts +2 -1
- package/src/cli/mcp.ts +13 -3
- package/src/cli/skills-content/design-visual-edit-skill.ts +169 -24
- package/src/cli/skills-content/rewind-skill.ts +36 -4
- package/src/cli/skills.ts +250 -37
- package/src/cli/telemetry-routing.ts +57 -0
- package/src/cli/telemetry.ts +3 -3
- package/src/client/AssistantChat.tsx +623 -607
- package/src/client/agent-chat-adapter.ts +176 -29
- package/src/client/chat/message-components.tsx +13 -0
- package/src/client/embed-auth.ts +3 -1
- package/src/client/integrations/IntegrationCard.tsx +41 -24
- package/src/client/integrations/IntegrationsPanel.tsx +37 -21
- package/src/client/integrations/webhook-url.ts +29 -0
- package/src/client/org/OrgSwitcher.tsx +41 -27
- package/src/client/org/RequireActiveOrg.tsx +7 -0
- package/src/client/org/TeamPage.tsx +144 -14
- package/src/client/org/hooks.ts +27 -0
- package/src/client/org/index.ts +2 -0
- package/src/client/require-session.tsx +40 -29
- package/src/client/session-replay.ts +1 -1
- package/src/client/settings/DemoModeSection.tsx +0 -5
- package/src/client/settings/SecretsSection.tsx +47 -42
- package/src/client/settings/VoiceTranscriptionSection.tsx +0 -5
- package/src/client/sse-event-processor.ts +83 -8
- package/src/client/use-action.ts +22 -13
- package/src/client/use-agent-engine-configured.ts +36 -4
- package/src/client/use-db-sync.ts +21 -1
- package/src/credentials/index.ts +124 -2
- package/src/deploy/build.ts +93 -30
- package/src/deploy/workspace-deploy.ts +21 -16
- package/src/guards/no-localhost-fallback.ts +76 -14
- package/src/integrations/google-docs-poller.ts +19 -12
- package/src/integrations/webhook-handler.ts +56 -33
- package/src/jobs/scheduler.ts +57 -23
- package/src/localization/default-messages.ts +23 -1
- package/src/mcp/screen-memory-stdio.ts +21 -2
- package/src/observability/evals.ts +7 -8
- package/src/observability/traces.ts +2 -0
- package/src/org/accept-pending.ts +2 -2
- package/src/org/active-org.ts +73 -0
- package/src/org/auto-join-domain.ts +7 -2
- package/src/org/context.ts +169 -66
- package/src/org/handlers.ts +148 -10
- package/src/org/plugin.ts +8 -1
- package/src/org/types.ts +6 -1
- package/src/provider-api/index.ts +6 -1
- package/src/resources/handlers.ts +2 -6
- package/src/resources/script-helpers.ts +2 -1
- package/src/scripts/chat/search-chats.ts +5 -2
- package/src/scripts/describe-workspace-apps.ts +59 -0
- package/src/scripts/resources/delete-memory.ts +5 -2
- package/src/scripts/resources/delete.ts +5 -2
- package/src/scripts/resources/effective.ts +5 -2
- package/src/scripts/resources/list.ts +5 -2
- package/src/scripts/resources/read.ts +5 -2
- package/src/scripts/resources/save-memory.ts +5 -2
- package/src/scripts/resources/write.ts +5 -2
- package/src/server/__snapshots__/agent-chat-plugin.surface.spec.ts.snap +11 -31
- package/src/server/agent-capabilities.ts +147 -0
- package/src/server/agent-chat/framework-prompts.ts +11 -13
- package/src/server/agent-chat/prompt-resources.ts +183 -57
- package/src/server/agent-chat/script-entries.ts +20 -7
- package/src/server/agent-chat-plugin.ts +27 -0
- package/src/server/auth.ts +38 -32
- package/src/server/core-routes-plugin.ts +229 -179
- package/src/server/credential-provider.ts +196 -44
- package/src/server/embed-session.ts +10 -0
- package/src/server/framework-request-handler.ts +43 -0
- package/src/server/google-auth-plugin.ts +13 -450
- package/src/server/index.ts +4 -1
- package/src/server/onboarding-html.ts +20 -56
- package/src/server/open-route.ts +6 -1
- package/src/server/poll.ts +1 -1
- package/src/server/prompts/framework-core-compact.ts +5 -5
- package/src/server/prompts/framework-core.ts +7 -9
- package/src/server/prompts/shared-rules.ts +20 -9
- package/src/server/request-context.ts +58 -2
- package/src/server/scoped-key-storage.ts +1 -1
- package/src/settings/org-settings.ts +9 -0
- package/src/settings/store.ts +29 -0
- package/src/shared/index.ts +13 -0
- package/src/shared/sign-in-journey.ts +331 -0
- package/src/styles/agent-native.css +8 -0
- package/src/templates/chat/.agents/skills/actions/SKILL.md +19 -1
- package/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +2 -0
- package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +20 -6
- package/src/templates/chat/.agents/skills/security/SKILL.md +2 -0
- package/src/templates/chat/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/src/templates/chat/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/src/templates/chat/.agents/skills/sharing/SKILL.md +228 -0
- package/src/templates/chat/.agents/skills/storing-data/SKILL.md +178 -0
- package/src/templates/chat/AGENTS.md +8 -0
- package/src/templates/chat/app/entry.client.tsx +3 -0
- package/src/templates/default/.agents/skills/actions/SKILL.md +19 -1
- package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +2 -0
- package/src/templates/default/.agents/skills/frontend-design/SKILL.md +20 -6
- package/src/templates/default/.agents/skills/security/SKILL.md +2 -0
- package/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/src/templates/default/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/src/templates/default/AGENTS.md +68 -195
- package/src/templates/default/app/entry.client.tsx +3 -0
- package/src/templates/default/app/i18n/ar-SA.ts +8 -0
- package/src/templates/default/app/i18n/de-DE.ts +8 -0
- package/src/templates/default/app/i18n/en-US.ts +8 -0
- package/src/templates/default/app/i18n/es-ES.ts +8 -0
- package/src/templates/default/app/i18n/fr-FR.ts +8 -0
- package/src/templates/default/app/i18n/hi-IN.ts +8 -0
- package/src/templates/default/app/i18n/ja-JP.ts +8 -0
- package/src/templates/default/app/i18n/ko-KR.ts +8 -0
- package/src/templates/default/app/i18n/pt-BR.ts +8 -0
- package/src/templates/default/app/i18n/zh-CN.ts +8 -0
- package/src/templates/default/app/i18n/zh-TW.ts +8 -0
- package/src/templates/headless/.agents/skills/actions/SKILL.md +19 -1
- package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +19 -1
- package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +2 -0
- package/src/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +100 -0
- package/src/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +2 -1
- package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +28 -0
- package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +14 -1
- package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +20 -6
- package/src/templates/workspace-core/.agents/skills/qa/SKILL.md +6 -3
- package/src/templates/workspace-core/.agents/skills/security/SKILL.md +2 -0
- package/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +4 -3
- package/src/templates/workspace-core/.agents/skills/shadcn-ui/SKILL.md +7 -3
- package/src/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +91 -0
- package/src/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +60 -0
- package/src/templates/workspace-core/AGENTS.md +62 -124
- package/src/templates/workspace-root/AGENTS.md +6 -1
- package/src/triggers/dispatcher.ts +28 -17
- package/src/vite/client.ts +20 -8
- package/corpus/core/src/client/components/MissingKeyCard.tsx +0 -61
- package/corpus/core/src/client/extensions/agent-native-extension-runtime.ts +0 -495
- package/corpus/core/src/client/settings/BackgroundAgentSection.tsx +0 -193
- package/corpus/core/src/client/settings/BrowserSection.tsx +0 -110
- package/corpus/templates/analytics/app/components/InlineMetric.tsx +0 -31
- package/corpus/templates/analytics/app/components/auth/LoginScreen.tsx +0 -4
- package/corpus/templates/analytics/app/components/dashboard/CumulativeNetChart.tsx +0 -128
- package/corpus/templates/analytics/app/components/dashboard/DataTable.tsx +0 -264
- package/corpus/templates/analytics/app/components/dashboard/RecentActivity.tsx +0 -84
- package/corpus/templates/analytics/app/components/dashboard/RevenueChart.tsx +0 -92
- package/corpus/templates/analytics/app/components/dashboard/RevenueComparisonChart.tsx +0 -154
- package/corpus/templates/analytics/app/components/dashboard/StatsCard.tsx +0 -49
- package/corpus/templates/analytics/app/components/dashboard/TimeSeriesChart.tsx +0 -120
- package/corpus/templates/analytics/server/handlers/dashboard-views.ts +0 -85
- package/corpus/templates/analytics/server/handlers/user-prefs.ts +0 -58
- package/corpus/templates/analytics/server/routes/api/dashboard-views/[dashboardId]/[viewId].delete.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/dashboard-views/[dashboardId].get.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/dashboard-views/[dashboardId].post.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/theme.get.ts +0 -17
- package/corpus/templates/analytics/server/routes/api/theme.post.ts +0 -15
- package/corpus/templates/analytics/server/routes/api/user-prefs/[key].delete.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/user-prefs/[key].get.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/user-prefs/[key].put.ts +0 -1
- package/corpus/templates/assets/app/components/library/CreateLibraryDialog.tsx +0 -156
- package/corpus/templates/assets/app/components/library/LibraryCard.tsx +0 -213
- package/corpus/templates/calendar/app/components/calendar/GoogleSyncButton.tsx +0 -49
- package/corpus/templates/calendar/server/routes/api/events/[id].delete.ts +0 -1
- package/corpus/templates/calendar/server/routes/api/events/[id].get.ts +0 -1
- package/corpus/templates/calendar/server/routes/api/events/[id].put.ts +0 -1
- package/corpus/templates/content/app/components/layout/AppLayout.tsx +0 -9
- package/corpus/templates/content/server/routes/api/comments/[id].delete.ts +0 -69
- package/corpus/templates/content/server/routes/api/comments/[id].patch.ts +0 -109
- package/corpus/templates/content/server/routes/api/documents/[id]/versions.get.ts +0 -53
- package/corpus/templates/design/app/components/design/code-workbench/ActivityBar.tsx +0 -85
- package/corpus/templates/design/app/components/design-system/DesignSystemCard.tsx +0 -129
- package/corpus/templates/forms/app/components/layout/AppLayout.tsx +0 -9
- package/corpus/templates/mail/app/components/email/SnoozePopover.tsx +0 -213
- package/corpus/templates/mail/server/handlers/aliases.ts +0 -98
- package/corpus/templates/mail/server/routes/api/aliases/[id].delete.ts +0 -1
- package/corpus/templates/mail/server/routes/api/aliases/[id].patch.ts +0 -1
- package/corpus/templates/mail/server/routes/api/aliases/index.get.ts +0 -1
- package/corpus/templates/mail/server/routes/api/aliases/index.post.ts +0 -1
- package/corpus/templates/mail/server/routes/api/automations/[id].delete.ts +0 -1
- package/corpus/templates/mail/server/routes/api/automations/[id].patch.ts +0 -1
- package/corpus/templates/mail/server/routes/api/automations/index.get.ts +0 -1
- package/corpus/templates/mail/server/routes/api/automations/index.post.ts +0 -1
- package/corpus/templates/mail/server/routes/api/automations/settings.get.ts +0 -22
- package/corpus/templates/mail/server/routes/api/automations/settings.put.ts +0 -25
- package/corpus/templates/mail/server/routes/api/scheduled-jobs/[id].delete.ts +0 -1
- package/corpus/templates/mail/server/routes/api/scheduled-jobs/[id].patch.ts +0 -1
- package/corpus/templates/mail/server/routes/api/scheduled-jobs/index.get.ts +0 -1
- package/corpus/templates/mail/server/routes/api/scheduled-jobs/index.post.ts +0 -1
- package/corpus/templates/mail/server/routes/api/settings.get.ts +0 -1
- package/corpus/templates/mail/server/routes/api/settings.patch.ts +0 -1
- package/corpus/templates/slides/app/components/deck/BuilderLogo.tsx +0 -22
- package/corpus/templates/slides/app/components/design-system/DesignSystemPreview.tsx +0 -176
- package/corpus/templates/slides/app/components/editor/GenerateSlidesDialog.tsx +0 -244
- package/corpus/templates/slides/app/components/editor/ImportButton.tsx +0 -84
- package/corpus/templates/slides/server/routes/api/comments/[id].delete.ts +0 -43
- package/corpus/templates/slides/server/routes/api/comments/[id].patch.ts +0 -50
- package/corpus/templates/slides/server/routes/api/decks/[id].delete.ts +0 -1
- package/corpus/templates/slides/server/routes/api/decks/[id].get.ts +0 -1
- package/corpus/templates/slides/server/routes/api/decks/[id].put.ts +0 -1
- package/corpus/templates/slides/server/routes/api/decks/index.get.ts +0 -1
- package/corpus/templates/slides/server/routes/api/decks/index.post.ts +0 -1
- package/dist/client/components/MissingKeyCard.d.ts +0 -7
- package/dist/client/components/MissingKeyCard.d.ts.map +0 -1
- package/dist/client/components/MissingKeyCard.js +0 -32
- package/dist/client/components/MissingKeyCard.js.map +0 -1
- package/dist/client/extensions/agent-native-extension-runtime.d.ts +0 -69
- package/dist/client/extensions/agent-native-extension-runtime.d.ts.map +0 -1
- package/dist/client/extensions/agent-native-extension-runtime.js +0 -348
- package/dist/client/extensions/agent-native-extension-runtime.js.map +0 -1
- package/dist/client/settings/BackgroundAgentSection.d.ts +0 -2
- package/dist/client/settings/BackgroundAgentSection.d.ts.map +0 -1
- package/dist/client/settings/BackgroundAgentSection.js +0 -68
- package/dist/client/settings/BackgroundAgentSection.js.map +0 -1
- package/dist/client/settings/BrowserSection.d.ts +0 -2
- package/dist/client/settings/BrowserSection.d.ts.map +0 -1
- package/dist/client/settings/BrowserSection.js +0 -40
- package/dist/client/settings/BrowserSection.js.map +0 -1
- package/dist/templates/chat/.react-router/types/+server-build.d.ts +0 -18
- package/dist/templates/chat/.react-router/types/app/+types/root.ts +0 -68
- package/src/client/components/MissingKeyCard.tsx +0 -61
- package/src/client/extensions/agent-native-extension-runtime.ts +0 -495
- package/src/client/settings/BackgroundAgentSection.tsx +0 -193
- package/src/client/settings/BrowserSection.tsx +0 -110
- package/src/templates/chat/.react-router/types/+server-build.d.ts +0 -18
- package/src/templates/chat/.react-router/types/app/+types/root.ts +0 -68
|
@@ -1,32 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { readdir, rm, stat } from "node:fs/promises";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import { join } from "node:path";
|
|
1
|
+
import { getAppProductionUrl, sendEmail } from "@agent-native/core/server";
|
|
6
2
|
|
|
7
|
-
import {
|
|
8
|
-
getAppProductionUrl,
|
|
9
|
-
sendEmail,
|
|
10
|
-
signEmbedSessionToken,
|
|
11
|
-
} from "@agent-native/core/server";
|
|
12
|
-
import {
|
|
13
|
-
EMBED_MODE_QUERY_PARAM,
|
|
14
|
-
EMBED_SESSION_COOKIE,
|
|
15
|
-
EMBED_TOKEN_QUERY_PARAM,
|
|
16
|
-
} from "@agent-native/core/shared";
|
|
17
|
-
|
|
18
|
-
import { interpolate } from "../../app/pages/adhoc/sql-dashboard/interpolate";
|
|
19
|
-
import { serializePanelSql } from "../../app/pages/adhoc/sql-dashboard/panel-sql";
|
|
20
|
-
import {
|
|
21
|
-
listReportablePanelIds,
|
|
22
|
-
REPORT_PANEL_CHUNK_SIZE,
|
|
23
|
-
} from "../../app/pages/adhoc/sql-dashboard/report-panel-window";
|
|
3
|
+
import { listReportablePanelIds } from "../../app/pages/adhoc/sql-dashboard/report-panel-window";
|
|
24
4
|
import type {
|
|
25
5
|
DashboardFilter,
|
|
26
6
|
FilterType,
|
|
27
7
|
SqlDashboardConfig,
|
|
28
8
|
} from "../../app/pages/adhoc/sql-dashboard/types";
|
|
29
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
fetchReportPanelData,
|
|
11
|
+
renderReportEmail,
|
|
12
|
+
type ReportSnapshot,
|
|
13
|
+
} from "./dashboard-report-render";
|
|
30
14
|
import {
|
|
31
15
|
getReportDashboard,
|
|
32
16
|
normalizeDashboardReportRecipients,
|
|
@@ -34,67 +18,25 @@ import {
|
|
|
34
18
|
type DashboardReportCaptureOutcome,
|
|
35
19
|
type DashboardReportSubscription,
|
|
36
20
|
} from "./dashboard-report-subscriptions";
|
|
37
|
-
import { queryFirstPartyAnalytics } from "./first-party-analytics.js";
|
|
38
|
-
|
|
39
|
-
type ReportSnapshot = {
|
|
40
|
-
dashboardId: string;
|
|
41
|
-
title: string;
|
|
42
|
-
description?: string;
|
|
43
|
-
filters: Record<string, string>;
|
|
44
|
-
dashboardUrl: string;
|
|
45
|
-
reportSettingsUrl: string;
|
|
46
|
-
generatedAt: string;
|
|
47
|
-
panelIds: string[];
|
|
48
|
-
panels: SqlDashboardConfig["panels"];
|
|
49
|
-
variables?: Record<string, string>;
|
|
50
|
-
};
|
|
51
21
|
|
|
52
22
|
const DATE_FILTER_TYPES: ReadonlySet<FilterType> = new Set([
|
|
53
23
|
"date",
|
|
54
24
|
"date-range",
|
|
55
25
|
"toggle-date",
|
|
56
26
|
]);
|
|
57
|
-
const DEFAULT_SERVERLESS_CHROMIUM_PACK_URL =
|
|
58
|
-
"https://github.com/Sparticuz/chromium/releases/download/v149.0.0/chromium-v149.0.0-pack.x64.tar";
|
|
59
|
-
const DASHBOARD_REPORT_SCREENSHOT_PARAM = "reportScreenshot";
|
|
60
27
|
const DASHBOARD_REPORT_SETTINGS_PARAM = "reportSettings";
|
|
61
|
-
const DASHBOARD_REPORT_CID = "dashboard-report-snapshot";
|
|
62
|
-
const LOCAL_SCREENSHOT_TIMEOUT_MS = 90_000;
|
|
63
|
-
const SERVERLESS_SCREENSHOT_TIMEOUT_MS = 90_000;
|
|
64
|
-
const SERVERLESS_SECOND_READY_TIMEOUT_MS = 45_000;
|
|
65
|
-
// Cap browser work separately from the sweep-level delivery deadline.
|
|
66
|
-
// Reserve time under Netlify's 300s background-function limit for cleanup and
|
|
67
|
-
// email delivery (see MAX_CAPTURE_CLEANUP_RESERVE_MS / delivery reserves below).
|
|
68
|
-
const SERVERLESS_CHUNKED_ATTEMPT_TIMEOUT_MS = 210_000;
|
|
69
|
-
const BROWSER_CLEANUP_TIMEOUT_MS = 10_000;
|
|
70
28
|
const DASHBOARD_REPORT_EMAIL_TIMEOUT_MS = 10_000;
|
|
71
29
|
const DASHBOARD_REPORT_EMAIL_OVERHEAD_RESERVE_MS = 5_000;
|
|
72
|
-
const MAX_CAPTURE_CLEANUP_RESERVE_MS = BROWSER_CLEANUP_TIMEOUT_MS * 3;
|
|
73
|
-
const SCREENSHOT_VIEWPORT_PADDING = 64;
|
|
74
|
-
const MAX_DASHBOARD_REPORT_CHUNKS = 10;
|
|
75
|
-
const MAX_DASHBOARD_REPORT_ATTACHMENT_BYTES = 14 * 1024 * 1024;
|
|
76
30
|
|
|
77
|
-
type
|
|
78
|
-
label: "chunked";
|
|
79
|
-
viewport: { width: number; height: number };
|
|
80
|
-
captureScale?: number;
|
|
81
|
-
readyTimeout?: number;
|
|
82
|
-
secondReadyTimeout?: number;
|
|
83
|
-
totalTimeout?: number;
|
|
84
|
-
};
|
|
31
|
+
export type DashboardReportMode = "complete" | "degraded";
|
|
85
32
|
|
|
86
|
-
type
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
type DashboardPngCapture = {
|
|
95
|
-
pngs: Array<Buffer | null> | null;
|
|
96
|
-
mode: "full" | "partial" | "none";
|
|
97
|
-
error?: string;
|
|
33
|
+
export type DashboardReportResult = {
|
|
34
|
+
dashboardUrl: string;
|
|
35
|
+
recipientCount: number;
|
|
36
|
+
reportMode: DashboardReportMode;
|
|
37
|
+
degradedPanelIds: string[];
|
|
38
|
+
reportError?: string;
|
|
39
|
+
emailsSent: boolean;
|
|
98
40
|
};
|
|
99
41
|
|
|
100
42
|
function daysAgo(n: number): string {
|
|
@@ -158,13 +100,10 @@ function dashboardBaseUrl(): string {
|
|
|
158
100
|
);
|
|
159
101
|
}
|
|
160
102
|
|
|
161
|
-
function
|
|
103
|
+
function buildDashboardUrl(
|
|
162
104
|
dashboardId: string,
|
|
163
105
|
filters: Record<string, string>,
|
|
164
|
-
options?: {
|
|
165
|
-
reportScreenshot?: boolean;
|
|
166
|
-
reportSettings?: boolean;
|
|
167
|
-
},
|
|
106
|
+
options?: { reportSettings?: boolean },
|
|
168
107
|
): string {
|
|
169
108
|
const url = new URL(
|
|
170
109
|
`/dashboards/${encodeURIComponent(dashboardId)}`,
|
|
@@ -173,38 +112,16 @@ function buildDashboardPath(
|
|
|
173
112
|
for (const [key, value] of Object.entries(filters)) {
|
|
174
113
|
if (value) url.searchParams.set(key, value);
|
|
175
114
|
}
|
|
176
|
-
if (options?.reportScreenshot) {
|
|
177
|
-
url.searchParams.set(DASHBOARD_REPORT_SCREENSHOT_PARAM, "1");
|
|
178
|
-
}
|
|
179
115
|
if (options?.reportSettings) {
|
|
180
116
|
url.searchParams.set(DASHBOARD_REPORT_SETTINGS_PARAM, "1");
|
|
181
117
|
}
|
|
182
|
-
return
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
dashboardId: string,
|
|
187
|
-
filters: Record<string, string>,
|
|
188
|
-
options?: {
|
|
189
|
-
reportScreenshot?: boolean;
|
|
190
|
-
reportSettings?: boolean;
|
|
191
|
-
},
|
|
192
|
-
): string {
|
|
193
|
-
const path = buildDashboardPath(dashboardId, filters, options);
|
|
194
|
-
const url = new URL(path, `${dashboardBaseUrl()}/`);
|
|
195
|
-
return url.toString();
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function escapeHtml(value: unknown): string {
|
|
199
|
-
return String(value ?? "")
|
|
200
|
-
.replace(/&/g, "&")
|
|
201
|
-
.replace(/</g, "<")
|
|
202
|
-
.replace(/>/g, ">")
|
|
203
|
-
.replace(/"/g, """)
|
|
204
|
-
.replace(/'/g, "'");
|
|
118
|
+
return new URL(
|
|
119
|
+
`${url.pathname}${url.search}`,
|
|
120
|
+
`${dashboardBaseUrl()}/`,
|
|
121
|
+
).toString();
|
|
205
122
|
}
|
|
206
123
|
|
|
207
|
-
async function collectReportSnapshot(
|
|
124
|
+
export async function collectReportSnapshot(
|
|
208
125
|
sub: DashboardReportSubscription,
|
|
209
126
|
): Promise<ReportSnapshot> {
|
|
210
127
|
const accessCtx: AccessCtx = {
|
|
@@ -238,184 +155,13 @@ async function collectReportSnapshot(
|
|
|
238
155
|
};
|
|
239
156
|
}
|
|
240
157
|
|
|
241
|
-
function isServerlessBrowserRuntime(): boolean {
|
|
242
|
-
return (
|
|
243
|
-
process.env.NETLIFY === "true" ||
|
|
244
|
-
Boolean(process.env.AWS_LAMBDA_FUNCTION_NAME) ||
|
|
245
|
-
Boolean(process.env.AWS_EXECUTION_ENV)
|
|
246
|
-
);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
function localChromiumExecutablePath(): string | null {
|
|
250
|
-
const configured =
|
|
251
|
-
process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH ||
|
|
252
|
-
process.env.CHROME_BIN ||
|
|
253
|
-
process.env.CHROMIUM_PATH;
|
|
254
|
-
if (configured && existsSync(configured)) return configured;
|
|
255
|
-
|
|
256
|
-
const candidates = [
|
|
257
|
-
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
258
|
-
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
|
259
|
-
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
|
|
260
|
-
"/usr/bin/google-chrome",
|
|
261
|
-
"/usr/bin/google-chrome-stable",
|
|
262
|
-
"/usr/bin/chromium",
|
|
263
|
-
"/usr/bin/chromium-browser",
|
|
264
|
-
];
|
|
265
|
-
return candidates.find((candidate) => existsSync(candidate)) ?? null;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
async function sweepStaleScreenshotProfiles(): Promise<void> {
|
|
269
|
-
let entries: string[];
|
|
270
|
-
try {
|
|
271
|
-
entries = await readdir(tmpdir());
|
|
272
|
-
} catch {
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
const stale = entries
|
|
276
|
-
.filter((entry) => entry.startsWith("dashboard-report-playwright-"))
|
|
277
|
-
.slice(0, 8);
|
|
278
|
-
for (const entry of stale) {
|
|
279
|
-
const full = join(tmpdir(), entry);
|
|
280
|
-
const info = await stat(full).catch(() => null);
|
|
281
|
-
if (info && Date.now() - info.mtimeMs > 30 * 60_000) {
|
|
282
|
-
await rm(full, { recursive: true, force: true }).catch(() => {});
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
async function launchScreenshotBrowser(
|
|
288
|
-
viewport: DashboardScreenshotAttempt["viewport"],
|
|
289
|
-
): Promise<LaunchedScreenshotBrowser> {
|
|
290
|
-
const { chromium: playwright } = await import("playwright-core");
|
|
291
|
-
const localExecutablePath = localChromiumExecutablePath();
|
|
292
|
-
if (localExecutablePath) {
|
|
293
|
-
const browser = await playwright.launch({
|
|
294
|
-
executablePath: localExecutablePath,
|
|
295
|
-
headless: true,
|
|
296
|
-
});
|
|
297
|
-
return {
|
|
298
|
-
browser,
|
|
299
|
-
cleanup: async () => {},
|
|
300
|
-
newPage: () =>
|
|
301
|
-
browser.newPage({
|
|
302
|
-
viewport,
|
|
303
|
-
deviceScaleFactor: 1,
|
|
304
|
-
}),
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if (isServerlessBrowserRuntime()) {
|
|
309
|
-
const { default: chromium } = await import("@sparticuz/chromium-min");
|
|
310
|
-
chromium.setGraphicsMode = false;
|
|
311
|
-
const packUrl =
|
|
312
|
-
process.env.DASHBOARD_REPORT_CHROMIUM_PACK_URL?.trim() ||
|
|
313
|
-
DEFAULT_SERVERLESS_CHROMIUM_PACK_URL;
|
|
314
|
-
await sweepStaleScreenshotProfiles();
|
|
315
|
-
const userDataDir = join(
|
|
316
|
-
tmpdir(),
|
|
317
|
-
`dashboard-report-playwright-${randomUUID()}`,
|
|
318
|
-
);
|
|
319
|
-
const cleanup = async () => {
|
|
320
|
-
await rm(userDataDir, { recursive: true, force: true }).catch((err) => {
|
|
321
|
-
console.error(
|
|
322
|
-
"[dashboard-report] Failed to clean Chromium profile:",
|
|
323
|
-
errorMessage(err),
|
|
324
|
-
);
|
|
325
|
-
});
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
try {
|
|
329
|
-
const browser = await playwright.launchPersistentContext(userDataDir, {
|
|
330
|
-
args: [
|
|
331
|
-
...chromium.args,
|
|
332
|
-
"--disable-dev-shm-usage",
|
|
333
|
-
"--disable-gpu",
|
|
334
|
-
"--hide-scrollbars",
|
|
335
|
-
],
|
|
336
|
-
deviceScaleFactor: 1,
|
|
337
|
-
executablePath: await chromium.executablePath(packUrl),
|
|
338
|
-
headless: true,
|
|
339
|
-
viewport,
|
|
340
|
-
});
|
|
341
|
-
return {
|
|
342
|
-
browser,
|
|
343
|
-
cleanup,
|
|
344
|
-
newPage: () => browser.newPage(),
|
|
345
|
-
};
|
|
346
|
-
} catch (err) {
|
|
347
|
-
await cleanup();
|
|
348
|
-
throw err;
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
const browser = await playwright.launch({ headless: true });
|
|
353
|
-
return {
|
|
354
|
-
browser,
|
|
355
|
-
cleanup: async () => {},
|
|
356
|
-
newPage: () =>
|
|
357
|
-
browser.newPage({
|
|
358
|
-
viewport,
|
|
359
|
-
deviceScaleFactor: 1,
|
|
360
|
-
}),
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
function screenshotTimeoutMs(): number {
|
|
365
|
-
const configured = positiveIntEnv("DASHBOARD_REPORT_SCREENSHOT_TIMEOUT_MS");
|
|
366
|
-
if (configured) return configured;
|
|
367
|
-
return isServerlessBrowserRuntime()
|
|
368
|
-
? SERVERLESS_SCREENSHOT_TIMEOUT_MS
|
|
369
|
-
: LOCAL_SCREENSHOT_TIMEOUT_MS;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
function secondReadyTimeoutMs(): number {
|
|
373
|
-
const configured = positiveIntEnv("DASHBOARD_REPORT_SECOND_READY_TIMEOUT_MS");
|
|
374
|
-
if (configured) return configured;
|
|
375
|
-
return isServerlessBrowserRuntime()
|
|
376
|
-
? SERVERLESS_SECOND_READY_TIMEOUT_MS
|
|
377
|
-
: screenshotTimeoutMs();
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
function boundedStageTimeout(capMs: number, deadlineAt?: number): number {
|
|
381
|
-
if (!deadlineAt) return capMs;
|
|
382
|
-
const remainingMs = deadlineAt - Date.now();
|
|
383
|
-
if (remainingMs <= 0) throw new Error("capture deadline exhausted");
|
|
384
|
-
return Math.max(1, Math.min(capMs, remainingMs));
|
|
385
|
-
}
|
|
386
|
-
|
|
387
158
|
function reportDeliveryReserveMs(recipientCount: number): number {
|
|
388
159
|
return (
|
|
389
|
-
MAX_CAPTURE_CLEANUP_RESERVE_MS +
|
|
390
160
|
recipientCount * DASHBOARD_REPORT_EMAIL_TIMEOUT_MS +
|
|
391
161
|
DASHBOARD_REPORT_EMAIL_OVERHEAD_RESERVE_MS
|
|
392
162
|
);
|
|
393
163
|
}
|
|
394
164
|
|
|
395
|
-
async function runWithinCaptureDeadline<T>(
|
|
396
|
-
operation: () => Promise<T>,
|
|
397
|
-
deadlineAt?: number,
|
|
398
|
-
): Promise<T> {
|
|
399
|
-
if (!deadlineAt) return operation();
|
|
400
|
-
const timeoutMs = deadlineAt - Date.now();
|
|
401
|
-
if (timeoutMs <= 0) throw new Error("capture deadline exhausted");
|
|
402
|
-
|
|
403
|
-
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
404
|
-
try {
|
|
405
|
-
return await Promise.race([
|
|
406
|
-
operation(),
|
|
407
|
-
new Promise<never>((_, reject) => {
|
|
408
|
-
timeout = setTimeout(
|
|
409
|
-
() => reject(new Error("capture deadline exhausted")),
|
|
410
|
-
timeoutMs,
|
|
411
|
-
);
|
|
412
|
-
}),
|
|
413
|
-
]);
|
|
414
|
-
} finally {
|
|
415
|
-
if (timeout) clearTimeout(timeout);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
165
|
async function runWithinReportDeadline<T>(
|
|
420
166
|
label: string,
|
|
421
167
|
operation: () => Promise<T>,
|
|
@@ -443,932 +189,6 @@ async function runWithinReportDeadline<T>(
|
|
|
443
189
|
}
|
|
444
190
|
}
|
|
445
191
|
|
|
446
|
-
function positiveIntEnv(name: string): number | null {
|
|
447
|
-
const raw = process.env[name]?.trim();
|
|
448
|
-
if (!raw) return null;
|
|
449
|
-
const parsed = Number.parseInt(raw, 10);
|
|
450
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
async function waitForDashboardReportReady(
|
|
454
|
-
page: any,
|
|
455
|
-
timeout: number,
|
|
456
|
-
consoleErrors: string[] = [],
|
|
457
|
-
failedRequests: string[] = [],
|
|
458
|
-
expectedPanelIds: string[] = [],
|
|
459
|
-
): Promise<boolean> {
|
|
460
|
-
try {
|
|
461
|
-
await page.waitForFunction(
|
|
462
|
-
`(() => {
|
|
463
|
-
const root = document.querySelector("[data-dashboard-report-capture]");
|
|
464
|
-
if (!root) return false;
|
|
465
|
-
if (root.getAttribute("data-dashboard-report-ready") !== "true") {
|
|
466
|
-
return false;
|
|
467
|
-
}
|
|
468
|
-
if (root.querySelector("[data-dashboard-report-loading='true']")) {
|
|
469
|
-
return false;
|
|
470
|
-
}
|
|
471
|
-
// A panel that errored (including its own query-call timeout) clears
|
|
472
|
-
// its loading marker just like a successful panel, so without this
|
|
473
|
-
// check the capture would treat a broken panel as "ready" and bake
|
|
474
|
-
// its raw error text into the delivered screenshot instead of
|
|
475
|
-
// failing the attempt so the retry sweep can pick it up.
|
|
476
|
-
return !root.querySelector("[role='alert']");
|
|
477
|
-
})()`,
|
|
478
|
-
undefined,
|
|
479
|
-
{ timeout },
|
|
480
|
-
);
|
|
481
|
-
await page.evaluate(`(async () => {
|
|
482
|
-
await document.fonts?.ready;
|
|
483
|
-
})()`);
|
|
484
|
-
await page.waitForTimeout(750);
|
|
485
|
-
return true;
|
|
486
|
-
} catch (err: any) {
|
|
487
|
-
const detail = await page
|
|
488
|
-
.evaluate(`(() => {
|
|
489
|
-
const root = document.querySelector("[data-dashboard-report-capture]");
|
|
490
|
-
const expectedPanelIds = ${JSON.stringify(expectedPanelIds.slice(0, REPORT_PANEL_STATE_DIAGNOSTICS_LIMIT))};
|
|
491
|
-
const cleanText = (value, limit = ${REPORT_PANEL_STATE_TEXT_LIMIT}) =>
|
|
492
|
-
String(value ?? "").replace(/\\s+/g, " ").trim().slice(0, limit);
|
|
493
|
-
const panelStates = expectedPanelIds.map((id) => {
|
|
494
|
-
const panel = Array.from(
|
|
495
|
-
root?.querySelectorAll("[data-dashboard-report-panel-id]") ?? [],
|
|
496
|
-
).find((node) =>
|
|
497
|
-
node.getAttribute("data-dashboard-report-panel-id") === id,
|
|
498
|
-
);
|
|
499
|
-
if (!panel) return { id: cleanText(id, 96), state: "missing" };
|
|
500
|
-
const errorNode = panel.querySelector(
|
|
501
|
-
"[data-dashboard-report-panel-error='true'], .text-red-400",
|
|
502
|
-
);
|
|
503
|
-
const error = cleanText(errorNode?.textContent);
|
|
504
|
-
return {
|
|
505
|
-
id: cleanText(id, 96),
|
|
506
|
-
title: cleanText(panel.getAttribute("data-dashboard-report-panel-title"), 120),
|
|
507
|
-
state: panel.querySelector("[data-dashboard-report-loading='true']")
|
|
508
|
-
? "loading"
|
|
509
|
-
: error
|
|
510
|
-
? "errored"
|
|
511
|
-
: "ready",
|
|
512
|
-
...(error ? { error } : {}),
|
|
513
|
-
};
|
|
514
|
-
});
|
|
515
|
-
return {
|
|
516
|
-
ready: root?.getAttribute("data-dashboard-report-ready") ?? null,
|
|
517
|
-
panelStates,
|
|
518
|
-
url: location.href,
|
|
519
|
-
};
|
|
520
|
-
})()`)
|
|
521
|
-
.catch(() => null);
|
|
522
|
-
const captureDiagnostics = { consoleErrors, failedRequests };
|
|
523
|
-
const message = detail
|
|
524
|
-
? `${err?.message ?? String(err)}; dashboard state: ${JSON.stringify({
|
|
525
|
-
...detail,
|
|
526
|
-
...captureDiagnostics,
|
|
527
|
-
})}`
|
|
528
|
-
: `${err?.message ?? String(err)}; dashboard page was not inspectable; capture diagnostics: ${JSON.stringify(captureDiagnostics)}`;
|
|
529
|
-
throw new Error(message);
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
const PREWARM_CONCURRENCY = 3;
|
|
534
|
-
const PREWARM_PANEL_TIMEOUT_MS = 20_000;
|
|
535
|
-
const PREWARM_MAX_BUDGET_MS = 45_000;
|
|
536
|
-
|
|
537
|
-
/**
|
|
538
|
-
* Runs first-party panel queries once, directly, before the browser capture
|
|
539
|
-
* starts, so the capture's own query-dashboard-panel calls hit a warm cache
|
|
540
|
-
* instead of several panels racing each other cold for database time inside
|
|
541
|
-
* a single capture window — that contention, not any one query alone, is
|
|
542
|
-
* what was pushing panels past their capture timeout. Best-effort: a panel
|
|
543
|
-
* that fails or times out here is simply computed cold by the capture later,
|
|
544
|
-
* exactly as it always was, so this can never make a report worse than
|
|
545
|
-
* before it existed. Bounded to time left after reserving the full chunked
|
|
546
|
-
* capture attempt and delivery tail, so prewarming cannot starve capture.
|
|
547
|
-
* The per-panel timeout only bounds how long a worker waits before logging;
|
|
548
|
-
* it is also passed to the database/cache layers, and the original query is
|
|
549
|
-
* still awaited before this function returns so it cannot overlap capture.
|
|
550
|
-
*/
|
|
551
|
-
async function prewarmFirstPartyPanelCache(
|
|
552
|
-
sub: DashboardReportSubscription,
|
|
553
|
-
snapshot: ReportSnapshot,
|
|
554
|
-
deadlineAt?: number,
|
|
555
|
-
recipientCount = 0,
|
|
556
|
-
): Promise<void> {
|
|
557
|
-
const panels = (snapshot.panels ?? []).filter(
|
|
558
|
-
(panel) => panel.source === "first-party" && panel.sql != null,
|
|
559
|
-
);
|
|
560
|
-
if (!panels.length) return;
|
|
561
|
-
|
|
562
|
-
const remaining = deadlineAt ? deadlineAt - Date.now() : Infinity;
|
|
563
|
-
const budgetMs = Math.max(
|
|
564
|
-
0,
|
|
565
|
-
Math.min(
|
|
566
|
-
PREWARM_MAX_BUDGET_MS,
|
|
567
|
-
deadlineAt
|
|
568
|
-
? remaining -
|
|
569
|
-
SERVERLESS_CHUNKED_ATTEMPT_TIMEOUT_MS -
|
|
570
|
-
reportDeliveryReserveMs(recipientCount)
|
|
571
|
-
: PREWARM_MAX_BUDGET_MS,
|
|
572
|
-
),
|
|
573
|
-
);
|
|
574
|
-
if (budgetMs <= 0) return;
|
|
575
|
-
const prewarmDeadline = Date.now() + budgetMs;
|
|
576
|
-
|
|
577
|
-
const vars: Record<string, string> = { ...snapshot.variables };
|
|
578
|
-
for (const [key, value] of Object.entries(snapshot.filters)) {
|
|
579
|
-
if (key.startsWith("f_")) vars[key.slice(2)] = value;
|
|
580
|
-
}
|
|
581
|
-
const scope = { userEmail: sub.ownerEmail, orgId: sub.orgId ?? null };
|
|
582
|
-
|
|
583
|
-
let index = 0;
|
|
584
|
-
async function worker(): Promise<void> {
|
|
585
|
-
while (index < panels.length && Date.now() < prewarmDeadline) {
|
|
586
|
-
const panel = panels[index++];
|
|
587
|
-
const sql = interpolate(serializePanelSql(panel.sql), vars, {
|
|
588
|
-
failClosedTimeVariables: true,
|
|
589
|
-
});
|
|
590
|
-
if (!sql.trim()) continue;
|
|
591
|
-
const panelTimeoutMs = Math.max(
|
|
592
|
-
1,
|
|
593
|
-
Math.min(PREWARM_PANEL_TIMEOUT_MS, prewarmDeadline - Date.now()),
|
|
594
|
-
);
|
|
595
|
-
const query = queryFirstPartyAnalytics(sql, scope, {
|
|
596
|
-
cache: true,
|
|
597
|
-
timeoutMs: panelTimeoutMs,
|
|
598
|
-
});
|
|
599
|
-
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
600
|
-
try {
|
|
601
|
-
await Promise.race([
|
|
602
|
-
query,
|
|
603
|
-
new Promise<never>((_, reject) => {
|
|
604
|
-
timeout = setTimeout(
|
|
605
|
-
() => reject(new Error("prewarm panel timeout")),
|
|
606
|
-
panelTimeoutMs,
|
|
607
|
-
);
|
|
608
|
-
timeout.unref?.();
|
|
609
|
-
}),
|
|
610
|
-
]);
|
|
611
|
-
} catch (err) {
|
|
612
|
-
console.warn(
|
|
613
|
-
`[dashboard-report] prewarm failed for panel ${panel.id}:`,
|
|
614
|
-
err instanceof Error ? err.message : err,
|
|
615
|
-
);
|
|
616
|
-
} finally {
|
|
617
|
-
if (timeout) clearTimeout(timeout);
|
|
618
|
-
await query.catch(() => undefined);
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
await Promise.all(
|
|
624
|
-
Array.from({ length: PREWARM_CONCURRENCY }, () => worker()),
|
|
625
|
-
);
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
async function assertDashboardReportPanelWindow(
|
|
629
|
-
page: any,
|
|
630
|
-
expectedPanelIds: string[],
|
|
631
|
-
): Promise<void> {
|
|
632
|
-
const rawPanelIds = await page.evaluate(`(() =>
|
|
633
|
-
document
|
|
634
|
-
.querySelector("[data-dashboard-report-capture]")
|
|
635
|
-
?.getAttribute("data-dashboard-report-panel-ids") ?? null
|
|
636
|
-
)()`);
|
|
637
|
-
let actualPanelIds: unknown;
|
|
638
|
-
try {
|
|
639
|
-
actualPanelIds =
|
|
640
|
-
typeof rawPanelIds === "string" ? JSON.parse(rawPanelIds) : null;
|
|
641
|
-
} catch {
|
|
642
|
-
actualPanelIds = null;
|
|
643
|
-
}
|
|
644
|
-
if (
|
|
645
|
-
!Array.isArray(actualPanelIds) ||
|
|
646
|
-
actualPanelIds.some((panelId) => typeof panelId !== "string") ||
|
|
647
|
-
actualPanelIds.length !== expectedPanelIds.length ||
|
|
648
|
-
actualPanelIds.some((panelId, index) => panelId !== expectedPanelIds[index])
|
|
649
|
-
) {
|
|
650
|
-
throw new DashboardReportPanelMismatchError(
|
|
651
|
-
`report chunk panel mismatch; expected=${JSON.stringify(expectedPanelIds)} actual=${JSON.stringify(actualPanelIds)}`,
|
|
652
|
-
);
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
async function scrollDashboardForLazyRendering(page: any): Promise<void> {
|
|
657
|
-
await page.evaluate(`(async () => {
|
|
658
|
-
const wait = (ms) =>
|
|
659
|
-
new Promise((resolve) => window.setTimeout(resolve, ms));
|
|
660
|
-
const maxY = Math.max(
|
|
661
|
-
document.body.scrollHeight,
|
|
662
|
-
document.documentElement.scrollHeight,
|
|
663
|
-
);
|
|
664
|
-
const step = Math.max(600, Math.floor(window.innerHeight * 0.75));
|
|
665
|
-
for (let y = 0; y < maxY; y += step) {
|
|
666
|
-
window.scrollTo(0, y);
|
|
667
|
-
await wait(120);
|
|
668
|
-
}
|
|
669
|
-
window.scrollTo(0, 0);
|
|
670
|
-
})()`);
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
async function fitViewportWidthToDashboardCapture(
|
|
674
|
-
page: any,
|
|
675
|
-
capture: any,
|
|
676
|
-
viewport: { width: number; height: number },
|
|
677
|
-
): Promise<void> {
|
|
678
|
-
const box = await capture.boundingBox();
|
|
679
|
-
if (!box) return;
|
|
680
|
-
|
|
681
|
-
const width = Math.max(
|
|
682
|
-
viewport.width,
|
|
683
|
-
Math.min(1800, Math.ceil(box.width + SCREENSHOT_VIEWPORT_PADDING)),
|
|
684
|
-
);
|
|
685
|
-
if (width === viewport.width) return;
|
|
686
|
-
|
|
687
|
-
// Keep the render surface bounded. Playwright's locator screenshot captures
|
|
688
|
-
// the full element beyond the viewport, while growing Chromium to the full
|
|
689
|
-
// dashboard height can exhaust memory and close the browser on serverless
|
|
690
|
-
// workers. Width-only fitting preserves the full dashboard without that
|
|
691
|
-
// oversized render surface.
|
|
692
|
-
await page.setViewportSize({ width, height: viewport.height });
|
|
693
|
-
await page.waitForTimeout(250);
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
async function scaleDashboardCapture(
|
|
697
|
-
page: any,
|
|
698
|
-
scale: number | undefined,
|
|
699
|
-
): Promise<void> {
|
|
700
|
-
if (!scale || scale >= 1) return;
|
|
701
|
-
await page.evaluate(`(() => {
|
|
702
|
-
const root = document.querySelector("[data-dashboard-report-capture]");
|
|
703
|
-
if (root instanceof HTMLElement) root.style.zoom = "${scale}";
|
|
704
|
-
})()`);
|
|
705
|
-
await page.waitForTimeout(250);
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
async function runBoundedBrowserCleanup(
|
|
709
|
-
label: string,
|
|
710
|
-
operation: () => Promise<void>,
|
|
711
|
-
): Promise<void> {
|
|
712
|
-
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
713
|
-
try {
|
|
714
|
-
await Promise.race([
|
|
715
|
-
operation(),
|
|
716
|
-
new Promise<never>((_, reject) => {
|
|
717
|
-
timeout = setTimeout(
|
|
718
|
-
() => reject(new Error(`${label} exceeded cleanup timeout`)),
|
|
719
|
-
BROWSER_CLEANUP_TIMEOUT_MS,
|
|
720
|
-
);
|
|
721
|
-
}),
|
|
722
|
-
]);
|
|
723
|
-
} catch (err) {
|
|
724
|
-
console.error(`[dashboard-report] ${label}:`, errorMessage(err));
|
|
725
|
-
} finally {
|
|
726
|
-
if (timeout) clearTimeout(timeout);
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
const DIAGNOSTICS_PROBE_TIMEOUT_MS = 2_000;
|
|
731
|
-
const DIAGNOSTICS_MAX_LENGTH = 700;
|
|
732
|
-
const DIAGNOSTICS_COLLECTOR_LIMIT = 5;
|
|
733
|
-
const REPORT_PANEL_STATE_DIAGNOSTICS_LIMIT = REPORT_PANEL_CHUNK_SIZE;
|
|
734
|
-
const REPORT_PANEL_STATE_TEXT_LIMIT = 160;
|
|
735
|
-
const DIAGNOSTICS_URL_LIMIT = 120;
|
|
736
|
-
const DIAGNOSTICS_TEXT_SNAPSHOT_LIMIT = 180;
|
|
737
|
-
const DIAGNOSTICS_REQUEST_TRACKING_LIMIT = 50;
|
|
738
|
-
const DIAGNOSTICS_IN_FLIGHT_SERIALIZATION_LIMIT = 3;
|
|
739
|
-
|
|
740
|
-
type InFlightReportRequest = {
|
|
741
|
-
method: string;
|
|
742
|
-
url: string;
|
|
743
|
-
startedAt: number;
|
|
744
|
-
};
|
|
745
|
-
|
|
746
|
-
type RecentReportResource = {
|
|
747
|
-
method: string;
|
|
748
|
-
url: string;
|
|
749
|
-
status?: number;
|
|
750
|
-
ageMs?: number;
|
|
751
|
-
outcome: "response" | "finished" | "failed";
|
|
752
|
-
};
|
|
753
|
-
|
|
754
|
-
function redactDiagnosticUrl(value: unknown): string {
|
|
755
|
-
return String(value ?? "")
|
|
756
|
-
.replace(
|
|
757
|
-
/([?&](?:__an_embed_token|token|access_token|authorization|sql|query)=)[^&\s]*/gi,
|
|
758
|
-
"$1[REDACTED]",
|
|
759
|
-
)
|
|
760
|
-
.slice(0, DIAGNOSTICS_URL_LIMIT);
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
function sanitizeDiagnosticText(
|
|
764
|
-
value: unknown,
|
|
765
|
-
limit = DIAGNOSTICS_TEXT_SNAPSHOT_LIMIT,
|
|
766
|
-
): string {
|
|
767
|
-
return errorMessage(String(value ?? ""))
|
|
768
|
-
.replace(/\b(?:bearer\s+)[a-z0-9._~+/=-]+/gi, "Bearer [REDACTED]")
|
|
769
|
-
.replace(
|
|
770
|
-
/\b((?:access[_-]?token|auth(?:orization)?|session|cookie)\s*[:=]\s*)[^\s,;"'<>]+/gi,
|
|
771
|
-
"$1[REDACTED]",
|
|
772
|
-
)
|
|
773
|
-
.replace(/\s+/g, " ")
|
|
774
|
-
.trim()
|
|
775
|
-
.slice(0, limit);
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
function requestDiagnostic(req: any): InFlightReportRequest {
|
|
779
|
-
return {
|
|
780
|
-
method: sanitizeDiagnosticText(req.method?.(), 16) || "GET",
|
|
781
|
-
url: redactDiagnosticUrl(req.url?.()),
|
|
782
|
-
startedAt: Date.now(),
|
|
783
|
-
};
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
function requestDiagnosticPriority(url: string): number {
|
|
787
|
-
return /\/(?:_agent-native\/actions|auth|session)(?:\/|[?]|$)|get-sql-dashboard/i.test(
|
|
788
|
-
url,
|
|
789
|
-
)
|
|
790
|
-
? 1
|
|
791
|
-
: 0;
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
function retainInFlightRequest(
|
|
795
|
-
requests: Map<any, InFlightReportRequest>,
|
|
796
|
-
req: any,
|
|
797
|
-
) {
|
|
798
|
-
if (
|
|
799
|
-
!requests.has(req) &&
|
|
800
|
-
requests.size >= DIAGNOSTICS_REQUEST_TRACKING_LIMIT
|
|
801
|
-
) {
|
|
802
|
-
const discard = [...requests.entries()].sort(([, left], [, right]) => {
|
|
803
|
-
const priority =
|
|
804
|
-
requestDiagnosticPriority(left.url) -
|
|
805
|
-
requestDiagnosticPriority(right.url);
|
|
806
|
-
return priority || left.startedAt - right.startedAt;
|
|
807
|
-
})[0];
|
|
808
|
-
if (discard) requests.delete(discard[0]);
|
|
809
|
-
}
|
|
810
|
-
requests.set(req, requestDiagnostic(req));
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
function pushRecentResource(
|
|
814
|
-
resources: RecentReportResource[],
|
|
815
|
-
resource: RecentReportResource,
|
|
816
|
-
) {
|
|
817
|
-
if (resources.length >= DIAGNOSTICS_COLLECTOR_LIMIT) resources.shift();
|
|
818
|
-
resources.push(resource);
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
// netlify.toml's memory = "2gb" is plan-gated and can be silently ignored, so
|
|
822
|
-
// capture the actual lambda memory ceiling alongside current RSS.
|
|
823
|
-
function memoryDiagnostics(): string {
|
|
824
|
-
const lambdaMemoryMb =
|
|
825
|
-
process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE ?? "unknown";
|
|
826
|
-
const rssMb = Math.round(process.memoryUsage().rss / 1024 / 1024);
|
|
827
|
-
return `lambdaMemoryMb=${lambdaMemoryMb} rssMb=${rssMb}`;
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
// Best-effort page inspection used when the report surface never becomes
|
|
831
|
-
// visible, so failures carry enough state to tell wrong-page/wedged-renderer/
|
|
832
|
-
// auth-bounce apart. Must never throw and must stay bounded even if the page
|
|
833
|
-
// is hung.
|
|
834
|
-
async function collectPageDiagnostics(
|
|
835
|
-
page: any,
|
|
836
|
-
consoleErrors: string[],
|
|
837
|
-
failedRequests: string[],
|
|
838
|
-
inFlightRequests: Map<any, InFlightReportRequest>,
|
|
839
|
-
recentResources: RecentReportResource[],
|
|
840
|
-
): Promise<string> {
|
|
841
|
-
const memory = memoryDiagnostics();
|
|
842
|
-
const pendingRequests = () =>
|
|
843
|
-
[...inFlightRequests.values()]
|
|
844
|
-
.sort((left, right) => {
|
|
845
|
-
const priority =
|
|
846
|
-
requestDiagnosticPriority(right.url) -
|
|
847
|
-
requestDiagnosticPriority(left.url);
|
|
848
|
-
return priority || right.startedAt - left.startedAt;
|
|
849
|
-
})
|
|
850
|
-
.slice(0, DIAGNOSTICS_IN_FLIGHT_SERIALIZATION_LIMIT)
|
|
851
|
-
.map((request) => ({
|
|
852
|
-
method: request.method,
|
|
853
|
-
url: request.url,
|
|
854
|
-
ageMs: Math.max(0, Date.now() - request.startedAt),
|
|
855
|
-
}));
|
|
856
|
-
try {
|
|
857
|
-
let responsive = true;
|
|
858
|
-
let probeTimeout: ReturnType<typeof setTimeout> | undefined;
|
|
859
|
-
try {
|
|
860
|
-
await Promise.race([
|
|
861
|
-
Promise.resolve(page.evaluate("1")),
|
|
862
|
-
new Promise((_, reject) => {
|
|
863
|
-
probeTimeout = setTimeout(
|
|
864
|
-
() => reject(new Error("diagnostics probe timed out")),
|
|
865
|
-
DIAGNOSTICS_PROBE_TIMEOUT_MS,
|
|
866
|
-
);
|
|
867
|
-
}),
|
|
868
|
-
]);
|
|
869
|
-
} catch {
|
|
870
|
-
responsive = false;
|
|
871
|
-
} finally {
|
|
872
|
-
if (probeTimeout) clearTimeout(probeTimeout);
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
if (!responsive) {
|
|
876
|
-
return `${memory} page unresponsive (renderer hung or crashed); consoleErrors=${JSON.stringify(
|
|
877
|
-
consoleErrors,
|
|
878
|
-
)} failedRequests=${JSON.stringify(failedRequests)} inFlightRequests=${JSON.stringify(
|
|
879
|
-
pendingRequests(),
|
|
880
|
-
)} recentResources=${JSON.stringify(recentResources)}`.slice(
|
|
881
|
-
0,
|
|
882
|
-
DIAGNOSTICS_MAX_LENGTH,
|
|
883
|
-
);
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
let url = "";
|
|
887
|
-
try {
|
|
888
|
-
url = page.url();
|
|
889
|
-
} catch {
|
|
890
|
-
// page may already be closed; leave url empty
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
let pageState: Record<string, unknown> = {};
|
|
894
|
-
let detailsTimeout: ReturnType<typeof setTimeout> | undefined;
|
|
895
|
-
try {
|
|
896
|
-
// page.evaluate ignores setDefaultTimeout, so race it like the probe —
|
|
897
|
-
// a renderer that wedges after the probe must not stall diagnostics.
|
|
898
|
-
const details = await Promise.race([
|
|
899
|
-
Promise.resolve(
|
|
900
|
-
page.evaluate(
|
|
901
|
-
`(() => ({
|
|
902
|
-
title: document.title,
|
|
903
|
-
readyState: document.readyState,
|
|
904
|
-
capture: (() => {
|
|
905
|
-
const root = document.querySelector("[data-dashboard-report-capture]");
|
|
906
|
-
return {
|
|
907
|
-
present: Boolean(root),
|
|
908
|
-
ready: root?.getAttribute("data-dashboard-report-ready") ?? null,
|
|
909
|
-
phase: root?.getAttribute("data-dashboard-report-phase") ?? root?.dataset?.phase ?? null,
|
|
910
|
-
fetchState: root?.getAttribute("data-dashboard-report-fetch-state") ?? root?.dataset?.fetchState ?? null,
|
|
911
|
-
error: root?.getAttribute("data-dashboard-report-error") ?? root?.dataset?.error ?? null,
|
|
912
|
-
childCount: root?.children.length ?? 0,
|
|
913
|
-
htmlLength: root?.innerHTML.length ?? 0,
|
|
914
|
-
textLength: root?.textContent.length ?? 0,
|
|
915
|
-
};
|
|
916
|
-
})(),
|
|
917
|
-
bodyTextSnapshot: document.body?.textContent?.replace(/\\s+/g, " ").trim().slice(0, ${DIAGNOSTICS_TEXT_SNAPSHOT_LIMIT}) ?? "",
|
|
918
|
-
}))()`,
|
|
919
|
-
),
|
|
920
|
-
),
|
|
921
|
-
new Promise<never>((_, reject) => {
|
|
922
|
-
detailsTimeout = setTimeout(
|
|
923
|
-
() => reject(new Error("diagnostics details timed out")),
|
|
924
|
-
DIAGNOSTICS_PROBE_TIMEOUT_MS,
|
|
925
|
-
);
|
|
926
|
-
}),
|
|
927
|
-
]);
|
|
928
|
-
const raw = details as any;
|
|
929
|
-
pageState = {
|
|
930
|
-
title: sanitizeDiagnosticText(raw?.title),
|
|
931
|
-
readyState: sanitizeDiagnosticText(raw?.readyState, 32),
|
|
932
|
-
capture: raw?.capture
|
|
933
|
-
? {
|
|
934
|
-
present: Boolean(raw.capture.present),
|
|
935
|
-
ready: sanitizeDiagnosticText(raw.capture.ready, 32) || null,
|
|
936
|
-
phase: sanitizeDiagnosticText(raw.capture.phase, 80) || null,
|
|
937
|
-
fetchState:
|
|
938
|
-
sanitizeDiagnosticText(raw.capture.fetchState, 80) || null,
|
|
939
|
-
error: sanitizeDiagnosticText(raw.capture.error) || null,
|
|
940
|
-
childCount: Number.isFinite(raw.capture.childCount)
|
|
941
|
-
? raw.capture.childCount
|
|
942
|
-
: 0,
|
|
943
|
-
htmlLength: Number.isFinite(raw.capture.htmlLength)
|
|
944
|
-
? raw.capture.htmlLength
|
|
945
|
-
: 0,
|
|
946
|
-
textLength: Number.isFinite(raw.capture.textLength)
|
|
947
|
-
? raw.capture.textLength
|
|
948
|
-
: 0,
|
|
949
|
-
}
|
|
950
|
-
: { present: false },
|
|
951
|
-
bodyTextSnapshot: sanitizeDiagnosticText(raw?.bodyTextSnapshot),
|
|
952
|
-
};
|
|
953
|
-
} catch {
|
|
954
|
-
// best effort; leave title/bodyText empty
|
|
955
|
-
} finally {
|
|
956
|
-
if (detailsTimeout) clearTimeout(detailsTimeout);
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
const { capture, readyState, title, bodyTextSnapshot } = pageState;
|
|
960
|
-
return `${memory} page state: ${JSON.stringify({
|
|
961
|
-
capture,
|
|
962
|
-
readyState,
|
|
963
|
-
inFlightRequests: pendingRequests(),
|
|
964
|
-
recentResources,
|
|
965
|
-
url: redactDiagnosticUrl(url),
|
|
966
|
-
title,
|
|
967
|
-
bodyTextSnapshot,
|
|
968
|
-
consoleErrors,
|
|
969
|
-
failedRequests,
|
|
970
|
-
})}`.slice(0, DIAGNOSTICS_MAX_LENGTH);
|
|
971
|
-
} catch {
|
|
972
|
-
return `${memory} diagnostics unavailable`;
|
|
973
|
-
}
|
|
974
|
-
}
|
|
975
|
-
|
|
976
|
-
function reportChunkOffsets(panelCount: number): number[] {
|
|
977
|
-
if (panelCount === 0) return [0];
|
|
978
|
-
return Array.from(
|
|
979
|
-
{ length: Math.ceil(panelCount / REPORT_PANEL_CHUNK_SIZE) },
|
|
980
|
-
(_, index) => index * REPORT_PANEL_CHUNK_SIZE,
|
|
981
|
-
);
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
function screenshotUrlForChunk(
|
|
985
|
-
sub: DashboardReportSubscription,
|
|
986
|
-
snapshot: ReportSnapshot,
|
|
987
|
-
offset: number,
|
|
988
|
-
): { token: string; url: string } {
|
|
989
|
-
const targetPath = buildDashboardPath(
|
|
990
|
-
snapshot.dashboardId,
|
|
991
|
-
snapshot.filters,
|
|
992
|
-
{ reportScreenshot: true },
|
|
993
|
-
);
|
|
994
|
-
const targetUrl = new URL(targetPath, "https://agent-native.invalid/");
|
|
995
|
-
targetUrl.searchParams.set("reportPanelOffset", String(offset));
|
|
996
|
-
targetUrl.searchParams.set(
|
|
997
|
-
"reportPanelLimit",
|
|
998
|
-
String(REPORT_PANEL_CHUNK_SIZE),
|
|
999
|
-
);
|
|
1000
|
-
const signedTargetPath = `${targetUrl.pathname}${targetUrl.search}`;
|
|
1001
|
-
const token = signEmbedSessionToken({
|
|
1002
|
-
ownerEmail: sub.ownerEmail,
|
|
1003
|
-
orgId: sub.orgId,
|
|
1004
|
-
targetPath: signedTargetPath,
|
|
1005
|
-
scope: `dashboard-report-screenshot:${sub.id}`,
|
|
1006
|
-
ttlSeconds: 5 * 60,
|
|
1007
|
-
});
|
|
1008
|
-
const url = new URL(signedTargetPath, `${dashboardBaseUrl()}/`);
|
|
1009
|
-
url.searchParams.set(EMBED_MODE_QUERY_PARAM, "1");
|
|
1010
|
-
url.searchParams.set(EMBED_TOKEN_QUERY_PARAM, token);
|
|
1011
|
-
return { token, url: url.toString() };
|
|
1012
|
-
}
|
|
1013
|
-
|
|
1014
|
-
async function captureDashboardChunk(
|
|
1015
|
-
page: any,
|
|
1016
|
-
attempt: DashboardScreenshotAttempt,
|
|
1017
|
-
token: string,
|
|
1018
|
-
screenshotUrl: string,
|
|
1019
|
-
expectedPanelIds: string[],
|
|
1020
|
-
deadlineAt?: number,
|
|
1021
|
-
): Promise<Buffer> {
|
|
1022
|
-
const timeout = screenshotTimeoutMs();
|
|
1023
|
-
let captureStage = "pre-seeding the embed session";
|
|
1024
|
-
const consoleErrors: string[] = [];
|
|
1025
|
-
const failedRequests: string[] = [];
|
|
1026
|
-
const inFlightRequests = new Map<any, InFlightReportRequest>();
|
|
1027
|
-
const recentResources: RecentReportResource[] = [];
|
|
1028
|
-
page.on("console", (msg: any) => {
|
|
1029
|
-
if (
|
|
1030
|
-
msg.type() !== "error" ||
|
|
1031
|
-
consoleErrors.length >= DIAGNOSTICS_COLLECTOR_LIMIT
|
|
1032
|
-
)
|
|
1033
|
-
return;
|
|
1034
|
-
consoleErrors.push(sanitizeDiagnosticText(msg.text()));
|
|
1035
|
-
});
|
|
1036
|
-
page.on("request", (req: any) => {
|
|
1037
|
-
retainInFlightRequest(inFlightRequests, req);
|
|
1038
|
-
});
|
|
1039
|
-
page.on("requestfailed", (req: any) => {
|
|
1040
|
-
const request = inFlightRequests.get(req) ?? requestDiagnostic(req);
|
|
1041
|
-
inFlightRequests.delete(req);
|
|
1042
|
-
pushRecentResource(recentResources, {
|
|
1043
|
-
method: request.method,
|
|
1044
|
-
url: request.url,
|
|
1045
|
-
ageMs: Math.max(0, Date.now() - request.startedAt),
|
|
1046
|
-
outcome: "failed",
|
|
1047
|
-
});
|
|
1048
|
-
if (failedRequests.length >= DIAGNOSTICS_COLLECTOR_LIMIT) return;
|
|
1049
|
-
failedRequests.push(
|
|
1050
|
-
`${request.method} ${request.url}: ${sanitizeDiagnosticText(req.failure()?.errorText ?? "failed")}`,
|
|
1051
|
-
);
|
|
1052
|
-
});
|
|
1053
|
-
page.on("response", (res: any) => {
|
|
1054
|
-
const req = res.request();
|
|
1055
|
-
const request = inFlightRequests.get(req) ?? requestDiagnostic(req);
|
|
1056
|
-
inFlightRequests.delete(req);
|
|
1057
|
-
pushRecentResource(recentResources, {
|
|
1058
|
-
method: request.method,
|
|
1059
|
-
url: request.url,
|
|
1060
|
-
status: res.status(),
|
|
1061
|
-
ageMs: Math.max(0, Date.now() - request.startedAt),
|
|
1062
|
-
outcome: "response",
|
|
1063
|
-
});
|
|
1064
|
-
if (
|
|
1065
|
-
res.status() < 400 ||
|
|
1066
|
-
failedRequests.length >= DIAGNOSTICS_COLLECTOR_LIMIT
|
|
1067
|
-
)
|
|
1068
|
-
return;
|
|
1069
|
-
failedRequests.push(
|
|
1070
|
-
`${request.method} ${request.url}: HTTP ${res.status()}`,
|
|
1071
|
-
);
|
|
1072
|
-
});
|
|
1073
|
-
page.on("requestfinished", (req: any) => {
|
|
1074
|
-
const request = inFlightRequests.get(req);
|
|
1075
|
-
if (!request) return;
|
|
1076
|
-
inFlightRequests.delete(req);
|
|
1077
|
-
pushRecentResource(recentResources, {
|
|
1078
|
-
method: request.method,
|
|
1079
|
-
url: request.url,
|
|
1080
|
-
ageMs: Math.max(0, Date.now() - request.startedAt),
|
|
1081
|
-
outcome: "finished",
|
|
1082
|
-
});
|
|
1083
|
-
});
|
|
1084
|
-
try {
|
|
1085
|
-
try {
|
|
1086
|
-
await page.context().addCookies([
|
|
1087
|
-
{
|
|
1088
|
-
name: EMBED_SESSION_COOKIE,
|
|
1089
|
-
value: token,
|
|
1090
|
-
url: `${dashboardBaseUrl()}/`,
|
|
1091
|
-
},
|
|
1092
|
-
]);
|
|
1093
|
-
} catch (err) {
|
|
1094
|
-
console.warn(
|
|
1095
|
-
"[dashboard-report] Failed to pre-seed embed session cookie:",
|
|
1096
|
-
errorMessage(err),
|
|
1097
|
-
);
|
|
1098
|
-
}
|
|
1099
|
-
page.setDefaultTimeout(boundedStageTimeout(timeout, deadlineAt));
|
|
1100
|
-
await page.emulateMedia({ media: "screen", colorScheme: "light" });
|
|
1101
|
-
await page.addInitScript(() =>
|
|
1102
|
-
window.localStorage.setItem("theme", "light"),
|
|
1103
|
-
);
|
|
1104
|
-
captureStage = "navigating to the report chunk";
|
|
1105
|
-
await page.goto(screenshotUrl, {
|
|
1106
|
-
waitUntil: "domcontentloaded",
|
|
1107
|
-
timeout: boundedStageTimeout(timeout, deadlineAt),
|
|
1108
|
-
});
|
|
1109
|
-
const capture = page.locator("[data-dashboard-report-capture]");
|
|
1110
|
-
captureStage = "waiting for the report chunk surface";
|
|
1111
|
-
try {
|
|
1112
|
-
await capture.waitFor({
|
|
1113
|
-
state: "visible",
|
|
1114
|
-
timeout: boundedStageTimeout(timeout, deadlineAt),
|
|
1115
|
-
});
|
|
1116
|
-
} catch (err) {
|
|
1117
|
-
const diagnostics = errorMessage(
|
|
1118
|
-
await collectPageDiagnostics(
|
|
1119
|
-
page,
|
|
1120
|
-
consoleErrors,
|
|
1121
|
-
failedRequests,
|
|
1122
|
-
inFlightRequests,
|
|
1123
|
-
recentResources,
|
|
1124
|
-
),
|
|
1125
|
-
);
|
|
1126
|
-
throw new Error(`${errorMessage(err)}; ${diagnostics}`);
|
|
1127
|
-
}
|
|
1128
|
-
captureStage = "waiting for report chunk queries";
|
|
1129
|
-
await waitForDashboardReportReady(
|
|
1130
|
-
page,
|
|
1131
|
-
boundedStageTimeout(attempt.readyTimeout ?? timeout, deadlineAt),
|
|
1132
|
-
consoleErrors,
|
|
1133
|
-
failedRequests,
|
|
1134
|
-
expectedPanelIds,
|
|
1135
|
-
);
|
|
1136
|
-
captureStage = "validating the report chunk panels";
|
|
1137
|
-
await assertDashboardReportPanelWindow(page, expectedPanelIds);
|
|
1138
|
-
captureStage = "rendering lazy report chunk panels";
|
|
1139
|
-
await scrollDashboardForLazyRendering(page);
|
|
1140
|
-
captureStage = "waiting for lazy report chunk panels";
|
|
1141
|
-
await waitForDashboardReportReady(
|
|
1142
|
-
page,
|
|
1143
|
-
boundedStageTimeout(
|
|
1144
|
-
attempt.secondReadyTimeout ?? secondReadyTimeoutMs(),
|
|
1145
|
-
deadlineAt,
|
|
1146
|
-
),
|
|
1147
|
-
consoleErrors,
|
|
1148
|
-
failedRequests,
|
|
1149
|
-
expectedPanelIds,
|
|
1150
|
-
);
|
|
1151
|
-
captureStage = "revalidating the report chunk panels";
|
|
1152
|
-
await assertDashboardReportPanelWindow(page, expectedPanelIds);
|
|
1153
|
-
captureStage = "sizing the report chunk";
|
|
1154
|
-
await fitViewportWidthToDashboardCapture(page, capture, attempt.viewport);
|
|
1155
|
-
await scaleDashboardCapture(page, attempt.captureScale);
|
|
1156
|
-
await capture.scrollIntoViewIfNeeded();
|
|
1157
|
-
captureStage = "rasterizing the report chunk PNG";
|
|
1158
|
-
page.setDefaultTimeout(boundedStageTimeout(timeout, deadlineAt));
|
|
1159
|
-
const image = await capture.screenshot({
|
|
1160
|
-
type: "png",
|
|
1161
|
-
animations: "disabled",
|
|
1162
|
-
});
|
|
1163
|
-
if (!image?.length) throw new Error("Dashboard screenshot was empty");
|
|
1164
|
-
return Buffer.from(image);
|
|
1165
|
-
} catch (err) {
|
|
1166
|
-
if (err instanceof DashboardReportPanelMismatchError) throw err;
|
|
1167
|
-
throw new Error(`${captureStage}: ${errorMessage(err)}`);
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
|
-
async function captureDashboardPngChunks(
|
|
1172
|
-
sub: DashboardReportSubscription,
|
|
1173
|
-
snapshot: ReportSnapshot,
|
|
1174
|
-
allowPartialCapture: boolean,
|
|
1175
|
-
totalTimeoutMs?: number,
|
|
1176
|
-
): Promise<DashboardPngCapture> {
|
|
1177
|
-
const offsets = reportChunkOffsets(snapshot.panelIds.length);
|
|
1178
|
-
if (offsets.length > MAX_DASHBOARD_REPORT_CHUNKS) {
|
|
1179
|
-
throw new Error(
|
|
1180
|
-
`complete dashboard requires ${offsets.length} image chunks; email delivery supports at most ${MAX_DASHBOARD_REPORT_CHUNKS}`,
|
|
1181
|
-
);
|
|
1182
|
-
}
|
|
1183
|
-
const serverless = isServerlessBrowserRuntime();
|
|
1184
|
-
const attempt: DashboardScreenshotAttempt = {
|
|
1185
|
-
label: "chunked",
|
|
1186
|
-
viewport: { width: 1200, height: 1400 },
|
|
1187
|
-
captureScale: 0.7,
|
|
1188
|
-
...(serverless
|
|
1189
|
-
? {
|
|
1190
|
-
readyTimeout: DASHBOARD_REPORT_READY_TIMEOUT_MS,
|
|
1191
|
-
secondReadyTimeout: 15_000,
|
|
1192
|
-
totalTimeout: totalTimeoutMs ?? SERVERLESS_CHUNKED_ATTEMPT_TIMEOUT_MS,
|
|
1193
|
-
}
|
|
1194
|
-
: {}),
|
|
1195
|
-
};
|
|
1196
|
-
let browser: any;
|
|
1197
|
-
let cleanup = async () => {};
|
|
1198
|
-
let launchPromise: Promise<LaunchedScreenshotBrowser> | undefined;
|
|
1199
|
-
let launchTimeout: ReturnType<typeof setTimeout> | undefined;
|
|
1200
|
-
let attemptTimedOut = false;
|
|
1201
|
-
const deadlineAt = attempt.totalTimeout
|
|
1202
|
-
? Date.now() + attempt.totalTimeout
|
|
1203
|
-
: undefined;
|
|
1204
|
-
const attemptTimeout = attempt.totalTimeout
|
|
1205
|
-
? setTimeout(() => {
|
|
1206
|
-
attemptTimedOut = true;
|
|
1207
|
-
if (browser) void browser.close().catch(() => {});
|
|
1208
|
-
}, attempt.totalTimeout)
|
|
1209
|
-
: null;
|
|
1210
|
-
const images: Array<Buffer | null> = Array(offsets.length).fill(null);
|
|
1211
|
-
try {
|
|
1212
|
-
launchPromise = launchScreenshotBrowser(attempt.viewport);
|
|
1213
|
-
const launched = attempt.totalTimeout
|
|
1214
|
-
? await Promise.race([
|
|
1215
|
-
launchPromise,
|
|
1216
|
-
new Promise<never>((_, reject) => {
|
|
1217
|
-
launchTimeout = setTimeout(
|
|
1218
|
-
() =>
|
|
1219
|
-
reject(
|
|
1220
|
-
new Error(
|
|
1221
|
-
`${attempt.label} browser launch exceeded ${attempt.totalTimeout}ms`,
|
|
1222
|
-
),
|
|
1223
|
-
),
|
|
1224
|
-
attempt.totalTimeout,
|
|
1225
|
-
);
|
|
1226
|
-
}),
|
|
1227
|
-
])
|
|
1228
|
-
: await launchPromise;
|
|
1229
|
-
browser = launched.browser;
|
|
1230
|
-
cleanup = launched.cleanup;
|
|
1231
|
-
let attachmentBytes = 0;
|
|
1232
|
-
for (const [index, offset] of offsets.entries()) {
|
|
1233
|
-
if (attemptTimedOut)
|
|
1234
|
-
throw new Error(`capture exceeded ${attempt.totalTimeout}ms`);
|
|
1235
|
-
const page = await runWithinCaptureDeadline(
|
|
1236
|
-
() => launched.newPage(),
|
|
1237
|
-
deadlineAt,
|
|
1238
|
-
);
|
|
1239
|
-
try {
|
|
1240
|
-
const { token, url } = screenshotUrlForChunk(sub, snapshot, offset);
|
|
1241
|
-
const expectedPanelIds = snapshot.panelIds.slice(
|
|
1242
|
-
offset,
|
|
1243
|
-
offset + REPORT_PANEL_CHUNK_SIZE,
|
|
1244
|
-
);
|
|
1245
|
-
const image = await runWithinCaptureDeadline(
|
|
1246
|
-
() =>
|
|
1247
|
-
captureDashboardChunk(
|
|
1248
|
-
page,
|
|
1249
|
-
attempt,
|
|
1250
|
-
token,
|
|
1251
|
-
url,
|
|
1252
|
-
expectedPanelIds,
|
|
1253
|
-
deadlineAt,
|
|
1254
|
-
),
|
|
1255
|
-
deadlineAt,
|
|
1256
|
-
);
|
|
1257
|
-
attachmentBytes += image.length;
|
|
1258
|
-
if (attachmentBytes > MAX_DASHBOARD_REPORT_ATTACHMENT_BYTES) {
|
|
1259
|
-
throw new Error(
|
|
1260
|
-
`complete dashboard images total ${attachmentBytes} bytes; email delivery supports at most ${MAX_DASHBOARD_REPORT_ATTACHMENT_BYTES} bytes`,
|
|
1261
|
-
);
|
|
1262
|
-
}
|
|
1263
|
-
images[index] = image;
|
|
1264
|
-
} finally {
|
|
1265
|
-
await runBoundedBrowserCleanup("Failed to close screenshot page", () =>
|
|
1266
|
-
page.close(),
|
|
1267
|
-
);
|
|
1268
|
-
}
|
|
1269
|
-
}
|
|
1270
|
-
return { pngs: images, mode: "full" };
|
|
1271
|
-
} catch (err) {
|
|
1272
|
-
const partialCapture =
|
|
1273
|
-
allowPartialCapture &&
|
|
1274
|
-
!(err instanceof DashboardReportPanelMismatchError) &&
|
|
1275
|
-
images.some((image) => image !== null);
|
|
1276
|
-
const suffix = attemptTimedOut
|
|
1277
|
-
? `${memoryDiagnostics()} ${attempt.label} capture exceeded ${attempt.totalTimeout}ms: ${errorMessage(err)}`
|
|
1278
|
-
: `${attempt.label}: ${errorMessage(err)}`;
|
|
1279
|
-
if (partialCapture) {
|
|
1280
|
-
return {
|
|
1281
|
-
pngs: images,
|
|
1282
|
-
mode: "partial",
|
|
1283
|
-
error: suffix.includes("lambdaMemoryMb=")
|
|
1284
|
-
? suffix
|
|
1285
|
-
: `${suffix}; ${memoryDiagnostics()}`,
|
|
1286
|
-
};
|
|
1287
|
-
}
|
|
1288
|
-
if (attemptTimedOut) {
|
|
1289
|
-
throw new Error(suffix);
|
|
1290
|
-
}
|
|
1291
|
-
throw new Error(suffix);
|
|
1292
|
-
} finally {
|
|
1293
|
-
if (attemptTimeout) clearTimeout(attemptTimeout);
|
|
1294
|
-
if (launchTimeout) clearTimeout(launchTimeout);
|
|
1295
|
-
if (!browser && launchPromise) {
|
|
1296
|
-
void launchPromise.then(
|
|
1297
|
-
async (lateBrowser) => {
|
|
1298
|
-
await runBoundedBrowserCleanup(
|
|
1299
|
-
"Failed to close late screenshot browser",
|
|
1300
|
-
() => lateBrowser.browser.close(),
|
|
1301
|
-
);
|
|
1302
|
-
await runBoundedBrowserCleanup(
|
|
1303
|
-
"Failed to clean late Chromium profile",
|
|
1304
|
-
lateBrowser.cleanup,
|
|
1305
|
-
);
|
|
1306
|
-
},
|
|
1307
|
-
() => {},
|
|
1308
|
-
);
|
|
1309
|
-
}
|
|
1310
|
-
if (browser) {
|
|
1311
|
-
await runBoundedBrowserCleanup("Failed to close screenshot browser", () =>
|
|
1312
|
-
browser.close(),
|
|
1313
|
-
);
|
|
1314
|
-
}
|
|
1315
|
-
await runBoundedBrowserCleanup("Failed to clean Chromium profile", cleanup);
|
|
1316
|
-
}
|
|
1317
|
-
}
|
|
1318
|
-
|
|
1319
|
-
function errorMessage(err: unknown): string {
|
|
1320
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
1321
|
-
return message.replace(
|
|
1322
|
-
new RegExp(`(${EMBED_TOKEN_QUERY_PARAM}=)[^&\\s]+`, "g"),
|
|
1323
|
-
"$1[REDACTED]",
|
|
1324
|
-
);
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
|
-
async function captureDashboardPngWithFallback(
|
|
1328
|
-
sub: DashboardReportSubscription,
|
|
1329
|
-
snapshot: ReportSnapshot,
|
|
1330
|
-
allowPartialCapture: boolean,
|
|
1331
|
-
totalTimeoutMs?: number,
|
|
1332
|
-
): Promise<DashboardPngCapture> {
|
|
1333
|
-
if (totalTimeoutMs !== undefined && totalTimeoutMs <= 0) {
|
|
1334
|
-
return {
|
|
1335
|
-
pngs: null,
|
|
1336
|
-
mode: "none",
|
|
1337
|
-
error: `report delivery deadline left no time for capture; ${memoryDiagnostics()}`,
|
|
1338
|
-
};
|
|
1339
|
-
}
|
|
1340
|
-
try {
|
|
1341
|
-
const capture = await captureDashboardPngChunks(
|
|
1342
|
-
sub,
|
|
1343
|
-
snapshot,
|
|
1344
|
-
allowPartialCapture,
|
|
1345
|
-
totalTimeoutMs,
|
|
1346
|
-
);
|
|
1347
|
-
if (isServerlessBrowserRuntime()) {
|
|
1348
|
-
console.info(
|
|
1349
|
-
`[dashboard-report] ${capture.mode} chunked capture finished: chunks=${capture.pngs?.filter(Boolean).length ?? 0}/${capture.pngs?.length ?? 0} ${memoryDiagnostics()}`,
|
|
1350
|
-
);
|
|
1351
|
-
}
|
|
1352
|
-
if (capture.mode === "partial") {
|
|
1353
|
-
console.error(
|
|
1354
|
-
`[dashboard-report] partial chunked screenshot capture for subscription ${sub.id}:`,
|
|
1355
|
-
capture.error,
|
|
1356
|
-
);
|
|
1357
|
-
}
|
|
1358
|
-
return capture;
|
|
1359
|
-
} catch (err) {
|
|
1360
|
-
const rawError = errorMessage(err).replace(/\s+/g, " ").trim();
|
|
1361
|
-
const error = rawError.includes("lambdaMemoryMb=")
|
|
1362
|
-
? rawError
|
|
1363
|
-
: `${rawError}; ${memoryDiagnostics()}`;
|
|
1364
|
-
console.error(
|
|
1365
|
-
`[dashboard-report] complete chunked screenshot failed for subscription ${sub.id}:`,
|
|
1366
|
-
error,
|
|
1367
|
-
);
|
|
1368
|
-
return { pngs: null, mode: "none", error };
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
1371
|
-
|
|
1372
192
|
function reportDate(snapshot: ReportSnapshot): string {
|
|
1373
193
|
return new Date(snapshot.generatedAt).toLocaleDateString("en-US", {
|
|
1374
194
|
year: "numeric",
|
|
@@ -1377,165 +197,114 @@ function reportDate(snapshot: ReportSnapshot): string {
|
|
|
1377
197
|
});
|
|
1378
198
|
}
|
|
1379
199
|
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
.map((screenshot, index) =>
|
|
1393
|
-
screenshot
|
|
1394
|
-
? `<a href="${dashboardUrl}" style="display:block;text-decoration:none;">
|
|
1395
|
-
<img src="cid:${DASHBOARD_REPORT_CID}-${index + 1}" alt="${title}${options.screenshotParts.length > 1 ? ` (part ${index + 1})` : ""}" width="100%" style="display:block;width:100%;max-width:1280px;height:auto;border:0;outline:0;border-radius:0;" />
|
|
1396
|
-
</a>`
|
|
1397
|
-
: `<div style="margin:18px 0;padding:14px 16px;border:1px solid #e5e7eb;border-radius:8px;background:#f9fafb;color:#374151;font-size:14px;line-height:1.5;">
|
|
1398
|
-
Dashboard image part ${index + 1} was unavailable for this run. Open the live dashboard to view the latest report.
|
|
1399
|
-
</div>`,
|
|
1400
|
-
)
|
|
1401
|
-
.join("\n")
|
|
1402
|
-
: `<div style="margin:18px 0;padding:14px 16px;border:1px solid #e5e7eb;border-radius:8px;background:#f9fafb;color:#374151;font-size:14px;line-height:1.5;">
|
|
1403
|
-
The dashboard image was unavailable for this run. Open the live dashboard to view the latest report.
|
|
1404
|
-
</div>`;
|
|
1405
|
-
|
|
1406
|
-
return `<!doctype html>
|
|
1407
|
-
<html>
|
|
1408
|
-
<body style="margin:0;padding:24px;background:#ffffff;color:#171717;font-family:Inter,Arial,sans-serif;">
|
|
1409
|
-
<p style="margin:0 0 12px;font-size:15px;line-height:1.4;font-weight:600;">
|
|
1410
|
-
Here's your report of <a href="${dashboardUrl}" style="color:#2563eb;text-decoration:none;">${title}</a> for ${date}
|
|
1411
|
-
</p>
|
|
1412
|
-
${screenshotBlock}
|
|
1413
|
-
<p style="margin:18px 0 0;color:#525866;font-size:13px;line-height:1.45;">
|
|
1414
|
-
<a href="${dashboardUrl}" style="color:#2563eb;text-decoration:none;">Open dashboard</a>
|
|
1415
|
-
<span style="color:#9ca3af;"> · </span>
|
|
1416
|
-
<a href="${reportSettingsUrl}" style="color:#2563eb;text-decoration:none;">Edit subscription settings</a>
|
|
1417
|
-
</p>
|
|
1418
|
-
</body>
|
|
1419
|
-
</html>`;
|
|
1420
|
-
}
|
|
1421
|
-
|
|
1422
|
-
function renderReportText(
|
|
1423
|
-
snapshot: ReportSnapshot,
|
|
1424
|
-
options: {
|
|
1425
|
-
screenshotParts: Array<Buffer | null>;
|
|
1426
|
-
},
|
|
1427
|
-
): string {
|
|
1428
|
-
const lines = [
|
|
1429
|
-
`Daily dashboard report: ${snapshot.title}`,
|
|
1430
|
-
`Date: ${reportDate(snapshot)}`,
|
|
1431
|
-
`Open dashboard: ${snapshot.dashboardUrl}`,
|
|
1432
|
-
`Edit subscription settings: ${snapshot.reportSettingsUrl}`,
|
|
1433
|
-
];
|
|
1434
|
-
if (!options.screenshotParts.some(Boolean)) {
|
|
1435
|
-
lines.push("Dashboard image unavailable for this run.");
|
|
1436
|
-
} else {
|
|
1437
|
-
for (const [index, screenshot] of options.screenshotParts.entries()) {
|
|
1438
|
-
if (!screenshot)
|
|
1439
|
-
lines.push(
|
|
1440
|
-
`Dashboard image part ${index + 1} unavailable for this run.`,
|
|
1441
|
-
);
|
|
1442
|
-
}
|
|
1443
|
-
}
|
|
1444
|
-
return lines.join("\n");
|
|
1445
|
-
}
|
|
1446
|
-
|
|
1447
|
-
function reportFilename(title: string, part: number, total: number): string {
|
|
1448
|
-
const slug = title
|
|
1449
|
-
.toLowerCase()
|
|
1450
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
1451
|
-
.replace(/^-|-$/g, "")
|
|
1452
|
-
.slice(0, 64);
|
|
1453
|
-
const suffix = total > 1 ? `-part-${part}` : "";
|
|
1454
|
-
return `${slug || "dashboard"}-report${suffix}.png`;
|
|
1455
|
-
}
|
|
1456
|
-
|
|
200
|
+
/**
|
|
201
|
+
* Renders and emails one dashboard report entirely on the server: each panel's
|
|
202
|
+
* query runs through the same source dispatcher the UI uses, charts are drawn
|
|
203
|
+
* as SVG and rasterized, and everything else becomes real email HTML.
|
|
204
|
+
*
|
|
205
|
+
* There is deliberately no headless browser here. The previous implementation
|
|
206
|
+
* screenshotted the live React dashboard in 4-panel chunks inside one
|
|
207
|
+
* serverless invocation, so a single slow panel abandoned every later chunk and
|
|
208
|
+
* shipped an email full of "image part N was unavailable" placeholders. Do not
|
|
209
|
+
* reintroduce a browser, a chunk loop, or a mode that emails a report the
|
|
210
|
+
* caller cannot tell apart from a complete one.
|
|
211
|
+
*/
|
|
1457
212
|
export async function sendDashboardReportSubscription(
|
|
1458
213
|
sub: DashboardReportSubscription,
|
|
1459
214
|
options: {
|
|
1460
|
-
|
|
1461
|
-
skipEmailWithoutScreenshot?: boolean;
|
|
215
|
+
skipEmailWhenDegraded?: boolean;
|
|
1462
216
|
deadlineAt?: number;
|
|
1463
217
|
onCaptureOutcome?: (
|
|
1464
218
|
outcome: DashboardReportCaptureOutcome,
|
|
1465
219
|
) => Promise<void>;
|
|
1466
220
|
} = {},
|
|
1467
|
-
): Promise<{
|
|
1468
|
-
dashboardUrl: string;
|
|
1469
|
-
recipientCount: number;
|
|
1470
|
-
screenshotAttached: boolean;
|
|
1471
|
-
screenshotMode: "full" | "partial" | "none";
|
|
1472
|
-
screenshotError?: string;
|
|
1473
|
-
emailsSent: boolean;
|
|
1474
|
-
}> {
|
|
221
|
+
): Promise<DashboardReportResult> {
|
|
1475
222
|
const recipients = normalizeDashboardReportRecipients(sub.recipients);
|
|
1476
223
|
const snapshot = await runWithinReportDeadline(
|
|
1477
224
|
"Dashboard report snapshot",
|
|
1478
225
|
() => collectReportSnapshot(sub),
|
|
1479
226
|
options.deadlineAt,
|
|
1480
227
|
);
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
recipients.length,
|
|
1487
|
-
);
|
|
1488
|
-
} catch (err) {
|
|
1489
|
-
console.warn(
|
|
1490
|
-
"[dashboard-report] panel cache prewarm failed (non-fatal):",
|
|
1491
|
-
err instanceof Error ? err.message : err,
|
|
1492
|
-
);
|
|
1493
|
-
}
|
|
1494
|
-
const captureTimeoutMs = options.deadlineAt
|
|
1495
|
-
? Math.min(
|
|
1496
|
-
SERVERLESS_CHUNKED_ATTEMPT_TIMEOUT_MS,
|
|
1497
|
-
options.deadlineAt -
|
|
1498
|
-
Date.now() -
|
|
1499
|
-
reportDeliveryReserveMs(recipients.length),
|
|
1500
|
-
)
|
|
1501
|
-
: undefined;
|
|
1502
|
-
const capture = await captureDashboardPngWithFallback(
|
|
1503
|
-
sub,
|
|
228
|
+
|
|
229
|
+
const emailReserveMs = reportDeliveryReserveMs(recipients.length);
|
|
230
|
+
const panelData = await fetchReportPanelData({
|
|
231
|
+
ownerEmail: sub.ownerEmail,
|
|
232
|
+
orgId: sub.orgId,
|
|
1504
233
|
snapshot,
|
|
1505
|
-
|
|
1506
|
-
|
|
234
|
+
...(options.deadlineAt
|
|
235
|
+
? { deadlineAt: options.deadlineAt - emailReserveMs }
|
|
236
|
+
: {}),
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// Only panels that were actually queried can vote on total failure. Counting
|
|
240
|
+
// never-queryable panels (extensions) as survivors would let a dashboard of
|
|
241
|
+
// pure placeholders pass this guard and ship as "complete".
|
|
242
|
+
const attemptedPanelIds = [...panelData.keys()].filter(
|
|
243
|
+
(panelId) => panelData.get(panelId)?.status !== "not-emailable",
|
|
1507
244
|
);
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
245
|
+
const failedPanelIds = attemptedPanelIds.filter((panelId) => {
|
|
246
|
+
const data = panelData.get(panelId);
|
|
247
|
+
return (
|
|
248
|
+
data?.status === "query-failed" || data?.status === "missing-credential"
|
|
249
|
+
);
|
|
1511
250
|
});
|
|
1512
|
-
if (
|
|
251
|
+
if (
|
|
252
|
+
attemptedPanelIds.length > 0 &&
|
|
253
|
+
failedPanelIds.length === attemptedPanelIds.length
|
|
254
|
+
) {
|
|
255
|
+
const firstError = failedPanelIds
|
|
256
|
+
.map((panelId) => {
|
|
257
|
+
const data = panelData.get(panelId);
|
|
258
|
+
return data && "message" in data ? data.message : "";
|
|
259
|
+
})
|
|
260
|
+
.find(Boolean);
|
|
261
|
+
await options.onCaptureOutcome?.({
|
|
262
|
+
mode: "none",
|
|
263
|
+
error: `every dashboard panel failed to load: ${firstError ?? "unknown error"}`,
|
|
264
|
+
});
|
|
1513
265
|
throw new Error(
|
|
1514
|
-
|
|
1515
|
-
? `Dashboard screenshot unavailable: ${capture.error}`
|
|
1516
|
-
: "Dashboard screenshot unavailable",
|
|
266
|
+
`Dashboard report has no usable data: every one of ${attemptedPanelIds.length} panels failed (${firstError ?? "unknown error"})`,
|
|
1517
267
|
);
|
|
1518
268
|
}
|
|
1519
|
-
|
|
269
|
+
|
|
270
|
+
const rendered = await runWithinReportDeadline(
|
|
271
|
+
"Dashboard report rendering",
|
|
272
|
+
() => renderReportEmail({ snapshot, panelData }),
|
|
273
|
+
options.deadlineAt ? options.deadlineAt - emailReserveMs : undefined,
|
|
274
|
+
);
|
|
275
|
+
// A dashboard whose only reportable panels are extensions renders nothing but
|
|
276
|
+
// "open the dashboard" links. Nothing failed, so degradedPanelIds is empty —
|
|
277
|
+
// but the report is not backed by data and must not claim to be complete. A
|
|
278
|
+
// section-only dashboard (panelData empty) has nothing to render and is fine.
|
|
279
|
+
const noPanelBackedByData =
|
|
280
|
+
panelData.size > 0 && attemptedPanelIds.length === 0;
|
|
281
|
+
const reportMode: DashboardReportMode =
|
|
282
|
+
rendered.degradedPanelIds.length || noPanelBackedByData
|
|
283
|
+
? "degraded"
|
|
284
|
+
: "complete";
|
|
285
|
+
const reportError = rendered.degradedPanelIds.length
|
|
286
|
+
? `${rendered.degradedPanelIds.length} of ${panelData.size} panels could not be rendered: ${rendered.degradedPanelIds.join(", ")}`
|
|
287
|
+
: noPanelBackedByData
|
|
288
|
+
? "No panel in this dashboard can be rendered into an email"
|
|
289
|
+
: undefined;
|
|
290
|
+
|
|
291
|
+
await options.onCaptureOutcome?.({
|
|
292
|
+
mode: reportMode === "complete" ? "full" : "partial",
|
|
293
|
+
...(reportError ? { error: reportError } : {}),
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
if (reportMode === "degraded" && options.skipEmailWhenDegraded) {
|
|
1520
297
|
return {
|
|
1521
298
|
dashboardUrl: snapshot.dashboardUrl,
|
|
1522
299
|
recipientCount: recipients.length,
|
|
1523
|
-
|
|
1524
|
-
|
|
300
|
+
reportMode,
|
|
301
|
+
degradedPanelIds: rendered.degradedPanelIds,
|
|
1525
302
|
emailsSent: false,
|
|
1526
|
-
...(
|
|
303
|
+
...(reportError ? { reportError } : {}),
|
|
1527
304
|
};
|
|
1528
305
|
}
|
|
1529
|
-
const screenshotAttached = Boolean(capture.pngs?.some(Boolean));
|
|
1530
|
-
const screenshotParts = capture.pngs ?? [];
|
|
1531
|
-
const html = renderReportEmailHtml(snapshot, {
|
|
1532
|
-
screenshotParts,
|
|
1533
|
-
});
|
|
1534
|
-
const text = renderReportText(snapshot, {
|
|
1535
|
-
screenshotParts,
|
|
1536
|
-
});
|
|
1537
|
-
const subject = `Daily dashboard: ${snapshot.title}`;
|
|
1538
306
|
|
|
307
|
+
const subject = `Daily dashboard: ${snapshot.title} — ${reportDate(snapshot)}`;
|
|
1539
308
|
for (const to of recipients) {
|
|
1540
309
|
const emailTimeoutMs = options.deadlineAt
|
|
1541
310
|
? Math.min(
|
|
@@ -1551,27 +320,11 @@ export async function sendDashboardReportSubscription(
|
|
|
1551
320
|
await sendEmail({
|
|
1552
321
|
to,
|
|
1553
322
|
subject,
|
|
1554
|
-
html,
|
|
1555
|
-
text,
|
|
1556
|
-
attachments
|
|
1557
|
-
?
|
|
1558
|
-
|
|
1559
|
-
? [
|
|
1560
|
-
{
|
|
1561
|
-
filename: reportFilename(
|
|
1562
|
-
snapshot.title,
|
|
1563
|
-
index + 1,
|
|
1564
|
-
capture.pngs!.length,
|
|
1565
|
-
),
|
|
1566
|
-
content: png,
|
|
1567
|
-
contentType: "image/png",
|
|
1568
|
-
contentId: `${DASHBOARD_REPORT_CID}-${index + 1}`,
|
|
1569
|
-
disposition: "inline",
|
|
1570
|
-
},
|
|
1571
|
-
]
|
|
1572
|
-
: [],
|
|
1573
|
-
)
|
|
1574
|
-
: undefined,
|
|
323
|
+
html: rendered.html,
|
|
324
|
+
text: rendered.text,
|
|
325
|
+
...(rendered.attachments.length
|
|
326
|
+
? { attachments: rendered.attachments }
|
|
327
|
+
: {}),
|
|
1575
328
|
timeoutMs: emailTimeoutMs,
|
|
1576
329
|
});
|
|
1577
330
|
}
|
|
@@ -1579,9 +332,9 @@ export async function sendDashboardReportSubscription(
|
|
|
1579
332
|
return {
|
|
1580
333
|
dashboardUrl: snapshot.dashboardUrl,
|
|
1581
334
|
recipientCount: recipients.length,
|
|
1582
|
-
|
|
1583
|
-
|
|
335
|
+
reportMode,
|
|
336
|
+
degradedPanelIds: rendered.degradedPanelIds,
|
|
1584
337
|
emailsSent: true,
|
|
1585
|
-
...(
|
|
338
|
+
...(reportError ? { reportError } : {}),
|
|
1586
339
|
};
|
|
1587
340
|
}
|