@agent-native/core 0.90.10 → 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.
Files changed (360) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +30 -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/durable-background.ts +5 -5
  6. package/corpus/core/src/agent/engine/ai-sdk-engine.ts +40 -8
  7. package/corpus/core/src/agent/engine/anthropic-engine.ts +25 -7
  8. package/corpus/core/src/agent/engine/output-tokens.ts +94 -0
  9. package/corpus/core/src/agent/production-agent.ts +34 -6
  10. package/corpus/core/src/agent/run-ownership.ts +29 -1
  11. package/corpus/core/src/agent/types.ts +3 -2
  12. package/corpus/core/src/changelog/parse.ts +78 -0
  13. package/corpus/core/src/chat-threads/schema.ts +43 -0
  14. package/corpus/core/src/chat-threads/store.ts +144 -12
  15. package/corpus/core/src/cli/workspace-dev.ts +25 -5
  16. package/corpus/core/src/client/AgentPanel.tsx +79 -14
  17. package/corpus/core/src/client/AssistantChat.tsx +359 -425
  18. package/corpus/core/src/client/analytics-session.ts +70 -0
  19. package/corpus/core/src/client/analytics.ts +175 -49
  20. package/corpus/core/src/client/chat/message-components.tsx +22 -2
  21. package/corpus/core/src/client/components/ui/message-scroller.tsx +131 -0
  22. package/corpus/core/src/client/conversation/AgentConversation.tsx +63 -41
  23. package/corpus/core/src/client/error-capture.ts +616 -0
  24. package/corpus/core/src/client/index.ts +12 -0
  25. package/corpus/core/src/client/session-replay.ts +57 -7
  26. package/corpus/core/src/client/settings/SettingsPanel.tsx +123 -1
  27. package/corpus/core/src/client/settings/SettingsTabsPage.tsx +292 -45
  28. package/corpus/core/src/client/settings/index.ts +1 -0
  29. package/corpus/core/src/client/sharing/ShareButton.tsx +14 -11
  30. package/corpus/core/src/client/sharing/ShareDialog.tsx +13 -10
  31. package/corpus/core/src/db/client.ts +12 -9
  32. package/corpus/core/src/mcp/builtin-tools.ts +29 -2
  33. package/corpus/core/src/server/agent-chat-plugin.ts +174 -79
  34. package/corpus/core/src/server/onboarding-html.ts +28 -16
  35. package/corpus/core/src/shared/reasoning-effort.ts +23 -0
  36. package/corpus/core/src/sharing/actions/list-resource-shares.ts +45 -1
  37. package/corpus/core/src/sharing/actions/share-resource.ts +9 -0
  38. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
  39. package/corpus/core/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
  40. package/corpus/core/src/vite/client.ts +217 -35
  41. package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +8 -7
  42. package/corpus/templates/analytics/.agents/skills/analysis-workspace/SKILL.md +14 -10
  43. package/corpus/templates/analytics/.agents/skills/bigquery/SKILL.md +15 -15
  44. package/corpus/templates/analytics/.agents/skills/cross-source-analysis/SKILL.md +1 -0
  45. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +38 -22
  46. package/corpus/templates/analytics/.agents/skills/data-programs/SKILL.md +114 -61
  47. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +1 -0
  48. package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +7 -7
  49. package/corpus/templates/analytics/.agents/skills/hubspot/SKILL.md +1 -0
  50. package/corpus/templates/analytics/.agents/skills/prometheus/SKILL.md +1 -1
  51. package/corpus/templates/analytics/.builder/skills/bigquery/SKILL.md +17 -17
  52. package/corpus/templates/analytics/.builder/skills/gcloud/SKILL.md +5 -5
  53. package/corpus/templates/analytics/.builder/skills/github/SKILL.md +7 -7
  54. package/corpus/templates/analytics/.builder/skills/gong/SKILL.md +12 -12
  55. package/corpus/templates/analytics/.builder/skills/grafana/SKILL.md +7 -7
  56. package/corpus/templates/analytics/.builder/skills/sentry/SKILL.md +7 -7
  57. package/corpus/templates/analytics/.builder/skills/slack/SKILL.md +6 -6
  58. package/corpus/templates/analytics/.builder/skills/stripe/SKILL.md +7 -7
  59. package/corpus/templates/analytics/AGENTS.md +47 -2
  60. package/corpus/templates/analytics/actions/add-status-page-monitor.ts +36 -0
  61. package/corpus/templates/analytics/actions/capture-test-error.ts +33 -0
  62. package/corpus/templates/analytics/actions/delete-monitor.ts +24 -0
  63. package/corpus/templates/analytics/actions/delete-status-page.ts +23 -0
  64. package/corpus/templates/analytics/actions/get-error-issue.ts +36 -0
  65. package/corpus/templates/analytics/actions/get-monitor-stats.ts +55 -0
  66. package/corpus/templates/analytics/actions/get-monitor.ts +27 -0
  67. package/corpus/templates/analytics/actions/get-public-status-page.ts +41 -0
  68. package/corpus/templates/analytics/actions/get-status-page.ts +29 -0
  69. package/corpus/templates/analytics/actions/list-error-issues.ts +40 -0
  70. package/corpus/templates/analytics/actions/list-monitors.ts +21 -0
  71. package/corpus/templates/analytics/actions/list-status-pages.ts +21 -0
  72. package/corpus/templates/analytics/actions/match-error-issues.ts +51 -0
  73. package/corpus/templates/analytics/actions/navigate.ts +58 -4
  74. package/corpus/templates/analytics/actions/remove-status-page-monitor.ts +22 -0
  75. package/corpus/templates/analytics/actions/reorder-status-page-monitors.ts +25 -0
  76. package/corpus/templates/analytics/actions/resolve-error-issue.ts +38 -0
  77. package/corpus/templates/analytics/actions/run-monitor-check.ts +23 -0
  78. package/corpus/templates/analytics/actions/save-analysis.ts +1 -0
  79. package/corpus/templates/analytics/actions/save-monitor.ts +145 -0
  80. package/corpus/templates/analytics/actions/save-status-page.ts +47 -0
  81. package/corpus/templates/analytics/actions/view-screen.ts +212 -0
  82. package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -0
  83. package/corpus/templates/analytics/app/components/layout/Layout.tsx +10 -1
  84. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +134 -39
  85. package/corpus/templates/analytics/app/components/monitoring/PublicStatusView.tsx +351 -0
  86. package/corpus/templates/analytics/app/components/monitoring/ResponseTimeChart.tsx +174 -0
  87. package/corpus/templates/analytics/app/components/monitoring/UptimeStatCards.tsx +85 -0
  88. package/corpus/templates/analytics/app/components/monitoring/UptimeTimelineBars.tsx +106 -0
  89. package/corpus/templates/analytics/app/components/monitoring/chart-utils.ts +101 -0
  90. package/corpus/templates/analytics/app/components/monitoring/index.ts +28 -0
  91. package/corpus/templates/analytics/app/components/monitoring/types.ts +42 -0
  92. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +34 -0
  93. package/corpus/templates/analytics/app/i18n/zh-TW.ts +6 -0
  94. package/corpus/templates/analytics/app/i18n-data.ts +33 -0
  95. package/corpus/templates/analytics/app/pages/DataSources.tsx +28 -0
  96. package/corpus/templates/analytics/app/pages/Settings.tsx +77 -9
  97. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +3 -3
  98. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +7 -0
  99. package/corpus/templates/analytics/app/pages/monitoring/ErrorsPanel.tsx +205 -0
  100. package/corpus/templates/analytics/app/pages/monitoring/MonitoringPage.tsx +100 -0
  101. package/corpus/templates/analytics/app/pages/monitoring/UptimePanel.tsx +475 -0
  102. package/corpus/templates/analytics/app/pages/monitoring/errors/IssueDetail.tsx +372 -0
  103. package/corpus/templates/analytics/app/pages/monitoring/errors/IssueList.tsx +360 -0
  104. package/corpus/templates/analytics/app/pages/monitoring/errors/Sparkline.tsx +55 -0
  105. package/corpus/templates/analytics/app/pages/monitoring/errors/i18n.ts +106 -0
  106. package/corpus/templates/analytics/app/pages/monitoring/errors/types.ts +75 -0
  107. package/corpus/templates/analytics/app/pages/monitoring/errors/utils.ts +132 -0
  108. package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorDetail.tsx +535 -0
  109. package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorFormPage.tsx +1026 -0
  110. package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorList.tsx +311 -0
  111. package/corpus/templates/analytics/app/pages/monitoring/uptime/i18n.ts +235 -0
  112. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/StatusPageEditor.tsx +661 -0
  113. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/StatusPagesView.tsx +355 -0
  114. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/i18n.ts +106 -0
  115. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/slug.ts +24 -0
  116. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/types.ts +20 -0
  117. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-summary.ts +87 -0
  118. package/corpus/templates/analytics/app/pages/monitoring/uptime/types.ts +161 -0
  119. package/corpus/templates/analytics/app/pages/monitoring/uptime/utils.ts +210 -0
  120. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +76 -1
  121. package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +74 -9
  122. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +197 -20
  123. package/corpus/templates/analytics/app/root.tsx +33 -1
  124. package/corpus/templates/analytics/app/routes/monitoring._index.tsx +10 -0
  125. package/corpus/templates/analytics/app/routes/status.$slug.tsx +118 -0
  126. package/corpus/templates/analytics/changelog/2026-07-08-add-uptime-monitors-that-ping-your-urls-and-alert-you-when-t.md +6 -0
  127. package/corpus/templates/analytics/changelog/2026-07-08-analytics-chats-keep-large-data-dictionaries-compact-so-prov.md +6 -0
  128. package/corpus/templates/analytics/changelog/2026-07-08-create-public-status-pages-that-share-the-live-health-of-cho.md +6 -0
  129. package/corpus/templates/analytics/changelog/2026-07-08-dashboard-extension-panels-use-clearer-open-copy.md +6 -0
  130. package/corpus/templates/analytics/changelog/2026-07-08-error-capture.md +6 -0
  131. package/corpus/templates/analytics/changelog/2026-07-08-fixed-single-panel-dashboard-drags-so-they-no-longer-rewrite.md +6 -0
  132. package/corpus/templates/analytics/changelog/2026-07-08-jump-straight-from-an-error-in-a-session-recording-to-its-fu.md +6 -0
  133. package/corpus/templates/analytics/changelog/2026-07-08-monitor-detail-and-list-now-show-colorful-uptime-timelines-r.md +6 -0
  134. package/corpus/templates/analytics/changelog/2026-07-08-pinned-ask-chats-now-show-a-pin-icon-in-the-sidebar.md +6 -0
  135. package/corpus/templates/analytics/changelog/2026-07-08-publish-a-public-uptime-status-page-with-colorful-uptime-tim.md +6 -0
  136. package/corpus/templates/analytics/changelog/2026-07-08-sessions-now-hide-visitor-emails-in-demo-mode-and-show-clean.md +6 -0
  137. package/corpus/templates/analytics/changelog/2026-07-08-settings-are-cleaner-searchable-and-alerts-have-their-own-tab.md +5 -0
  138. package/corpus/templates/analytics/changelog/2026-07-08-sidebar-sections-stay-collapsed-until-opened.md +5 -0
  139. package/corpus/templates/analytics/changelog/2026-07-08-the-uptime-monitor-list-now-has-a-current-status-overview-wi.md +6 -0
  140. package/corpus/templates/analytics/docs/error-capture.md +172 -0
  141. package/corpus/templates/analytics/docs/uptime-monitoring.md +150 -0
  142. package/corpus/templates/analytics/server/db/schema-errors.ts +150 -0
  143. package/corpus/templates/analytics/server/db/schema-monitoring.ts +177 -0
  144. package/corpus/templates/analytics/server/db/schema.ts +6 -0
  145. package/corpus/templates/analytics/server/jobs/uptime-monitors.ts +123 -0
  146. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +41 -0
  147. package/corpus/templates/analytics/server/lib/data-dictionary-context.ts +55 -12
  148. package/corpus/templates/analytics/server/lib/error-capture.ts +1331 -0
  149. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +47 -1
  150. package/corpus/templates/analytics/server/lib/monitor-stats.ts +494 -0
  151. package/corpus/templates/analytics/server/lib/status-pages.ts +798 -0
  152. package/corpus/templates/analytics/server/lib/uptime-monitors.ts +1665 -0
  153. package/corpus/templates/analytics/server/plugins/agent-chat.ts +7 -37
  154. package/corpus/templates/analytics/server/plugins/auth.ts +11 -1
  155. package/corpus/templates/analytics/server/plugins/db.ts +408 -0
  156. package/corpus/templates/analytics/server/plugins/uptime-monitor-jobs.ts +63 -0
  157. package/corpus/templates/assets/app/routes/_index.tsx +1 -1
  158. package/corpus/templates/assets/app/routes/settings.tsx +22 -1
  159. package/corpus/templates/assets/changelog/2026-07-08-recent-drafts-keep-comfortable-side-padding.md +6 -0
  160. package/corpus/templates/assets/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  161. package/corpus/templates/brain/app/routes/settings.tsx +43 -5
  162. package/corpus/templates/brain/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  163. package/corpus/templates/calendar/app/pages/Settings.tsx +44 -6
  164. package/corpus/templates/calendar/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  165. package/corpus/templates/chat/app/routes/settings.tsx +16 -1
  166. package/corpus/templates/chat/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  167. package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +79 -37
  168. package/corpus/templates/clips/actions/regenerate-chapters.ts +7 -0
  169. package/corpus/templates/clips/app/components/player/player-controls.tsx +35 -0
  170. package/corpus/templates/clips/app/components/player/video-player.tsx +162 -18
  171. package/corpus/templates/clips/app/hooks/use-auto-title.ts +15 -5
  172. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +63 -6
  173. package/corpus/templates/clips/app/routes/download.tsx +12 -4
  174. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -0
  175. package/corpus/templates/clips/app/routes/record.tsx +18 -1
  176. package/corpus/templates/clips/changelog/2026-07-07-auto-generated-chapter-requests-now-open-the-matching-agent-.md +6 -0
  177. package/corpus/templates/clips/changelog/2026-07-07-shared-clips-start-playback-reliably-from-the-first-play-click.md +6 -0
  178. package/corpus/templates/clips/changelog/2026-07-07-the-clips-desktop-download-page-now-uses-the-agent-native-ap.md +6 -0
  179. package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-camera-and-microphone-menus-now-show-which-.md +6 -0
  180. package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-copies-new-clip-links-after-saving.md +6 -0
  181. package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-recordings-now-continue-after-granting-came.md +6 -0
  182. package/corpus/templates/clips/changelog/2026-07-08-mobile-shared-clips-now-have-loom-style-tap-and-skip-controls.md +6 -0
  183. package/corpus/templates/clips/changelog/2026-07-08-recordings-and-uploads-copy-links-after-saving.md +6 -0
  184. package/corpus/templates/clips/changelog/2026-07-08-settings-are-cleaner-searchable-and-collapse-s3-with-builder.md +5 -0
  185. package/corpus/templates/clips/changelog/2026-07-08-transcripts-are-more-reliable-for-longer-desktop-recordings-.md +6 -0
  186. package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -0
  187. package/corpus/templates/clips/chrome-extension/src/background.ts +162 -13
  188. package/corpus/templates/clips/chrome-extension/src/content-script.ts +14 -0
  189. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +36 -0
  190. package/corpus/templates/clips/chrome-extension/src/overlay.ts +99 -25
  191. package/corpus/templates/clips/chrome-extension/src/permission.ts +63 -14
  192. package/corpus/templates/clips/chrome-extension/src/popup.ts +123 -23
  193. package/corpus/templates/content/actions/_builder-cms-read-client.ts +47 -0
  194. package/corpus/templates/content/actions/_database-source-utils.ts +33 -4
  195. package/corpus/templates/content/actions/add-content-database-source-field-property.ts +214 -29
  196. package/corpus/templates/content/actions/attach-content-database-source.ts +3 -0
  197. package/corpus/templates/content/actions/change-content-database-source-role.ts +1 -0
  198. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +42 -32
  199. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +352 -81
  200. package/corpus/templates/content/app/components/editor/database/settings.tsx +49 -24
  201. package/corpus/templates/content/app/routes/_app.settings.tsx +19 -1
  202. package/corpus/templates/content/changelog/2026-07-07-builder-source-tag-fields-now-import-as-multi-select.md +6 -0
  203. package/corpus/templates/content/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  204. package/corpus/templates/content/shared/api.ts +3 -0
  205. package/corpus/templates/content/shared/properties.ts +42 -0
  206. package/corpus/templates/design/actions/generate-design.ts +3 -0
  207. package/corpus/templates/design/actions/get-design-system.ts +147 -1
  208. package/corpus/templates/design/app/routes/settings.tsx +16 -1
  209. package/corpus/templates/design/changelog/2026-07-08-design-generation-now-follows-hydrated-builder-design-system.md +6 -0
  210. package/corpus/templates/design/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  211. package/corpus/templates/dispatch/app/routes/settings.tsx +23 -2
  212. package/corpus/templates/dispatch/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  213. package/corpus/templates/forms/app/routes/_app.settings.tsx +16 -1
  214. package/corpus/templates/forms/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  215. package/corpus/templates/macros/app/routes/settings.tsx +16 -1
  216. package/corpus/templates/macros/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  217. package/corpus/templates/mail/app/components/settings/GmailFiltersSection.tsx +1 -1
  218. package/corpus/templates/mail/app/components/settings/SnippetsSection.tsx +1 -1
  219. package/corpus/templates/mail/app/pages/SettingsPage.tsx +123 -105
  220. package/corpus/templates/mail/changelog/2026-07-08-settings-redesigned-with-a-consistent-searchable-layout.md +5 -0
  221. package/corpus/templates/plan/app/routes/settings.tsx +23 -2
  222. package/corpus/templates/plan/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  223. package/corpus/templates/slides/actions/add-slide.ts +1 -0
  224. package/corpus/templates/slides/actions/get-design-system.ts +147 -1
  225. package/corpus/templates/slides/app/pages/Index.tsx +46 -1
  226. package/corpus/templates/slides/app/routes/settings.tsx +16 -1
  227. package/corpus/templates/slides/changelog/2026-07-08-deck-generation-now-follows-hydrated-builder-design-system-g.md +6 -0
  228. package/corpus/templates/slides/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  229. package/dist/agent/durable-background.d.ts +1 -1
  230. package/dist/agent/durable-background.d.ts.map +1 -1
  231. package/dist/agent/durable-background.js +5 -3
  232. package/dist/agent/durable-background.js.map +1 -1
  233. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  234. package/dist/agent/engine/ai-sdk-engine.js +24 -4
  235. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  236. package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
  237. package/dist/agent/engine/anthropic-engine.js +13 -3
  238. package/dist/agent/engine/anthropic-engine.js.map +1 -1
  239. package/dist/agent/engine/output-tokens.d.ts +27 -0
  240. package/dist/agent/engine/output-tokens.d.ts.map +1 -1
  241. package/dist/agent/engine/output-tokens.js +70 -0
  242. package/dist/agent/engine/output-tokens.js.map +1 -1
  243. package/dist/agent/production-agent.d.ts.map +1 -1
  244. package/dist/agent/production-agent.js +28 -7
  245. package/dist/agent/production-agent.js.map +1 -1
  246. package/dist/agent/run-ownership.d.ts +6 -0
  247. package/dist/agent/run-ownership.d.ts.map +1 -1
  248. package/dist/agent/run-ownership.js +11 -1
  249. package/dist/agent/run-ownership.js.map +1 -1
  250. package/dist/agent/types.d.ts +3 -2
  251. package/dist/agent/types.d.ts.map +1 -1
  252. package/dist/agent/types.js.map +1 -1
  253. package/dist/changelog/parse.d.ts +7 -0
  254. package/dist/changelog/parse.d.ts.map +1 -1
  255. package/dist/changelog/parse.js +64 -0
  256. package/dist/changelog/parse.js.map +1 -1
  257. package/dist/chat-threads/schema.d.ts +445 -0
  258. package/dist/chat-threads/schema.d.ts.map +1 -0
  259. package/dist/chat-threads/schema.js +39 -0
  260. package/dist/chat-threads/schema.js.map +1 -0
  261. package/dist/chat-threads/store.d.ts +12 -0
  262. package/dist/chat-threads/store.d.ts.map +1 -1
  263. package/dist/chat-threads/store.js +99 -10
  264. package/dist/chat-threads/store.js.map +1 -1
  265. package/dist/cli/workspace-dev.d.ts.map +1 -1
  266. package/dist/cli/workspace-dev.js +20 -5
  267. package/dist/cli/workspace-dev.js.map +1 -1
  268. package/dist/client/AgentPanel.d.ts.map +1 -1
  269. package/dist/client/AgentPanel.js +35 -7
  270. package/dist/client/AgentPanel.js.map +1 -1
  271. package/dist/client/AssistantChat.d.ts.map +1 -1
  272. package/dist/client/AssistantChat.js +105 -183
  273. package/dist/client/AssistantChat.js.map +1 -1
  274. package/dist/client/analytics-session.d.ts +3 -0
  275. package/dist/client/analytics-session.d.ts.map +1 -0
  276. package/dist/client/analytics-session.js +66 -0
  277. package/dist/client/analytics-session.js.map +1 -0
  278. package/dist/client/analytics.d.ts +32 -0
  279. package/dist/client/analytics.d.ts.map +1 -1
  280. package/dist/client/analytics.js +116 -46
  281. package/dist/client/analytics.js.map +1 -1
  282. package/dist/client/chat/message-components.d.ts +2 -1
  283. package/dist/client/chat/message-components.d.ts.map +1 -1
  284. package/dist/client/chat/message-components.js +16 -6
  285. package/dist/client/chat/message-components.js.map +1 -1
  286. package/dist/client/components/ui/message-scroller.d.ts +16 -0
  287. package/dist/client/components/ui/message-scroller.d.ts.map +1 -0
  288. package/dist/client/components/ui/message-scroller.js +25 -0
  289. package/dist/client/components/ui/message-scroller.js.map +1 -0
  290. package/dist/client/conversation/AgentConversation.d.ts +1 -1
  291. package/dist/client/conversation/AgentConversation.d.ts.map +1 -1
  292. package/dist/client/conversation/AgentConversation.js +3 -8
  293. package/dist/client/conversation/AgentConversation.js.map +1 -1
  294. package/dist/client/error-capture.d.ts +99 -0
  295. package/dist/client/error-capture.d.ts.map +1 -0
  296. package/dist/client/error-capture.js +437 -0
  297. package/dist/client/error-capture.js.map +1 -0
  298. package/dist/client/index.d.ts +2 -2
  299. package/dist/client/index.d.ts.map +1 -1
  300. package/dist/client/index.js +3 -1
  301. package/dist/client/index.js.map +1 -1
  302. package/dist/client/session-replay.d.ts +22 -0
  303. package/dist/client/session-replay.d.ts.map +1 -1
  304. package/dist/client/session-replay.js +45 -4
  305. package/dist/client/session-replay.js.map +1 -1
  306. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  307. package/dist/client/settings/SettingsPanel.js +100 -5
  308. package/dist/client/settings/SettingsPanel.js.map +1 -1
  309. package/dist/client/settings/SettingsTabsPage.d.ts +49 -1
  310. package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
  311. package/dist/client/settings/SettingsTabsPage.js +131 -19
  312. package/dist/client/settings/SettingsTabsPage.js.map +1 -1
  313. package/dist/client/settings/index.d.ts +1 -1
  314. package/dist/client/settings/index.d.ts.map +1 -1
  315. package/dist/client/settings/index.js.map +1 -1
  316. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  317. package/dist/client/sharing/ShareButton.js +13 -8
  318. package/dist/client/sharing/ShareButton.js.map +1 -1
  319. package/dist/client/sharing/ShareDialog.d.ts.map +1 -1
  320. package/dist/client/sharing/ShareDialog.js +12 -7
  321. package/dist/client/sharing/ShareDialog.js.map +1 -1
  322. package/dist/collab/routes.d.ts +1 -1
  323. package/dist/collab/struct-routes.d.ts +1 -1
  324. package/dist/db/client.d.ts.map +1 -1
  325. package/dist/db/client.js +12 -7
  326. package/dist/db/client.js.map +1 -1
  327. package/dist/mcp/builtin-tools.d.ts.map +1 -1
  328. package/dist/mcp/builtin-tools.js +21 -2
  329. package/dist/mcp/builtin-tools.js.map +1 -1
  330. package/dist/notifications/routes.d.ts +1 -1
  331. package/dist/observability/routes.d.ts +5 -5
  332. package/dist/org/schema.d.ts +15 -15
  333. package/dist/progress/routes.d.ts +1 -1
  334. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  335. package/dist/resources/handlers.d.ts +3 -3
  336. package/dist/secrets/routes.d.ts +9 -9
  337. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  338. package/dist/server/agent-chat-plugin.js +109 -73
  339. package/dist/server/agent-chat-plugin.js.map +1 -1
  340. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  341. package/dist/server/onboarding-html.d.ts.map +1 -1
  342. package/dist/server/onboarding-html.js +28 -16
  343. package/dist/server/onboarding-html.js.map +1 -1
  344. package/dist/shared/reasoning-effort.d.ts +1 -0
  345. package/dist/shared/reasoning-effort.d.ts.map +1 -1
  346. package/dist/shared/reasoning-effort.js +18 -0
  347. package/dist/shared/reasoning-effort.js.map +1 -1
  348. package/dist/sharing/actions/list-resource-shares.js +30 -1
  349. package/dist/sharing/actions/list-resource-shares.js.map +1 -1
  350. package/dist/sharing/actions/share-resource.js +6 -0
  351. package/dist/sharing/actions/share-resource.js.map +1 -1
  352. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
  353. package/dist/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
  354. package/dist/vite/client.d.ts.map +1 -1
  355. package/dist/vite/client.js +192 -30
  356. package/dist/vite/client.js.map +1 -1
  357. package/docs/content/toolkit-settings.mdx +56 -3
  358. package/package.json +2 -1
  359. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
  360. package/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
@@ -0,0 +1,661 @@
1
+ /**
2
+ * Full-page status-page editor: a config form on the left (basics, layout,
3
+ * monitor selection + ordering) and a live preview on the right that reuses the
4
+ * public `PublicStatusView`. Everything persists through the `save-status-page`
5
+ * action (the single write); `get-status-page` supplies both the seed config and
6
+ * the sanitized live preview (drafts included).
7
+ */
8
+ import { useActionMutation, useActionQuery } from "@agent-native/core/client";
9
+ import {
10
+ IconArrowLeft,
11
+ IconCheck,
12
+ IconChevronDown,
13
+ IconChevronUp,
14
+ IconCopy,
15
+ IconExternalLink,
16
+ IconLoader2,
17
+ IconPlus,
18
+ IconX,
19
+ } from "@tabler/icons-react";
20
+ import { useEffect, useMemo, useRef, useState } from "react";
21
+ import { toast } from "sonner";
22
+
23
+ import { PublicStatusView } from "@/components/monitoring/PublicStatusView";
24
+ import { Badge } from "@/components/ui/badge";
25
+ import { Button } from "@/components/ui/button";
26
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
27
+ import { Input } from "@/components/ui/input";
28
+ import { Label } from "@/components/ui/label";
29
+ import {
30
+ Select,
31
+ SelectContent,
32
+ SelectItem,
33
+ SelectTrigger,
34
+ SelectValue,
35
+ } from "@/components/ui/select";
36
+ import { Skeleton } from "@/components/ui/skeleton";
37
+ import { Switch } from "@/components/ui/switch";
38
+ import { Textarea } from "@/components/ui/textarea";
39
+ import { cn } from "@/lib/utils";
40
+
41
+ import type { MonitorSummary } from "../types";
42
+ import { hostFromUrl } from "../utils";
43
+ import { fmt, useStatusPagesT } from "./i18n";
44
+ import { isValidSlug, slugify } from "./slug";
45
+ import type {
46
+ StatusPageAlignment,
47
+ StatusPageDensity,
48
+ StatusPageInput,
49
+ StatusPagePreview,
50
+ } from "./types";
51
+
52
+ interface MonitorDraft {
53
+ monitorId: string;
54
+ displayName: string;
55
+ showUrl: boolean;
56
+ }
57
+
58
+ interface Draft {
59
+ title: string;
60
+ slug: string;
61
+ description: string;
62
+ published: boolean;
63
+ showUptimeBars: boolean;
64
+ showOverallUptime: boolean;
65
+ showResponseTime: boolean;
66
+ density: StatusPageDensity;
67
+ alignment: StatusPageAlignment;
68
+ monitors: MonitorDraft[];
69
+ }
70
+
71
+ function emptyDraft(): Draft {
72
+ return {
73
+ title: "",
74
+ slug: "",
75
+ description: "",
76
+ published: false,
77
+ showUptimeBars: true,
78
+ showOverallUptime: true,
79
+ showResponseTime: false,
80
+ density: "comfortable",
81
+ alignment: "left",
82
+ monitors: [],
83
+ };
84
+ }
85
+
86
+ function statusPageOrigin(): string {
87
+ if (typeof window === "undefined") return "";
88
+ return window.location.origin;
89
+ }
90
+
91
+ export function StatusPageEditor({
92
+ pageId,
93
+ onBack,
94
+ onCreated,
95
+ }: {
96
+ pageId: string | null;
97
+ onBack: () => void;
98
+ onCreated: (id: string) => void;
99
+ }) {
100
+ const t = useStatusPagesT();
101
+ const isEdit = !!pageId;
102
+
103
+ const { data, isLoading } = useActionQuery<StatusPagePreview>(
104
+ "get-status-page",
105
+ { id: pageId ?? "" },
106
+ { enabled: isEdit, staleTime: 10_000 },
107
+ );
108
+ const { data: monitorList } = useActionQuery<MonitorSummary[]>(
109
+ "list-monitors",
110
+ undefined,
111
+ { staleTime: 30_000 },
112
+ );
113
+
114
+ const save = useActionMutation<{ id: string; slug: string }, StatusPageInput>(
115
+ "save-status-page",
116
+ );
117
+
118
+ const [draft, setDraft] = useState<Draft>(() => emptyDraft());
119
+ const slugTouched = useRef(false);
120
+ const seededRef = useRef<string | null>(null);
121
+
122
+ // Seed the draft once from the loaded page (edit) or reset for a new page.
123
+ useEffect(() => {
124
+ if (!isEdit) {
125
+ if (seededRef.current !== "new") {
126
+ setDraft(emptyDraft());
127
+ slugTouched.current = false;
128
+ seededRef.current = "new";
129
+ }
130
+ return;
131
+ }
132
+ const page = data?.page;
133
+ if (page && seededRef.current !== page.id) {
134
+ setDraft({
135
+ title: page.title,
136
+ slug: page.slug,
137
+ description: page.description ?? "",
138
+ published: page.published,
139
+ showUptimeBars: page.showUptimeBars,
140
+ showOverallUptime: page.showOverallUptime,
141
+ showResponseTime: page.showResponseTime,
142
+ density: page.density,
143
+ alignment: page.alignment,
144
+ monitors: page.monitors.map((ref) => ({
145
+ monitorId: ref.monitorId,
146
+ displayName: ref.displayName ?? "",
147
+ showUrl: ref.showUrl,
148
+ })),
149
+ });
150
+ slugTouched.current = true;
151
+ seededRef.current = page.id;
152
+ }
153
+ }, [isEdit, data]);
154
+
155
+ const monitors = useMemo(
156
+ () => (Array.isArray(monitorList) ? monitorList : []),
157
+ [monitorList],
158
+ );
159
+ const monitorById = useMemo(() => {
160
+ const map = new Map<string, MonitorSummary>();
161
+ for (const monitor of monitors) map.set(monitor.id, monitor);
162
+ return map;
163
+ }, [monitors]);
164
+ const availableMonitors = useMemo(() => {
165
+ const chosen = new Set(draft.monitors.map((m) => m.monitorId));
166
+ return monitors.filter((monitor) => !chosen.has(monitor.id));
167
+ }, [monitors, draft.monitors]);
168
+
169
+ const patch = (next: Partial<Draft>) =>
170
+ setDraft((prev) => ({ ...prev, ...next }));
171
+
172
+ const onTitleChange = (value: string) => {
173
+ setDraft((prev) => ({
174
+ ...prev,
175
+ title: value,
176
+ slug: slugTouched.current ? prev.slug : slugify(value),
177
+ }));
178
+ };
179
+
180
+ const onSlugChange = (value: string) => {
181
+ slugTouched.current = true;
182
+ patch({ slug: value.toLowerCase().replace(/[^a-z0-9-]/g, "") });
183
+ };
184
+
185
+ const addMonitor = (monitorId: string) => {
186
+ if (!monitorId) return;
187
+ setDraft((prev) =>
188
+ prev.monitors.some((m) => m.monitorId === monitorId)
189
+ ? prev
190
+ : {
191
+ ...prev,
192
+ monitors: [
193
+ ...prev.monitors,
194
+ { monitorId, displayName: "", showUrl: false },
195
+ ],
196
+ },
197
+ );
198
+ };
199
+
200
+ const updateMonitor = (index: number, next: Partial<MonitorDraft>) =>
201
+ setDraft((prev) => ({
202
+ ...prev,
203
+ monitors: prev.monitors.map((m, i) =>
204
+ i === index ? { ...m, ...next } : m,
205
+ ),
206
+ }));
207
+
208
+ const removeMonitor = (index: number) =>
209
+ setDraft((prev) => ({
210
+ ...prev,
211
+ monitors: prev.monitors.filter((_, i) => i !== index),
212
+ }));
213
+
214
+ const moveMonitor = (index: number, dir: -1 | 1) =>
215
+ setDraft((prev) => {
216
+ const target = index + dir;
217
+ if (target < 0 || target >= prev.monitors.length) return prev;
218
+ const next = [...prev.monitors];
219
+ const [moved] = next.splice(index, 1);
220
+ next.splice(target, 0, moved);
221
+ return { ...prev, monitors: next };
222
+ });
223
+
224
+ const slugForLink = draft.slug.trim();
225
+ const publicUrl = slugForLink
226
+ ? `${statusPageOrigin()}/status/${slugForLink}`
227
+ : "";
228
+ const [copied, setCopied] = useState(false);
229
+
230
+ const copyLink = async () => {
231
+ if (!publicUrl) return;
232
+ try {
233
+ await navigator.clipboard.writeText(publicUrl);
234
+ setCopied(true);
235
+ window.setTimeout(() => setCopied(false), 1500);
236
+ } catch {
237
+ toast.error(t.copyFailed);
238
+ }
239
+ };
240
+
241
+ const submit = async () => {
242
+ const title = draft.title.trim();
243
+ if (!title) {
244
+ toast.error(t.titleRequired);
245
+ return;
246
+ }
247
+ const slug = draft.slug.trim();
248
+ if (slug && !isValidSlug(slug)) {
249
+ toast.error(t.slugInvalid);
250
+ return;
251
+ }
252
+ const input: StatusPageInput = {
253
+ id: pageId ?? undefined,
254
+ title,
255
+ slug: slug || undefined,
256
+ description: draft.description.trim() || null,
257
+ published: draft.published,
258
+ showUptimeBars: draft.showUptimeBars,
259
+ showOverallUptime: draft.showOverallUptime,
260
+ showResponseTime: draft.showResponseTime,
261
+ density: draft.density,
262
+ alignment: draft.alignment,
263
+ monitors: draft.monitors.map((m) => ({
264
+ monitorId: m.monitorId,
265
+ displayName: m.displayName.trim() || null,
266
+ showUrl: m.showUrl,
267
+ })),
268
+ };
269
+ try {
270
+ const saved = await save.mutateAsync(input);
271
+ toast.success(t.savedToast);
272
+ if (!isEdit && saved?.id) onCreated(saved.id);
273
+ } catch (err) {
274
+ toast.error(
275
+ fmt(t.saveFailed, {
276
+ message: err instanceof Error ? err.message : String(err),
277
+ }),
278
+ );
279
+ }
280
+ };
281
+
282
+ if (isEdit && isLoading && !data) {
283
+ return (
284
+ <div className="space-y-4">
285
+ <Skeleton className="h-9 w-40" />
286
+ <Skeleton className="h-64 w-full" />
287
+ </div>
288
+ );
289
+ }
290
+
291
+ const view = data?.view ?? null;
292
+
293
+ return (
294
+ <div className="space-y-5 pb-16">
295
+ <Button
296
+ variant="ghost"
297
+ size="sm"
298
+ className="-ms-2 w-fit text-muted-foreground"
299
+ onClick={onBack}
300
+ >
301
+ <IconArrowLeft className="size-3.5" />
302
+ {t.backToPages}
303
+ </Button>
304
+
305
+ <div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
306
+ <div className="min-w-0">
307
+ <h2 className="text-lg font-semibold">
308
+ {isEdit ? t.editTitle : t.createTitle}
309
+ </h2>
310
+ <p className="text-sm text-muted-foreground">
311
+ {isEdit ? t.editSubtitle : t.createSubtitle}
312
+ </p>
313
+ </div>
314
+ <div className="flex shrink-0 flex-wrap items-center gap-2">
315
+ <Button
316
+ variant="outline"
317
+ size="sm"
318
+ onClick={copyLink}
319
+ disabled={!publicUrl}
320
+ >
321
+ {copied ? (
322
+ <IconCheck className="size-3.5" />
323
+ ) : (
324
+ <IconCopy className="size-3.5" />
325
+ )}
326
+ {copied ? t.copied : t.copyLink}
327
+ </Button>
328
+ <Button
329
+ variant="outline"
330
+ size="sm"
331
+ asChild
332
+ disabled={!publicUrl || !draft.published}
333
+ >
334
+ <a
335
+ href={publicUrl || "#"}
336
+ target="_blank"
337
+ rel="noreferrer noopener"
338
+ aria-disabled={!publicUrl || !draft.published}
339
+ className={cn(
340
+ (!publicUrl || !draft.published) &&
341
+ "pointer-events-none opacity-50",
342
+ )}
343
+ >
344
+ <IconExternalLink className="size-3.5" />
345
+ {t.openPage}
346
+ </a>
347
+ </Button>
348
+ <Button size="sm" onClick={submit} disabled={save.isPending}>
349
+ {save.isPending ? (
350
+ <IconLoader2 className="size-3.5 animate-spin" />
351
+ ) : null}
352
+ {save.isPending ? t.saving : t.save}
353
+ </Button>
354
+ </div>
355
+ </div>
356
+
357
+ {publicUrl ? (
358
+ <p className="text-xs text-muted-foreground">
359
+ {draft.published
360
+ ? fmt(t.linkLive, { url: `/status/${slugForLink}` })
361
+ : fmt(t.linkLiveHint, { url: `/status/${slugForLink}` })}
362
+ </p>
363
+ ) : null}
364
+
365
+ <div className="grid gap-6 lg:grid-cols-5">
366
+ {/* Config */}
367
+ <div className="space-y-5 lg:col-span-3">
368
+ <Card className="bg-card border-border/50">
369
+ <CardHeader className="pb-3">
370
+ <CardTitle className="text-sm font-medium">
371
+ {t.sectionBasics}
372
+ </CardTitle>
373
+ </CardHeader>
374
+ <CardContent className="space-y-4">
375
+ <div className="space-y-1.5">
376
+ <Label htmlFor="sp-title">{t.fieldTitle}</Label>
377
+ <Input
378
+ id="sp-title"
379
+ value={draft.title}
380
+ placeholder={t.fieldTitlePlaceholder}
381
+ onChange={(e) => onTitleChange(e.target.value)}
382
+ />
383
+ </div>
384
+ <div className="space-y-1.5">
385
+ <Label htmlFor="sp-slug">{t.fieldSlug}</Label>
386
+ <div className="flex items-center gap-1.5">
387
+ <span className="shrink-0 text-xs text-muted-foreground">
388
+ /status/
389
+ </span>
390
+ <Input
391
+ id="sp-slug"
392
+ value={draft.slug}
393
+ placeholder="acme-status"
394
+ onChange={(e) => onSlugChange(e.target.value)}
395
+ className={cn(
396
+ draft.slug && !isValidSlug(draft.slug)
397
+ ? "border-destructive"
398
+ : undefined,
399
+ )}
400
+ />
401
+ </div>
402
+ <p className="text-xs text-muted-foreground">
403
+ {t.fieldSlugHint}
404
+ </p>
405
+ </div>
406
+ <div className="space-y-1.5">
407
+ <Label htmlFor="sp-desc">{t.fieldDescription}</Label>
408
+ <Textarea
409
+ id="sp-desc"
410
+ value={draft.description}
411
+ placeholder={t.fieldDescriptionPlaceholder}
412
+ rows={2}
413
+ onChange={(e) => patch({ description: e.target.value })}
414
+ />
415
+ </div>
416
+ <ToggleRow
417
+ label={t.fieldPublished}
418
+ hint={t.fieldPublishedHint}
419
+ checked={draft.published}
420
+ onChange={(v) => patch({ published: v })}
421
+ />
422
+ </CardContent>
423
+ </Card>
424
+
425
+ <Card className="bg-card border-border/50">
426
+ <CardHeader className="pb-3">
427
+ <CardTitle className="text-sm font-medium">
428
+ {t.sectionLayout}
429
+ </CardTitle>
430
+ </CardHeader>
431
+ <CardContent className="space-y-4">
432
+ <ToggleRow
433
+ label={t.fieldShowOverallUptime}
434
+ checked={draft.showOverallUptime}
435
+ onChange={(v) => patch({ showOverallUptime: v })}
436
+ />
437
+ <ToggleRow
438
+ label={t.fieldShowUptimeBars}
439
+ checked={draft.showUptimeBars}
440
+ onChange={(v) => patch({ showUptimeBars: v })}
441
+ />
442
+ <ToggleRow
443
+ label={t.fieldShowResponseTime}
444
+ checked={draft.showResponseTime}
445
+ onChange={(v) => patch({ showResponseTime: v })}
446
+ />
447
+ <div className="grid grid-cols-2 gap-3">
448
+ <div className="space-y-1.5">
449
+ <Label>{t.fieldDensity}</Label>
450
+ <Select
451
+ value={draft.density}
452
+ onValueChange={(v) =>
453
+ patch({ density: v as StatusPageDensity })
454
+ }
455
+ >
456
+ <SelectTrigger>
457
+ <SelectValue />
458
+ </SelectTrigger>
459
+ <SelectContent>
460
+ <SelectItem value="comfortable">
461
+ {t.densityComfortable}
462
+ </SelectItem>
463
+ <SelectItem value="compact">
464
+ {t.densityCompact}
465
+ </SelectItem>
466
+ </SelectContent>
467
+ </Select>
468
+ </div>
469
+ <div className="space-y-1.5">
470
+ <Label>{t.fieldAlignment}</Label>
471
+ <Select
472
+ value={draft.alignment}
473
+ onValueChange={(v) =>
474
+ patch({ alignment: v as StatusPageAlignment })
475
+ }
476
+ >
477
+ <SelectTrigger>
478
+ <SelectValue />
479
+ </SelectTrigger>
480
+ <SelectContent>
481
+ <SelectItem value="left">{t.alignmentLeft}</SelectItem>
482
+ <SelectItem value="center">
483
+ {t.alignmentCenter}
484
+ </SelectItem>
485
+ </SelectContent>
486
+ </Select>
487
+ </div>
488
+ </div>
489
+ </CardContent>
490
+ </Card>
491
+
492
+ <Card className="bg-card border-border/50">
493
+ <CardHeader className="pb-3">
494
+ <CardTitle className="text-sm font-medium">
495
+ {t.sectionMonitors}
496
+ </CardTitle>
497
+ <p className="text-xs text-muted-foreground">
498
+ {t.sectionMonitorsHint}
499
+ </p>
500
+ </CardHeader>
501
+ <CardContent className="space-y-3">
502
+ {draft.monitors.length === 0 ? (
503
+ <p className="rounded-md border border-dashed border-border/60 px-3 py-4 text-center text-xs text-muted-foreground">
504
+ {t.noMonitorsSelected}
505
+ </p>
506
+ ) : (
507
+ <div className="space-y-2">
508
+ {draft.monitors.map((ref, index) => {
509
+ const monitor = monitorById.get(ref.monitorId);
510
+ return (
511
+ <div
512
+ key={ref.monitorId}
513
+ className="flex flex-wrap items-center gap-2 rounded-md border border-border/50 bg-muted/20 px-3 py-2"
514
+ >
515
+ <div className="flex shrink-0 flex-col">
516
+ <button
517
+ type="button"
518
+ className="text-muted-foreground hover:text-foreground disabled:opacity-30"
519
+ onClick={() => moveMonitor(index, -1)}
520
+ disabled={index === 0}
521
+ aria-label={t.moveUp}
522
+ >
523
+ <IconChevronUp className="size-3.5" />
524
+ </button>
525
+ <button
526
+ type="button"
527
+ className="text-muted-foreground hover:text-foreground disabled:opacity-30"
528
+ onClick={() => moveMonitor(index, 1)}
529
+ disabled={index === draft.monitors.length - 1}
530
+ aria-label={t.moveDown}
531
+ >
532
+ <IconChevronDown className="size-3.5" />
533
+ </button>
534
+ </div>
535
+ <div className="min-w-0 flex-1">
536
+ <div className="truncate text-xs font-medium">
537
+ {monitor?.name ?? ref.monitorId}
538
+ </div>
539
+ {monitor ? (
540
+ <div className="truncate text-[11px] text-muted-foreground">
541
+ {hostFromUrl(monitor.url)}
542
+ </div>
543
+ ) : null}
544
+ </div>
545
+ <Input
546
+ value={ref.displayName}
547
+ placeholder={t.displayNamePlaceholder}
548
+ onChange={(e) =>
549
+ updateMonitor(index, {
550
+ displayName: e.target.value,
551
+ })
552
+ }
553
+ className="h-8 w-full text-xs sm:w-44"
554
+ />
555
+ <label className="flex shrink-0 items-center gap-1.5 text-[11px] text-muted-foreground">
556
+ <Switch
557
+ checked={ref.showUrl}
558
+ onCheckedChange={(v) =>
559
+ updateMonitor(index, { showUrl: v })
560
+ }
561
+ />
562
+ {t.showUrl}
563
+ </label>
564
+ <button
565
+ type="button"
566
+ className="shrink-0 text-muted-foreground hover:text-destructive"
567
+ onClick={() => removeMonitor(index)}
568
+ aria-label={t.remove}
569
+ >
570
+ <IconX className="size-4" />
571
+ </button>
572
+ </div>
573
+ );
574
+ })}
575
+ </div>
576
+ )}
577
+
578
+ {monitors.length === 0 ? (
579
+ <p className="text-xs text-muted-foreground">
580
+ {t.createMonitorsFirst}
581
+ </p>
582
+ ) : availableMonitors.length === 0 ? (
583
+ <p className="text-xs text-muted-foreground">
584
+ {t.noMonitorsAvailable}
585
+ </p>
586
+ ) : (
587
+ <Select value="" onValueChange={addMonitor}>
588
+ <SelectTrigger className="w-full">
589
+ <span className="inline-flex items-center gap-1.5 text-muted-foreground">
590
+ <IconPlus className="size-3.5" />
591
+ {t.addMonitor}
592
+ </span>
593
+ </SelectTrigger>
594
+ <SelectContent>
595
+ {availableMonitors.map((monitor) => (
596
+ <SelectItem key={monitor.id} value={monitor.id}>
597
+ {monitor.name}
598
+ </SelectItem>
599
+ ))}
600
+ </SelectContent>
601
+ </Select>
602
+ )}
603
+ </CardContent>
604
+ </Card>
605
+ </div>
606
+
607
+ {/* Live preview */}
608
+ <div className="lg:col-span-2">
609
+ <div className="lg:sticky lg:top-2">
610
+ <div className="mb-2 flex items-center justify-between">
611
+ <span className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
612
+ {t.sectionPreview}
613
+ </span>
614
+ {!draft.published ? (
615
+ <Badge variant="secondary" className="text-[10px]">
616
+ {t.draftBadge}
617
+ </Badge>
618
+ ) : null}
619
+ </div>
620
+ {view ? (
621
+ <div className="max-h-[75vh] overflow-y-auto rounded-lg border border-border/50">
622
+ <PublicStatusView page={view} />
623
+ </div>
624
+ ) : (
625
+ <div className="flex h-64 items-center justify-center rounded-lg border border-dashed border-border/60 px-4 text-center text-sm text-muted-foreground">
626
+ {t.previewSaveFirst}
627
+ </div>
628
+ )}
629
+ <p className="mt-2 text-xs text-muted-foreground">
630
+ {view && !draft.published ? t.previewDraftNote : t.previewHint}
631
+ </p>
632
+ </div>
633
+ </div>
634
+ </div>
635
+ </div>
636
+ );
637
+ }
638
+
639
+ function ToggleRow({
640
+ label,
641
+ hint,
642
+ checked,
643
+ onChange,
644
+ }: {
645
+ label: string;
646
+ hint?: string;
647
+ checked: boolean;
648
+ onChange: (value: boolean) => void;
649
+ }) {
650
+ return (
651
+ <div className="flex items-center justify-between gap-3">
652
+ <div className="min-w-0">
653
+ <div className="text-sm">{label}</div>
654
+ {hint ? (
655
+ <div className="text-xs text-muted-foreground">{hint}</div>
656
+ ) : null}
657
+ </div>
658
+ <Switch checked={checked} onCheckedChange={onChange} />
659
+ </div>
660
+ );
661
+ }