@agent-native/core 0.90.11 → 0.91.1

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.
Files changed (322) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +34 -0
  3. package/corpus/core/docs/content/toolkit-settings.mdx +56 -3
  4. package/corpus/core/package.json +2 -1
  5. package/corpus/core/src/agent/run-ownership.ts +29 -1
  6. package/corpus/core/src/changelog/parse.ts +78 -0
  7. package/corpus/core/src/chat-threads/schema.ts +43 -0
  8. package/corpus/core/src/chat-threads/store.ts +144 -12
  9. package/corpus/core/src/cli/design-connect.ts +53 -9
  10. package/corpus/core/src/cli/workspace-dev.ts +25 -5
  11. package/corpus/core/src/client/AgentPanel.tsx +79 -14
  12. package/corpus/core/src/client/AssistantChat.tsx +359 -425
  13. package/corpus/core/src/client/analytics-session.ts +70 -0
  14. package/corpus/core/src/client/analytics.ts +175 -49
  15. package/corpus/core/src/client/chat/message-components.tsx +22 -2
  16. package/corpus/core/src/client/components/ui/message-scroller.tsx +131 -0
  17. package/corpus/core/src/client/conversation/AgentConversation.tsx +63 -41
  18. package/corpus/core/src/client/error-capture.ts +616 -0
  19. package/corpus/core/src/client/index.ts +12 -0
  20. package/corpus/core/src/client/session-replay.ts +57 -7
  21. package/corpus/core/src/client/settings/SettingsPanel.tsx +123 -1
  22. package/corpus/core/src/client/settings/SettingsTabsPage.tsx +292 -45
  23. package/corpus/core/src/client/settings/index.ts +1 -0
  24. package/corpus/core/src/client/sharing/ShareButton.tsx +14 -11
  25. package/corpus/core/src/client/sharing/ShareDialog.tsx +13 -10
  26. package/corpus/core/src/mcp/builtin-tools.ts +29 -2
  27. package/corpus/core/src/server/agent-chat-plugin.ts +174 -79
  28. package/corpus/core/src/server/onboarding-html.ts +28 -16
  29. package/corpus/core/src/sharing/actions/list-resource-shares.ts +45 -1
  30. package/corpus/core/src/sharing/actions/share-resource.ts +9 -0
  31. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
  32. package/corpus/core/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
  33. package/corpus/core/src/vite/client.ts +217 -35
  34. package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +8 -7
  35. package/corpus/templates/analytics/.agents/skills/analysis-workspace/SKILL.md +14 -10
  36. package/corpus/templates/analytics/.agents/skills/bigquery/SKILL.md +15 -15
  37. package/corpus/templates/analytics/.agents/skills/cross-source-analysis/SKILL.md +1 -0
  38. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +38 -22
  39. package/corpus/templates/analytics/.agents/skills/data-programs/SKILL.md +114 -61
  40. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +1 -0
  41. package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +7 -7
  42. package/corpus/templates/analytics/.agents/skills/hubspot/SKILL.md +1 -0
  43. package/corpus/templates/analytics/.agents/skills/prometheus/SKILL.md +1 -1
  44. package/corpus/templates/analytics/.builder/skills/bigquery/SKILL.md +17 -17
  45. package/corpus/templates/analytics/.builder/skills/gcloud/SKILL.md +5 -5
  46. package/corpus/templates/analytics/.builder/skills/github/SKILL.md +7 -7
  47. package/corpus/templates/analytics/.builder/skills/gong/SKILL.md +12 -12
  48. package/corpus/templates/analytics/.builder/skills/grafana/SKILL.md +7 -7
  49. package/corpus/templates/analytics/.builder/skills/sentry/SKILL.md +7 -7
  50. package/corpus/templates/analytics/.builder/skills/slack/SKILL.md +6 -6
  51. package/corpus/templates/analytics/.builder/skills/stripe/SKILL.md +7 -7
  52. package/corpus/templates/analytics/AGENTS.md +47 -2
  53. package/corpus/templates/analytics/actions/add-status-page-monitor.ts +36 -0
  54. package/corpus/templates/analytics/actions/capture-test-error.ts +33 -0
  55. package/corpus/templates/analytics/actions/delete-monitor.ts +24 -0
  56. package/corpus/templates/analytics/actions/delete-status-page.ts +23 -0
  57. package/corpus/templates/analytics/actions/get-error-issue.ts +36 -0
  58. package/corpus/templates/analytics/actions/get-monitor-stats.ts +55 -0
  59. package/corpus/templates/analytics/actions/get-monitor.ts +27 -0
  60. package/corpus/templates/analytics/actions/get-public-status-page.ts +41 -0
  61. package/corpus/templates/analytics/actions/get-status-page.ts +29 -0
  62. package/corpus/templates/analytics/actions/list-error-issues.ts +40 -0
  63. package/corpus/templates/analytics/actions/list-monitors.ts +21 -0
  64. package/corpus/templates/analytics/actions/list-status-pages.ts +21 -0
  65. package/corpus/templates/analytics/actions/match-error-issues.ts +51 -0
  66. package/corpus/templates/analytics/actions/navigate.ts +58 -4
  67. package/corpus/templates/analytics/actions/remove-status-page-monitor.ts +22 -0
  68. package/corpus/templates/analytics/actions/reorder-status-page-monitors.ts +25 -0
  69. package/corpus/templates/analytics/actions/resolve-error-issue.ts +38 -0
  70. package/corpus/templates/analytics/actions/run-monitor-check.ts +23 -0
  71. package/corpus/templates/analytics/actions/save-analysis.ts +1 -0
  72. package/corpus/templates/analytics/actions/save-monitor.ts +145 -0
  73. package/corpus/templates/analytics/actions/save-status-page.ts +47 -0
  74. package/corpus/templates/analytics/actions/view-screen.ts +212 -0
  75. package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -0
  76. package/corpus/templates/analytics/app/components/layout/Layout.tsx +10 -1
  77. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +134 -39
  78. package/corpus/templates/analytics/app/components/monitoring/PublicStatusView.tsx +351 -0
  79. package/corpus/templates/analytics/app/components/monitoring/ResponseTimeChart.tsx +174 -0
  80. package/corpus/templates/analytics/app/components/monitoring/UptimeStatCards.tsx +85 -0
  81. package/corpus/templates/analytics/app/components/monitoring/UptimeTimelineBars.tsx +106 -0
  82. package/corpus/templates/analytics/app/components/monitoring/chart-utils.ts +101 -0
  83. package/corpus/templates/analytics/app/components/monitoring/index.ts +28 -0
  84. package/corpus/templates/analytics/app/components/monitoring/types.ts +42 -0
  85. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +34 -0
  86. package/corpus/templates/analytics/app/i18n/zh-TW.ts +6 -0
  87. package/corpus/templates/analytics/app/i18n-data.ts +33 -0
  88. package/corpus/templates/analytics/app/pages/DataSources.tsx +28 -0
  89. package/corpus/templates/analytics/app/pages/Settings.tsx +77 -9
  90. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +3 -3
  91. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +7 -0
  92. package/corpus/templates/analytics/app/pages/monitoring/ErrorsPanel.tsx +205 -0
  93. package/corpus/templates/analytics/app/pages/monitoring/MonitoringPage.tsx +100 -0
  94. package/corpus/templates/analytics/app/pages/monitoring/UptimePanel.tsx +475 -0
  95. package/corpus/templates/analytics/app/pages/monitoring/errors/IssueDetail.tsx +372 -0
  96. package/corpus/templates/analytics/app/pages/monitoring/errors/IssueList.tsx +360 -0
  97. package/corpus/templates/analytics/app/pages/monitoring/errors/Sparkline.tsx +55 -0
  98. package/corpus/templates/analytics/app/pages/monitoring/errors/i18n.ts +106 -0
  99. package/corpus/templates/analytics/app/pages/monitoring/errors/types.ts +75 -0
  100. package/corpus/templates/analytics/app/pages/monitoring/errors/utils.ts +132 -0
  101. package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorDetail.tsx +535 -0
  102. package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorFormPage.tsx +1026 -0
  103. package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorList.tsx +311 -0
  104. package/corpus/templates/analytics/app/pages/monitoring/uptime/i18n.ts +235 -0
  105. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/StatusPageEditor.tsx +661 -0
  106. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/StatusPagesView.tsx +355 -0
  107. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/i18n.ts +106 -0
  108. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/slug.ts +24 -0
  109. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/types.ts +20 -0
  110. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-summary.ts +87 -0
  111. package/corpus/templates/analytics/app/pages/monitoring/uptime/types.ts +161 -0
  112. package/corpus/templates/analytics/app/pages/monitoring/uptime/utils.ts +210 -0
  113. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +76 -1
  114. package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +74 -9
  115. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +197 -20
  116. package/corpus/templates/analytics/app/root.tsx +33 -1
  117. package/corpus/templates/analytics/app/routes/monitoring._index.tsx +10 -0
  118. package/corpus/templates/analytics/app/routes/status.$slug.tsx +118 -0
  119. package/corpus/templates/analytics/changelog/2026-07-08-add-uptime-monitors-that-ping-your-urls-and-alert-you-when-t.md +6 -0
  120. package/corpus/templates/analytics/changelog/2026-07-08-analytics-chats-keep-large-data-dictionaries-compact-so-prov.md +6 -0
  121. package/corpus/templates/analytics/changelog/2026-07-08-create-public-status-pages-that-share-the-live-health-of-cho.md +6 -0
  122. package/corpus/templates/analytics/changelog/2026-07-08-dashboard-extension-panels-use-clearer-open-copy.md +6 -0
  123. package/corpus/templates/analytics/changelog/2026-07-08-error-capture.md +6 -0
  124. package/corpus/templates/analytics/changelog/2026-07-08-fixed-single-panel-dashboard-drags-so-they-no-longer-rewrite.md +6 -0
  125. package/corpus/templates/analytics/changelog/2026-07-08-jump-straight-from-an-error-in-a-session-recording-to-its-fu.md +6 -0
  126. package/corpus/templates/analytics/changelog/2026-07-08-monitor-detail-and-list-now-show-colorful-uptime-timelines-r.md +6 -0
  127. package/corpus/templates/analytics/changelog/2026-07-08-pinned-ask-chats-now-show-a-pin-icon-in-the-sidebar.md +6 -0
  128. package/corpus/templates/analytics/changelog/2026-07-08-publish-a-public-uptime-status-page-with-colorful-uptime-tim.md +6 -0
  129. package/corpus/templates/analytics/changelog/2026-07-08-sessions-now-hide-visitor-emails-in-demo-mode-and-show-clean.md +6 -0
  130. package/corpus/templates/analytics/changelog/2026-07-08-settings-are-cleaner-searchable-and-alerts-have-their-own-tab.md +5 -0
  131. package/corpus/templates/analytics/changelog/2026-07-08-sidebar-sections-stay-collapsed-until-opened.md +5 -0
  132. package/corpus/templates/analytics/changelog/2026-07-08-the-uptime-monitor-list-now-has-a-current-status-overview-wi.md +6 -0
  133. package/corpus/templates/analytics/docs/error-capture.md +172 -0
  134. package/corpus/templates/analytics/docs/uptime-monitoring.md +150 -0
  135. package/corpus/templates/analytics/server/db/schema-errors.ts +150 -0
  136. package/corpus/templates/analytics/server/db/schema-monitoring.ts +177 -0
  137. package/corpus/templates/analytics/server/db/schema.ts +6 -0
  138. package/corpus/templates/analytics/server/jobs/uptime-monitors.ts +123 -0
  139. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +41 -0
  140. package/corpus/templates/analytics/server/lib/data-dictionary-context.ts +55 -12
  141. package/corpus/templates/analytics/server/lib/error-capture.ts +1331 -0
  142. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +47 -1
  143. package/corpus/templates/analytics/server/lib/monitor-stats.ts +494 -0
  144. package/corpus/templates/analytics/server/lib/status-pages.ts +798 -0
  145. package/corpus/templates/analytics/server/lib/uptime-monitors.ts +1665 -0
  146. package/corpus/templates/analytics/server/plugins/agent-chat.ts +7 -37
  147. package/corpus/templates/analytics/server/plugins/auth.ts +11 -1
  148. package/corpus/templates/analytics/server/plugins/db.ts +408 -0
  149. package/corpus/templates/analytics/server/plugins/uptime-monitor-jobs.ts +63 -0
  150. package/corpus/templates/assets/app/routes/_index.tsx +1 -1
  151. package/corpus/templates/assets/app/routes/settings.tsx +22 -1
  152. package/corpus/templates/assets/changelog/2026-07-08-recent-drafts-keep-comfortable-side-padding.md +6 -0
  153. package/corpus/templates/assets/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  154. package/corpus/templates/brain/app/routes/settings.tsx +43 -5
  155. package/corpus/templates/brain/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  156. package/corpus/templates/calendar/app/pages/Settings.tsx +44 -6
  157. package/corpus/templates/calendar/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  158. package/corpus/templates/chat/app/routes/settings.tsx +16 -1
  159. package/corpus/templates/chat/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  160. package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +79 -37
  161. package/corpus/templates/clips/app/components/player/player-controls.tsx +35 -0
  162. package/corpus/templates/clips/app/components/player/video-player.tsx +162 -18
  163. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +63 -6
  164. package/corpus/templates/clips/app/routes/record.tsx +18 -1
  165. package/corpus/templates/clips/changelog/2026-07-07-shared-clips-start-playback-reliably-from-the-first-play-click.md +6 -0
  166. package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-camera-and-microphone-menus-now-show-which-.md +6 -0
  167. package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-copies-new-clip-links-after-saving.md +6 -0
  168. package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-recordings-now-continue-after-granting-came.md +6 -0
  169. package/corpus/templates/clips/changelog/2026-07-08-mobile-shared-clips-now-have-loom-style-tap-and-skip-controls.md +6 -0
  170. package/corpus/templates/clips/changelog/2026-07-08-recordings-and-uploads-copy-links-after-saving.md +6 -0
  171. package/corpus/templates/clips/changelog/2026-07-08-settings-are-cleaner-searchable-and-collapse-s3-with-builder.md +5 -0
  172. package/corpus/templates/clips/changelog/2026-07-08-transcripts-are-more-reliable-for-longer-desktop-recordings-.md +6 -0
  173. package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -0
  174. package/corpus/templates/clips/chrome-extension/src/background.ts +162 -13
  175. package/corpus/templates/clips/chrome-extension/src/content-script.ts +14 -0
  176. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +36 -0
  177. package/corpus/templates/clips/chrome-extension/src/overlay.ts +99 -25
  178. package/corpus/templates/clips/chrome-extension/src/permission.ts +63 -14
  179. package/corpus/templates/clips/chrome-extension/src/popup.ts +123 -23
  180. package/corpus/templates/content/actions/_builder-cms-read-client.ts +47 -0
  181. package/corpus/templates/content/actions/_database-source-utils.ts +33 -4
  182. package/corpus/templates/content/actions/add-content-database-source-field-property.ts +214 -29
  183. package/corpus/templates/content/actions/attach-content-database-source.ts +3 -0
  184. package/corpus/templates/content/actions/change-content-database-source-role.ts +1 -0
  185. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +42 -32
  186. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +352 -81
  187. package/corpus/templates/content/app/components/editor/database/settings.tsx +49 -24
  188. package/corpus/templates/content/app/routes/_app.settings.tsx +19 -1
  189. package/corpus/templates/content/changelog/2026-07-07-builder-source-tag-fields-now-import-as-multi-select.md +6 -0
  190. package/corpus/templates/content/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  191. package/corpus/templates/content/shared/api.ts +3 -0
  192. package/corpus/templates/content/shared/properties.ts +42 -0
  193. package/corpus/templates/design/AGENTS.md +9 -0
  194. package/corpus/templates/design/actions/generate-design.ts +3 -0
  195. package/corpus/templates/design/actions/get-design-system.ts +147 -1
  196. package/corpus/templates/design/actions/request-localhost-write-consent.ts +141 -0
  197. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +13 -19
  198. package/corpus/templates/design/app/routes/settings.tsx +16 -1
  199. package/corpus/templates/design/changelog/2026-07-08-design-generation-now-follows-hydrated-builder-design-system.md +6 -0
  200. package/corpus/templates/design/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  201. package/corpus/templates/design/server/lib/verify-write-grant.ts +4 -2
  202. package/corpus/templates/dispatch/app/routes/settings.tsx +23 -2
  203. package/corpus/templates/dispatch/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  204. package/corpus/templates/forms/app/routes/_app.settings.tsx +16 -1
  205. package/corpus/templates/forms/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  206. package/corpus/templates/macros/app/routes/settings.tsx +16 -1
  207. package/corpus/templates/macros/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  208. package/corpus/templates/mail/app/components/settings/GmailFiltersSection.tsx +1 -1
  209. package/corpus/templates/mail/app/components/settings/SnippetsSection.tsx +1 -1
  210. package/corpus/templates/mail/app/pages/SettingsPage.tsx +123 -105
  211. package/corpus/templates/mail/changelog/2026-07-08-settings-redesigned-with-a-consistent-searchable-layout.md +5 -0
  212. package/corpus/templates/plan/app/routes/settings.tsx +23 -2
  213. package/corpus/templates/plan/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  214. package/corpus/templates/slides/actions/add-slide.ts +1 -0
  215. package/corpus/templates/slides/actions/get-design-system.ts +147 -1
  216. package/corpus/templates/slides/app/pages/Index.tsx +46 -1
  217. package/corpus/templates/slides/app/routes/settings.tsx +16 -1
  218. package/corpus/templates/slides/changelog/2026-07-08-deck-generation-now-follows-hydrated-builder-design-system-g.md +6 -0
  219. package/corpus/templates/slides/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  220. package/dist/agent/run-ownership.d.ts +6 -0
  221. package/dist/agent/run-ownership.d.ts.map +1 -1
  222. package/dist/agent/run-ownership.js +11 -1
  223. package/dist/agent/run-ownership.js.map +1 -1
  224. package/dist/changelog/parse.d.ts +7 -0
  225. package/dist/changelog/parse.d.ts.map +1 -1
  226. package/dist/changelog/parse.js +64 -0
  227. package/dist/changelog/parse.js.map +1 -1
  228. package/dist/chat-threads/schema.d.ts +445 -0
  229. package/dist/chat-threads/schema.d.ts.map +1 -0
  230. package/dist/chat-threads/schema.js +39 -0
  231. package/dist/chat-threads/schema.js.map +1 -0
  232. package/dist/chat-threads/store.d.ts +12 -0
  233. package/dist/chat-threads/store.d.ts.map +1 -1
  234. package/dist/chat-threads/store.js +99 -10
  235. package/dist/chat-threads/store.js.map +1 -1
  236. package/dist/cli/design-connect.d.ts.map +1 -1
  237. package/dist/cli/design-connect.js +40 -10
  238. package/dist/cli/design-connect.js.map +1 -1
  239. package/dist/cli/workspace-dev.d.ts.map +1 -1
  240. package/dist/cli/workspace-dev.js +20 -5
  241. package/dist/cli/workspace-dev.js.map +1 -1
  242. package/dist/client/AgentPanel.d.ts.map +1 -1
  243. package/dist/client/AgentPanel.js +35 -7
  244. package/dist/client/AgentPanel.js.map +1 -1
  245. package/dist/client/AssistantChat.d.ts.map +1 -1
  246. package/dist/client/AssistantChat.js +105 -183
  247. package/dist/client/AssistantChat.js.map +1 -1
  248. package/dist/client/analytics-session.d.ts +3 -0
  249. package/dist/client/analytics-session.d.ts.map +1 -0
  250. package/dist/client/analytics-session.js +66 -0
  251. package/dist/client/analytics-session.js.map +1 -0
  252. package/dist/client/analytics.d.ts +32 -0
  253. package/dist/client/analytics.d.ts.map +1 -1
  254. package/dist/client/analytics.js +116 -46
  255. package/dist/client/analytics.js.map +1 -1
  256. package/dist/client/chat/message-components.d.ts +2 -1
  257. package/dist/client/chat/message-components.d.ts.map +1 -1
  258. package/dist/client/chat/message-components.js +16 -6
  259. package/dist/client/chat/message-components.js.map +1 -1
  260. package/dist/client/components/ui/message-scroller.d.ts +16 -0
  261. package/dist/client/components/ui/message-scroller.d.ts.map +1 -0
  262. package/dist/client/components/ui/message-scroller.js +25 -0
  263. package/dist/client/components/ui/message-scroller.js.map +1 -0
  264. package/dist/client/conversation/AgentConversation.d.ts +1 -1
  265. package/dist/client/conversation/AgentConversation.d.ts.map +1 -1
  266. package/dist/client/conversation/AgentConversation.js +3 -8
  267. package/dist/client/conversation/AgentConversation.js.map +1 -1
  268. package/dist/client/error-capture.d.ts +99 -0
  269. package/dist/client/error-capture.d.ts.map +1 -0
  270. package/dist/client/error-capture.js +437 -0
  271. package/dist/client/error-capture.js.map +1 -0
  272. package/dist/client/index.d.ts +2 -2
  273. package/dist/client/index.d.ts.map +1 -1
  274. package/dist/client/index.js +3 -1
  275. package/dist/client/index.js.map +1 -1
  276. package/dist/client/session-replay.d.ts +22 -0
  277. package/dist/client/session-replay.d.ts.map +1 -1
  278. package/dist/client/session-replay.js +45 -4
  279. package/dist/client/session-replay.js.map +1 -1
  280. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  281. package/dist/client/settings/SettingsPanel.js +100 -5
  282. package/dist/client/settings/SettingsPanel.js.map +1 -1
  283. package/dist/client/settings/SettingsTabsPage.d.ts +49 -1
  284. package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
  285. package/dist/client/settings/SettingsTabsPage.js +131 -19
  286. package/dist/client/settings/SettingsTabsPage.js.map +1 -1
  287. package/dist/client/settings/index.d.ts +1 -1
  288. package/dist/client/settings/index.d.ts.map +1 -1
  289. package/dist/client/settings/index.js.map +1 -1
  290. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  291. package/dist/client/sharing/ShareButton.js +13 -8
  292. package/dist/client/sharing/ShareButton.js.map +1 -1
  293. package/dist/client/sharing/ShareDialog.d.ts.map +1 -1
  294. package/dist/client/sharing/ShareDialog.js +12 -7
  295. package/dist/client/sharing/ShareDialog.js.map +1 -1
  296. package/dist/collab/routes.d.ts +1 -1
  297. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  298. package/dist/mcp/builtin-tools.d.ts.map +1 -1
  299. package/dist/mcp/builtin-tools.js +21 -2
  300. package/dist/mcp/builtin-tools.js.map +1 -1
  301. package/dist/observability/routes.d.ts +1 -1
  302. package/dist/org/schema.d.ts +15 -15
  303. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  304. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  305. package/dist/server/agent-chat-plugin.js +109 -73
  306. package/dist/server/agent-chat-plugin.js.map +1 -1
  307. package/dist/server/onboarding-html.d.ts.map +1 -1
  308. package/dist/server/onboarding-html.js +28 -16
  309. package/dist/server/onboarding-html.js.map +1 -1
  310. package/dist/sharing/actions/list-resource-shares.js +30 -1
  311. package/dist/sharing/actions/list-resource-shares.js.map +1 -1
  312. package/dist/sharing/actions/share-resource.js +6 -0
  313. package/dist/sharing/actions/share-resource.js.map +1 -1
  314. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
  315. package/dist/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
  316. package/dist/vite/client.d.ts.map +1 -1
  317. package/dist/vite/client.js +192 -30
  318. package/dist/vite/client.js.map +1 -1
  319. package/docs/content/toolkit-settings.mdx +56 -3
  320. package/package.json +2 -1
  321. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
  322. 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 { SessionDevToolsPanel } from "./SessionDevToolsPanel";
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 entry={selectedConsole} onSeek={onSeek} />
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
- <button
830
- type="button"
831
- 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"
832
- onClick={onSeek}
833
- >
834
- <IconPlayerPlay className="h-3 w-3" />
835
- {t("sessions.devtoolsJumpTo")}
836
- </button>
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>