@agent-native/core 0.98.0 → 0.98.2
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 +32 -0
- package/corpus/core/docs/content/locales/ar-SA/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/ar-SA/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/de-DE/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/es-ES/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/fr-FR/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/hi-IN/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/ja-JP/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/ko-KR/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/pt-BR/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/zh-CN/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/zh-TW/template-plan.mdx +1 -1
- package/corpus/core/docs/content/pr-visual-recap.mdx +50 -1
- package/corpus/core/docs/content/template-plan.mdx +1 -1
- package/corpus/core/package.json +2 -2
- package/corpus/core/src/action-change-marker.ts +8 -1
- package/corpus/core/src/changelog/parse.ts +8 -3
- package/corpus/core/src/cli/plan-local.ts +43 -11
- package/corpus/core/src/cli/pr-visual-recap-workflow.ts +2 -9
- package/corpus/core/src/cli/recap.ts +356 -4
- package/corpus/core/src/cli/skills-content/local-files.ts +17 -12
- package/corpus/core/src/client/AgentPanel.tsx +2 -3
- package/corpus/core/src/client/AssistantChat.tsx +83 -39
- package/corpus/core/src/client/analytics.ts +125 -14
- package/corpus/core/src/client/blocks/library/wireframe-kit.tsx +16 -2
- package/corpus/core/src/client/chat-model-groups.ts +28 -0
- package/corpus/core/src/client/composer/RealtimeVoiceMode.tsx +442 -85
- package/corpus/core/src/client/composer/TiptapComposer.tsx +46 -29
- package/corpus/core/src/client/composer/VoiceButton.tsx +2 -1
- package/corpus/core/src/client/composer/index.ts +5 -0
- package/corpus/core/src/client/composer/useRealtimeVoiceMode.tsx +1206 -67
- package/corpus/core/src/client/index.ts +10 -0
- package/corpus/core/src/client/progress/RunsTray.tsx +13 -1
- package/corpus/core/src/client/session-replay.ts +10 -0
- package/corpus/core/src/client/settings/DemoModeSection.tsx +4 -28
- package/corpus/core/src/client/settings/SecretsSection.tsx +387 -266
- package/corpus/core/src/client/settings/SettingsPanel.tsx +117 -38
- package/corpus/core/src/client/url-scrub.ts +13 -0
- package/corpus/core/src/client/use-action.ts +12 -0
- package/corpus/core/src/client/use-agent-chat-home-handoff.ts +8 -1
- package/corpus/core/src/client/use-agent-engine-configured.ts +17 -3
- package/corpus/core/src/client/use-db-sync.ts +84 -34
- package/corpus/core/src/client/use-demo-mode-status.ts +44 -0
- package/corpus/core/src/client/use-pausing-interval.ts +14 -4
- package/corpus/core/src/integrations/scope-store.ts +1 -1
- package/corpus/core/src/integrations/usage-budget-store.ts +1 -1
- package/corpus/core/src/localization/default-messages.ts +44 -1
- package/corpus/core/src/mcp-client/workspace-servers.ts +4 -4
- package/corpus/core/src/secrets/crypto.ts +28 -8
- package/corpus/core/src/server/action-change.ts +5 -1
- package/corpus/core/src/server/action-routes.ts +8 -0
- package/corpus/core/src/server/poll.ts +1 -0
- package/corpus/core/src/server/realtime-voice.ts +299 -13
- package/corpus/core/src/styles/agent-native.css +2 -2
- package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/core/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +7 -3
- package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +39 -9
- package/corpus/core/src/vite/client.ts +9 -1
- package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +10 -5
- package/corpus/templates/analytics/AGENTS.md +17 -13
- package/corpus/templates/analytics/actions/navigate.ts +59 -5
- package/corpus/templates/analytics/actions/view-screen.ts +3 -6
- package/corpus/templates/analytics/app/components/ProviderCorpusJobNotifier.tsx +20 -3
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +20 -5
- package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +21 -6
- package/corpus/templates/analytics/app/global.css +19 -20
- package/corpus/templates/analytics/app/lib/demo-chart-trend.ts +156 -0
- package/corpus/templates/analytics/app/lib/provider-corpus-job-sync.ts +26 -0
- package/corpus/templates/analytics/app/pages/Settings.tsx +35 -341
- package/corpus/templates/analytics/app/pages/monitoring/ErrorsPanel.tsx +38 -7
- package/corpus/templates/analytics/app/pages/monitoring/MonitoringPage.tsx +1 -1
- package/corpus/templates/analytics/app/pages/monitoring/errors/i18n.ts +3 -0
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +333 -272
- package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +72 -17
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +297 -108
- package/corpus/templates/analytics/app/root.tsx +28 -8
- package/corpus/templates/analytics/changelog/2026-06-24-first-party-signup-and-pageview-panels-now-honor-dashboard-filters.md +2 -1
- package/corpus/templates/analytics/changelog/2026-06-25-referrer-dashboard-panels-show-external-domains.md +2 -1
- package/corpus/templates/analytics/changelog/2026-07-06-mobile-chat-header-is-more-compact-and-the-menu-button-opens-navigation.md +1 -0
- package/corpus/templates/analytics/changelog/2026-07-08-dashboard-history-and-chat-context.md +1 -0
- package/corpus/templates/analytics/changelog/2026-07-08-settings-are-cleaner-searchable-and-alerts-have-their-own-tab.md +1 -0
- package/corpus/templates/analytics/changelog/2026-07-08-sidebar-sections-stay-collapsed-until-opened.md +1 -0
- package/corpus/templates/analytics/changelog/2026-07-11-analytics-no-longer-repeatedly-restarts-background-requests-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-analytics-only-asks-for-replay-storage-when-you-enable-sessi.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-charts-now-show-their-loading-skeleton-while-refreshing.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-realtime-voice-now-shows-a-clear-connection-indicator-comple.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-replay-event-counts-stay-hidden-until-recordings-finish-load.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-replay-storage-key-mismatches-show-actionable-setup-guidance.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-replay-timelines-group-continuous-scrolling-and-dev-tools-co.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-session-filters-now-stay-compact-in-a-settings-menu-at-mediu.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-session-replay-console-errors-now-link-to-matching-issues-or.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-session-replays-load-large-recordings-faster-and-surface-fai.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-session-replays-preserve-recorded-styles-and-viewport-layout.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-session-replays-stay-centered-instead-of-clipping-wide-recor.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-daily-dashboard-emails-reliably-include-the-complete-dashboa.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-demo-mode-charts-trend-upward.md +6 -0
- package/corpus/templates/analytics/package.json +1 -1
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +1 -303
- package/corpus/templates/analytics/server/handlers/session-replay.ts +57 -0
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +2 -0
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +1 -1
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +17 -33
- package/corpus/templates/analytics/server/lib/demo-dashboards.ts +16 -3
- package/corpus/templates/analytics/server/lib/session-replay-agent-context.ts +12 -0
- package/corpus/templates/analytics/server/lib/session-replay.ts +208 -2
- package/corpus/templates/analytics/server/plugins/onboarding.ts +7 -79
- package/corpus/templates/analytics/server/routes/api/session-replay/recordings/[recordingId]/chunks.get.ts +1 -0
- package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/templates/assets/app/global.css +4 -4
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +0 -1
- package/corpus/templates/assets/app/routes/library.tsx +0 -1
- package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/templates/brain/app/global.css +5 -5
- package/corpus/templates/brain/app/root.tsx +0 -3
- package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/templates/calendar/app/root.tsx +1 -0
- package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/templates/clips/app/components/player/video-player.tsx +5 -1
- package/corpus/templates/clips/app/hooks/use-auto-title.ts +74 -8
- package/corpus/templates/clips/app/hooks/use-library.ts +12 -25
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +20 -22
- package/corpus/templates/clips/changelog/2026-07-11-clips-no-longer-stay-stuck-on-preparing-clip-when-they-are-r.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-11-generated-titles-no-longer-cause-continuous-background-refreshes.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-11-s3-storage-setup-stays-collapsed-until-you-choose-it-as-the-.md +6 -0
- package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +2 -2
- package/corpus/templates/content/app/hooks/use-comments.ts +0 -1
- package/corpus/templates/content/changelog/2026-07-11-comments-now-update-from-live-collaboration-events-without-c.md +6 -0
- package/corpus/templates/content/changelog/2026-07-12-the-left-sidebar-stays-fixed-horizontally-while-scrolling-on.md +6 -0
- package/corpus/templates/design/app/components/layout/Header.tsx +1 -1
- package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/templates/macros/app/components/layout/AppLayout.tsx +1 -2
- package/corpus/templates/macros/app/root.tsx +0 -3
- package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/templates/mail/app/hooks/use-compose-state.ts +1 -0
- package/corpus/templates/mail/app/root.tsx +1 -12
- package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/templates/plan/.agents/skills/visual-plan/references/local-files.md +17 -12
- package/corpus/templates/plan/.agents/skills/visual-recap/references/local-files.md +17 -12
- package/corpus/templates/plan/actions/validate-local-plan-source.ts +4 -4
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +2 -1
- package/corpus/templates/plan/app/hooks/use-navigation-state.ts +5 -2
- package/corpus/templates/plan/app/hooks/use-plans.ts +6 -13
- package/corpus/templates/plan/app/lib/plan-local-bridge.ts +41 -0
- package/corpus/templates/plan/app/lib/plan-tracking.ts +3 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +14 -36
- package/corpus/templates/plan/app/root.tsx +13 -3
- package/corpus/templates/plan/changelog/2026-07-11-plan-refreshes-only-when-content-changes.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-12-local-plan-source-now-stays-on-device.md +6 -0
- package/corpus/templates/slides/app/components/comments/SlideCommentsPanel.tsx +4 -1
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +1 -1
- package/corpus/templates/slides/app/components/layout/Header.tsx +1 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +1 -0
- package/corpus/templates/slides/app/hooks/use-slide-comments.ts +7 -31
- package/corpus/templates/slides/changelog/2026-07-11-comments-now-update-from-live-collaboration-events-without-c.md +6 -0
- package/dist/action-change-marker.d.ts +1 -0
- package/dist/action-change-marker.d.ts.map +1 -1
- package/dist/action-change-marker.js +7 -1
- package/dist/action-change-marker.js.map +1 -1
- package/dist/changelog/parse.d.ts +4 -2
- package/dist/changelog/parse.d.ts.map +1 -1
- package/dist/changelog/parse.js +5 -3
- package/dist/changelog/parse.js.map +1 -1
- package/dist/cli/plan-local.d.ts +6 -6
- package/dist/cli/plan-local.d.ts.map +1 -1
- package/dist/cli/plan-local.js +36 -7
- package/dist/cli/plan-local.js.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.d.ts +2 -8
- package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.js +2 -8
- package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
- package/dist/cli/recap.d.ts +22 -1
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +286 -2
- package/dist/cli/recap.js.map +1 -1
- package/dist/cli/skills-content/local-files.d.ts +1 -1
- package/dist/cli/skills-content/local-files.d.ts.map +1 -1
- package/dist/cli/skills-content/local-files.js +17 -12
- package/dist/cli/skills-content/local-files.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +2 -3
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +7 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +62 -40
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/analytics.d.ts +8 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +103 -13
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/blocks/library/wireframe-kit.d.ts +2 -0
- package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -1
- package/dist/client/blocks/library/wireframe-kit.js +9 -2
- package/dist/client/blocks/library/wireframe-kit.js.map +1 -1
- package/dist/client/chat-model-groups.d.ts.map +1 -1
- package/dist/client/chat-model-groups.js +24 -0
- package/dist/client/chat-model-groups.js.map +1 -1
- package/dist/client/composer/RealtimeVoiceMode.d.ts +40 -4
- package/dist/client/composer/RealtimeVoiceMode.d.ts.map +1 -1
- package/dist/client/composer/RealtimeVoiceMode.js +172 -42
- package/dist/client/composer/RealtimeVoiceMode.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts +4 -0
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +47 -29
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/composer/VoiceButton.d.ts.map +1 -1
- package/dist/client/composer/VoiceButton.js +2 -2
- package/dist/client/composer/VoiceButton.js.map +1 -1
- package/dist/client/composer/index.d.ts +2 -2
- package/dist/client/composer/index.d.ts.map +1 -1
- package/dist/client/composer/index.js +1 -1
- package/dist/client/composer/index.js.map +1 -1
- package/dist/client/composer/useRealtimeVoiceMode.d.ts +100 -3
- package/dist/client/composer/useRealtimeVoiceMode.d.ts.map +1 -1
- package/dist/client/composer/useRealtimeVoiceMode.js +952 -51
- package/dist/client/composer/useRealtimeVoiceMode.js.map +1 -1
- package/dist/client/index.d.ts +3 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/progress/RunsTray.d.ts.map +1 -1
- package/dist/client/progress/RunsTray.js +10 -1
- package/dist/client/progress/RunsTray.js.map +1 -1
- package/dist/client/session-replay.d.ts +2 -0
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +7 -0
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/settings/DemoModeSection.d.ts.map +1 -1
- package/dist/client/settings/DemoModeSection.js +4 -23
- package/dist/client/settings/DemoModeSection.js.map +1 -1
- package/dist/client/settings/SecretsSection.d.ts +2 -3
- package/dist/client/settings/SecretsSection.d.ts.map +1 -1
- package/dist/client/settings/SecretsSection.js +46 -22
- package/dist/client/settings/SecretsSection.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts +9 -0
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +46 -12
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/url-scrub.d.ts.map +1 -1
- package/dist/client/url-scrub.js +14 -0
- package/dist/client/url-scrub.js.map +1 -1
- package/dist/client/use-action.d.ts +2 -0
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +10 -0
- package/dist/client/use-action.js.map +1 -1
- package/dist/client/use-agent-chat-home-handoff.d.ts +2 -0
- package/dist/client/use-agent-chat-home-handoff.d.ts.map +1 -1
- package/dist/client/use-agent-chat-home-handoff.js +7 -1
- package/dist/client/use-agent-chat-home-handoff.js.map +1 -1
- package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
- package/dist/client/use-agent-engine-configured.js +17 -3
- package/dist/client/use-agent-engine-configured.js.map +1 -1
- package/dist/client/use-db-sync.d.ts +8 -2
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +57 -32
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/client/use-demo-mode-status.d.ts +12 -0
- package/dist/client/use-demo-mode-status.d.ts.map +1 -0
- package/dist/client/use-demo-mode-status.js +30 -0
- package/dist/client/use-demo-mode-status.js.map +1 -0
- package/dist/client/use-pausing-interval.d.ts.map +1 -1
- package/dist/client/use-pausing-interval.js +16 -4
- package/dist/client/use-pausing-interval.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/integrations/scope-store.js +1 -1
- package/dist/integrations/scope-store.js.map +1 -1
- package/dist/integrations/usage-budget-store.js +1 -1
- package/dist/integrations/usage-budget-store.js.map +1 -1
- package/dist/localization/default-messages.d.ts +41 -1
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +41 -1
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/mcp-client/workspace-servers.js +4 -4
- package/dist/mcp-client/workspace-servers.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/secrets/crypto.d.ts +7 -6
- package/dist/secrets/crypto.d.ts.map +1 -1
- package/dist/secrets/crypto.js +30 -11
- package/dist/secrets/crypto.js.map +1 -1
- package/dist/server/action-change.d.ts +1 -0
- package/dist/server/action-change.d.ts.map +1 -1
- package/dist/server/action-change.js +4 -1
- package/dist/server/action-change.js.map +1 -1
- package/dist/server/action-routes.d.ts.map +1 -1
- package/dist/server/action-routes.js +5 -0
- package/dist/server/action-routes.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/poll.d.ts.map +1 -1
- package/dist/server/poll.js +1 -0
- package/dist/server/poll.js.map +1 -1
- package/dist/server/realtime-voice.d.ts +7 -0
- package/dist/server/realtime-voice.d.ts.map +1 -1
- package/dist/server/realtime-voice.js +222 -12
- package/dist/server/realtime-voice.js.map +1 -1
- package/dist/styles/agent-native.css +2 -2
- package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +7 -3
- package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +39 -9
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +6 -1
- package/dist/vite/client.js.map +1 -1
- package/docs/content/locales/ar-SA/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/ar-SA/template-plan.mdx +1 -1
- package/docs/content/locales/de-DE/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/de-DE/template-plan.mdx +1 -1
- package/docs/content/locales/es-ES/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/es-ES/template-plan.mdx +1 -1
- package/docs/content/locales/fr-FR/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/fr-FR/template-plan.mdx +1 -1
- package/docs/content/locales/hi-IN/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/hi-IN/template-plan.mdx +1 -1
- package/docs/content/locales/ja-JP/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/ja-JP/template-plan.mdx +1 -1
- package/docs/content/locales/ko-KR/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/ko-KR/template-plan.mdx +1 -1
- package/docs/content/locales/pt-BR/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/pt-BR/template-plan.mdx +1 -1
- package/docs/content/locales/zh-CN/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/zh-CN/template-plan.mdx +1 -1
- package/docs/content/locales/zh-TW/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/zh-TW/template-plan.mdx +1 -1
- package/docs/content/pr-visual-recap.mdx +50 -1
- package/docs/content/template-plan.mdx +1 -1
- package/package.json +2 -2
- package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +7 -3
- package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +39 -9
|
@@ -42,9 +42,8 @@ const DASHBOARD_REPORT_SCREENSHOT_PARAM = "reportScreenshot";
|
|
|
42
42
|
const DASHBOARD_REPORT_SETTINGS_PARAM = "reportSettings";
|
|
43
43
|
const DASHBOARD_REPORT_CID = "dashboard-report-snapshot";
|
|
44
44
|
const LOCAL_SCREENSHOT_TIMEOUT_MS = 90_000;
|
|
45
|
-
const SERVERLESS_SCREENSHOT_TIMEOUT_MS =
|
|
46
|
-
const SERVERLESS_SECOND_READY_TIMEOUT_MS =
|
|
47
|
-
const MAX_SCREENSHOT_VIEWPORT_HEIGHT = 30_000;
|
|
45
|
+
const SERVERLESS_SCREENSHOT_TIMEOUT_MS = 90_000;
|
|
46
|
+
const SERVERLESS_SECOND_READY_TIMEOUT_MS = 45_000;
|
|
48
47
|
const SCREENSHOT_VIEWPORT_PADDING = 64;
|
|
49
48
|
|
|
50
49
|
type DashboardScreenshotAttempt = {
|
|
@@ -328,42 +327,27 @@ async function scrollDashboardForLazyRendering(page: any): Promise<void> {
|
|
|
328
327
|
})()`);
|
|
329
328
|
}
|
|
330
329
|
|
|
331
|
-
async function
|
|
330
|
+
async function fitViewportWidthToDashboardCapture(
|
|
332
331
|
page: any,
|
|
333
332
|
capture: any,
|
|
334
|
-
|
|
333
|
+
viewport: { width: number; height: number },
|
|
335
334
|
): Promise<void> {
|
|
336
335
|
const box = await capture.boundingBox();
|
|
337
336
|
if (!box) return;
|
|
338
337
|
|
|
339
|
-
const
|
|
340
|
-
width
|
|
341
|
-
|
|
342
|
-
Math.min(1800, Math.ceil(box.width + SCREENSHOT_VIEWPORT_PADDING)),
|
|
343
|
-
),
|
|
344
|
-
height: Math.max(
|
|
345
|
-
minViewport.height,
|
|
346
|
-
Math.min(
|
|
347
|
-
MAX_SCREENSHOT_VIEWPORT_HEIGHT,
|
|
348
|
-
Math.ceil(box.height + SCREENSHOT_VIEWPORT_PADDING),
|
|
349
|
-
),
|
|
350
|
-
),
|
|
351
|
-
};
|
|
352
|
-
await page.setViewportSize(size);
|
|
353
|
-
await page.waitForTimeout(250);
|
|
354
|
-
|
|
355
|
-
const resizedBox = await capture.boundingBox();
|
|
356
|
-
if (!resizedBox) return;
|
|
357
|
-
const resizedHeight = Math.ceil(
|
|
358
|
-
resizedBox.height + SCREENSHOT_VIEWPORT_PADDING,
|
|
338
|
+
const width = Math.max(
|
|
339
|
+
viewport.width,
|
|
340
|
+
Math.min(1800, Math.ceil(box.width + SCREENSHOT_VIEWPORT_PADDING)),
|
|
359
341
|
);
|
|
360
|
-
if (
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
342
|
+
if (width === viewport.width) return;
|
|
343
|
+
|
|
344
|
+
// Keep the render surface bounded. Playwright's locator screenshot captures
|
|
345
|
+
// the full element beyond the viewport, while growing Chromium to the full
|
|
346
|
+
// dashboard height can exhaust memory and close the browser on serverless
|
|
347
|
+
// workers. Width-only fitting preserves the full dashboard without that
|
|
348
|
+
// oversized render surface.
|
|
349
|
+
await page.setViewportSize({ width, height: viewport.height });
|
|
350
|
+
await page.waitForTimeout(250);
|
|
367
351
|
}
|
|
368
352
|
|
|
369
353
|
async function captureDashboardPng(
|
|
@@ -412,7 +396,7 @@ async function captureDashboardPng(
|
|
|
412
396
|
await scrollDashboardForLazyRendering(page);
|
|
413
397
|
await waitForDashboardReportReady(page, secondReadyTimeoutMs());
|
|
414
398
|
|
|
415
|
-
await
|
|
399
|
+
await fitViewportWidthToDashboardCapture(page, capture, attempt.viewport);
|
|
416
400
|
await capture.scrollIntoViewIfNeeded();
|
|
417
401
|
const image = await capture.screenshot({
|
|
418
402
|
type: "png",
|
|
@@ -104,6 +104,15 @@ function publicState(state: DemoDashboardState): Record<string, unknown> {
|
|
|
104
104
|
};
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
function stateContent(state: DemoDashboardState): string {
|
|
108
|
+
return JSON.stringify({
|
|
109
|
+
version: state.version,
|
|
110
|
+
initializedAt: state.initializedAt,
|
|
111
|
+
dashboards: state.dashboards ?? {},
|
|
112
|
+
deleted: state.deleted ?? {},
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
107
116
|
export function demoDashboardIdForUser(
|
|
108
117
|
email: string,
|
|
109
118
|
demoId: DemoDashboardId,
|
|
@@ -291,14 +300,18 @@ export async function ensureDemoDashboardsForUser(
|
|
|
291
300
|
});
|
|
292
301
|
}
|
|
293
302
|
|
|
294
|
-
const
|
|
303
|
+
const updatedStateContent: DemoDashboardState = {
|
|
295
304
|
version: DEMO_DASHBOARD_VERSION,
|
|
296
305
|
initializedAt: state.initializedAt ?? nowIso(),
|
|
297
|
-
updatedAt: nowIso(),
|
|
298
306
|
dashboards,
|
|
299
307
|
deleted,
|
|
300
308
|
};
|
|
301
|
-
|
|
309
|
+
if (reset || stateContent(state) !== stateContent(updatedStateContent)) {
|
|
310
|
+
await writeDemoState(ctx.email, {
|
|
311
|
+
...updatedStateContent,
|
|
312
|
+
updatedAt: nowIso(),
|
|
313
|
+
});
|
|
314
|
+
}
|
|
302
315
|
|
|
303
316
|
const firstActive = results.find((row) => row.installed && !row.archivedAt);
|
|
304
317
|
return {
|
|
@@ -50,6 +50,7 @@ const MOUSE_INTERACTION = {
|
|
|
50
50
|
DblClick: 4,
|
|
51
51
|
Focus: 5,
|
|
52
52
|
} as const;
|
|
53
|
+
const SCROLL_MARKER_BURST_MS = 1_000;
|
|
53
54
|
|
|
54
55
|
function appBasePath(): string {
|
|
55
56
|
const raw = process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH || "";
|
|
@@ -499,6 +500,7 @@ function capReplayTimelineMarkers(
|
|
|
499
500
|
function buildReplayTimeline(events: AgentReplayEvent[]) {
|
|
500
501
|
const startedAt = replayStartedAt(events);
|
|
501
502
|
const markers: ReplayTimelineMarker[] = [];
|
|
503
|
+
const lastScrollByTarget = new Map<string, number>();
|
|
502
504
|
|
|
503
505
|
for (const event of events) {
|
|
504
506
|
const timestamp = Number(event.timestamp ?? 0);
|
|
@@ -568,6 +570,15 @@ function buildReplayTimeline(events: AgentReplayEvent[]) {
|
|
|
568
570
|
event.type === RRWEB_EVENT_TYPE.IncrementalSnapshot &&
|
|
569
571
|
event.data?.source === INCREMENTAL_SOURCE.Scroll
|
|
570
572
|
) {
|
|
573
|
+
const target = String(event.data?.id ?? "viewport");
|
|
574
|
+
const previousTimestamp = lastScrollByTarget.get(target);
|
|
575
|
+
if (
|
|
576
|
+
previousTimestamp !== undefined &&
|
|
577
|
+
timestamp - previousTimestamp <= SCROLL_MARKER_BURST_MS
|
|
578
|
+
) {
|
|
579
|
+
lastScrollByTarget.set(target, timestamp);
|
|
580
|
+
continue;
|
|
581
|
+
}
|
|
571
582
|
markers.push({
|
|
572
583
|
timestamp,
|
|
573
584
|
offsetMs: Math.max(0, timestamp - startedAt),
|
|
@@ -575,6 +586,7 @@ function buildReplayTimeline(events: AgentReplayEvent[]) {
|
|
|
575
586
|
label: "Scroll",
|
|
576
587
|
detail: null,
|
|
577
588
|
});
|
|
589
|
+
lastScrollByTarget.set(target, timestamp);
|
|
578
590
|
} else if (
|
|
579
591
|
event.type === RRWEB_EVENT_TYPE.IncrementalSnapshot &&
|
|
580
592
|
event.data?.source === INCREMENTAL_SOURCE.MouseInteraction &&
|
|
@@ -16,7 +16,19 @@ import {
|
|
|
16
16
|
roleSatisfies,
|
|
17
17
|
type ShareRole,
|
|
18
18
|
} from "@agent-native/core/sharing";
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
and,
|
|
21
|
+
asc,
|
|
22
|
+
desc,
|
|
23
|
+
eq,
|
|
24
|
+
gte,
|
|
25
|
+
inArray,
|
|
26
|
+
isNull,
|
|
27
|
+
lt,
|
|
28
|
+
lte,
|
|
29
|
+
or,
|
|
30
|
+
sql,
|
|
31
|
+
} from "drizzle-orm";
|
|
20
32
|
|
|
21
33
|
import {
|
|
22
34
|
isFailedSessionReplayNetworkStatus,
|
|
@@ -229,6 +241,10 @@ const DEFAULT_REPLAY_EVENTS_READ = 10_000;
|
|
|
229
241
|
const MAX_REPLAY_EVENTS_READ = 100_000;
|
|
230
242
|
const MAX_REPLAY_EVENTS_RESPONSE_BYTES =
|
|
231
243
|
MAX_BLOB_REPLAY_CHUNK_BYTES + 512 * 1024;
|
|
244
|
+
export const MAX_REPLAY_CHUNK_READ_BATCH_SIZE = 20;
|
|
245
|
+
export const MAX_REPLAY_CHUNK_READ_BATCH_BYTES =
|
|
246
|
+
MAX_REPLAY_EVENTS_RESPONSE_BYTES;
|
|
247
|
+
const REPLAY_CHUNK_READ_CONCURRENCY = 10;
|
|
232
248
|
const DEFAULT_SESSION_RECORDINGS_LIMIT = 50;
|
|
233
249
|
const MAX_SESSION_RECORDINGS_LIMIT = 100;
|
|
234
250
|
const DEFAULT_REPLAY_RETENTION_DAYS = 30;
|
|
@@ -1954,7 +1970,16 @@ async function readSessionReplayChunkBytesForRecording(
|
|
|
1954
1970
|
const ref = decodeReplayBlobRef(row.storageRef);
|
|
1955
1971
|
if (!ref)
|
|
1956
1972
|
throw replayError("Session replay blob reference is invalid", 500);
|
|
1957
|
-
const blob = await readPrivateBlob(ref.handle)
|
|
1973
|
+
const blob = await readPrivateBlob(ref.handle).catch((error) => {
|
|
1974
|
+
console.error(
|
|
1975
|
+
`[session-replay] Failed to decrypt blob chunk ${recording.id}/${row.seq}:`,
|
|
1976
|
+
error,
|
|
1977
|
+
);
|
|
1978
|
+
throw replayError(
|
|
1979
|
+
"Session replay storage could not be decrypted with this environment's encryption key. When using a production Analytics database locally, set ANALYTICS_SECRETS_ENCRYPTION_KEY to the matching production key.",
|
|
1980
|
+
503,
|
|
1981
|
+
);
|
|
1982
|
+
});
|
|
1958
1983
|
return {
|
|
1959
1984
|
recording,
|
|
1960
1985
|
seq: row.seq,
|
|
@@ -1972,6 +1997,187 @@ async function readSessionReplayChunkBytesForRecording(
|
|
|
1972
1997
|
};
|
|
1973
1998
|
}
|
|
1974
1999
|
|
|
2000
|
+
export interface SessionReplayChunkBatchItem {
|
|
2001
|
+
seq: number;
|
|
2002
|
+
checksum: string;
|
|
2003
|
+
byteLength: number;
|
|
2004
|
+
eventCount: number;
|
|
2005
|
+
events: unknown[];
|
|
2006
|
+
unavailable?: true;
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
export interface SessionReplayChunkBatchResult {
|
|
2010
|
+
chunks: SessionReplayChunkBatchItem[];
|
|
2011
|
+
unavailableChunks: number;
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
function validateReplayChunkReadSeqs(seqs: number[]): number[] {
|
|
2015
|
+
if (!seqs.length) {
|
|
2016
|
+
throw replayError("At least one replay chunk seq is required", 400);
|
|
2017
|
+
}
|
|
2018
|
+
if (seqs.length > MAX_REPLAY_CHUNK_READ_BATCH_SIZE) {
|
|
2019
|
+
throw replayError(
|
|
2020
|
+
`At most ${MAX_REPLAY_CHUNK_READ_BATCH_SIZE} replay chunks may be read per request`,
|
|
2021
|
+
400,
|
|
2022
|
+
);
|
|
2023
|
+
}
|
|
2024
|
+
const unique = new Set<number>();
|
|
2025
|
+
for (const seq of seqs) {
|
|
2026
|
+
if (!Number.isSafeInteger(seq) || seq < 0) {
|
|
2027
|
+
throw replayError("Replay chunk seqs must be non-negative integers", 400);
|
|
2028
|
+
}
|
|
2029
|
+
if (unique.has(seq)) {
|
|
2030
|
+
throw replayError("Replay chunk seqs must be unique", 400);
|
|
2031
|
+
}
|
|
2032
|
+
unique.add(seq);
|
|
2033
|
+
}
|
|
2034
|
+
return [...seqs];
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
function unavailableReplayChunkBatchItem(
|
|
2038
|
+
seq: number,
|
|
2039
|
+
row?: any,
|
|
2040
|
+
): SessionReplayChunkBatchItem {
|
|
2041
|
+
return {
|
|
2042
|
+
seq,
|
|
2043
|
+
checksum: row?.checksum ?? "",
|
|
2044
|
+
byteLength: Number(row?.byteLength ?? 0),
|
|
2045
|
+
eventCount: Number(row?.eventCount ?? 0),
|
|
2046
|
+
events: [],
|
|
2047
|
+
unavailable: true,
|
|
2048
|
+
};
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
async function readReplayChunkBatchRow(
|
|
2052
|
+
recording: SessionRecordingSummary,
|
|
2053
|
+
row: any,
|
|
2054
|
+
): Promise<SessionReplayChunkBatchItem> {
|
|
2055
|
+
let json: string;
|
|
2056
|
+
if (row.storageKind === "blob" && row.storageRef) {
|
|
2057
|
+
const ref = decodeReplayBlobRef(row.storageRef);
|
|
2058
|
+
if (!ref) return unavailableReplayChunkBatchItem(row.seq, row);
|
|
2059
|
+
let blob: Awaited<ReturnType<typeof readPrivateBlob>>;
|
|
2060
|
+
try {
|
|
2061
|
+
blob = await readPrivateBlob(ref.handle);
|
|
2062
|
+
} catch (error) {
|
|
2063
|
+
console.error(
|
|
2064
|
+
`[session-replay] Failed to read blob chunk ${recording.id}/${row.seq}:`,
|
|
2065
|
+
error,
|
|
2066
|
+
);
|
|
2067
|
+
throw replayError(
|
|
2068
|
+
"Session replay storage could not be read with this environment's storage configuration or encryption key.",
|
|
2069
|
+
503,
|
|
2070
|
+
);
|
|
2071
|
+
}
|
|
2072
|
+
try {
|
|
2073
|
+
json = gunzipSync(Buffer.from(blob.data)).toString("utf8");
|
|
2074
|
+
} catch {
|
|
2075
|
+
return unavailableReplayChunkBatchItem(row.seq, row);
|
|
2076
|
+
}
|
|
2077
|
+
} else if (row.inlineData) {
|
|
2078
|
+
json = row.inlineData;
|
|
2079
|
+
} else {
|
|
2080
|
+
return unavailableReplayChunkBatchItem(row.seq, row);
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
return {
|
|
2084
|
+
seq: row.seq,
|
|
2085
|
+
checksum: row.checksum,
|
|
2086
|
+
byteLength: row.byteLength,
|
|
2087
|
+
eventCount: row.eventCount,
|
|
2088
|
+
events: parseInlineReplayEvents(json),
|
|
2089
|
+
};
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
async function readSessionReplayChunkBatchForRecording(
|
|
2093
|
+
recording: SessionRecordingSummary,
|
|
2094
|
+
requestedSeqs: number[],
|
|
2095
|
+
): Promise<SessionReplayChunkBatchResult> {
|
|
2096
|
+
const seqs = validateReplayChunkReadSeqs(requestedSeqs);
|
|
2097
|
+
const db = getDb() as any;
|
|
2098
|
+
// guard:allow-unscoped -- rows are loaded only after one recording-scoped resolveAccess check or a signed recording-scoped agent token verifies access.
|
|
2099
|
+
const rows = await db
|
|
2100
|
+
.select()
|
|
2101
|
+
.from(schema.sessionReplayChunks)
|
|
2102
|
+
.where(
|
|
2103
|
+
and(
|
|
2104
|
+
eq(schema.sessionReplayChunks.recordingId, recording.id),
|
|
2105
|
+
inArray(schema.sessionReplayChunks.seq, seqs),
|
|
2106
|
+
),
|
|
2107
|
+
)
|
|
2108
|
+
.orderBy(asc(schema.sessionReplayChunks.seq));
|
|
2109
|
+
|
|
2110
|
+
const declaredBytes = rows.reduce(
|
|
2111
|
+
(total: number, row: any) => total + Math.max(0, Number(row.byteLength)),
|
|
2112
|
+
0,
|
|
2113
|
+
);
|
|
2114
|
+
if (declaredBytes > MAX_REPLAY_CHUNK_READ_BATCH_BYTES) {
|
|
2115
|
+
throw replayError(
|
|
2116
|
+
`Replay chunk batches must be ${MAX_REPLAY_CHUNK_READ_BATCH_BYTES} bytes or smaller`,
|
|
2117
|
+
413,
|
|
2118
|
+
);
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
const rowBySeq = new Map<number, any>(
|
|
2122
|
+
rows.map((row: any) => [Number(row.seq), row]),
|
|
2123
|
+
);
|
|
2124
|
+
const chunks = new Array<SessionReplayChunkBatchItem>(seqs.length);
|
|
2125
|
+
let nextIndex = 0;
|
|
2126
|
+
|
|
2127
|
+
async function worker(): Promise<void> {
|
|
2128
|
+
while (nextIndex < seqs.length) {
|
|
2129
|
+
const index = nextIndex;
|
|
2130
|
+
nextIndex += 1;
|
|
2131
|
+
const seq = seqs[index];
|
|
2132
|
+
const row = rowBySeq.get(seq);
|
|
2133
|
+
chunks[index] = row
|
|
2134
|
+
? await readReplayChunkBatchRow(recording, row)
|
|
2135
|
+
: unavailableReplayChunkBatchItem(seq);
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2139
|
+
await Promise.all(
|
|
2140
|
+
Array.from(
|
|
2141
|
+
{
|
|
2142
|
+
length: Math.min(REPLAY_CHUNK_READ_CONCURRENCY, seqs.length),
|
|
2143
|
+
},
|
|
2144
|
+
worker,
|
|
2145
|
+
),
|
|
2146
|
+
);
|
|
2147
|
+
|
|
2148
|
+
const result = {
|
|
2149
|
+
chunks,
|
|
2150
|
+
unavailableChunks: chunks.filter((chunk) => chunk.unavailable).length,
|
|
2151
|
+
};
|
|
2152
|
+
if (
|
|
2153
|
+
Buffer.byteLength(JSON.stringify(result), "utf8") >
|
|
2154
|
+
MAX_REPLAY_CHUNK_READ_BATCH_BYTES
|
|
2155
|
+
) {
|
|
2156
|
+
throw replayError(
|
|
2157
|
+
`Replay chunk batch responses must be ${MAX_REPLAY_CHUNK_READ_BATCH_BYTES} bytes or smaller`,
|
|
2158
|
+
413,
|
|
2159
|
+
);
|
|
2160
|
+
}
|
|
2161
|
+
return result;
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
export async function readSessionReplayChunkBatch(
|
|
2165
|
+
recordingId: string,
|
|
2166
|
+
seqs: number[],
|
|
2167
|
+
scope: SessionReplayScope,
|
|
2168
|
+
): Promise<SessionReplayChunkBatchResult> {
|
|
2169
|
+
const recording = await getSessionReplaySummary(recordingId, scope);
|
|
2170
|
+
return readSessionReplayChunkBatchForRecording(recording, seqs);
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
export async function readSessionReplayTokenizedChunkBatch(
|
|
2174
|
+
recordingId: string,
|
|
2175
|
+
seqs: number[],
|
|
2176
|
+
): Promise<SessionReplayChunkBatchResult> {
|
|
2177
|
+
const recording = await getSessionReplayTokenizedSummary(recordingId);
|
|
2178
|
+
return readSessionReplayChunkBatchForRecording(recording, seqs);
|
|
2179
|
+
}
|
|
2180
|
+
|
|
1975
2181
|
export async function getSessionReplayEvents(
|
|
1976
2182
|
recordingId: string,
|
|
1977
2183
|
scope: SessionReplayScope,
|
|
@@ -1,24 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Custom onboarding plugin for Analytics.
|
|
3
3
|
*
|
|
4
|
-
* Overrides the framework's default onboarding plugin to
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* The step is `required: false` because session replay is opt-in: capturing
|
|
11
|
-
* replays only matters once a site embeds the tracking SDK with replay enabled,
|
|
12
|
-
* so we surface storage setup without forcing it into the onboarding checklist.
|
|
4
|
+
* Overrides the framework's default onboarding plugin to register the S3 file
|
|
5
|
+
* upload provider. Must live in server/plugins/ so the framework skips its
|
|
6
|
+
* default onboarding plugin, and all registrations share the same module
|
|
7
|
+
* context as the onboarding route handlers (which read from the same in-memory
|
|
8
|
+
* Map). Analytics only needs storage when someone enables session replay, so
|
|
9
|
+
* replay setup lives with that workflow instead of onboarding.
|
|
13
10
|
*/
|
|
14
11
|
|
|
15
12
|
import { registerFileUploadProvider } from "@agent-native/core/file-upload";
|
|
16
|
-
import {
|
|
17
|
-
createOnboardingPlugin,
|
|
18
|
-
registerOnboardingStep,
|
|
19
|
-
} from "@agent-native/core/onboarding";
|
|
13
|
+
import { createOnboardingPlugin } from "@agent-native/core/onboarding";
|
|
20
14
|
|
|
21
|
-
import { hasRequestReplayStorage } from "../lib/replay-storage.js";
|
|
22
15
|
import { s3FileUploadProvider } from "../lib/s3-upload-provider.js";
|
|
23
16
|
|
|
24
17
|
const basePlugin = createOnboardingPlugin();
|
|
@@ -29,69 +22,4 @@ export default async (nitroApp: any): Promise<void> => {
|
|
|
29
22
|
|
|
30
23
|
// Register S3-compatible file upload provider for session-replay chunks.
|
|
31
24
|
registerFileUploadProvider(s3FileUploadProvider);
|
|
32
|
-
|
|
33
|
-
// Add the optional "Session replay storage" onboarding step.
|
|
34
|
-
registerOnboardingStep({
|
|
35
|
-
id: "replay-storage",
|
|
36
|
-
order: 15,
|
|
37
|
-
required: false,
|
|
38
|
-
title: "Session replay storage",
|
|
39
|
-
description:
|
|
40
|
-
"Store session replay recordings with Builder.io or S3-compatible storage.",
|
|
41
|
-
methods: [
|
|
42
|
-
{
|
|
43
|
-
id: "builder",
|
|
44
|
-
kind: "builder-cli-auth",
|
|
45
|
-
label: "Connect Builder.io",
|
|
46
|
-
description:
|
|
47
|
-
"Builder.io's free tier includes object storage for replay chunks.",
|
|
48
|
-
primary: true,
|
|
49
|
-
badge: "free",
|
|
50
|
-
payload: { scope: "browser" },
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
id: "s3",
|
|
54
|
-
kind: "form",
|
|
55
|
-
label: "Use S3-compatible storage",
|
|
56
|
-
description:
|
|
57
|
-
"AWS S3, Cloudflare R2, DigitalOcean Spaces, MinIO, or any S3-compatible service.",
|
|
58
|
-
payload: {
|
|
59
|
-
writeScope: "workspace",
|
|
60
|
-
fields: [
|
|
61
|
-
{
|
|
62
|
-
key: "S3_ENDPOINT",
|
|
63
|
-
label: "Endpoint URL",
|
|
64
|
-
placeholder: "https://s3.us-east-1.amazonaws.com",
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
key: "S3_BUCKET",
|
|
68
|
-
label: "Bucket name",
|
|
69
|
-
placeholder: "my-replays-bucket",
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
key: "S3_ACCESS_KEY_ID",
|
|
73
|
-
label: "Access key ID",
|
|
74
|
-
placeholder: "AKIA...",
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
key: "S3_SECRET_ACCESS_KEY",
|
|
78
|
-
label: "Secret access key",
|
|
79
|
-
secret: true,
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
key: "S3_REGION",
|
|
83
|
-
label: "Region (optional)",
|
|
84
|
-
placeholder: "us-east-1",
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
key: "S3_PUBLIC_BASE_URL",
|
|
88
|
-
label: "Public base URL (optional)",
|
|
89
|
-
placeholder: "https://cdn.example.com",
|
|
90
|
-
},
|
|
91
|
-
],
|
|
92
|
-
},
|
|
93
|
-
},
|
|
94
|
-
],
|
|
95
|
-
isComplete: hasRequestReplayStorage,
|
|
96
|
-
});
|
|
97
25
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { handleSessionReplayChunkBatch as default } from "../../../../../handlers/session-replay";
|
|
@@ -30,7 +30,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
|
|
|
30
30
|
useDbSync({ queryClient });
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
For each non-own event, `useDbSync` bumps a per-source counter (e.g. `dashboards`, `analyses`, `settings`, `action`) and invalidates a small fixed list of framework-internal prefixes (`["action"]`, `["app-state"]`, `["__set_url__"]`, etc.). It does **not** blanket-invalidate templates' own data queries
|
|
33
|
+
For each non-own event, `useDbSync` bumps a per-source counter (e.g. `dashboards`, `analyses`, `settings`, `action`) and invalidates a small fixed list of framework-internal prefixes (`["action"]`, `["app-state"]`, `["__set_url__"]`, etc.). It does **not** blanket-invalidate templates' own data queries — that caused request storms in production. A successful mutating action refreshes active `useActionQuery` observers under the `["action"]` prefix. Browser actions carry a tab id so their originating tab ignores the sync echo while other tabs refresh. Legacy apps can opt into broader compatibility with `actionInvalidatePredicate`, but first-party apps should use action-backed or source-versioned query keys. Idle fallback polling runs once per minute; active agent work temporarily uses the faster cadence.
|
|
34
34
|
|
|
35
35
|
3. **Templates fold per-source counters into their query keys.** This is the pattern that makes "agent writes show up without a manual refresh" reliable:
|
|
36
36
|
|
|
@@ -117,7 +117,7 @@ useQuery({
|
|
|
117
117
|
| UI not updating after agent writes | Is `useDbSync` called with the correct `queryClient`? Does the affected query have an active observer? |
|
|
118
118
|
| Poll endpoint not responding | Is `/_agent-native/poll` accessible? Is the server running? |
|
|
119
119
|
| SSE not connecting | Is `/_agent-native/events` accessible and authenticated? Polling should still keep the UI fresh as fallback. |
|
|
120
|
-
| High CPU / event storms |
|
|
120
|
+
| High CPU / event storms | Use targeted source keys, settle bursty list counters, and avoid broad action invalidation. |
|
|
121
121
|
|
|
122
122
|
## Jitter Prevention
|
|
123
123
|
|
|
@@ -257,14 +257,14 @@
|
|
|
257
257
|
[data-agent-empty-state="centered"]
|
|
258
258
|
.agent-composer-area {
|
|
259
259
|
width: 100%;
|
|
260
|
-
max-width: min(
|
|
260
|
+
max-width: min(570px, 90%);
|
|
261
261
|
padding: 0;
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
.assets-create-chat-panel
|
|
265
265
|
[data-agent-empty-state="centered"]
|
|
266
266
|
.agent-composer-root {
|
|
267
|
-
min-height:
|
|
267
|
+
min-height: 7.875rem;
|
|
268
268
|
border-color: hsl(var(--border));
|
|
269
269
|
border-radius: 1rem;
|
|
270
270
|
background: hsl(var(--card));
|
|
@@ -274,7 +274,7 @@
|
|
|
274
274
|
.assets-create-chat-panel
|
|
275
275
|
[data-agent-empty-state="centered"]
|
|
276
276
|
.agent-composer-prosemirror {
|
|
277
|
-
min-height:
|
|
277
|
+
min-height: 5.0625rem;
|
|
278
278
|
font-size: 1rem;
|
|
279
279
|
line-height: 1.625rem;
|
|
280
280
|
}
|
|
@@ -305,6 +305,6 @@
|
|
|
305
305
|
.assets-create-chat-panel
|
|
306
306
|
[data-agent-empty-state="centered"]
|
|
307
307
|
.agent-composer-root {
|
|
308
|
-
min-height:
|
|
308
|
+
min-height: 6.75rem;
|
|
309
309
|
}
|
|
310
310
|
}
|
|
@@ -30,7 +30,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
|
|
|
30
30
|
useDbSync({ queryClient });
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
For each non-own event, `useDbSync` bumps a per-source counter (e.g. `dashboards`, `analyses`, `settings`, `action`) and invalidates a small fixed list of framework-internal prefixes (`["action"]`, `["app-state"]`, `["__set_url__"]`, etc.). It does **not** blanket-invalidate templates' own data queries
|
|
33
|
+
For each non-own event, `useDbSync` bumps a per-source counter (e.g. `dashboards`, `analyses`, `settings`, `action`) and invalidates a small fixed list of framework-internal prefixes (`["action"]`, `["app-state"]`, `["__set_url__"]`, etc.). It does **not** blanket-invalidate templates' own data queries — that caused request storms in production. A successful mutating action refreshes active `useActionQuery` observers under the `["action"]` prefix. Browser actions carry a tab id so their originating tab ignores the sync echo while other tabs refresh. Legacy apps can opt into broader compatibility with `actionInvalidatePredicate`, but first-party apps should use action-backed or source-versioned query keys. Idle fallback polling runs once per minute; active agent work temporarily uses the faster cadence.
|
|
34
34
|
|
|
35
35
|
3. **Templates fold per-source counters into their query keys.** This is the pattern that makes "agent writes show up without a manual refresh" reliable:
|
|
36
36
|
|
|
@@ -117,7 +117,7 @@ useQuery({
|
|
|
117
117
|
| UI not updating after agent writes | Is `useDbSync` called with the correct `queryClient`? Does the affected query have an active observer? |
|
|
118
118
|
| Poll endpoint not responding | Is `/_agent-native/poll` accessible? Is the server running? |
|
|
119
119
|
| SSE not connecting | Is `/_agent-native/events` accessible and authenticated? Polling should still keep the UI fresh as fallback. |
|
|
120
|
-
| High CPU / event storms |
|
|
120
|
+
| High CPU / event storms | Use targeted source keys, settle bursty list counters, and avoid broad action invalidation. |
|
|
121
121
|
|
|
122
122
|
## Jitter Prevention
|
|
123
123
|
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
.brain-chat-panel [data-agent-empty-state="centered"] .brain-chat-intro {
|
|
136
136
|
display: grid;
|
|
137
137
|
width: 100%;
|
|
138
|
-
max-width: min(
|
|
138
|
+
max-width: min(570px, 90%);
|
|
139
139
|
gap: 0.5rem;
|
|
140
140
|
margin: 0 auto 1rem;
|
|
141
141
|
text-align: center;
|
|
@@ -165,12 +165,12 @@
|
|
|
165
165
|
|
|
166
166
|
.brain-chat-panel [data-agent-empty-state="centered"] .agent-composer-area {
|
|
167
167
|
width: 100%;
|
|
168
|
-
max-width: min(
|
|
168
|
+
max-width: min(570px, 90%);
|
|
169
169
|
padding: 0;
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
.brain-chat-panel [data-agent-empty-state="centered"] .agent-composer-root {
|
|
173
|
-
min-height:
|
|
173
|
+
min-height: 7.875rem;
|
|
174
174
|
border-color: hsl(var(--border));
|
|
175
175
|
border-radius: 1rem;
|
|
176
176
|
background: hsl(var(--card));
|
|
@@ -187,7 +187,7 @@
|
|
|
187
187
|
.brain-chat-panel
|
|
188
188
|
[data-agent-empty-state="centered"]
|
|
189
189
|
.agent-composer-prosemirror {
|
|
190
|
-
min-height:
|
|
190
|
+
min-height: 5.0625rem;
|
|
191
191
|
font-size: 1rem;
|
|
192
192
|
line-height: 1.625rem;
|
|
193
193
|
}
|
|
@@ -212,6 +212,6 @@
|
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
.brain-chat-panel [data-agent-empty-state="centered"] .agent-composer-root {
|
|
215
|
-
min-height:
|
|
215
|
+
min-height: 6.75rem;
|
|
216
216
|
}
|
|
217
217
|
}
|
|
@@ -204,9 +204,6 @@ export default function Root() {
|
|
|
204
204
|
// Brain has a faster sync cadence for source distillation status;
|
|
205
205
|
// 20 s keeps the source list fresh without hammering the server.
|
|
206
206
|
staleTime: 20_000,
|
|
207
|
-
// Brain shows live ingestion progress — refetch on focus to pick
|
|
208
|
-
// up background sync jobs that don't emit DB events.
|
|
209
|
-
refetchOnWindowFocus: true,
|
|
210
207
|
// Flat retry: Brain data fetches are rarely auth failures so a
|
|
211
208
|
// flat count is sufficient.
|
|
212
209
|
retry: 1,
|