@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,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side types for the uptime monitoring feature. These mirror the server
|
|
3
|
+
* shapes returned by the monitor actions (see server/lib/uptime-monitors.ts).
|
|
4
|
+
* Kept feature-local so the panel owns its own contract.
|
|
5
|
+
*/
|
|
6
|
+
import type {
|
|
7
|
+
ResponseTimePoint,
|
|
8
|
+
UptimeBucket,
|
|
9
|
+
UptimeWindows,
|
|
10
|
+
} from "@/components/monitoring";
|
|
11
|
+
|
|
12
|
+
export type MonitorMethod =
|
|
13
|
+
| "GET"
|
|
14
|
+
| "HEAD"
|
|
15
|
+
| "POST"
|
|
16
|
+
| "PUT"
|
|
17
|
+
| "PATCH"
|
|
18
|
+
| "DELETE"
|
|
19
|
+
| "OPTIONS";
|
|
20
|
+
|
|
21
|
+
export type MonitorSeverity = "warning" | "critical";
|
|
22
|
+
|
|
23
|
+
export type MonitorStatus =
|
|
24
|
+
| "up"
|
|
25
|
+
| "down"
|
|
26
|
+
| "degraded"
|
|
27
|
+
| "error"
|
|
28
|
+
| "unknown"
|
|
29
|
+
| "running";
|
|
30
|
+
|
|
31
|
+
export type AssertionType =
|
|
32
|
+
| "body_contains"
|
|
33
|
+
| "body_absent"
|
|
34
|
+
| "header_contains"
|
|
35
|
+
| "header_equals"
|
|
36
|
+
| "max_latency_ms";
|
|
37
|
+
|
|
38
|
+
export interface Assertion {
|
|
39
|
+
type: AssertionType;
|
|
40
|
+
value: string | number;
|
|
41
|
+
header?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type StatusMatcher =
|
|
45
|
+
| { mode: "class"; classes: string[] }
|
|
46
|
+
| { mode: "list"; codes: number[] }
|
|
47
|
+
| { mode: "range"; min: number; max: number };
|
|
48
|
+
|
|
49
|
+
export interface MonitorSummary {
|
|
50
|
+
id: string;
|
|
51
|
+
name: string;
|
|
52
|
+
url: string;
|
|
53
|
+
method: MonitorMethod;
|
|
54
|
+
requestHeaders: Record<string, string>;
|
|
55
|
+
requestBody: string | null;
|
|
56
|
+
intervalSeconds: number;
|
|
57
|
+
timeoutMs: number;
|
|
58
|
+
expectedStatus: StatusMatcher;
|
|
59
|
+
assertions: Assertion[];
|
|
60
|
+
followRedirects: boolean;
|
|
61
|
+
severity: MonitorSeverity;
|
|
62
|
+
channels: string[];
|
|
63
|
+
emailRecipients: string[];
|
|
64
|
+
cooldownMinutes: number;
|
|
65
|
+
enabled: boolean;
|
|
66
|
+
lastStatus: MonitorStatus | null;
|
|
67
|
+
lastCheckedAt: string | null;
|
|
68
|
+
lastSuccessAt: string | null;
|
|
69
|
+
lastError: string | null;
|
|
70
|
+
lastLatencyMs: number | null;
|
|
71
|
+
lastStatusCode: number | null;
|
|
72
|
+
consecutiveFailures: number;
|
|
73
|
+
createdAt: string;
|
|
74
|
+
updatedAt: string;
|
|
75
|
+
ownerEmail: string;
|
|
76
|
+
orgId: string | null;
|
|
77
|
+
uptime24h: number | null;
|
|
78
|
+
uptime7d: number | null;
|
|
79
|
+
checks24h: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface MonitorCheckResult {
|
|
83
|
+
id: string;
|
|
84
|
+
monitorId: string;
|
|
85
|
+
checkedAt: string;
|
|
86
|
+
ok: boolean;
|
|
87
|
+
status: MonitorStatus;
|
|
88
|
+
statusCode: number | null;
|
|
89
|
+
latencyMs: number | null;
|
|
90
|
+
error: string | null;
|
|
91
|
+
failedAssertions: string[];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface MonitorIncident {
|
|
95
|
+
id: string;
|
|
96
|
+
monitorId: string;
|
|
97
|
+
startedAt: string;
|
|
98
|
+
resolvedAt: string | null;
|
|
99
|
+
status: MonitorStatus;
|
|
100
|
+
severity: MonitorSeverity;
|
|
101
|
+
cause: string;
|
|
102
|
+
lastError: string | null;
|
|
103
|
+
notificationId: string | null;
|
|
104
|
+
checksFailed: number;
|
|
105
|
+
createdAt: string;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface MonitorDetail {
|
|
109
|
+
monitor: MonitorSummary;
|
|
110
|
+
recentResults: MonitorCheckResult[];
|
|
111
|
+
incidents: MonitorIncident[];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Aggregated stats for one monitor, as returned by the `get-monitor-stats`
|
|
116
|
+
* action (one entry per requested monitor). Structurally identical to the
|
|
117
|
+
* server `MonitorStats` shape; the reusable chart components consume the
|
|
118
|
+
* `windows` / `timeline` / `responseSeries` fields directly.
|
|
119
|
+
*/
|
|
120
|
+
export interface MonitorStats {
|
|
121
|
+
monitorId: string;
|
|
122
|
+
status: MonitorStatus | null;
|
|
123
|
+
lastCheckedAt: string | null;
|
|
124
|
+
lastLatencyMs: number | null;
|
|
125
|
+
windows: UptimeWindows;
|
|
126
|
+
timeline: UptimeBucket[];
|
|
127
|
+
responseSeries: ResponseTimePoint[];
|
|
128
|
+
avgResponseMs: number | null;
|
|
129
|
+
incidentCount: number;
|
|
130
|
+
mtbfMs: number | null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export interface CheckOutcome {
|
|
134
|
+
checkedAt: string;
|
|
135
|
+
status: MonitorStatus;
|
|
136
|
+
ok: boolean;
|
|
137
|
+
statusCode: number | null;
|
|
138
|
+
latencyMs: number | null;
|
|
139
|
+
error: string | null;
|
|
140
|
+
failedAssertions: string[];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Payload accepted by the save-monitor action. */
|
|
144
|
+
export interface SaveMonitorInput {
|
|
145
|
+
id?: string;
|
|
146
|
+
name: string;
|
|
147
|
+
url: string;
|
|
148
|
+
method?: MonitorMethod;
|
|
149
|
+
requestHeaders?: Record<string, string>;
|
|
150
|
+
requestBody?: string | null;
|
|
151
|
+
intervalSeconds?: number;
|
|
152
|
+
timeoutMs?: number;
|
|
153
|
+
expectedStatus?: StatusMatcher;
|
|
154
|
+
assertions?: Assertion[];
|
|
155
|
+
followRedirects?: boolean;
|
|
156
|
+
severity?: MonitorSeverity;
|
|
157
|
+
channels?: string[];
|
|
158
|
+
emailRecipients?: string[];
|
|
159
|
+
cooldownMinutes?: number;
|
|
160
|
+
enabled?: boolean;
|
|
161
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatting + presentation helpers for the uptime monitoring UI. Pure
|
|
3
|
+
* functions only so they can be reused across the list, detail, and dialog.
|
|
4
|
+
*/
|
|
5
|
+
import { fmt } from "./i18n";
|
|
6
|
+
import type { Assertion, MonitorStatus, StatusMatcher } from "./types";
|
|
7
|
+
|
|
8
|
+
export function hostFromUrl(url: string): string {
|
|
9
|
+
try {
|
|
10
|
+
return new URL(url).host;
|
|
11
|
+
} catch {
|
|
12
|
+
return url;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Derive a friendly default monitor name from a URL: the host without a leading
|
|
18
|
+
* `www.` (e.g. `example.com` from `https://www.example.com/health`). Falls back
|
|
19
|
+
* to a best-effort parse for partial input so it still works while typing.
|
|
20
|
+
*/
|
|
21
|
+
export function deriveMonitorName(url: string): string {
|
|
22
|
+
const raw = (url ?? "").trim();
|
|
23
|
+
if (!raw) return "";
|
|
24
|
+
try {
|
|
25
|
+
return new URL(raw).host.replace(/^www\./i, "") || raw;
|
|
26
|
+
} catch {
|
|
27
|
+
return (
|
|
28
|
+
raw
|
|
29
|
+
.replace(/^[a-z][a-z0-9+.-]*:\/\//i, "")
|
|
30
|
+
.replace(/^www\./i, "")
|
|
31
|
+
.split(/[/?#]/, 1)[0]
|
|
32
|
+
?.trim() ?? ""
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function isHttpUrl(url: string): boolean {
|
|
38
|
+
try {
|
|
39
|
+
const parsed = new URL(url);
|
|
40
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
41
|
+
} catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function formatRelativeTime(value: string | null): string | null {
|
|
47
|
+
if (!value) return null;
|
|
48
|
+
const then = Date.parse(value);
|
|
49
|
+
if (!Number.isFinite(then)) return null;
|
|
50
|
+
const diff = Date.now() - then;
|
|
51
|
+
const abs = Math.abs(diff);
|
|
52
|
+
const mins = Math.round(abs / 60000);
|
|
53
|
+
if (mins < 1) return "just now";
|
|
54
|
+
if (mins < 60) return diff >= 0 ? `${mins}m ago` : `in ${mins}m`;
|
|
55
|
+
const hours = Math.round(mins / 60);
|
|
56
|
+
if (hours < 24) return diff >= 0 ? `${hours}h ago` : `in ${hours}h`;
|
|
57
|
+
const days = Math.round(hours / 24);
|
|
58
|
+
return diff >= 0 ? `${days}d ago` : `in ${days}d`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function formatDateTime(value: string | null): string {
|
|
62
|
+
if (!value) return "—";
|
|
63
|
+
const date = new Date(value);
|
|
64
|
+
if (Number.isNaN(date.getTime())) return "—";
|
|
65
|
+
return date.toLocaleString(undefined, {
|
|
66
|
+
month: "short",
|
|
67
|
+
day: "numeric",
|
|
68
|
+
hour: "numeric",
|
|
69
|
+
minute: "2-digit",
|
|
70
|
+
second: "2-digit",
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function formatDuration(ms: number): string {
|
|
75
|
+
if (!Number.isFinite(ms) || ms < 0) return "—";
|
|
76
|
+
const secs = Math.round(ms / 1000);
|
|
77
|
+
if (secs < 60) return `${secs}s`;
|
|
78
|
+
const mins = Math.round(secs / 60);
|
|
79
|
+
if (mins < 60) return `${mins}m`;
|
|
80
|
+
const hours = Math.floor(mins / 60);
|
|
81
|
+
const rem = mins % 60;
|
|
82
|
+
if (hours < 24) return rem ? `${hours}h ${rem}m` : `${hours}h`;
|
|
83
|
+
const days = Math.floor(hours / 24);
|
|
84
|
+
return `${days}d ${hours % 24}h`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function formatLatency(ms: number | null): string {
|
|
88
|
+
if (ms == null) return "—";
|
|
89
|
+
if (ms < 1000) return `${ms} ms`;
|
|
90
|
+
return `${(ms / 1000).toFixed(2)} s`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function formatUptime(pct: number | null): string {
|
|
94
|
+
if (pct == null) return "—";
|
|
95
|
+
if (pct >= 99.995) return "100%";
|
|
96
|
+
return `${pct.toFixed(pct >= 99.9 ? 2 : 1)}%`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Health bucket for coloring: 3 states surfaced in the UI. */
|
|
100
|
+
export type HealthTone = "up" | "down" | "degraded" | "neutral";
|
|
101
|
+
|
|
102
|
+
export function statusTone(status: MonitorStatus | null): HealthTone {
|
|
103
|
+
switch (status) {
|
|
104
|
+
case "up":
|
|
105
|
+
return "up";
|
|
106
|
+
case "down":
|
|
107
|
+
case "error":
|
|
108
|
+
return "down";
|
|
109
|
+
case "degraded":
|
|
110
|
+
return "degraded";
|
|
111
|
+
default:
|
|
112
|
+
return "neutral";
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function toneDotClass(tone: HealthTone): string {
|
|
117
|
+
switch (tone) {
|
|
118
|
+
case "up":
|
|
119
|
+
return "bg-emerald-500";
|
|
120
|
+
case "down":
|
|
121
|
+
return "bg-red-500";
|
|
122
|
+
case "degraded":
|
|
123
|
+
return "bg-amber-500";
|
|
124
|
+
default:
|
|
125
|
+
return "bg-muted-foreground/40";
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function toneTextClass(tone: HealthTone): string {
|
|
130
|
+
switch (tone) {
|
|
131
|
+
case "up":
|
|
132
|
+
return "text-emerald-500";
|
|
133
|
+
case "down":
|
|
134
|
+
return "text-red-500";
|
|
135
|
+
case "degraded":
|
|
136
|
+
return "text-amber-500";
|
|
137
|
+
default:
|
|
138
|
+
return "text-muted-foreground";
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function statusLabel(
|
|
143
|
+
status: MonitorStatus | null,
|
|
144
|
+
t: {
|
|
145
|
+
statusUp: string;
|
|
146
|
+
statusDown: string;
|
|
147
|
+
statusDegraded: string;
|
|
148
|
+
statusError: string;
|
|
149
|
+
statusRunning: string;
|
|
150
|
+
statusUnknown: string;
|
|
151
|
+
},
|
|
152
|
+
): string {
|
|
153
|
+
switch (status) {
|
|
154
|
+
case "up":
|
|
155
|
+
return t.statusUp;
|
|
156
|
+
case "down":
|
|
157
|
+
return t.statusDown;
|
|
158
|
+
case "degraded":
|
|
159
|
+
return t.statusDegraded;
|
|
160
|
+
case "error":
|
|
161
|
+
return t.statusError;
|
|
162
|
+
case "running":
|
|
163
|
+
return t.statusRunning;
|
|
164
|
+
default:
|
|
165
|
+
return t.statusUnknown;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function describeMatcher(
|
|
170
|
+
matcher: StatusMatcher,
|
|
171
|
+
t: { matcherClass: string; matcherList: string; matcherRange: string },
|
|
172
|
+
): string {
|
|
173
|
+
if (matcher.mode === "class") {
|
|
174
|
+
return fmt(t.matcherClass, {
|
|
175
|
+
classes: matcher.classes.join(", ").toUpperCase(),
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
if (matcher.mode === "list") {
|
|
179
|
+
return fmt(t.matcherList, { codes: matcher.codes.join(", ") });
|
|
180
|
+
}
|
|
181
|
+
return fmt(t.matcherRange, { min: matcher.min, max: matcher.max });
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function describeAssertion(
|
|
185
|
+
assertion: Assertion,
|
|
186
|
+
t: {
|
|
187
|
+
assertBodyContains: string;
|
|
188
|
+
assertBodyAbsent: string;
|
|
189
|
+
assertHeaderContains: string;
|
|
190
|
+
assertHeaderEquals: string;
|
|
191
|
+
assertMaxLatency: string;
|
|
192
|
+
},
|
|
193
|
+
): string {
|
|
194
|
+
const value = String(assertion.value);
|
|
195
|
+
const header = assertion.header ?? "";
|
|
196
|
+
switch (assertion.type) {
|
|
197
|
+
case "body_contains":
|
|
198
|
+
return fmt(t.assertBodyContains, { value });
|
|
199
|
+
case "body_absent":
|
|
200
|
+
return fmt(t.assertBodyAbsent, { value });
|
|
201
|
+
case "header_contains":
|
|
202
|
+
return fmt(t.assertHeaderContains, { header, value });
|
|
203
|
+
case "header_equals":
|
|
204
|
+
return fmt(t.assertHeaderEquals, { header, value });
|
|
205
|
+
case "max_latency_ms":
|
|
206
|
+
return fmt(t.assertMaxLatency, { value });
|
|
207
|
+
default:
|
|
208
|
+
return value;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AgentToggleButton,
|
|
3
3
|
appApiPath,
|
|
4
|
+
callAction,
|
|
4
5
|
PromptComposer,
|
|
5
6
|
useActionMutation,
|
|
6
7
|
useSendToAgentChat,
|
|
@@ -25,6 +26,7 @@ import {
|
|
|
25
26
|
IconTerminal2,
|
|
26
27
|
IconTimelineEvent,
|
|
27
28
|
} from "@tabler/icons-react";
|
|
29
|
+
import { useQuery } from "@tanstack/react-query";
|
|
28
30
|
import {
|
|
29
31
|
type ReactNode,
|
|
30
32
|
useCallback,
|
|
@@ -53,7 +55,10 @@ import { getIdToken } from "@/lib/auth";
|
|
|
53
55
|
import { cn } from "@/lib/utils";
|
|
54
56
|
|
|
55
57
|
import { extractReplayDiagnostics } from "./session-replay-devtools";
|
|
56
|
-
import {
|
|
58
|
+
import {
|
|
59
|
+
type SessionIssueMatch,
|
|
60
|
+
SessionDevToolsPanel,
|
|
61
|
+
} from "./SessionDevToolsPanel";
|
|
57
62
|
|
|
58
63
|
type SessionRecordingSummary = {
|
|
59
64
|
id: string;
|
|
@@ -167,6 +172,42 @@ const EMPTY_DIAGNOSTICS: ReturnType<typeof extractReplayDiagnostics> = {
|
|
|
167
172
|
networkFailedCount: 0,
|
|
168
173
|
};
|
|
169
174
|
|
|
175
|
+
type ReplayConsoleDiagnostics = ReturnType<
|
|
176
|
+
typeof extractReplayDiagnostics
|
|
177
|
+
>["console"];
|
|
178
|
+
|
|
179
|
+
type ConsoleErrorSignaturePayload = {
|
|
180
|
+
key: string;
|
|
181
|
+
source: string;
|
|
182
|
+
message: string;
|
|
183
|
+
stack?: string;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Distill the resolvable error lines from a session's console diagnostics for
|
|
188
|
+
* issue matching. Only error-level lines are worth sending: window errors,
|
|
189
|
+
* unhandled rejections, and manual `captureException` all surface at `error`
|
|
190
|
+
* level with a serialized `Name: message` (+ stack) that the server can
|
|
191
|
+
* fingerprint back to a captured issue. Non-error console lines are left alone,
|
|
192
|
+
* and anything without a captured issue simply comes back unmatched.
|
|
193
|
+
*/
|
|
194
|
+
function buildConsoleErrorSignatures(
|
|
195
|
+
entries: ReplayConsoleDiagnostics,
|
|
196
|
+
): ConsoleErrorSignaturePayload[] {
|
|
197
|
+
const signatures: ConsoleErrorSignaturePayload[] = [];
|
|
198
|
+
for (const entry of entries) {
|
|
199
|
+
if (entry.level !== "error" || !entry.message) continue;
|
|
200
|
+
signatures.push({
|
|
201
|
+
key: entry.id,
|
|
202
|
+
source: entry.source,
|
|
203
|
+
message: entry.message,
|
|
204
|
+
...(entry.stack ? { stack: entry.stack } : {}),
|
|
205
|
+
});
|
|
206
|
+
if (signatures.length >= 100) break;
|
|
207
|
+
}
|
|
208
|
+
return signatures;
|
|
209
|
+
}
|
|
210
|
+
|
|
170
211
|
const RRWEB_EVENT_TYPE = {
|
|
171
212
|
FullSnapshot: 2,
|
|
172
213
|
IncrementalSnapshot: 3,
|
|
@@ -459,6 +500,39 @@ function ReplayPlayer({
|
|
|
459
500
|
const devToolsIssueCount = devToolsOpen
|
|
460
501
|
? diagnostics.consoleErrorCount + diagnostics.networkFailedCount
|
|
461
502
|
: response.recording.errorCount;
|
|
503
|
+
|
|
504
|
+
// Resolve captured console errors in this replay to their Sentry-style issue
|
|
505
|
+
// groups (one batched, access-scoped call, server-computed fingerprints) so
|
|
506
|
+
// each error can deep-link to its full issue detail. Only runs once devtools
|
|
507
|
+
// are open and there is at least one error line worth looking up.
|
|
508
|
+
const errorSignatures = useMemo(
|
|
509
|
+
() => buildConsoleErrorSignatures(diagnostics.console),
|
|
510
|
+
[diagnostics.console],
|
|
511
|
+
);
|
|
512
|
+
const errorSignaturesKey = useMemo(
|
|
513
|
+
() => JSON.stringify(errorSignatures),
|
|
514
|
+
[errorSignatures],
|
|
515
|
+
);
|
|
516
|
+
const recordingId = response.recording.id;
|
|
517
|
+
const issueMatchQuery = useQuery({
|
|
518
|
+
queryKey: ["match-error-issues", recordingId, errorSignaturesKey],
|
|
519
|
+
queryFn: () =>
|
|
520
|
+
callAction<Record<string, SessionIssueMatch>>(
|
|
521
|
+
"match-error-issues",
|
|
522
|
+
{ signatures: errorSignatures },
|
|
523
|
+
{ method: "POST" },
|
|
524
|
+
),
|
|
525
|
+
enabled: devToolsOpen && errorSignatures.length > 0,
|
|
526
|
+
staleTime: 60_000,
|
|
527
|
+
});
|
|
528
|
+
const issueMatches = useMemo(() => {
|
|
529
|
+
const map = new Map<string, SessionIssueMatch>();
|
|
530
|
+
const data = issueMatchQuery.data;
|
|
531
|
+
if (data) {
|
|
532
|
+
for (const [key, value] of Object.entries(data)) map.set(key, value);
|
|
533
|
+
}
|
|
534
|
+
return map;
|
|
535
|
+
}, [issueMatchQuery.data]);
|
|
462
536
|
const loadingPercent =
|
|
463
537
|
response.totalChunks > 0
|
|
464
538
|
? clamp(response.loadedChunks / response.totalChunks, 0, 1)
|
|
@@ -929,6 +1003,7 @@ function ReplayPlayer({
|
|
|
929
1003
|
height={devToolsHeight}
|
|
930
1004
|
onHeightChange={setDevToolsHeight}
|
|
931
1005
|
onSeek={(ms) => seek(ms, true)}
|
|
1006
|
+
issueMatches={issueMatches}
|
|
932
1007
|
/>
|
|
933
1008
|
) : null}
|
|
934
1009
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useT } from "@agent-native/core/client";
|
|
2
2
|
import {
|
|
3
|
+
IconArrowUpRight,
|
|
3
4
|
IconChevronRight,
|
|
4
5
|
IconCloudDataConnection,
|
|
5
6
|
IconPlayerPlay,
|
|
@@ -14,11 +15,13 @@ import {
|
|
|
14
15
|
useRef,
|
|
15
16
|
useState,
|
|
16
17
|
} from "react";
|
|
18
|
+
import { Link } from "react-router";
|
|
17
19
|
|
|
18
20
|
import { Input } from "@/components/ui/input";
|
|
19
21
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
20
22
|
import { cn } from "@/lib/utils";
|
|
21
23
|
|
|
24
|
+
import { useErrorsT } from "../monitoring/errors/i18n";
|
|
22
25
|
import {
|
|
23
26
|
type ConsoleLevelFilter,
|
|
24
27
|
consoleLevelBucket,
|
|
@@ -34,6 +37,18 @@ import {
|
|
|
34
37
|
type ReplayNetworkEntry,
|
|
35
38
|
} from "./session-replay-devtools";
|
|
36
39
|
|
|
40
|
+
/**
|
|
41
|
+
* A session console error line resolved to its captured, Sentry-style issue.
|
|
42
|
+
* Keyed by `ReplayConsoleEntry.id`, computed server-side by `match-error-issues`
|
|
43
|
+
* so the resolution shares one fingerprint implementation with ingest.
|
|
44
|
+
*/
|
|
45
|
+
export type SessionIssueMatch = { issueId: string; status: string };
|
|
46
|
+
|
|
47
|
+
/** Deep-link from a session error to the Monitoring → Errors issue detail. */
|
|
48
|
+
function issueDetailPath(issueId: string): string {
|
|
49
|
+
return `/monitoring?view=errors&issue=${encodeURIComponent(issueId)}`;
|
|
50
|
+
}
|
|
51
|
+
|
|
37
52
|
/** Pause row auto-follow for a while after the user scrolls the list. */
|
|
38
53
|
const MANUAL_SCROLL_FOLLOW_PAUSE_MS = 4000;
|
|
39
54
|
const DEVTOOLS_ROW_HEIGHT = 34;
|
|
@@ -47,12 +62,15 @@ export function SessionDevToolsPanel({
|
|
|
47
62
|
height,
|
|
48
63
|
onHeightChange,
|
|
49
64
|
onSeek,
|
|
65
|
+
issueMatches,
|
|
50
66
|
}: {
|
|
51
67
|
diagnostics: ReplayDevToolsDiagnostics;
|
|
52
68
|
currentTime: number;
|
|
53
69
|
height: number;
|
|
54
70
|
onHeightChange: (height: number) => void;
|
|
55
71
|
onSeek: (ms: number) => void;
|
|
72
|
+
/** Resolved error issues by console entry id, for cross-linking to Errors. */
|
|
73
|
+
issueMatches?: ReadonlyMap<string, SessionIssueMatch>;
|
|
56
74
|
}) {
|
|
57
75
|
const t = useT();
|
|
58
76
|
const [tab, setTab] = useState<"console" | "network">("console");
|
|
@@ -222,6 +240,7 @@ export function SessionDevToolsPanel({
|
|
|
222
240
|
entry={entry}
|
|
223
241
|
active={entry.id === activeConsoleId}
|
|
224
242
|
selected={entry.id === selectedConsoleId}
|
|
243
|
+
issueMatch={issueMatches?.get(entry.id) ?? null}
|
|
225
244
|
onSelect={() =>
|
|
226
245
|
setSelectedConsoleId((current) =>
|
|
227
246
|
current === entry.id ? null : entry.id,
|
|
@@ -232,7 +251,11 @@ export function SessionDevToolsPanel({
|
|
|
232
251
|
)}
|
|
233
252
|
/>
|
|
234
253
|
{selectedConsole ? (
|
|
235
|
-
<ConsoleDetailPane
|
|
254
|
+
<ConsoleDetailPane
|
|
255
|
+
entry={selectedConsole}
|
|
256
|
+
issueMatch={issueMatches?.get(selectedConsole.id) ?? null}
|
|
257
|
+
onSeek={onSeek}
|
|
258
|
+
/>
|
|
236
259
|
) : null}
|
|
237
260
|
</TabsContent>
|
|
238
261
|
|
|
@@ -550,16 +573,47 @@ function JumpToButton({
|
|
|
550
573
|
);
|
|
551
574
|
}
|
|
552
575
|
|
|
576
|
+
/**
|
|
577
|
+
* Compact link from a captured session error to its Errors issue detail. Kept
|
|
578
|
+
* outside the row's toggle `<button>` (an anchor nested in a button is invalid)
|
|
579
|
+
* and stops click propagation so following the link never also toggles/seeks.
|
|
580
|
+
*/
|
|
581
|
+
function ViewIssueLink({
|
|
582
|
+
issueId,
|
|
583
|
+
className,
|
|
584
|
+
}: {
|
|
585
|
+
issueId: string;
|
|
586
|
+
className?: string;
|
|
587
|
+
}) {
|
|
588
|
+
const et = useErrorsT();
|
|
589
|
+
return (
|
|
590
|
+
<Link
|
|
591
|
+
to={issueDetailPath(issueId)}
|
|
592
|
+
title={et.viewIssueTooltip}
|
|
593
|
+
onClick={(event) => event.stopPropagation()}
|
|
594
|
+
className={cn(
|
|
595
|
+
"inline-flex shrink-0 items-center gap-1 rounded border border-primary/40 bg-primary/10 px-1.5 py-0.5 text-[11px] font-medium text-primary transition-colors hover:bg-primary/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
596
|
+
className,
|
|
597
|
+
)}
|
|
598
|
+
>
|
|
599
|
+
<IconArrowUpRight className="h-3 w-3" />
|
|
600
|
+
{et.viewIssue}
|
|
601
|
+
</Link>
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
|
|
553
605
|
function ConsoleRow({
|
|
554
606
|
entry,
|
|
555
607
|
active,
|
|
556
608
|
selected,
|
|
609
|
+
issueMatch,
|
|
557
610
|
onSelect,
|
|
558
611
|
onSeek,
|
|
559
612
|
}: {
|
|
560
613
|
entry: ReplayConsoleEntry;
|
|
561
614
|
active: boolean;
|
|
562
615
|
selected: boolean;
|
|
616
|
+
issueMatch: SessionIssueMatch | null;
|
|
563
617
|
onSelect: () => void;
|
|
564
618
|
onSeek: (ms: number) => void;
|
|
565
619
|
}) {
|
|
@@ -621,6 +675,7 @@ function ConsoleRow({
|
|
|
621
675
|
)}
|
|
622
676
|
/>
|
|
623
677
|
</button>
|
|
678
|
+
{issueMatch ? <ViewIssueLink issueId={issueMatch.issueId} /> : null}
|
|
624
679
|
<JumpToButton offsetMs={entry.offsetMs} onSeek={onSeek} />
|
|
625
680
|
</div>
|
|
626
681
|
);
|
|
@@ -709,15 +764,20 @@ function NetworkRow({
|
|
|
709
764
|
|
|
710
765
|
function ConsoleDetailPane({
|
|
711
766
|
entry,
|
|
767
|
+
issueMatch,
|
|
712
768
|
onSeek,
|
|
713
769
|
}: {
|
|
714
770
|
entry: ReplayConsoleEntry;
|
|
771
|
+
issueMatch: SessionIssueMatch | null;
|
|
715
772
|
onSeek: (ms: number) => void;
|
|
716
773
|
}) {
|
|
717
774
|
const t = useT();
|
|
718
775
|
return (
|
|
719
776
|
<DevToolsDetailPane
|
|
720
777
|
title={`${entry.level} at ${formatOffsetClock(entry.offsetMs)}`}
|
|
778
|
+
action={
|
|
779
|
+
issueMatch ? <ViewIssueLink issueId={issueMatch.issueId} /> : null
|
|
780
|
+
}
|
|
721
781
|
onSeek={() => onSeek(entry.offsetMs)}
|
|
722
782
|
>
|
|
723
783
|
<DetailField label={t("sessions.devtoolsMessage")}>
|
|
@@ -813,10 +873,12 @@ function NetworkDetailPane({
|
|
|
813
873
|
function DevToolsDetailPane({
|
|
814
874
|
title,
|
|
815
875
|
onSeek,
|
|
876
|
+
action,
|
|
816
877
|
children,
|
|
817
878
|
}: {
|
|
818
879
|
title: string;
|
|
819
880
|
onSeek: () => void;
|
|
881
|
+
action?: ReactNode;
|
|
820
882
|
children: ReactNode;
|
|
821
883
|
}) {
|
|
822
884
|
const t = useT();
|
|
@@ -826,14 +888,17 @@ function DevToolsDetailPane({
|
|
|
826
888
|
<p className="truncate text-xs font-semibold text-foreground">
|
|
827
889
|
{title}
|
|
828
890
|
</p>
|
|
829
|
-
<
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
891
|
+
<div className="flex shrink-0 items-center gap-1.5">
|
|
892
|
+
{action}
|
|
893
|
+
<button
|
|
894
|
+
type="button"
|
|
895
|
+
className="inline-flex shrink-0 items-center gap-1 rounded border px-1.5 py-0.5 text-[11px] font-medium text-muted-foreground hover:bg-muted hover:text-foreground"
|
|
896
|
+
onClick={onSeek}
|
|
897
|
+
>
|
|
898
|
+
<IconPlayerPlay className="h-3 w-3" />
|
|
899
|
+
{t("sessions.devtoolsJumpTo")}
|
|
900
|
+
</button>
|
|
901
|
+
</div>
|
|
837
902
|
</div>
|
|
838
903
|
<div className="space-y-2">{children}</div>
|
|
839
904
|
</div>
|