@agent-native/core 0.90.11 → 0.91.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 +22 -0
- package/corpus/core/docs/content/toolkit-settings.mdx +56 -3
- package/corpus/core/package.json +2 -1
- package/corpus/core/src/agent/run-ownership.ts +29 -1
- package/corpus/core/src/changelog/parse.ts +78 -0
- package/corpus/core/src/chat-threads/schema.ts +43 -0
- package/corpus/core/src/chat-threads/store.ts +144 -12
- package/corpus/core/src/cli/workspace-dev.ts +25 -5
- package/corpus/core/src/client/AgentPanel.tsx +79 -14
- package/corpus/core/src/client/AssistantChat.tsx +359 -425
- package/corpus/core/src/client/analytics-session.ts +70 -0
- package/corpus/core/src/client/analytics.ts +175 -49
- package/corpus/core/src/client/chat/message-components.tsx +22 -2
- package/corpus/core/src/client/components/ui/message-scroller.tsx +131 -0
- package/corpus/core/src/client/conversation/AgentConversation.tsx +63 -41
- package/corpus/core/src/client/error-capture.ts +616 -0
- package/corpus/core/src/client/index.ts +12 -0
- package/corpus/core/src/client/session-replay.ts +57 -7
- package/corpus/core/src/client/settings/SettingsPanel.tsx +123 -1
- package/corpus/core/src/client/settings/SettingsTabsPage.tsx +292 -45
- package/corpus/core/src/client/settings/index.ts +1 -0
- package/corpus/core/src/client/sharing/ShareButton.tsx +14 -11
- package/corpus/core/src/client/sharing/ShareDialog.tsx +13 -10
- package/corpus/core/src/mcp/builtin-tools.ts +29 -2
- package/corpus/core/src/server/agent-chat-plugin.ts +174 -79
- package/corpus/core/src/server/onboarding-html.ts +28 -16
- package/corpus/core/src/sharing/actions/list-resource-shares.ts +45 -1
- package/corpus/core/src/sharing/actions/share-resource.ts +9 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
- package/corpus/core/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
- package/corpus/core/src/vite/client.ts +217 -35
- package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +8 -7
- package/corpus/templates/analytics/.agents/skills/analysis-workspace/SKILL.md +14 -10
- package/corpus/templates/analytics/.agents/skills/bigquery/SKILL.md +15 -15
- package/corpus/templates/analytics/.agents/skills/cross-source-analysis/SKILL.md +1 -0
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +38 -22
- package/corpus/templates/analytics/.agents/skills/data-programs/SKILL.md +114 -61
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +1 -0
- package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +7 -7
- package/corpus/templates/analytics/.agents/skills/hubspot/SKILL.md +1 -0
- package/corpus/templates/analytics/.agents/skills/prometheus/SKILL.md +1 -1
- package/corpus/templates/analytics/.builder/skills/bigquery/SKILL.md +17 -17
- package/corpus/templates/analytics/.builder/skills/gcloud/SKILL.md +5 -5
- package/corpus/templates/analytics/.builder/skills/github/SKILL.md +7 -7
- package/corpus/templates/analytics/.builder/skills/gong/SKILL.md +12 -12
- package/corpus/templates/analytics/.builder/skills/grafana/SKILL.md +7 -7
- package/corpus/templates/analytics/.builder/skills/sentry/SKILL.md +7 -7
- package/corpus/templates/analytics/.builder/skills/slack/SKILL.md +6 -6
- package/corpus/templates/analytics/.builder/skills/stripe/SKILL.md +7 -7
- package/corpus/templates/analytics/AGENTS.md +47 -2
- package/corpus/templates/analytics/actions/add-status-page-monitor.ts +36 -0
- package/corpus/templates/analytics/actions/capture-test-error.ts +33 -0
- package/corpus/templates/analytics/actions/delete-monitor.ts +24 -0
- package/corpus/templates/analytics/actions/delete-status-page.ts +23 -0
- package/corpus/templates/analytics/actions/get-error-issue.ts +36 -0
- package/corpus/templates/analytics/actions/get-monitor-stats.ts +55 -0
- package/corpus/templates/analytics/actions/get-monitor.ts +27 -0
- package/corpus/templates/analytics/actions/get-public-status-page.ts +41 -0
- package/corpus/templates/analytics/actions/get-status-page.ts +29 -0
- package/corpus/templates/analytics/actions/list-error-issues.ts +40 -0
- package/corpus/templates/analytics/actions/list-monitors.ts +21 -0
- package/corpus/templates/analytics/actions/list-status-pages.ts +21 -0
- package/corpus/templates/analytics/actions/match-error-issues.ts +51 -0
- package/corpus/templates/analytics/actions/navigate.ts +58 -4
- package/corpus/templates/analytics/actions/remove-status-page-monitor.ts +22 -0
- package/corpus/templates/analytics/actions/reorder-status-page-monitors.ts +25 -0
- package/corpus/templates/analytics/actions/resolve-error-issue.ts +38 -0
- package/corpus/templates/analytics/actions/run-monitor-check.ts +23 -0
- package/corpus/templates/analytics/actions/save-analysis.ts +1 -0
- package/corpus/templates/analytics/actions/save-monitor.ts +145 -0
- package/corpus/templates/analytics/actions/save-status-page.ts +47 -0
- package/corpus/templates/analytics/actions/view-screen.ts +212 -0
- package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -0
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +10 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +134 -39
- package/corpus/templates/analytics/app/components/monitoring/PublicStatusView.tsx +351 -0
- package/corpus/templates/analytics/app/components/monitoring/ResponseTimeChart.tsx +174 -0
- package/corpus/templates/analytics/app/components/monitoring/UptimeStatCards.tsx +85 -0
- package/corpus/templates/analytics/app/components/monitoring/UptimeTimelineBars.tsx +106 -0
- package/corpus/templates/analytics/app/components/monitoring/chart-utils.ts +101 -0
- package/corpus/templates/analytics/app/components/monitoring/index.ts +28 -0
- package/corpus/templates/analytics/app/components/monitoring/types.ts +42 -0
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +34 -0
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +6 -0
- package/corpus/templates/analytics/app/i18n-data.ts +33 -0
- package/corpus/templates/analytics/app/pages/DataSources.tsx +28 -0
- package/corpus/templates/analytics/app/pages/Settings.tsx +77 -9
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +3 -3
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +7 -0
- package/corpus/templates/analytics/app/pages/monitoring/ErrorsPanel.tsx +205 -0
- package/corpus/templates/analytics/app/pages/monitoring/MonitoringPage.tsx +100 -0
- package/corpus/templates/analytics/app/pages/monitoring/UptimePanel.tsx +475 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/IssueDetail.tsx +372 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/IssueList.tsx +360 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/Sparkline.tsx +55 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/i18n.ts +106 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/types.ts +75 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/utils.ts +132 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorDetail.tsx +535 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorFormPage.tsx +1026 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorList.tsx +311 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/i18n.ts +235 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/StatusPageEditor.tsx +661 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/StatusPagesView.tsx +355 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/i18n.ts +106 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/slug.ts +24 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/types.ts +20 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-summary.ts +87 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/types.ts +161 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/utils.ts +210 -0
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +76 -1
- package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +74 -9
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +197 -20
- package/corpus/templates/analytics/app/root.tsx +33 -1
- package/corpus/templates/analytics/app/routes/monitoring._index.tsx +10 -0
- package/corpus/templates/analytics/app/routes/status.$slug.tsx +118 -0
- package/corpus/templates/analytics/changelog/2026-07-08-add-uptime-monitors-that-ping-your-urls-and-alert-you-when-t.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-analytics-chats-keep-large-data-dictionaries-compact-so-prov.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-create-public-status-pages-that-share-the-live-health-of-cho.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-dashboard-extension-panels-use-clearer-open-copy.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-error-capture.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-fixed-single-panel-dashboard-drags-so-they-no-longer-rewrite.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-jump-straight-from-an-error-in-a-session-recording-to-its-fu.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-monitor-detail-and-list-now-show-colorful-uptime-timelines-r.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-pinned-ask-chats-now-show-a-pin-icon-in-the-sidebar.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-publish-a-public-uptime-status-page-with-colorful-uptime-tim.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-sessions-now-hide-visitor-emails-in-demo-mode-and-show-clean.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-settings-are-cleaner-searchable-and-alerts-have-their-own-tab.md +5 -0
- package/corpus/templates/analytics/changelog/2026-07-08-sidebar-sections-stay-collapsed-until-opened.md +5 -0
- package/corpus/templates/analytics/changelog/2026-07-08-the-uptime-monitor-list-now-has-a-current-status-overview-wi.md +6 -0
- package/corpus/templates/analytics/docs/error-capture.md +172 -0
- package/corpus/templates/analytics/docs/uptime-monitoring.md +150 -0
- package/corpus/templates/analytics/server/db/schema-errors.ts +150 -0
- package/corpus/templates/analytics/server/db/schema-monitoring.ts +177 -0
- package/corpus/templates/analytics/server/db/schema.ts +6 -0
- package/corpus/templates/analytics/server/jobs/uptime-monitors.ts +123 -0
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +41 -0
- package/corpus/templates/analytics/server/lib/data-dictionary-context.ts +55 -12
- package/corpus/templates/analytics/server/lib/error-capture.ts +1331 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +47 -1
- package/corpus/templates/analytics/server/lib/monitor-stats.ts +494 -0
- package/corpus/templates/analytics/server/lib/status-pages.ts +798 -0
- package/corpus/templates/analytics/server/lib/uptime-monitors.ts +1665 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +7 -37
- package/corpus/templates/analytics/server/plugins/auth.ts +11 -1
- package/corpus/templates/analytics/server/plugins/db.ts +408 -0
- package/corpus/templates/analytics/server/plugins/uptime-monitor-jobs.ts +63 -0
- package/corpus/templates/assets/app/routes/_index.tsx +1 -1
- package/corpus/templates/assets/app/routes/settings.tsx +22 -1
- package/corpus/templates/assets/changelog/2026-07-08-recent-drafts-keep-comfortable-side-padding.md +6 -0
- package/corpus/templates/assets/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/brain/app/routes/settings.tsx +43 -5
- package/corpus/templates/brain/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/calendar/app/pages/Settings.tsx +44 -6
- package/corpus/templates/calendar/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/chat/app/routes/settings.tsx +16 -1
- package/corpus/templates/chat/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +79 -37
- package/corpus/templates/clips/app/components/player/player-controls.tsx +35 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +162 -18
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +63 -6
- package/corpus/templates/clips/app/routes/record.tsx +18 -1
- package/corpus/templates/clips/changelog/2026-07-07-shared-clips-start-playback-reliably-from-the-first-play-click.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-camera-and-microphone-menus-now-show-which-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-copies-new-clip-links-after-saving.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-recordings-now-continue-after-granting-came.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-mobile-shared-clips-now-have-loom-style-tap-and-skip-controls.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-recordings-and-uploads-copy-links-after-saving.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-settings-are-cleaner-searchable-and-collapse-s3-with-builder.md +5 -0
- package/corpus/templates/clips/changelog/2026-07-08-transcripts-are-more-reliable-for-longer-desktop-recordings-.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -0
- package/corpus/templates/clips/chrome-extension/src/background.ts +162 -13
- package/corpus/templates/clips/chrome-extension/src/content-script.ts +14 -0
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +36 -0
- package/corpus/templates/clips/chrome-extension/src/overlay.ts +99 -25
- package/corpus/templates/clips/chrome-extension/src/permission.ts +63 -14
- package/corpus/templates/clips/chrome-extension/src/popup.ts +123 -23
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +47 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +33 -4
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +214 -29
- package/corpus/templates/content/actions/attach-content-database-source.ts +3 -0
- package/corpus/templates/content/actions/change-content-database-source-role.ts +1 -0
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +42 -32
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +352 -81
- package/corpus/templates/content/app/components/editor/database/settings.tsx +49 -24
- package/corpus/templates/content/app/routes/_app.settings.tsx +19 -1
- package/corpus/templates/content/changelog/2026-07-07-builder-source-tag-fields-now-import-as-multi-select.md +6 -0
- package/corpus/templates/content/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/content/shared/api.ts +3 -0
- package/corpus/templates/content/shared/properties.ts +42 -0
- package/corpus/templates/design/actions/generate-design.ts +3 -0
- package/corpus/templates/design/actions/get-design-system.ts +147 -1
- package/corpus/templates/design/app/routes/settings.tsx +16 -1
- package/corpus/templates/design/changelog/2026-07-08-design-generation-now-follows-hydrated-builder-design-system.md +6 -0
- package/corpus/templates/design/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/dispatch/app/routes/settings.tsx +23 -2
- package/corpus/templates/dispatch/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/forms/app/routes/_app.settings.tsx +16 -1
- package/corpus/templates/forms/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/macros/app/routes/settings.tsx +16 -1
- package/corpus/templates/macros/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/mail/app/components/settings/GmailFiltersSection.tsx +1 -1
- package/corpus/templates/mail/app/components/settings/SnippetsSection.tsx +1 -1
- package/corpus/templates/mail/app/pages/SettingsPage.tsx +123 -105
- package/corpus/templates/mail/changelog/2026-07-08-settings-redesigned-with-a-consistent-searchable-layout.md +5 -0
- package/corpus/templates/plan/app/routes/settings.tsx +23 -2
- package/corpus/templates/plan/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/slides/actions/add-slide.ts +1 -0
- package/corpus/templates/slides/actions/get-design-system.ts +147 -1
- package/corpus/templates/slides/app/pages/Index.tsx +46 -1
- package/corpus/templates/slides/app/routes/settings.tsx +16 -1
- package/corpus/templates/slides/changelog/2026-07-08-deck-generation-now-follows-hydrated-builder-design-system-g.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/dist/agent/run-ownership.d.ts +6 -0
- package/dist/agent/run-ownership.d.ts.map +1 -1
- package/dist/agent/run-ownership.js +11 -1
- package/dist/agent/run-ownership.js.map +1 -1
- package/dist/changelog/parse.d.ts +7 -0
- package/dist/changelog/parse.d.ts.map +1 -1
- package/dist/changelog/parse.js +64 -0
- package/dist/changelog/parse.js.map +1 -1
- package/dist/chat-threads/schema.d.ts +445 -0
- package/dist/chat-threads/schema.d.ts.map +1 -0
- package/dist/chat-threads/schema.js +39 -0
- package/dist/chat-threads/schema.js.map +1 -0
- package/dist/chat-threads/store.d.ts +12 -0
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +99 -10
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/cli/workspace-dev.d.ts.map +1 -1
- package/dist/cli/workspace-dev.js +20 -5
- package/dist/cli/workspace-dev.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +35 -7
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +105 -183
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/analytics-session.d.ts +3 -0
- package/dist/client/analytics-session.d.ts.map +1 -0
- package/dist/client/analytics-session.js +66 -0
- package/dist/client/analytics-session.js.map +1 -0
- package/dist/client/analytics.d.ts +32 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +116 -46
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +2 -1
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +16 -6
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/components/ui/message-scroller.d.ts +16 -0
- package/dist/client/components/ui/message-scroller.d.ts.map +1 -0
- package/dist/client/components/ui/message-scroller.js +25 -0
- package/dist/client/components/ui/message-scroller.js.map +1 -0
- package/dist/client/conversation/AgentConversation.d.ts +1 -1
- package/dist/client/conversation/AgentConversation.d.ts.map +1 -1
- package/dist/client/conversation/AgentConversation.js +3 -8
- package/dist/client/conversation/AgentConversation.js.map +1 -1
- package/dist/client/error-capture.d.ts +99 -0
- package/dist/client/error-capture.d.ts.map +1 -0
- package/dist/client/error-capture.js +437 -0
- package/dist/client/error-capture.js.map +1 -0
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/session-replay.d.ts +22 -0
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +45 -4
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +100 -5
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/SettingsTabsPage.d.ts +49 -1
- package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
- package/dist/client/settings/SettingsTabsPage.js +131 -19
- package/dist/client/settings/SettingsTabsPage.js.map +1 -1
- package/dist/client/settings/index.d.ts +1 -1
- package/dist/client/settings/index.d.ts.map +1 -1
- package/dist/client/settings/index.js.map +1 -1
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +13 -8
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/client/sharing/ShareDialog.d.ts.map +1 -1
- package/dist/client/sharing/ShareDialog.js +12 -7
- package/dist/client/sharing/ShareDialog.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/mcp/builtin-tools.d.ts.map +1 -1
- package/dist/mcp/builtin-tools.js +21 -2
- package/dist/mcp/builtin-tools.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/org/schema.d.ts +15 -15
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +109 -73
- 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/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +28 -16
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/sharing/actions/list-resource-shares.js +30 -1
- package/dist/sharing/actions/list-resource-shares.js.map +1 -1
- package/dist/sharing/actions/share-resource.js +6 -0
- package/dist/sharing/actions/share-resource.js.map +1 -1
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
- package/dist/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +192 -30
- package/dist/vite/client.js.map +1 -1
- package/docs/content/toolkit-settings.mdx +56 -3
- package/package.json +2 -1
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
- package/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Error capture
|
|
2
|
+
|
|
3
|
+
First-party, Sentry-style exception tracking built into the analytics product.
|
|
4
|
+
The browser SDK automatically captures uncaught exceptions and unhandled
|
|
5
|
+
promise rejections, exposes a manual `captureException` / `captureMessage` API,
|
|
6
|
+
and links every error to the **session replay** it happened in. Captured errors
|
|
7
|
+
are grouped into **issues** by fingerprint and triaged under **Monitoring →
|
|
8
|
+
Errors**.
|
|
9
|
+
|
|
10
|
+
## How it works
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
Browser SDK ──$exception──▶ /api/analytics/track ──▶ error_issues + error_events
|
|
14
|
+
(auto + manual capture) (first-party ingest fork) (grouped issues + occurrences)
|
|
15
|
+
│ │
|
|
16
|
+
└── session replay id (localStorage) ───────────────────▶ linked to /sessions/<id>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
- **Capture** happens in the analytics client SDK
|
|
20
|
+
(`@agent-native/core/client`), installed by `configureTracking`.
|
|
21
|
+
- **Transport** reuses the existing first-party analytics ingest: exceptions are
|
|
22
|
+
sent as a dedicated `$exception` event using the same public-key auth and
|
|
23
|
+
`sendBeacon`/`keepalive` transport as pageviews. No extra endpoint, CORS, or
|
|
24
|
+
key to configure.
|
|
25
|
+
- **Server** forks `$exception` events out of the analytics batch, parses the
|
|
26
|
+
stack, computes a stable fingerprint, upserts the grouped issue, appends the
|
|
27
|
+
occurrence, and links the session replay. The event is still recorded in
|
|
28
|
+
`analytics_events`, so existing alerting keeps working.
|
|
29
|
+
|
|
30
|
+
## Enabling capture
|
|
31
|
+
|
|
32
|
+
Templates already call `configureTracking`. Error capture **auto-enables**
|
|
33
|
+
whenever a first-party analytics public key is configured (the same trigger as
|
|
34
|
+
pageview tracking and session replay). To be explicit or to tune it:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { configureTracking } from "@agent-native/core/client";
|
|
38
|
+
|
|
39
|
+
configureTracking({
|
|
40
|
+
key: "anpk_...", // first-party analytics public key
|
|
41
|
+
endpoint: "https://analytics.example.com/api/analytics/track",
|
|
42
|
+
errorCapture: true, // or an options object; pass `false` to disable
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Options (`errorCapture` object form):
|
|
47
|
+
|
|
48
|
+
| Option | Default | Description |
|
|
49
|
+
| ---------------------------- | ----------- | --------------------------------------------- |
|
|
50
|
+
| `release` | `undefined` | Build/release id attached to every exception. |
|
|
51
|
+
| `environment` | Vite `MODE` | Deployment environment (e.g. `production`). |
|
|
52
|
+
| `captureGlobalErrors` | `true` | Auto-capture `window.onerror`. |
|
|
53
|
+
| `captureUnhandledRejections` | `true` | Auto-capture `unhandledrejection`. |
|
|
54
|
+
| `maxBreadcrumbs` | `20` | Breadcrumb ring-buffer size. |
|
|
55
|
+
|
|
56
|
+
> Exceptions are only transmitted from non-local hostnames (same rule as the
|
|
57
|
+
> rest of first-party analytics). In local dev the handlers still install, but
|
|
58
|
+
> nothing is sent — use the **Send test error** button or the
|
|
59
|
+
> `capture-test-error` action to exercise the pipeline end to end.
|
|
60
|
+
|
|
61
|
+
## Automatic capture
|
|
62
|
+
|
|
63
|
+
Once installed, the SDK listens for:
|
|
64
|
+
|
|
65
|
+
- **`window.onerror`** — uncaught synchronous and asynchronous errors.
|
|
66
|
+
- **`unhandledrejection`** — promise rejections with no `.catch`.
|
|
67
|
+
|
|
68
|
+
Each is normalized into `{ type, message, stack, url, handled, level, … }`,
|
|
69
|
+
redacted, deduped (identical signatures within a short window are dropped), and
|
|
70
|
+
sent. The session replay recorder already logs these to the replay timeline, so
|
|
71
|
+
auto-captured errors are **not** re-emitted onto the timeline to avoid
|
|
72
|
+
double-counting.
|
|
73
|
+
|
|
74
|
+
## Manual API (Sentry-style)
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import { captureException, captureMessage } from "@agent-native/core/client";
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
doRiskyThing();
|
|
81
|
+
} catch (err) {
|
|
82
|
+
captureException(err, {
|
|
83
|
+
level: "error",
|
|
84
|
+
tags: { area: "checkout", plan: "pro" },
|
|
85
|
+
extra: { cartId, itemCount },
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
captureMessage("Payment webhook retried", "warning");
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
- `captureException(error, context?)` — `context` accepts `tags` (low-cardinality
|
|
93
|
+
strings), `extra` (structured detail), and `level`
|
|
94
|
+
(`fatal | error | warning | info | debug`, default `error`).
|
|
95
|
+
- `captureMessage(message, level?)` — capture a string as an exception-like
|
|
96
|
+
event (default level `info`).
|
|
97
|
+
- `addErrorBreadcrumb({ category, message, level? })` — add a privacy-safe
|
|
98
|
+
breadcrumb to the bounded trail attached to the next captured error.
|
|
99
|
+
|
|
100
|
+
Manual captures **are** surfaced on the active session replay timeline as a
|
|
101
|
+
custom event, so they show up when you watch the replay.
|
|
102
|
+
|
|
103
|
+
Both functions are safe to call before `configureTracking` runs (they no-op
|
|
104
|
+
until transport is installed) and never throw back into your app.
|
|
105
|
+
|
|
106
|
+
## Session replay linkage
|
|
107
|
+
|
|
108
|
+
The SDK reads the current session replay id from `localStorage`
|
|
109
|
+
(`agent-native.session_replay_id`) and attaches it to each exception. At ingest
|
|
110
|
+
the server resolves it to the real recording (`sr_...`) and stores it on the
|
|
111
|
+
occurrence and the issue (`lastSessionRecordingId`). In the Errors UI, each
|
|
112
|
+
issue and occurrence with a linked replay shows a **Watch session replay** link
|
|
113
|
+
straight to `/sessions/<recordingId>`, so you can watch what the user did right
|
|
114
|
+
before the error.
|
|
115
|
+
|
|
116
|
+
The link goes both ways. When you watch a recording and open its devtools
|
|
117
|
+
**Console** panel, any captured error line (uncaught exceptions, unhandled
|
|
118
|
+
rejections, manual `captureException`) gets a **View issue** link straight to
|
|
119
|
+
its grouped issue detail (`/monitoring?view=errors&issue=<id>`) — how many users
|
|
120
|
+
hit it, the stack trace, and recent occurrences. Resolution is exact, not
|
|
121
|
+
heuristic: the `match-error-issues` action recomputes each console line's
|
|
122
|
+
fingerprint with the same helpers used at ingest and looks it up under access
|
|
123
|
+
scope, so a link only appears when the error was actually captured as an issue.
|
|
124
|
+
|
|
125
|
+
## Privacy & redaction
|
|
126
|
+
|
|
127
|
+
- Messages and stacks are scrubbed for credential-looking values
|
|
128
|
+
(`Authorization`, `Cookie`, `token`, `apiKey`, bearer/basic tokens, …) before
|
|
129
|
+
they leave the browser, reusing the same redaction as replay capture.
|
|
130
|
+
- URLs are scrubbed of query strings/tokens.
|
|
131
|
+
- Breadcrumbs are bounded (ring buffer) and only record navigation + explicit
|
|
132
|
+
messages — no DOM values or input contents.
|
|
133
|
+
- Payloads are size-bounded (message, stack, tags, extra, breadcrumbs).
|
|
134
|
+
|
|
135
|
+
## Data model
|
|
136
|
+
|
|
137
|
+
Two additive, owner-scoped tables (`server/db/schema-errors.ts`):
|
|
138
|
+
|
|
139
|
+
- **`error_issues`** — one row per fingerprint per owner scope. `ownableColumns()`
|
|
140
|
+
- `error_issue_shares`, so an org-scoped analytics key surfaces issues to the
|
|
141
|
+
whole org via `accessFilter` (mirrors `session_recordings`). Tracks status
|
|
142
|
+
(`unresolved | resolved | ignored`), counts, first/last seen, users affected,
|
|
143
|
+
culprit/title, and the last linked recording.
|
|
144
|
+
- **`error_events`** — individual occurrences (owner-scoped like
|
|
145
|
+
`analytics_events`), pruned to a bounded retention per issue so occurrences
|
|
146
|
+
can't grow unbounded. Stores normalized stack frames, breadcrumbs, tags/extra,
|
|
147
|
+
and the resolved session recording.
|
|
148
|
+
|
|
149
|
+
Grouping keys off error type + top in-app stack frame (function + normalized
|
|
150
|
+
file, ignoring line/column so small edits don't split a group), falling back to
|
|
151
|
+
a normalized message when there is no usable stack. A resolved issue is
|
|
152
|
+
automatically **reopened** when it recurs; **ignored** issues stay muted.
|
|
153
|
+
|
|
154
|
+
## How the agent triages issues
|
|
155
|
+
|
|
156
|
+
The agent uses the same owner-scoped actions the UI does:
|
|
157
|
+
|
|
158
|
+
- **`list-error-issues`** — list grouped issues, filter by status, search, sort
|
|
159
|
+
by last seen / event count / first seen.
|
|
160
|
+
- **`get-error-issue`** — one issue with recent occurrences (parsed stack
|
|
161
|
+
frames, breadcrumbs, tags/extra) and links to the session replays where it
|
|
162
|
+
happened.
|
|
163
|
+
- **`resolve-error-issue`** — set status (`unresolved` / `resolved` / `ignored`)
|
|
164
|
+
and optionally (re)assign a triage owner.
|
|
165
|
+
- **`capture-test-error`** — generate a sample captured error to verify the
|
|
166
|
+
pipeline end to end.
|
|
167
|
+
- **`match-error-issues`** — resolve a batch of session console error lines
|
|
168
|
+
(message/stack/source) to their captured issue ids, so a session recording can
|
|
169
|
+
deep-link to issue detail. Read-only; fingerprints match ingest exactly.
|
|
170
|
+
|
|
171
|
+
New issues also raise a best-effort inbox notification (via
|
|
172
|
+
`notifyWithDelivery`) so a fresh error surfaces without opening the dashboard.
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Uptime monitoring
|
|
2
|
+
|
|
3
|
+
Uptime monitoring lets you create **monitors** — synthetic HTTP checks that ping
|
|
4
|
+
a URL on a schedule and alert you (or others) when something is wrong:
|
|
5
|
+
|
|
6
|
+
- the URL is **unreachable** or **times out**,
|
|
7
|
+
- it returns a **non-expected status** (e.g. a `5xx` when you expect `2xx`),
|
|
8
|
+
- it is **too slow** (a latency budget you set), or
|
|
9
|
+
- its response body is **missing expected text** or **contains forbidden text**.
|
|
10
|
+
|
|
11
|
+
It reuses the same notification pipeline as the analytics alert rules, so alerts
|
|
12
|
+
land in the in-app inbox and can also fan out to email, Slack, and webhooks.
|
|
13
|
+
|
|
14
|
+
The feature lives under **Monitoring → Uptime** (`/monitoring?view=uptime`). A
|
|
15
|
+
selected monitor is reflected in the URL as `?view=uptime&monitor=<id>` so links
|
|
16
|
+
are shareable and the agent can deep-link a monitor.
|
|
17
|
+
|
|
18
|
+
## How a check works
|
|
19
|
+
|
|
20
|
+
Each check runs on the server (`server/lib/uptime-monitors.ts`):
|
|
21
|
+
|
|
22
|
+
1. Fetch the monitor's `url` with the configured `method`, headers, and body,
|
|
23
|
+
through an SSRF-safe path, with an `AbortController` timeout.
|
|
24
|
+
2. Measure latency and read up to **512 KB** of the response body (skipped for
|
|
25
|
+
`HEAD`).
|
|
26
|
+
3. Evaluate the **status matcher** and every **assertion**.
|
|
27
|
+
4. Classify the result:
|
|
28
|
+
- `up` — status matches and all assertions pass.
|
|
29
|
+
- `degraded` — status matches but only a `max_latency_ms` assertion fails
|
|
30
|
+
(the endpoint responded, just too slowly). Alerts at `warning` severity.
|
|
31
|
+
- `down` — the status does not match, a content/header assertion fails, or
|
|
32
|
+
the request errored/timed out. Alerts at the monitor's configured severity.
|
|
33
|
+
- `error` — a configuration/SSRF problem prevented the check from running.
|
|
34
|
+
|
|
35
|
+
### Status matcher
|
|
36
|
+
|
|
37
|
+
`expectedStatus` accepts one of three shapes (stored as JSON):
|
|
38
|
+
|
|
39
|
+
```jsonc
|
|
40
|
+
{ "mode": "class", "classes": ["2xx", "3xx"] } // any 2xx or 3xx
|
|
41
|
+
{ "mode": "list", "codes": [200, 204] } // exact codes
|
|
42
|
+
{ "mode": "range", "min": 200, "max": 299 } // inclusive range
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Assertions
|
|
46
|
+
|
|
47
|
+
`assertions` is a JSON array. All assertions must pass for a check to be `up`.
|
|
48
|
+
|
|
49
|
+
| type | meaning | fields |
|
|
50
|
+
| ----------------- | ------------------------------------------------ | ----------------- |
|
|
51
|
+
| `body_contains` | response body must contain the text | `value` |
|
|
52
|
+
| `body_absent` | response body must NOT contain the text | `value` |
|
|
53
|
+
| `header_contains` | a response header must contain the text | `header`, `value` |
|
|
54
|
+
| `header_equals` | a response header must equal the text | `header`, `value` |
|
|
55
|
+
| `max_latency_ms` | response must arrive within N ms (else degraded) | `value` (number) |
|
|
56
|
+
|
|
57
|
+
## Alerting and recovery
|
|
58
|
+
|
|
59
|
+
`evaluateAndNotifyMonitor` manages incidents like the analytics alert engine:
|
|
60
|
+
|
|
61
|
+
- On a transition **into failure**, it opens a `monitor_incidents` row (one per
|
|
62
|
+
continuous failure streak) and calls `notifyWithDelivery` with a clear title
|
|
63
|
+
and body plus metadata
|
|
64
|
+
`{ kind: "uptime_monitor", monitorId, url, statusCode, latencyMs, failedAssertions }`.
|
|
65
|
+
The `inbox` channel is always included; `email`/`slack`/`webhook` are added
|
|
66
|
+
when configured, and email uses the monitor's `emailRecipients`.
|
|
67
|
+
- While an incident is open it will not re-alert. After an incident resolves,
|
|
68
|
+
`cooldownMinutes` suppresses a fresh "down" alert for that window to prevent
|
|
69
|
+
flapping.
|
|
70
|
+
- On **recovery**, it resolves the open incident and sends an informational
|
|
71
|
+
"recovered" notification (with downtime duration).
|
|
72
|
+
|
|
73
|
+
A `lastStatus === "running"` claim guard (with a staleness timeout) ensures that
|
|
74
|
+
concurrent sweeps never double-run the same monitor.
|
|
75
|
+
|
|
76
|
+
## Security (SSRF)
|
|
77
|
+
|
|
78
|
+
Because monitors fetch user-supplied URLs from the server, `runMonitorCheck`
|
|
79
|
+
guards against SSRF:
|
|
80
|
+
|
|
81
|
+
- Only `http:` / `https:` URLs are allowed.
|
|
82
|
+
- Requests to loopback, link-local, private RFC1918 ranges, and cloud metadata
|
|
83
|
+
IPs are blocked — both by a literal pre-flight check and by DNS resolution of
|
|
84
|
+
the resolved host (including across redirects). Blocked hosts classify as
|
|
85
|
+
`error`, never a successful check.
|
|
86
|
+
- Redirects are followed manually (max 5 hops) and each hop is re-validated; when
|
|
87
|
+
`followRedirects` is off, a `3xx` is returned as-is.
|
|
88
|
+
- The response body read is capped at 512 KB before text assertions run.
|
|
89
|
+
|
|
90
|
+
To monitor internal/private hosts in development or a self-hosted deployment,
|
|
91
|
+
set `UPTIME_MONITOR_ALLOW_PRIVATE_HOSTS=1` (off by default).
|
|
92
|
+
|
|
93
|
+
## Background job
|
|
94
|
+
|
|
95
|
+
The sweep is registered by `server/plugins/uptime-monitor-jobs.ts` and runs
|
|
96
|
+
`runDueMonitorsOnce()` (`server/jobs/uptime-monitors.ts`), which selects enabled
|
|
97
|
+
monitors whose interval has elapsed, checks them, records results, opens/resolves
|
|
98
|
+
incidents, and prunes old check results.
|
|
99
|
+
|
|
100
|
+
Environment flags (mirrors the analytics alert job):
|
|
101
|
+
|
|
102
|
+
| flag | effect |
|
|
103
|
+
| -------------------------------------- | ------------------------------------------------------------------- |
|
|
104
|
+
| `UPTIME_MONITOR_JOBS` | `1` enables the in-process cron; `0` disables it. |
|
|
105
|
+
| `RUN_BACKGROUND_JOBS` | fallback flag when `UPTIME_MONITOR_JOBS` is unset. |
|
|
106
|
+
| (production) | on by default unless a flag is `0` or a platform scheduler owns it. |
|
|
107
|
+
| `UPTIME_MONITOR_INTERVAL_MS` | wake interval for the sweep (default 30s, min 10s). |
|
|
108
|
+
| `UPTIME_MONITOR_SWEEP_LIMIT` | max monitors processed per sweep (default 100). |
|
|
109
|
+
| `UPTIME_MONITOR_RESULT_RETENTION_DAYS` | how long check results are kept (default 30). |
|
|
110
|
+
| `UPTIME_MONITOR_ALLOW_PRIVATE_HOSTS` | allow probing private/internal hosts. |
|
|
111
|
+
|
|
112
|
+
The monitor tables (`monitors`, `monitor_check_results`, `monitor_incidents`)
|
|
113
|
+
are created by the app migration list in `server/plugins/db.ts`, which runs at
|
|
114
|
+
boot regardless of whether the cron is enabled — so the actions and UI always
|
|
115
|
+
have their schema.
|
|
116
|
+
|
|
117
|
+
## Managing monitors from the agent
|
|
118
|
+
|
|
119
|
+
Every operation is an owner-scoped action, so the agent can create and triage
|
|
120
|
+
monitors from chat exactly like the UI:
|
|
121
|
+
|
|
122
|
+
| action | method | what it does |
|
|
123
|
+
| ------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
124
|
+
| `save-monitor` | POST | create or update a monitor (name, url, method, interval, timeout, expected status, assertions, redirects, severity, channels, email recipients, cooldown, enabled). |
|
|
125
|
+
| `list-monitors` | GET | list monitors with latest status, latency, and 24h/7d uptime %. |
|
|
126
|
+
| `get-monitor` | GET | one monitor plus its recent check results and incidents. |
|
|
127
|
+
| `delete-monitor` | POST | delete a monitor and its results + incidents. |
|
|
128
|
+
| `run-monitor-check` | POST | run one check now, record it, and open/resolve incidents. |
|
|
129
|
+
|
|
130
|
+
Example prompts:
|
|
131
|
+
|
|
132
|
+
- "Monitor https://example.com every 5 minutes and email me if it returns a 5xx
|
|
133
|
+
or the page stops containing 'Sign in'."
|
|
134
|
+
- "Which monitors are down right now?" (→ `list-monitors`)
|
|
135
|
+
- "Run a check on the marketing site now." (→ `run-monitor-check`)
|
|
136
|
+
|
|
137
|
+
## Data model
|
|
138
|
+
|
|
139
|
+
All three tables carry `ownableColumns()` (`owner_email` / `org_id` /
|
|
140
|
+
`visibility`) and every read/write is scoped by owner + org.
|
|
141
|
+
|
|
142
|
+
- **`monitors`** — configuration plus mutable status fields (`last_status`,
|
|
143
|
+
`last_checked_at`, `last_success_at`, `last_error`, `last_latency_ms`,
|
|
144
|
+
`last_status_code`, `consecutive_failures`).
|
|
145
|
+
- **`monitor_check_results`** — one row per probe (`ok`, `status`, `status_code`,
|
|
146
|
+
`latency_ms`, `error`, `failed_assertions`), indexed on
|
|
147
|
+
`(monitor_id, checked_at)`; pruned by the sweep so it stays bounded.
|
|
148
|
+
- **`monitor_incidents`** — one row per failure streak (`started_at`,
|
|
149
|
+
`resolved_at` null = ongoing, `cause`, `severity`, `notification_id`,
|
|
150
|
+
`checks_failed`).
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error capture schema — OWNED BY THE ERROR CAPTURE FEATURE.
|
|
3
|
+
*
|
|
4
|
+
* Everything exported here is re-exported from ./schema.ts via `export *`, so
|
|
5
|
+
* these tables join the app's Drizzle schema namespace and are reachable as
|
|
6
|
+
* `schema.<table>` throughout the server. Keep all schema changes additive
|
|
7
|
+
* (never drop/rename/retype existing columns) per the storing-data rules.
|
|
8
|
+
*
|
|
9
|
+
* Two tables, Sentry-style:
|
|
10
|
+
* - `error_issues` — the grouped issue (one row per fingerprint per owner
|
|
11
|
+
* scope). Ownable + shareable so an org-scoped analytics key surfaces its
|
|
12
|
+
* issues to the whole org via `accessFilter`, mirroring session_recordings.
|
|
13
|
+
* - `error_events` — individual occurrences. High-volume, owner-scoped like
|
|
14
|
+
* `analytics_events` (plain owner columns, not `ownableColumns()`), always
|
|
15
|
+
* read behind an issue the caller already has access to, and pruned to a
|
|
16
|
+
* bounded retention per issue so occurrences can't grow unbounded.
|
|
17
|
+
*/
|
|
18
|
+
import {
|
|
19
|
+
createSharesTable,
|
|
20
|
+
index,
|
|
21
|
+
integer,
|
|
22
|
+
now,
|
|
23
|
+
ownableColumns,
|
|
24
|
+
table,
|
|
25
|
+
text,
|
|
26
|
+
uniqueIndex,
|
|
27
|
+
} from "@agent-native/core/db/schema";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Grouped error issues. A stable `fingerprint` (error type + top meaningful
|
|
31
|
+
* stack frame, or message when there's no usable stack) collapses many
|
|
32
|
+
* occurrences into one triageable issue.
|
|
33
|
+
*/
|
|
34
|
+
export const errorIssues = table(
|
|
35
|
+
"error_issues",
|
|
36
|
+
{
|
|
37
|
+
id: text("id").primaryKey(),
|
|
38
|
+
/** Stable grouping key; unique per owner scope. */
|
|
39
|
+
fingerprint: text("fingerprint").notNull(),
|
|
40
|
+
/** Error class/name, e.g. "TypeError" or "Error" (or "Message"). */
|
|
41
|
+
type: text("type").notNull().default("Error"),
|
|
42
|
+
/** Human-readable issue title (type + first line of the message). */
|
|
43
|
+
title: text("title").notNull(),
|
|
44
|
+
/** Best-effort culprit — the top in-app frame ("fn (file:line)"). */
|
|
45
|
+
culprit: text("culprit"),
|
|
46
|
+
level: text("level", {
|
|
47
|
+
enum: ["fatal", "error", "warning", "info", "debug"],
|
|
48
|
+
})
|
|
49
|
+
.notNull()
|
|
50
|
+
.default("error"),
|
|
51
|
+
status: text("status", {
|
|
52
|
+
enum: ["unresolved", "resolved", "ignored"],
|
|
53
|
+
})
|
|
54
|
+
.notNull()
|
|
55
|
+
.default("unresolved"),
|
|
56
|
+
firstSeenAt: text("first_seen_at").notNull(),
|
|
57
|
+
lastSeenAt: text("last_seen_at").notNull(),
|
|
58
|
+
/** Lifetime occurrence count (monotonic; not affected by retention). */
|
|
59
|
+
eventCount: integer("event_count").notNull().default(0),
|
|
60
|
+
/** Approximate distinct users, recomputed over retained occurrences. */
|
|
61
|
+
usersAffected: integer("users_affected").notNull().default(0),
|
|
62
|
+
/** id of a representative occurrence for the detail view. */
|
|
63
|
+
sampleEventId: text("sample_event_id"),
|
|
64
|
+
/** Most recent linked session_recordings.id (sr_...), if any. */
|
|
65
|
+
lastSessionRecordingId: text("last_session_recording_id"),
|
|
66
|
+
/** Optional triage owner (email). */
|
|
67
|
+
assignee: text("assignee"),
|
|
68
|
+
/** Denormalized product dimensions for filtering/display. */
|
|
69
|
+
app: text("app"),
|
|
70
|
+
template: text("template"),
|
|
71
|
+
createdAt: text("created_at").notNull().default(now()),
|
|
72
|
+
updatedAt: text("updated_at").notNull().default(now()),
|
|
73
|
+
...ownableColumns(),
|
|
74
|
+
},
|
|
75
|
+
(issue) => ({
|
|
76
|
+
scopeFingerprintUnique: uniqueIndex(
|
|
77
|
+
"error_issues_scope_fingerprint_idx",
|
|
78
|
+
).on(issue.ownerEmail, issue.orgId, issue.fingerprint),
|
|
79
|
+
scopeLastSeenIdx: index("error_issues_scope_last_seen_idx").on(
|
|
80
|
+
issue.ownerEmail,
|
|
81
|
+
issue.orgId,
|
|
82
|
+
issue.lastSeenAt,
|
|
83
|
+
),
|
|
84
|
+
scopeStatusIdx: index("error_issues_scope_status_idx").on(
|
|
85
|
+
issue.orgId,
|
|
86
|
+
issue.ownerEmail,
|
|
87
|
+
issue.status,
|
|
88
|
+
issue.lastSeenAt,
|
|
89
|
+
),
|
|
90
|
+
}),
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
export const errorIssueShares = createSharesTable("error_issue_shares");
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Individual error occurrences (events). Owner-scoped like analytics_events.
|
|
97
|
+
* Always read behind an issue whose access the caller already resolved through
|
|
98
|
+
* `accessFilter`, and additionally filtered by owner scope for defense in
|
|
99
|
+
* depth. Pruned to a bounded retention per issue at ingest time.
|
|
100
|
+
*/
|
|
101
|
+
export const errorEvents = table(
|
|
102
|
+
"error_events",
|
|
103
|
+
{
|
|
104
|
+
id: text("id").primaryKey(),
|
|
105
|
+
issueId: text("issue_id").notNull(),
|
|
106
|
+
fingerprint: text("fingerprint").notNull(),
|
|
107
|
+
type: text("type").notNull().default("Error"),
|
|
108
|
+
message: text("message").notNull().default(""),
|
|
109
|
+
culprit: text("culprit"),
|
|
110
|
+
level: text("level", {
|
|
111
|
+
enum: ["fatal", "error", "warning", "info", "debug"],
|
|
112
|
+
})
|
|
113
|
+
.notNull()
|
|
114
|
+
.default("error"),
|
|
115
|
+
/** Normalized stack frames as JSON (ParsedStackFrame[]). */
|
|
116
|
+
stack: text("stack").notNull().default("[]"),
|
|
117
|
+
/** Bounded raw stack string kept for display fidelity. */
|
|
118
|
+
rawStack: text("raw_stack"),
|
|
119
|
+
handled: integer("handled", { mode: "boolean" }).notNull().default(true),
|
|
120
|
+
url: text("url"),
|
|
121
|
+
userId: text("user_id"),
|
|
122
|
+
anonymousId: text("anonymous_id"),
|
|
123
|
+
userKey: text("user_key"),
|
|
124
|
+
sessionId: text("session_id"),
|
|
125
|
+
/** Client replay id (localStorage) reported by the SDK. */
|
|
126
|
+
clientRecordingId: text("client_recording_id"),
|
|
127
|
+
/** Resolved session_recordings.id (sr_...) when a replay exists. */
|
|
128
|
+
sessionRecordingId: text("session_recording_id"),
|
|
129
|
+
release: text("release"),
|
|
130
|
+
environment: text("environment"),
|
|
131
|
+
tags: text("tags").notNull().default("{}"),
|
|
132
|
+
extra: text("extra").notNull().default("{}"),
|
|
133
|
+
breadcrumbs: text("breadcrumbs").notNull().default("[]"),
|
|
134
|
+
occurredAt: text("occurred_at").notNull(),
|
|
135
|
+
createdAt: text("created_at").notNull().default(now()),
|
|
136
|
+
ownerEmail: text("owner_email").notNull().default("local@localhost"),
|
|
137
|
+
orgId: text("org_id"),
|
|
138
|
+
},
|
|
139
|
+
(event) => ({
|
|
140
|
+
issueOccurredIdx: index("error_events_issue_occurred_idx").on(
|
|
141
|
+
event.issueId,
|
|
142
|
+
event.occurredAt,
|
|
143
|
+
),
|
|
144
|
+
scopeOccurredIdx: index("error_events_scope_occurred_idx").on(
|
|
145
|
+
event.ownerEmail,
|
|
146
|
+
event.orgId,
|
|
147
|
+
event.occurredAt,
|
|
148
|
+
),
|
|
149
|
+
}),
|
|
150
|
+
);
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Uptime monitoring schema — OWNED BY THE UPTIME MONITORING FEATURE.
|
|
3
|
+
*
|
|
4
|
+
* Everything exported here is re-exported from ./schema.ts via `export *`, so
|
|
5
|
+
* these tables join the app's Drizzle schema namespace and are reachable as
|
|
6
|
+
* `schema.<table>` throughout the server. Keep all schema changes additive
|
|
7
|
+
* (never drop/rename/retype existing columns) per the storing-data rules.
|
|
8
|
+
*
|
|
9
|
+
* Physical table creation + indexes are applied by the isolated migration list
|
|
10
|
+
* in server/plugins/uptime-monitor-jobs.ts (`uptime_monitor_migrations`), NOT
|
|
11
|
+
* by drizzle-kit. These Drizzle definitions must stay in lockstep with that
|
|
12
|
+
* DDL (snake_case column names, dialect-agnostic types).
|
|
13
|
+
*
|
|
14
|
+
* All three tables carry `ownableColumns()` (owner_email / org_id / visibility)
|
|
15
|
+
* and every read/write in server/lib/uptime-monitors.ts is scoped by
|
|
16
|
+
* owner_email + org_id, mirroring the analytics-alerts engine.
|
|
17
|
+
*/
|
|
18
|
+
import {
|
|
19
|
+
integer,
|
|
20
|
+
now,
|
|
21
|
+
ownableColumns,
|
|
22
|
+
table,
|
|
23
|
+
text,
|
|
24
|
+
} from "@agent-native/core/db/schema";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A single uptime check ("monitor"). Pings `url` on `intervalSeconds` and
|
|
28
|
+
* evaluates the response against a status matcher + a list of assertions.
|
|
29
|
+
*/
|
|
30
|
+
export const monitors = table("monitors", {
|
|
31
|
+
id: text("id").primaryKey(),
|
|
32
|
+
name: text("name").notNull(),
|
|
33
|
+
url: text("url").notNull(),
|
|
34
|
+
/** HTTP method used for the probe. */
|
|
35
|
+
method: text("method", {
|
|
36
|
+
enum: ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
|
|
37
|
+
})
|
|
38
|
+
.notNull()
|
|
39
|
+
.default("GET"),
|
|
40
|
+
/** Extra request headers as a JSON object (`Record<string,string>`). */
|
|
41
|
+
requestHeaders: text("request_headers").notNull().default("{}"),
|
|
42
|
+
/** Optional request body (POST/PUT/PATCH). */
|
|
43
|
+
requestBody: text("request_body"),
|
|
44
|
+
intervalSeconds: integer("interval_seconds").notNull().default(300),
|
|
45
|
+
timeoutMs: integer("timeout_ms").notNull().default(15000),
|
|
46
|
+
/**
|
|
47
|
+
* Status matcher as JSON. One of:
|
|
48
|
+
* { "mode": "class", "classes": ["2xx","3xx"] }
|
|
49
|
+
* { "mode": "list", "codes": [200,204] }
|
|
50
|
+
* { "mode": "range", "min": 200, "max": 299 }
|
|
51
|
+
*/
|
|
52
|
+
expectedStatus: text("expected_status")
|
|
53
|
+
.notNull()
|
|
54
|
+
.default('{"mode":"class","classes":["2xx"]}'),
|
|
55
|
+
/**
|
|
56
|
+
* JSON array of assertions. Each entry:
|
|
57
|
+
* { "type": "body_contains" | "body_absent" | "header_contains" |
|
|
58
|
+
* "header_equals" | "max_latency_ms",
|
|
59
|
+
* "value": string | number, "header"?: string }
|
|
60
|
+
*/
|
|
61
|
+
assertions: text("assertions").notNull().default("[]"),
|
|
62
|
+
followRedirects: integer("follow_redirects", { mode: "boolean" })
|
|
63
|
+
.notNull()
|
|
64
|
+
.default(true),
|
|
65
|
+
/** Alert severity when the monitor fails. */
|
|
66
|
+
severity: text("severity", { enum: ["warning", "critical"] })
|
|
67
|
+
.notNull()
|
|
68
|
+
.default("critical"),
|
|
69
|
+
/** Notification channels as JSON (e.g. ["inbox","email","slack","webhook"]). */
|
|
70
|
+
channels: text("channels").notNull().default('["inbox"]'),
|
|
71
|
+
/** Email recipients as JSON array of addresses. */
|
|
72
|
+
emailRecipients: text("email_recipients").notNull().default("[]"),
|
|
73
|
+
/** Minutes to suppress repeat alerts while an incident is ongoing. */
|
|
74
|
+
cooldownMinutes: integer("cooldown_minutes").notNull().default(15),
|
|
75
|
+
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
|
|
76
|
+
|
|
77
|
+
// ---- Mutable status fields (updated by the runner) ----
|
|
78
|
+
/** up | down | degraded | error | unknown | running */
|
|
79
|
+
lastStatus: text("last_status"),
|
|
80
|
+
lastCheckedAt: text("last_checked_at"),
|
|
81
|
+
lastSuccessAt: text("last_success_at"),
|
|
82
|
+
lastError: text("last_error"),
|
|
83
|
+
lastLatencyMs: integer("last_latency_ms"),
|
|
84
|
+
lastStatusCode: integer("last_status_code"),
|
|
85
|
+
consecutiveFailures: integer("consecutive_failures").notNull().default(0),
|
|
86
|
+
|
|
87
|
+
createdAt: text("created_at").notNull().default(now()),
|
|
88
|
+
updatedAt: text("updated_at").notNull().default(now()),
|
|
89
|
+
...ownableColumns(),
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Historical probe results. Bounded retention is enforced by the sweep job
|
|
94
|
+
* (server/jobs/uptime-monitors.ts) so this table cannot grow unbounded.
|
|
95
|
+
*/
|
|
96
|
+
export const monitorCheckResults = table("monitor_check_results", {
|
|
97
|
+
id: text("id").primaryKey(),
|
|
98
|
+
monitorId: text("monitor_id").notNull(),
|
|
99
|
+
checkedAt: text("checked_at").notNull(),
|
|
100
|
+
ok: integer("ok", { mode: "boolean" }).notNull(),
|
|
101
|
+
/** Classification for this probe: up | down | degraded | error. */
|
|
102
|
+
status: text("status").notNull().default("up"),
|
|
103
|
+
statusCode: integer("status_code"),
|
|
104
|
+
latencyMs: integer("latency_ms"),
|
|
105
|
+
error: text("error"),
|
|
106
|
+
/** JSON array of human-readable assertion failures. */
|
|
107
|
+
failedAssertions: text("failed_assertions").notNull().default("[]"),
|
|
108
|
+
createdAt: text("created_at").notNull().default(now()),
|
|
109
|
+
...ownableColumns(),
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* One incident per continuous failure streak. `resolvedAt` null = ongoing.
|
|
114
|
+
* Mirrors analyticsAlertIncidents.
|
|
115
|
+
*/
|
|
116
|
+
export const monitorIncidents = table("monitor_incidents", {
|
|
117
|
+
id: text("id").primaryKey(),
|
|
118
|
+
monitorId: text("monitor_id").notNull(),
|
|
119
|
+
startedAt: text("started_at").notNull(),
|
|
120
|
+
resolvedAt: text("resolved_at"),
|
|
121
|
+
/** down | degraded — the classification at incident open. */
|
|
122
|
+
status: text("status").notNull().default("down"),
|
|
123
|
+
severity: text("severity").notNull().default("critical"),
|
|
124
|
+
/** Short summary of what failed (status code / failed assertions). */
|
|
125
|
+
cause: text("cause").notNull().default(""),
|
|
126
|
+
lastError: text("last_error"),
|
|
127
|
+
notificationId: text("notification_id"),
|
|
128
|
+
checksFailed: integer("checks_failed").notNull().default(1),
|
|
129
|
+
createdAt: text("created_at").notNull().default(now()),
|
|
130
|
+
...ownableColumns(),
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Owner-authored public status page. A status page bundles a set of the owner's
|
|
135
|
+
* monitors under a public `slug` (`/status/<slug>`) and renders their SAFE
|
|
136
|
+
* aggregate health (status, uptime %s, colored timelines) to anyone with the
|
|
137
|
+
* link — but only when `published` is true. The public read
|
|
138
|
+
* (server/lib/status-pages.ts `getPublicStatusPage`) strictly filters to
|
|
139
|
+
* published pages and the page owner's included monitors, and never leaks
|
|
140
|
+
* monitor URLs/headers/assertions/alert config unless a per-monitor "show URL"
|
|
141
|
+
* opt-in is set.
|
|
142
|
+
*
|
|
143
|
+
* `monitors` is a JSON array of
|
|
144
|
+
* { monitorId: string; order: number; displayName?: string | null;
|
|
145
|
+
* showUrl?: boolean }
|
|
146
|
+
* kept additive so page layout can grow without a join table migration.
|
|
147
|
+
*/
|
|
148
|
+
export const statusPages = table("status_pages", {
|
|
149
|
+
id: text("id").primaryKey(),
|
|
150
|
+
/** Public, globally-unique URL slug (`/status/<slug>`). */
|
|
151
|
+
slug: text("slug").notNull(),
|
|
152
|
+
title: text("title").notNull(),
|
|
153
|
+
description: text("description"),
|
|
154
|
+
/** Only published pages are readable by the unauthenticated public route. */
|
|
155
|
+
published: integer("published", { mode: "boolean" }).notNull().default(false),
|
|
156
|
+
// ---- Layout options ----
|
|
157
|
+
showUptimeBars: integer("show_uptime_bars", { mode: "boolean" })
|
|
158
|
+
.notNull()
|
|
159
|
+
.default(true),
|
|
160
|
+
showOverallUptime: integer("show_overall_uptime", { mode: "boolean" })
|
|
161
|
+
.notNull()
|
|
162
|
+
.default(true),
|
|
163
|
+
showResponseTime: integer("show_response_time", { mode: "boolean" })
|
|
164
|
+
.notNull()
|
|
165
|
+
.default(false),
|
|
166
|
+
density: text("density", { enum: ["comfortable", "compact"] })
|
|
167
|
+
.notNull()
|
|
168
|
+
.default("comfortable"),
|
|
169
|
+
alignment: text("alignment", { enum: ["left", "center"] })
|
|
170
|
+
.notNull()
|
|
171
|
+
.default("left"),
|
|
172
|
+
/** JSON array of included monitors with order + optional display overrides. */
|
|
173
|
+
monitors: text("monitors").notNull().default("[]"),
|
|
174
|
+
createdAt: text("created_at").notNull().default(now()),
|
|
175
|
+
updatedAt: text("updated_at").notNull().default(now()),
|
|
176
|
+
...ownableColumns(),
|
|
177
|
+
});
|
|
@@ -9,6 +9,12 @@ import {
|
|
|
9
9
|
uniqueIndex,
|
|
10
10
|
} from "@agent-native/core/db/schema";
|
|
11
11
|
|
|
12
|
+
// Feature-owned schema modules. Re-exported so their tables join this app's
|
|
13
|
+
// Drizzle schema namespace (schema.<table>). Each file is owned by a single
|
|
14
|
+
// feature so parallel work never collides on this shared file.
|
|
15
|
+
export * from "./schema-monitoring.js";
|
|
16
|
+
export * from "./schema-errors.js";
|
|
17
|
+
|
|
12
18
|
/**
|
|
13
19
|
* Dashboards table — covers both Explorer and SQL dashboards. The
|
|
14
20
|
* distinction lives in `kind` and the shape of the `config` JSON blob.
|