@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,132 @@
1
+ import { useErrorsT } from "./i18n";
2
+ import type { ExceptionLevel, IssueStatus } from "./types";
3
+
4
+ /** Compact "x ago" relative time; falls back to a short date for old items. */
5
+ export function formatRelativeTime(value: string | null | undefined): string {
6
+ if (!value) return "—";
7
+ const date = new Date(value);
8
+ const ms = date.getTime();
9
+ if (!Number.isFinite(ms)) return "—";
10
+ const diff = Date.now() - ms;
11
+ const sec = Math.round(diff / 1000);
12
+ if (sec < 45) return "just now";
13
+ const min = Math.round(sec / 60);
14
+ if (min < 60) return `${min}m ago`;
15
+ const hr = Math.round(min / 60);
16
+ if (hr < 24) return `${hr}h ago`;
17
+ const day = Math.round(hr / 24);
18
+ if (day < 30) return `${day}d ago`;
19
+ return new Intl.DateTimeFormat(undefined, {
20
+ month: "short",
21
+ day: "numeric",
22
+ year: day > 300 ? "numeric" : undefined,
23
+ }).format(date);
24
+ }
25
+
26
+ export function formatDateTime(value: string | null | undefined): string {
27
+ if (!value) return "—";
28
+ const date = new Date(value);
29
+ if (!Number.isFinite(date.getTime())) return String(value);
30
+ return new Intl.DateTimeFormat(undefined, {
31
+ month: "short",
32
+ day: "numeric",
33
+ hour: "numeric",
34
+ minute: "2-digit",
35
+ }).format(date);
36
+ }
37
+
38
+ export function formatNumber(value: number): string {
39
+ return new Intl.NumberFormat(undefined, { notation: "compact" }).format(
40
+ value || 0,
41
+ );
42
+ }
43
+
44
+ /** Tailwind classes for the small level pill (dark analytics aesthetic). */
45
+ export function levelBadgeClass(level: ExceptionLevel): string {
46
+ switch (level) {
47
+ case "fatal":
48
+ return "bg-red-500/15 text-red-400 border-red-500/25";
49
+ case "error":
50
+ return "bg-red-500/10 text-red-400 border-red-500/20";
51
+ case "warning":
52
+ return "bg-amber-500/15 text-amber-400 border-amber-500/25";
53
+ case "info":
54
+ return "bg-sky-500/15 text-sky-400 border-sky-500/25";
55
+ case "debug":
56
+ default:
57
+ return "bg-muted text-muted-foreground border-border/60";
58
+ }
59
+ }
60
+
61
+ /** A vertical accent color that echoes the severity on each list row. */
62
+ export function levelAccentClass(level: ExceptionLevel): string {
63
+ switch (level) {
64
+ case "fatal":
65
+ case "error":
66
+ return "bg-red-500/70";
67
+ case "warning":
68
+ return "bg-amber-500/70";
69
+ case "info":
70
+ return "bg-sky-500/70";
71
+ case "debug":
72
+ default:
73
+ return "bg-muted-foreground/40";
74
+ }
75
+ }
76
+
77
+ export function statusBadgeClass(status: IssueStatus): string {
78
+ switch (status) {
79
+ case "resolved":
80
+ return "bg-emerald-500/15 text-emerald-400 border-emerald-500/25";
81
+ case "ignored":
82
+ return "bg-muted text-muted-foreground border-border/60";
83
+ case "unresolved":
84
+ default:
85
+ return "bg-orange-500/15 text-orange-400 border-orange-500/25";
86
+ }
87
+ }
88
+
89
+ export function useLevelLabel() {
90
+ const t = useErrorsT();
91
+ return (level: ExceptionLevel): string => {
92
+ switch (level) {
93
+ case "fatal":
94
+ return t.levelFatal;
95
+ case "warning":
96
+ return t.levelWarning;
97
+ case "info":
98
+ return t.levelInfo;
99
+ case "debug":
100
+ return t.levelDebug;
101
+ case "error":
102
+ default:
103
+ return t.levelError;
104
+ }
105
+ };
106
+ }
107
+
108
+ export function useStatusLabel() {
109
+ const t = useErrorsT();
110
+ return (status: IssueStatus): string => {
111
+ switch (status) {
112
+ case "resolved":
113
+ return t.statusResolved;
114
+ case "ignored":
115
+ return t.statusIgnored;
116
+ case "unresolved":
117
+ default:
118
+ return t.statusUnresolved;
119
+ }
120
+ };
121
+ }
122
+
123
+ /** Shorten a stack-frame filename to a readable "…/dir/file.ts" tail. */
124
+ export function shortFrameFile(file: string | null): string {
125
+ if (!file) return "<anonymous>";
126
+ let out = file.replace(/[?#].*$/, "");
127
+ const urlMatch = out.match(/^[a-z]+:\/\/[^/]+(\/.*)$/i);
128
+ if (urlMatch) out = urlMatch[1];
129
+ const parts = out.split("/").filter(Boolean);
130
+ if (parts.length <= 2) return out;
131
+ return `…/${parts.slice(-2).join("/")}`;
132
+ }
@@ -0,0 +1,535 @@
1
+ /**
2
+ * Detail view for a single monitor: status header, overview stats, response-time
3
+ * chart, a 90-day uptime timeline, config summary, recent check results, and
4
+ * incident history. The colorful charts + uptime windows are driven by the
5
+ * shared `get-monitor-stats` aggregate and the reusable `@/components/monitoring`
6
+ * chart components; per-check config/history comes from `get-monitor`.
7
+ */
8
+ import { useActionQuery } from "@agent-native/core/client";
9
+ import {
10
+ IconArrowLeft,
11
+ IconExternalLink,
12
+ IconLoader2,
13
+ IconPencil,
14
+ IconPlayerPlay,
15
+ IconTrash,
16
+ } from "@tabler/icons-react";
17
+
18
+ import {
19
+ ResponseTimeChart,
20
+ UptimeStatCards,
21
+ UptimeTimelineBars,
22
+ } from "@/components/monitoring";
23
+ import { Badge } from "@/components/ui/badge";
24
+ import { Button } from "@/components/ui/button";
25
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
26
+ import { Skeleton } from "@/components/ui/skeleton";
27
+ import {
28
+ Table,
29
+ TableBody,
30
+ TableCell,
31
+ TableHead,
32
+ TableHeader,
33
+ TableRow,
34
+ } from "@/components/ui/table";
35
+ import { cn } from "@/lib/utils";
36
+
37
+ import { fmt, useUptimeT } from "./i18n";
38
+ import type {
39
+ MonitorDetail as MonitorDetailData,
40
+ MonitorStats,
41
+ MonitorSummary,
42
+ } from "./types";
43
+ import {
44
+ describeAssertion,
45
+ describeMatcher,
46
+ formatDateTime,
47
+ formatDuration,
48
+ formatLatency,
49
+ formatRelativeTime,
50
+ statusLabel,
51
+ statusTone,
52
+ toneDotClass,
53
+ toneTextClass,
54
+ } from "./utils";
55
+
56
+ export function MonitorDetail({
57
+ monitorId,
58
+ fallback,
59
+ onBack,
60
+ onEdit,
61
+ onDelete,
62
+ onRunCheck,
63
+ running,
64
+ }: {
65
+ monitorId: string;
66
+ fallback?: MonitorSummary;
67
+ onBack: () => void;
68
+ onEdit: (monitor: MonitorSummary) => void;
69
+ onDelete: (monitor: MonitorSummary) => void;
70
+ onRunCheck: (monitor: MonitorSummary) => void;
71
+ running: boolean;
72
+ }) {
73
+ const t = useUptimeT();
74
+ const { data, isLoading } = useActionQuery<MonitorDetailData>(
75
+ "get-monitor",
76
+ { id: monitorId },
77
+ { staleTime: 5_000 },
78
+ );
79
+ // Aggregated windows / timeline / response series over the standard windows.
80
+ const { data: statsData } = useActionQuery<MonitorStats[]>(
81
+ "get-monitor-stats",
82
+ { monitorIds: [monitorId], timelineDays: 90, responseWindowHours: 24 * 7 },
83
+ { staleTime: 15_000 },
84
+ );
85
+
86
+ const monitor = data?.monitor ?? fallback ?? null;
87
+ const results = data?.recentResults ?? [];
88
+ const incidents = data?.incidents ?? [];
89
+ const stats = statsData?.[0] ?? null;
90
+
91
+ if (!monitor) {
92
+ if (isLoading) {
93
+ return (
94
+ <div className="space-y-4">
95
+ <Skeleton className="h-9 w-40" />
96
+ <Skeleton className="h-32 w-full" />
97
+ <Skeleton className="h-64 w-full" />
98
+ </div>
99
+ );
100
+ }
101
+ return (
102
+ <div className="rounded-lg border border-border/60 bg-muted/20 p-8 text-sm text-muted-foreground">
103
+ {t.noChecks}
104
+ <div className="mt-4">
105
+ <Button variant="outline" size="sm" onClick={onBack}>
106
+ <IconArrowLeft className="size-3.5" />
107
+ {t.back}
108
+ </Button>
109
+ </div>
110
+ </div>
111
+ );
112
+ }
113
+
114
+ const tone = statusTone(monitor.lastStatus);
115
+ const lastChecked = formatRelativeTime(monitor.lastCheckedAt);
116
+ const windows = stats?.windows ?? {
117
+ uptime24h: monitor.uptime24h,
118
+ uptime7d: monitor.uptime7d,
119
+ uptime30d: null,
120
+ uptime90d: null,
121
+ };
122
+ const incidentCount = stats?.incidentCount ?? incidents.length;
123
+ const mtbf = stats?.mtbfMs ?? null;
124
+
125
+ return (
126
+ <div className="space-y-5">
127
+ <div className="flex flex-col gap-3">
128
+ <Button
129
+ variant="ghost"
130
+ size="sm"
131
+ className="-ms-2 w-fit text-muted-foreground"
132
+ onClick={onBack}
133
+ >
134
+ <IconArrowLeft className="size-3.5" />
135
+ {t.back}
136
+ </Button>
137
+
138
+ <div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
139
+ <div className="min-w-0">
140
+ <div className="flex items-center gap-2.5">
141
+ <span
142
+ className={cn(
143
+ "size-2.5 rounded-full",
144
+ toneDotClass(tone),
145
+ monitor.lastStatus === "running" && "animate-pulse",
146
+ )}
147
+ />
148
+ <h2 className="truncate text-lg font-semibold">{monitor.name}</h2>
149
+ <Badge
150
+ variant={
151
+ monitor.severity === "critical" ? "destructive" : "outline"
152
+ }
153
+ className="shrink-0 text-[10px]"
154
+ >
155
+ {monitor.severity === "critical"
156
+ ? t.severityCritical
157
+ : t.severityWarning}
158
+ </Badge>
159
+ {!monitor.enabled ? (
160
+ <Badge variant="secondary" className="shrink-0 text-[10px]">
161
+ {t.pausedBadge}
162
+ </Badge>
163
+ ) : null}
164
+ </div>
165
+ <a
166
+ href={monitor.url}
167
+ target="_blank"
168
+ rel="noreferrer noopener"
169
+ className="mt-1 inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground"
170
+ >
171
+ {monitor.url}
172
+ <IconExternalLink className="size-3" />
173
+ </a>
174
+ </div>
175
+
176
+ <div className="flex shrink-0 flex-wrap items-center gap-2">
177
+ <Button
178
+ variant="outline"
179
+ size="sm"
180
+ onClick={() => onRunCheck(monitor)}
181
+ disabled={running}
182
+ >
183
+ {running ? (
184
+ <IconLoader2 className="size-3.5 animate-spin" />
185
+ ) : (
186
+ <IconPlayerPlay className="size-3.5" />
187
+ )}
188
+ {running ? t.runningCheck : t.checkNow}
189
+ </Button>
190
+ <Button variant="outline" size="sm" onClick={() => onEdit(monitor)}>
191
+ <IconPencil className="size-3.5" />
192
+ {t.edit}
193
+ </Button>
194
+ <Button
195
+ variant="ghost"
196
+ size="sm"
197
+ className="text-destructive hover:text-destructive"
198
+ onClick={() => onDelete(monitor)}
199
+ >
200
+ <IconTrash className="size-3.5" />
201
+ {t.delete}
202
+ </Button>
203
+ </div>
204
+ </div>
205
+ </div>
206
+
207
+ {/* Overview stats — wrap cleanly on narrow widths */}
208
+ <div className="grid grid-cols-2 gap-3 sm:grid-cols-4">
209
+ <StatCard label={t.currentStatus}>
210
+ <span className={cn("text-lg font-semibold", toneTextClass(tone))}>
211
+ {statusLabel(monitor.lastStatus, t)}
212
+ </span>
213
+ <span className="truncate text-xs text-muted-foreground">
214
+ {lastChecked
215
+ ? fmt(t.lastChecked, { time: lastChecked })
216
+ : t.neverChecked}
217
+ </span>
218
+ </StatCard>
219
+ <StatCard label={t.latency}>
220
+ <span className="text-lg font-semibold tabular-nums">
221
+ {formatLatency(monitor.lastLatencyMs)}
222
+ </span>
223
+ {monitor.lastStatusCode != null ? (
224
+ <span className="text-xs text-muted-foreground">
225
+ {t.colCode} {monitor.lastStatusCode}
226
+ </span>
227
+ ) : null}
228
+ </StatCard>
229
+ <StatCard label={t.statIncidents}>
230
+ <span className="text-lg font-semibold tabular-nums">
231
+ {incidentCount}
232
+ </span>
233
+ <span className="text-xs text-muted-foreground">{t.statLast90d}</span>
234
+ </StatCard>
235
+ <StatCard label={t.statMtbf}>
236
+ <span className="text-lg font-semibold tabular-nums">
237
+ {mtbf != null ? formatDuration(mtbf) : "—"}
238
+ </span>
239
+ <span className="truncate text-xs text-muted-foreground">
240
+ {t.statMtbfHint}
241
+ </span>
242
+ </StatCard>
243
+ </div>
244
+
245
+ {/* Uptime windows (24h / 7d / 30d / 90d) */}
246
+ <UptimeStatCards
247
+ windows={windows}
248
+ items={[
249
+ { key: "uptime24h", label: t.uptime24h },
250
+ { key: "uptime7d", label: t.uptime7d },
251
+ { key: "uptime30d", label: t.uptime30d },
252
+ { key: "uptime90d", label: t.uptime90d },
253
+ ]}
254
+ />
255
+
256
+ {monitor.lastError ? (
257
+ <div className="rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive">
258
+ {monitor.lastError}
259
+ </div>
260
+ ) : null}
261
+
262
+ {/* Response time + 90-day uptime timeline */}
263
+ <Card className="bg-card border-border/50">
264
+ <CardHeader className="pb-2">
265
+ <CardTitle className="text-sm font-medium">
266
+ {t.responseTime}
267
+ </CardTitle>
268
+ <p className="text-xs text-muted-foreground">
269
+ {t.responseTimeSubtitle}
270
+ </p>
271
+ </CardHeader>
272
+ <CardContent>
273
+ <ResponseTimeChart
274
+ series={stats?.responseSeries ?? []}
275
+ showMinMax
276
+ heightClassName="h-[220px]"
277
+ emptyText={t.noChecks}
278
+ />
279
+
280
+ <div className="mt-5">
281
+ <div className="mb-1.5 flex items-center justify-between">
282
+ <span className="text-xs font-medium">{t.uptimeTimeline90d}</span>
283
+ <span className="text-[10px] text-muted-foreground">
284
+ {t.uptimeTimelineDaily}
285
+ </span>
286
+ </div>
287
+ <UptimeTimelineBars
288
+ buckets={stats?.timeline ?? []}
289
+ heightClassName="h-9"
290
+ ariaLabel={fmt(t.uptimeTimelineAria, { name: monitor.name })}
291
+ />
292
+ {stats && stats.timeline.length > 0 ? (
293
+ <div className="mt-1 flex justify-between text-[10px] text-muted-foreground">
294
+ <span>{t.timelineNinetyDaysAgo}</span>
295
+ <span>{t.timelineToday}</span>
296
+ </div>
297
+ ) : null}
298
+ </div>
299
+ </CardContent>
300
+ </Card>
301
+
302
+ <div className="grid gap-4 lg:grid-cols-3">
303
+ {/* Config summary */}
304
+ <Card className="bg-card border-border/50 lg:col-span-1">
305
+ <CardHeader className="pb-2">
306
+ <CardTitle className="text-sm font-medium">
307
+ {t.configTitle}
308
+ </CardTitle>
309
+ </CardHeader>
310
+ <CardContent className="space-y-2.5 text-xs">
311
+ <ConfigRow label={t.configMethod} value={monitor.method} />
312
+ <ConfigRow
313
+ label={t.configInterval}
314
+ value={
315
+ t.intervals[String(monitor.intervalSeconds)] ??
316
+ `${monitor.intervalSeconds}s`
317
+ }
318
+ />
319
+ <ConfigRow
320
+ label={t.configTimeout}
321
+ value={`${Math.round(monitor.timeoutMs / 1000)}s`}
322
+ />
323
+ <ConfigRow
324
+ label={t.configExpected}
325
+ value={describeMatcher(monitor.expectedStatus, t)}
326
+ />
327
+ <ConfigRow
328
+ label={t.configRedirects}
329
+ value={monitor.followRedirects ? t.yes : t.no}
330
+ />
331
+ <ConfigRow
332
+ label={t.configCooldown}
333
+ value={`${monitor.cooldownMinutes}m`}
334
+ />
335
+ <div className="space-y-1">
336
+ <span className="text-muted-foreground">{t.configChannels}</span>
337
+ <div className="flex flex-wrap gap-1">
338
+ {monitor.channels.map((channel) => (
339
+ <Badge
340
+ key={channel}
341
+ variant="secondary"
342
+ className="text-[10px]"
343
+ >
344
+ {channel}
345
+ </Badge>
346
+ ))}
347
+ </div>
348
+ </div>
349
+ <div className="space-y-1">
350
+ <span className="text-muted-foreground">
351
+ {t.configAssertions}
352
+ </span>
353
+ {monitor.assertions.length === 0 ? (
354
+ <p className="text-muted-foreground/80">{t.noAssertions}</p>
355
+ ) : (
356
+ <ul className="space-y-1">
357
+ {monitor.assertions.map((assertion, index) => (
358
+ <li
359
+ key={`${assertion.type}-${index}`}
360
+ className="rounded bg-muted/40 px-2 py-1"
361
+ >
362
+ {describeAssertion(assertion, t)}
363
+ </li>
364
+ ))}
365
+ </ul>
366
+ )}
367
+ </div>
368
+ </CardContent>
369
+ </Card>
370
+
371
+ {/* Recent checks */}
372
+ <Card className="bg-card border-border/50 lg:col-span-2">
373
+ <CardHeader className="pb-2">
374
+ <CardTitle className="text-sm font-medium">
375
+ {t.recentChecks}
376
+ </CardTitle>
377
+ </CardHeader>
378
+ <CardContent>
379
+ {results.length === 0 ? (
380
+ <p className="py-6 text-center text-sm text-muted-foreground">
381
+ {t.noChecks}
382
+ </p>
383
+ ) : (
384
+ <div className="max-h-[320px] overflow-y-auto">
385
+ <Table>
386
+ <TableHeader>
387
+ <TableRow>
388
+ <TableHead>{t.colTime}</TableHead>
389
+ <TableHead>{t.colStatus}</TableHead>
390
+ <TableHead className="text-end">{t.colCode}</TableHead>
391
+ <TableHead className="text-end">{t.colLatency}</TableHead>
392
+ <TableHead>{t.colDetails}</TableHead>
393
+ </TableRow>
394
+ </TableHeader>
395
+ <TableBody>
396
+ {results.slice(0, 50).map((result) => {
397
+ const resultTone = statusTone(result.status);
398
+ return (
399
+ <TableRow key={result.id}>
400
+ <TableCell className="whitespace-nowrap text-xs text-muted-foreground">
401
+ {formatDateTime(result.checkedAt)}
402
+ </TableCell>
403
+ <TableCell>
404
+ <div className="flex items-center gap-1.5">
405
+ <span
406
+ className={cn(
407
+ "size-2 rounded-full",
408
+ toneDotClass(resultTone),
409
+ )}
410
+ />
411
+ <span className="text-xs">
412
+ {statusLabel(result.status, t)}
413
+ </span>
414
+ </div>
415
+ </TableCell>
416
+ <TableCell className="text-end text-xs tabular-nums">
417
+ {result.statusCode ?? "—"}
418
+ </TableCell>
419
+ <TableCell className="text-end text-xs tabular-nums">
420
+ {formatLatency(result.latencyMs)}
421
+ </TableCell>
422
+ <TableCell className="max-w-[220px] text-xs text-muted-foreground">
423
+ {result.failedAssertions.length > 0 ? (
424
+ <span className="text-amber-500">
425
+ {result.failedAssertions.join("; ")}
426
+ </span>
427
+ ) : result.error ? (
428
+ <span className="text-destructive">
429
+ {result.error}
430
+ </span>
431
+ ) : (
432
+ <span className="text-emerald-500">{t.ok}</span>
433
+ )}
434
+ </TableCell>
435
+ </TableRow>
436
+ );
437
+ })}
438
+ </TableBody>
439
+ </Table>
440
+ </div>
441
+ )}
442
+ </CardContent>
443
+ </Card>
444
+ </div>
445
+
446
+ {/* Incidents */}
447
+ <Card className="bg-card border-border/50">
448
+ <CardHeader className="pb-2">
449
+ <CardTitle className="text-sm font-medium">{t.incidents}</CardTitle>
450
+ </CardHeader>
451
+ <CardContent>
452
+ {incidents.length === 0 ? (
453
+ <p className="py-4 text-center text-sm text-muted-foreground">
454
+ {t.noIncidents}
455
+ </p>
456
+ ) : (
457
+ <div className="space-y-2">
458
+ {incidents.map((incident) => {
459
+ const start = Date.parse(incident.startedAt);
460
+ const end = incident.resolvedAt
461
+ ? Date.parse(incident.resolvedAt)
462
+ : Date.now();
463
+ const duration = formatDuration(end - start);
464
+ const incidentTone = statusTone(incident.status);
465
+ return (
466
+ <div
467
+ key={incident.id}
468
+ className="flex flex-col gap-1 rounded-md border border-border/60 px-3 py-2 sm:flex-row sm:items-center sm:justify-between"
469
+ >
470
+ <div className="min-w-0">
471
+ <div className="flex items-center gap-2">
472
+ <span
473
+ className={cn(
474
+ "size-2 rounded-full",
475
+ toneDotClass(incidentTone),
476
+ )}
477
+ />
478
+ <span className="truncate text-sm font-medium">
479
+ {incident.cause || statusLabel(incident.status, t)}
480
+ </span>
481
+ <Badge
482
+ variant={
483
+ incident.resolvedAt ? "secondary" : "destructive"
484
+ }
485
+ className="text-[10px]"
486
+ >
487
+ {incident.resolvedAt ? t.resolved : t.ongoing}
488
+ </Badge>
489
+ </div>
490
+ <div className="mt-0.5 text-xs text-muted-foreground">
491
+ {t.started}: {formatDateTime(incident.startedAt)} ·{" "}
492
+ {fmt(t.checksFailedLabel, {
493
+ count: incident.checksFailed,
494
+ })}
495
+ </div>
496
+ </div>
497
+ <div className="shrink-0 text-xs text-muted-foreground">
498
+ {t.duration}: {duration}
499
+ </div>
500
+ </div>
501
+ );
502
+ })}
503
+ </div>
504
+ )}
505
+ </CardContent>
506
+ </Card>
507
+ </div>
508
+ );
509
+ }
510
+
511
+ function StatCard({
512
+ label,
513
+ children,
514
+ }: {
515
+ label: string;
516
+ children: React.ReactNode;
517
+ }) {
518
+ return (
519
+ <div className="flex min-w-0 flex-col gap-0.5 rounded-lg border border-border/50 bg-card px-3 py-2.5">
520
+ <span className="text-[11px] uppercase tracking-wide text-muted-foreground">
521
+ {label}
522
+ </span>
523
+ {children}
524
+ </div>
525
+ );
526
+ }
527
+
528
+ function ConfigRow({ label, value }: { label: string; value: string }) {
529
+ return (
530
+ <div className="flex items-center justify-between gap-2">
531
+ <span className="text-muted-foreground">{label}</span>
532
+ <span className="truncate text-end font-medium">{value}</span>
533
+ </div>
534
+ );
535
+ }