@agent-native/core 0.120.1 → 0.120.3

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 (396) hide show
  1. package/corpus/README.md +3 -3
  2. package/corpus/core/CHANGELOG.md +29 -0
  3. package/corpus/core/docs/content/extensions.mdx +23 -4
  4. package/corpus/core/package.json +1 -1
  5. package/corpus/core/src/agent/production-agent.ts +4 -0
  6. package/corpus/core/src/agent/run-manager.ts +36 -10
  7. package/corpus/core/src/agent/types.ts +2 -0
  8. package/corpus/core/src/cli/context-xray-local.ts +1 -1
  9. package/corpus/core/src/cli/index.ts +63 -18
  10. package/corpus/core/src/cli/skills.ts +5 -0
  11. package/corpus/core/src/cli/telemetry.ts +118 -1
  12. package/corpus/core/src/client/AgentPanel.tsx +10 -0
  13. package/corpus/core/src/client/CommandMenu.tsx +13 -1
  14. package/corpus/core/src/client/agent-page/AgentTabsPage.tsx +39 -4
  15. package/corpus/core/src/client/analytics.ts +13 -0
  16. package/corpus/core/src/client/error-capture.ts +6 -1
  17. package/corpus/core/src/client/extensions/ExtensionsListPage.tsx +28 -8
  18. package/corpus/core/src/client/extensions/agent-native-extension-runtime.ts +1 -1
  19. package/corpus/core/src/client/navigation/index.ts +2 -0
  20. package/corpus/core/src/client/org/OrgSwitcher.tsx +14 -32
  21. package/corpus/core/src/client/settings/ExtensionsSettingsContent.tsx +24 -0
  22. package/corpus/core/src/client/settings/SettingsPanel.tsx +10 -0
  23. package/corpus/core/src/deploy/build.ts +3 -0
  24. package/corpus/core/src/extensions/theme.ts +1 -1
  25. package/corpus/core/src/localization/default-messages.ts +2 -0
  26. package/corpus/core/src/server/analytics.ts +154 -25
  27. package/corpus/core/src/server/core-routes-plugin.ts +10 -1
  28. package/corpus/core/src/server/framework-request-handler.ts +17 -26
  29. package/corpus/core/src/styles/agent-native.css +13 -0
  30. package/corpus/core/src/templates/chat/app/components/layout/Layout.tsx +3 -0
  31. package/corpus/core/src/templates/chat/app/components/layout/Sidebar.tsx +113 -51
  32. package/corpus/core/src/templates/chat/app/global.css +1 -1
  33. package/corpus/core/src/templates/chat/app/routes/extensions._index.tsx +2 -2
  34. package/corpus/core/src/templates/chat/netlify.toml +1 -0
  35. package/corpus/core/src/templates/default/app/global.css +1 -1
  36. package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +16 -0
  37. package/corpus/core/src/tracking/error-capture.ts +151 -0
  38. package/corpus/core/src/tracking/index.ts +5 -0
  39. package/corpus/core/src/vite/client.ts +6 -0
  40. package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +27 -43
  41. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +19 -8
  42. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +2 -2
  43. package/corpus/templates/analytics/AGENTS.md +20 -8
  44. package/corpus/templates/analytics/actions/get-explorer-dashboard.ts +3 -0
  45. package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +140 -46
  46. package/corpus/templates/analytics/actions/migrate-analytics-artifacts.ts +48 -0
  47. package/corpus/templates/analytics/actions/save-analysis.ts +2 -3
  48. package/corpus/templates/analytics/actions/view-screen.ts +1 -1
  49. package/corpus/templates/analytics/app/components/dashboard/CumulativeNetChart.tsx +1 -1
  50. package/corpus/templates/analytics/app/components/dashboard/DashboardHistoryPanel.tsx +1 -4
  51. package/corpus/templates/analytics/app/components/dashboard/DashboardMetadata.tsx +77 -0
  52. package/corpus/templates/analytics/app/components/dashboard/DashboardPanelSkeleton.tsx +7 -1
  53. package/corpus/templates/analytics/app/components/dashboard/DataTable.tsx +1 -1
  54. package/corpus/templates/analytics/app/components/dashboard/DateRangePicker.tsx +2 -2
  55. package/corpus/templates/analytics/app/components/dashboard/MetricCard.tsx +1 -1
  56. package/corpus/templates/analytics/app/components/dashboard/RecentActivity.tsx +1 -1
  57. package/corpus/templates/analytics/app/components/dashboard/RevenueChart.tsx +1 -1
  58. package/corpus/templates/analytics/app/components/dashboard/RevenueComparisonChart.tsx +1 -1
  59. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +41 -9
  60. package/corpus/templates/analytics/app/components/dashboard/StatsCard.tsx +1 -1
  61. package/corpus/templates/analytics/app/components/dashboard/TimeSeriesChart.tsx +1 -1
  62. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +2 -0
  63. package/corpus/templates/analytics/app/components/layout/Layout.tsx +28 -14
  64. package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +1 -0
  65. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +255 -626
  66. package/corpus/templates/analytics/app/global.css +31 -1
  67. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +2 -2
  68. package/corpus/templates/analytics/app/i18n-data.ts +80 -0
  69. package/corpus/templates/analytics/app/lib/dashboard-report-capture.ts +42 -0
  70. package/corpus/templates/analytics/app/pages/Agents.tsx +49 -2
  71. package/corpus/templates/analytics/app/pages/adhoc/_shared/KpiChart.tsx +1 -1
  72. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/ChartTypePicker.tsx +1 -1
  73. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/DateRangePicker.tsx +1 -1
  74. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/EventRow.tsx +1 -1
  75. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/SqlPreview.tsx +2 -2
  76. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +54 -11
  77. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +3 -3
  78. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/EmailReportDialog.tsx +2 -2
  79. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +1 -1
  80. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +4 -54
  81. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +178 -69
  82. package/corpus/templates/analytics/app/pages/analyses/AnalysisDetail.tsx +2 -2
  83. package/corpus/templates/analytics/app/root.tsx +28 -0
  84. package/corpus/templates/analytics/app/routes/analyses._index.tsx +3 -2
  85. package/corpus/templates/analytics/app/routes/extensions._index.tsx +2 -2
  86. package/corpus/templates/analytics/changelog/2026-07-23-analytics-now-groups-saved-analyses-and-embedded-extensions-.md +6 -0
  87. package/corpus/templates/analytics/changelog/2026-07-23-dashboard-menus-show-who-created-and-last-updated-each-dashb.md +6 -0
  88. package/corpus/templates/analytics/changelog/2026-07-23-dashboard-usage-now-loads-reliably-for-organizations-with-ma.md +6 -0
  89. package/corpus/templates/analytics/changelog/2026-07-23-long-dashboard-building-requests-now-continue-without-stoppi.md +6 -0
  90. package/corpus/templates/analytics/changelog/2026-07-24-analytics-charts-now-explain-slow-loads-and-offer-a-direct-r.md +6 -0
  91. package/corpus/templates/analytics/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  92. package/corpus/templates/analytics/changelog/2026-07-24-daily-dashboard-emails-now-load-signed-reports-more-reliably.md +6 -0
  93. package/corpus/templates/analytics/changelog/2026-07-24-manage-agent-is-clearly-marked-as-a-link-to-its-dedicated-pa.md +6 -0
  94. package/corpus/templates/analytics/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  95. package/corpus/templates/analytics/netlify.toml +4 -0
  96. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +1 -1
  97. package/corpus/templates/analytics/server/db/schema.ts +9 -0
  98. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +21 -0
  99. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +0 -1
  100. package/corpus/templates/analytics/server/lib/agent-readable-resource-context.ts +1 -0
  101. package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +11 -0
  102. package/corpus/templates/analytics/server/lib/dashboard-report-subscriptions.ts +54 -0
  103. package/corpus/templates/analytics/server/lib/dashboard-report.ts +235 -26
  104. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +4 -1
  105. package/corpus/templates/analytics/server/lib/migrate-analytics-artifacts.ts +1062 -0
  106. package/corpus/templates/analytics/server/plugins/agent-chat.ts +6 -52
  107. package/corpus/templates/analytics/server/plugins/core-routes.ts +1 -1
  108. package/corpus/templates/analytics/server/plugins/db.ts +19 -0
  109. package/corpus/templates/analytics/shared/dashboard-report-timeouts.ts +1 -1
  110. package/corpus/templates/assets/actions/generate-image-batch.ts +36 -1
  111. package/corpus/templates/assets/actions/generate-image.ts +28 -1
  112. package/corpus/templates/assets/app/components/asset/AssetPreviewDialog.tsx +376 -0
  113. package/corpus/templates/assets/app/components/create/RecentDraftsSection.tsx +14 -4
  114. package/corpus/templates/assets/app/components/layout/Layout.tsx +5 -0
  115. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +164 -82
  116. package/corpus/templates/assets/app/global.css +1 -1
  117. package/corpus/templates/assets/app/i18n-data.ts +10 -0
  118. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +99 -10
  119. package/corpus/templates/assets/app/routes/extensions._index.tsx +2 -2
  120. package/corpus/templates/assets/app/routes/library.tsx +21 -198
  121. package/corpus/templates/assets/changelog/2026-07-21-unified-asset-preview-click-any-asset-to-open-one-preview-wi.md +6 -0
  122. package/corpus/templates/assets/changelog/2026-07-23-assets-image-generation-now-recovers-after-a-completed-tool-.md +6 -0
  123. package/corpus/templates/assets/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  124. package/corpus/templates/assets/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  125. package/corpus/templates/assets/netlify.toml +1 -0
  126. package/corpus/templates/brain/app/components/layout/Layout.tsx +3 -0
  127. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +114 -51
  128. package/corpus/templates/brain/app/global.css +1 -1
  129. package/corpus/templates/brain/app/routes/extensions._index.tsx +2 -2
  130. package/corpus/templates/brain/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  131. package/corpus/templates/brain/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  132. package/corpus/templates/brain/netlify.toml +1 -0
  133. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +110 -57
  134. package/corpus/templates/calendar/app/global.css +1 -1
  135. package/corpus/templates/calendar/app/routes/_app.extensions._index.tsx +2 -16
  136. package/corpus/templates/calendar/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  137. package/corpus/templates/calendar/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  138. package/corpus/templates/calendar/netlify.toml +1 -0
  139. package/corpus/templates/chat/app/components/layout/Layout.tsx +3 -0
  140. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +113 -51
  141. package/corpus/templates/chat/app/global.css +1 -1
  142. package/corpus/templates/chat/app/routes/extensions._index.tsx +2 -2
  143. package/corpus/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  144. package/corpus/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  145. package/corpus/templates/chat/netlify.toml +1 -0
  146. package/corpus/templates/clips/app/components/library/library-layout.tsx +117 -37
  147. package/corpus/templates/clips/app/components/library/organization-switcher.tsx +2 -2
  148. package/corpus/templates/clips/app/components/player/video-player.tsx +16 -1
  149. package/corpus/templates/clips/app/global.css +1 -1
  150. package/corpus/templates/clips/app/hooks/use-view-tracking.ts +55 -12
  151. package/corpus/templates/clips/app/routes/_app.extensions._index.tsx +2 -16
  152. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +6 -5
  153. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +7 -7
  154. package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -5
  155. package/corpus/templates/clips/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  156. package/corpus/templates/clips/changelog/2026-07-23-meeting-recording-meters-and-dismissed-prompts.md +6 -0
  157. package/corpus/templates/clips/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  158. package/corpus/templates/clips/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  159. package/corpus/templates/clips/desktop/src/hooks/useMicMeter.ts +1 -1
  160. package/corpus/templates/clips/desktop/src/lib/meeting-notification-dismissal.ts +2 -0
  161. package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +1 -3
  162. package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +86 -0
  163. package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +24 -0
  164. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +5 -69
  165. package/corpus/templates/clips/desktop/src/styles.css +35 -3
  166. package/corpus/templates/clips/desktop/src-tauri/src/adhoc_meetings_watcher.rs +13 -44
  167. package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +119 -17
  168. package/corpus/templates/clips/netlify.toml +1 -0
  169. package/corpus/templates/clips/server/plugins/db.ts +113 -68
  170. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +69 -49
  171. package/corpus/templates/content/app/global.css +1 -1
  172. package/corpus/templates/content/app/routes/_app.extensions._index.tsx +2 -2
  173. package/corpus/templates/content/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  174. package/corpus/templates/content/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  175. package/corpus/templates/content/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  176. package/corpus/templates/content/netlify.toml +1 -0
  177. package/corpus/templates/design/app/components/layout/Sidebar.tsx +115 -42
  178. package/corpus/templates/design/app/entry.client.tsx +14 -1
  179. package/corpus/templates/design/app/global.css +1 -1
  180. package/corpus/templates/design/app/routes/extensions._index.tsx +2 -2
  181. package/corpus/templates/design/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  182. package/corpus/templates/design/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  183. package/corpus/templates/design/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  184. package/corpus/templates/design/netlify.toml +1 -0
  185. package/corpus/templates/dispatch/app/dispatch-extensions.tsx +1 -1
  186. package/corpus/templates/dispatch/app/global.css +1 -1
  187. package/corpus/templates/dispatch/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  188. package/corpus/templates/dispatch/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  189. package/corpus/templates/dispatch/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  190. package/corpus/templates/dispatch/netlify.toml +1 -0
  191. package/corpus/templates/forms/app/components/layout/Layout.tsx +3 -0
  192. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +113 -82
  193. package/corpus/templates/forms/app/global.css +1 -1
  194. package/corpus/templates/forms/app/routes/_app.extensions._index.tsx +2 -2
  195. package/corpus/templates/forms/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  196. package/corpus/templates/forms/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  197. package/corpus/templates/forms/changelog/2026-07-24-forms-sidebar-actions-now-keep-search-language-feedback-and-.md +6 -0
  198. package/corpus/templates/forms/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  199. package/corpus/templates/forms/netlify.toml +1 -0
  200. package/corpus/templates/macros/app/components/DailyProgress.tsx +5 -5
  201. package/corpus/templates/macros/app/components/ExerciseCard.tsx +2 -2
  202. package/corpus/templates/macros/app/components/MealCard.tsx +2 -2
  203. package/corpus/templates/macros/app/components/WeightCard.tsx +2 -2
  204. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +92 -34
  205. package/corpus/templates/macros/app/components/ui/button.tsx +1 -2
  206. package/corpus/templates/macros/app/components/ui/card.tsx +1 -1
  207. package/corpus/templates/macros/app/global.css +1 -1
  208. package/corpus/templates/macros/app/routes/_index.tsx +1 -1
  209. package/corpus/templates/macros/app/routes/analytics.tsx +4 -7
  210. package/corpus/templates/macros/app/routes/extensions._index.tsx +2 -2
  211. package/corpus/templates/macros/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  212. package/corpus/templates/macros/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  213. package/corpus/templates/macros/netlify.toml +1 -0
  214. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +125 -46
  215. package/corpus/templates/mail/app/global.css +1 -1
  216. package/corpus/templates/mail/app/routes/extensions._index.tsx +2 -2
  217. package/corpus/templates/mail/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  218. package/corpus/templates/mail/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  219. package/corpus/templates/mail/netlify.toml +1 -0
  220. package/corpus/templates/plan/app/components/layout/Layout.tsx +3 -0
  221. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +128 -65
  222. package/corpus/templates/plan/app/global.css +1 -1
  223. package/corpus/templates/plan/app/routes/extensions._index.tsx +2 -2
  224. package/corpus/templates/plan/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  225. package/corpus/templates/plan/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  226. package/corpus/templates/plan/netlify.toml +1 -0
  227. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +116 -36
  228. package/corpus/templates/slides/app/global.css +1 -1
  229. package/corpus/templates/slides/app/routes/extensions._index.tsx +2 -2
  230. package/corpus/templates/slides/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  231. package/corpus/templates/slides/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  232. package/corpus/templates/slides/netlify.toml +1 -0
  233. package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +37 -6
  234. package/corpus/templates/tasks/app/global.css +1 -1
  235. package/corpus/templates/tasks/app/routes/extensions._index.tsx +2 -2
  236. package/corpus/templates/tasks/app/routes/settings.tsx +31 -0
  237. package/corpus/templates/tasks/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  238. package/corpus/templates/tasks/netlify.toml +1 -0
  239. package/corpus/toolkit/CHANGELOG.md +8 -0
  240. package/corpus/toolkit/README.md +8 -1
  241. package/corpus/toolkit/agent-native.eject.json +1 -1
  242. package/corpus/toolkit/package.json +1 -1
  243. package/corpus/toolkit/src/app-shell/index.ts +1 -0
  244. package/corpus/toolkit/src/app-shell/sidebar-footer-actions.tsx +48 -0
  245. package/corpus/toolkit/src/chat-history.css +52 -1
  246. package/corpus/toolkit/src/design-system/default-adapter.tsx +1 -1
  247. package/corpus/toolkit/src/ui/button.tsx +1 -2
  248. package/corpus/toolkit/src/ui/card.tsx +1 -1
  249. package/corpus/toolkit/src/ui/table.tsx +4 -11
  250. package/dist/agent/production-agent.d.ts.map +1 -1
  251. package/dist/agent/production-agent.js +4 -0
  252. package/dist/agent/production-agent.js.map +1 -1
  253. package/dist/agent/run-manager.d.ts +9 -0
  254. package/dist/agent/run-manager.d.ts.map +1 -1
  255. package/dist/agent/run-manager.js +25 -10
  256. package/dist/agent/run-manager.js.map +1 -1
  257. package/dist/agent/types.d.ts +2 -2
  258. package/dist/agent/types.d.ts.map +1 -1
  259. package/dist/agent/types.js.map +1 -1
  260. package/dist/cli/context-xray-local.js +1 -1
  261. package/dist/cli/context-xray-local.js.map +1 -1
  262. package/dist/cli/index.js +56 -17
  263. package/dist/cli/index.js.map +1 -1
  264. package/dist/cli/skills.d.ts.map +1 -1
  265. package/dist/cli/skills.js +5 -0
  266. package/dist/cli/skills.js.map +1 -1
  267. package/dist/cli/telemetry.d.ts +7 -0
  268. package/dist/cli/telemetry.d.ts.map +1 -1
  269. package/dist/cli/telemetry.js +91 -1
  270. package/dist/cli/telemetry.js.map +1 -1
  271. package/dist/client/AgentPanel.d.ts +7 -1
  272. package/dist/client/AgentPanel.d.ts.map +1 -1
  273. package/dist/client/AgentPanel.js +2 -2
  274. package/dist/client/AgentPanel.js.map +1 -1
  275. package/dist/client/CommandMenu.d.ts +2 -0
  276. package/dist/client/CommandMenu.d.ts.map +1 -1
  277. package/dist/client/CommandMenu.js +12 -1
  278. package/dist/client/CommandMenu.js.map +1 -1
  279. package/dist/client/agent-page/AgentTabsPage.d.ts +4 -0
  280. package/dist/client/agent-page/AgentTabsPage.d.ts.map +1 -1
  281. package/dist/client/agent-page/AgentTabsPage.js +8 -4
  282. package/dist/client/agent-page/AgentTabsPage.js.map +1 -1
  283. package/dist/client/analytics.d.ts.map +1 -1
  284. package/dist/client/analytics.js +7 -0
  285. package/dist/client/analytics.js.map +1 -1
  286. package/dist/client/error-capture.d.ts.map +1 -1
  287. package/dist/client/error-capture.js +8 -1
  288. package/dist/client/error-capture.js.map +1 -1
  289. package/dist/client/extensions/ExtensionsListPage.d.ts +5 -1
  290. package/dist/client/extensions/ExtensionsListPage.d.ts.map +1 -1
  291. package/dist/client/extensions/ExtensionsListPage.js +6 -4
  292. package/dist/client/extensions/ExtensionsListPage.js.map +1 -1
  293. package/dist/client/extensions/agent-native-extension-runtime.js +1 -1
  294. package/dist/client/extensions/agent-native-extension-runtime.js.map +1 -1
  295. package/dist/client/navigation/index.d.ts +1 -1
  296. package/dist/client/navigation/index.d.ts.map +1 -1
  297. package/dist/client/navigation/index.js +1 -1
  298. package/dist/client/navigation/index.js.map +1 -1
  299. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  300. package/dist/client/org/OrgSwitcher.js +9 -13
  301. package/dist/client/org/OrgSwitcher.js.map +1 -1
  302. package/dist/client/settings/ExtensionsSettingsContent.d.ts +2 -0
  303. package/dist/client/settings/ExtensionsSettingsContent.d.ts.map +1 -0
  304. package/dist/client/settings/ExtensionsSettingsContent.js +10 -0
  305. package/dist/client/settings/ExtensionsSettingsContent.js.map +1 -0
  306. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  307. package/dist/client/settings/SettingsPanel.js +10 -1
  308. package/dist/client/settings/SettingsPanel.js.map +1 -1
  309. package/dist/deploy/build.js +1 -0
  310. package/dist/deploy/build.js.map +1 -1
  311. package/dist/extensions/theme.js +1 -1
  312. package/dist/extensions/theme.js.map +1 -1
  313. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  314. package/dist/localization/default-messages.d.ts +2 -0
  315. package/dist/localization/default-messages.d.ts.map +1 -1
  316. package/dist/localization/default-messages.js +2 -0
  317. package/dist/localization/default-messages.js.map +1 -1
  318. package/dist/observability/routes.d.ts +3 -3
  319. package/dist/progress/routes.d.ts +1 -1
  320. package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
  321. package/dist/provider-api/actions/provider-api.d.ts +9 -9
  322. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  323. package/dist/resources/handlers.d.ts +1 -1
  324. package/dist/server/analytics.d.ts +9 -4
  325. package/dist/server/analytics.d.ts.map +1 -1
  326. package/dist/server/analytics.js +111 -22
  327. package/dist/server/analytics.js.map +1 -1
  328. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  329. package/dist/server/core-routes-plugin.js +8 -1
  330. package/dist/server/core-routes-plugin.js.map +1 -1
  331. package/dist/server/framework-request-handler.d.ts.map +1 -1
  332. package/dist/server/framework-request-handler.js +17 -27
  333. package/dist/server/framework-request-handler.js.map +1 -1
  334. package/dist/server/realtime-token.d.ts +1 -1
  335. package/dist/styles/agent-native.css +13 -0
  336. package/dist/templates/chat/app/components/layout/Layout.tsx +3 -0
  337. package/dist/templates/chat/app/components/layout/Sidebar.tsx +113 -51
  338. package/dist/templates/chat/app/global.css +1 -1
  339. package/dist/templates/chat/app/routes/extensions._index.tsx +2 -2
  340. package/dist/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  341. package/dist/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  342. package/dist/templates/chat/netlify.toml +1 -0
  343. package/dist/templates/default/app/global.css +1 -1
  344. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +16 -0
  345. package/dist/tracking/error-capture.d.ts +14 -0
  346. package/dist/tracking/error-capture.d.ts.map +1 -0
  347. package/dist/tracking/error-capture.js +113 -0
  348. package/dist/tracking/error-capture.js.map +1 -0
  349. package/dist/tracking/index.d.ts +1 -0
  350. package/dist/tracking/index.d.ts.map +1 -1
  351. package/dist/tracking/index.js +1 -0
  352. package/dist/tracking/index.js.map +1 -1
  353. package/dist/vite/client.d.ts.map +1 -1
  354. package/dist/vite/client.js +2 -0
  355. package/dist/vite/client.js.map +1 -1
  356. package/docs/content/extensions.mdx +23 -4
  357. package/package.json +2 -2
  358. package/src/agent/production-agent.ts +4 -0
  359. package/src/agent/run-manager.ts +36 -10
  360. package/src/agent/types.ts +2 -0
  361. package/src/cli/context-xray-local.ts +1 -1
  362. package/src/cli/index.ts +63 -18
  363. package/src/cli/skills.ts +5 -0
  364. package/src/cli/telemetry.ts +118 -1
  365. package/src/client/AgentPanel.tsx +10 -0
  366. package/src/client/CommandMenu.tsx +13 -1
  367. package/src/client/agent-page/AgentTabsPage.tsx +39 -4
  368. package/src/client/analytics.ts +13 -0
  369. package/src/client/error-capture.ts +6 -1
  370. package/src/client/extensions/ExtensionsListPage.tsx +28 -8
  371. package/src/client/extensions/agent-native-extension-runtime.ts +1 -1
  372. package/src/client/navigation/index.ts +2 -0
  373. package/src/client/org/OrgSwitcher.tsx +14 -32
  374. package/src/client/settings/ExtensionsSettingsContent.tsx +24 -0
  375. package/src/client/settings/SettingsPanel.tsx +10 -0
  376. package/src/deploy/build.ts +3 -0
  377. package/src/extensions/theme.ts +1 -1
  378. package/src/localization/default-messages.ts +2 -0
  379. package/src/server/analytics.ts +154 -25
  380. package/src/server/core-routes-plugin.ts +10 -1
  381. package/src/server/framework-request-handler.ts +17 -26
  382. package/src/styles/agent-native.css +13 -0
  383. package/src/templates/chat/app/components/layout/Layout.tsx +3 -0
  384. package/src/templates/chat/app/components/layout/Sidebar.tsx +113 -51
  385. package/src/templates/chat/app/global.css +1 -1
  386. package/src/templates/chat/app/routes/extensions._index.tsx +2 -2
  387. package/src/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  388. package/src/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  389. package/src/templates/chat/netlify.toml +1 -0
  390. package/src/templates/default/app/global.css +1 -1
  391. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +16 -0
  392. package/src/tracking/error-capture.ts +151 -0
  393. package/src/tracking/index.ts +5 -0
  394. package/src/vite/client.ts +6 -0
  395. package/corpus/templates/analytics/app/components/layout/NewAnalysisDialog.tsx +0 -165
  396. package/corpus/templates/analytics/app/pages/analyses/AnalysesList.tsx +0 -175
@@ -5,6 +5,7 @@ import {
5
5
  IconExternalLink,
6
6
  IconFolder,
7
7
  IconHistory,
8
+ IconHelpCircle,
8
9
  IconHierarchy2,
9
10
  IconNotes,
10
11
  IconPlugConnected,
@@ -421,7 +422,19 @@ interface AccessUrls {
421
422
  agentCardUrl: string;
422
423
  }
423
424
 
424
- function CopyField({ label, value }: { label: string; value: string }) {
425
+ export const AGENT_ACCESS_DOCS_HREF = {
426
+ mcp: "https://agent-native.com/docs/mcp-protocol",
427
+ a2a: "https://agent-native.com/docs/a2a-protocol",
428
+ } as const;
429
+
430
+ interface CopyFieldProps {
431
+ label: string;
432
+ value: string;
433
+ docsHref?: string;
434
+ docsLabel?: string;
435
+ }
436
+
437
+ function CopyField({ label, value, docsHref, docsLabel }: CopyFieldProps) {
425
438
  const [copied, setCopied] = useState(false);
426
439
  const copy = async () => {
427
440
  try {
@@ -435,8 +448,20 @@ function CopyField({ label, value }: { label: string; value: string }) {
435
448
  return (
436
449
  <div className="flex min-w-0 items-center gap-2 rounded-md border border-border bg-muted/20 p-2">
437
450
  <div className="min-w-0 flex-1">
438
- <div className="text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/70">
451
+ <div className="flex items-center gap-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/70">
439
452
  {label}
453
+ {docsHref && (
454
+ <a
455
+ href={docsHref}
456
+ target="_blank"
457
+ rel="noopener noreferrer"
458
+ aria-label={docsLabel ?? `Open ${label} documentation`}
459
+ title={docsLabel ?? `Open ${label} documentation`}
460
+ className="inline-flex size-4 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:text-foreground"
461
+ >
462
+ <IconHelpCircle className="size-3" />
463
+ </a>
464
+ )}
440
465
  </div>
441
466
  <code className="mt-1 block truncate text-xs text-foreground">
442
467
  {value}
@@ -530,9 +555,19 @@ function AccessTab({
530
555
  <div className="space-y-6">
531
556
  {urls ? (
532
557
  <>
533
- <CopyField label="MCP URL" value={urls.mcpUrl} />
558
+ <CopyField
559
+ label="MCP URL"
560
+ value={urls.mcpUrl}
561
+ docsHref={AGENT_ACCESS_DOCS_HREF.mcp}
562
+ docsLabel="Open MCP documentation"
563
+ />
534
564
  {agentCardAvailable && (
535
- <CopyField label="A2A agent card" value={urls.agentCardUrl} />
565
+ <CopyField
566
+ label="A2A agent card"
567
+ value={urls.agentCardUrl}
568
+ docsHref={AGENT_ACCESS_DOCS_HREF.a2a}
569
+ docsLabel="Open A2A documentation"
570
+ />
536
571
  )}
537
572
  <section className="space-y-3 border-t border-border/70 pt-6">
538
573
  <div>
@@ -14,6 +14,7 @@ import {
14
14
  installErrorCapture,
15
15
  type CapturedExceptionEvent,
16
16
  } from "./error-capture.js";
17
+ import { isDynamicImportFailureMessage } from "./route-chunk-recovery.js";
17
18
  import type {
18
19
  SessionReplayOptions,
19
20
  SessionReplayStartResult,
@@ -677,6 +678,18 @@ function shouldDropBrowserSentryNoise(event: Sentry.Event): boolean {
677
678
  typeof event.tags?.url === "string" ? event.tags.url : undefined;
678
679
  const requestUrl = (event.request?.url ?? taggedUrl ?? "").toLowerCase();
679
680
  const isDocsPage = isAgentNativeDocsUrl(requestUrl);
681
+ // React Router's stale-chunk recovery handles these failures by reloading
682
+ // the page. Keep the external Sentry stream aligned with first-party
683
+ // capture, which already drops the prevented browser event.
684
+ if (
685
+ exceptionValues.some((value) =>
686
+ isDynamicImportFailureMessage(
687
+ `${value.type ?? ""}: ${value.value ?? ""}`,
688
+ ),
689
+ )
690
+ ) {
691
+ return true;
692
+ }
680
693
  // A server-owned run can emit an expected run_timeout while handing off to
681
694
  // its continuation. AssistantChat retries these transitions automatically;
682
695
  // only locally timed-out or ultimately unrecoverable runs should create a
@@ -383,7 +383,7 @@ function shouldIgnoreAutoCapturedError(normalized: {
383
383
  /\binjectScriptAdjust\.js\b/i.test(stack);
384
384
  if (
385
385
  hasExtensionFrame &&
386
- /^(?:TypeError:\s*)?Failed to fetch$/i.test(message)
386
+ /^(?:TypeError:\s*)?Failed to fetch(?:\s*\([^)]*\))?$/i.test(message)
387
387
  ) {
388
388
  return true;
389
389
  }
@@ -614,6 +614,10 @@ export function installErrorCapture(
614
614
  if (runtime.config.captureGlobalErrors) {
615
615
  const onError = (event: ErrorEvent) => {
616
616
  try {
617
+ // Route-chunk recovery and other host listeners may intentionally
618
+ // prevent a browser error after handling it. Respect that decision so
619
+ // the same transient failure is not stored as an application issue.
620
+ if (event.defaultPrevented) return;
617
621
  const normalized = normalizeGlobalErrorEvent(event);
618
622
  if (shouldIgnoreAutoCapturedError(normalized)) return;
619
623
  // Global errors are already logged by the session replay recorder, so
@@ -639,6 +643,7 @@ export function installErrorCapture(
639
643
  if (runtime.config.captureUnhandledRejections) {
640
644
  const onRejection = (event: PromiseRejectionEvent) => {
641
645
  try {
646
+ if (event.defaultPrevented) return;
642
647
  const reason = event?.reason;
643
648
  const normalized = normalizeCapturedError(reason);
644
649
  if (!normalized.type || normalized.type === "Error") {
@@ -99,7 +99,14 @@ function CreateToolInput({ className }: { className?: string }) {
99
99
  );
100
100
  }
101
101
 
102
- export function ExtensionsListPage() {
102
+ export interface ExtensionsListPageProps {
103
+ /** Skip the standalone extensions navigation state when embedded in Settings. */
104
+ embedded?: boolean;
105
+ }
106
+
107
+ export function ExtensionsListPage({
108
+ embedded = false,
109
+ }: ExtensionsListPageProps = {}) {
103
110
  const t = useT();
104
111
  const [showCreate, setShowCreate] = useState(false);
105
112
  const [confirmDeleteId, setConfirmDeleteId] = useState<string | null>(null);
@@ -111,12 +118,13 @@ export function ExtensionsListPage() {
111
118
  );
112
119
 
113
120
  useEffect(() => {
121
+ if (embedded) return;
114
122
  fetch(agentNativePath("/_agent-native/application-state/navigation"), {
115
123
  method: "PUT",
116
124
  headers: { "Content-Type": "application/json" },
117
125
  body: JSON.stringify({ view: "extensions" }),
118
126
  }).catch(() => {});
119
- }, []);
127
+ }, [embedded]);
120
128
 
121
129
  useEffect(() => {
122
130
  if (typeof window === "undefined") return;
@@ -189,11 +197,23 @@ export function ExtensionsListPage() {
189
197
  };
190
198
 
191
199
  return (
192
- <div className="flex h-full w-full flex-col">
193
- <header className="flex h-12 items-center justify-between border-b px-4 shrink-0">
194
- <div className="flex items-center gap-2">
195
- <h1 className="text-sm font-semibold">{t("extensions.title")}</h1>
196
- </div>
200
+ <div
201
+ className={cn(
202
+ "flex w-full flex-col",
203
+ embedded ? "min-h-[28rem]" : "h-full",
204
+ )}
205
+ >
206
+ <header
207
+ className={cn(
208
+ "flex h-12 items-center justify-between px-4 shrink-0",
209
+ !embedded && "border-b",
210
+ )}
211
+ >
212
+ {!embedded ? (
213
+ <div className="flex items-center gap-2">
214
+ <h1 className="text-sm font-semibold">{t("extensions.title")}</h1>
215
+ </div>
216
+ ) : null}
197
217
  <div className="flex items-center gap-2">
198
218
  <Popover open={showCreate} onOpenChange={setShowCreate}>
199
219
  <PopoverTrigger asChild>
@@ -244,7 +264,7 @@ export function ExtensionsListPage() {
244
264
  </DropdownMenuCheckboxItem>
245
265
  </DropdownMenuContent>
246
266
  </DropdownMenu>
247
- <AgentToggleButton />
267
+ {!embedded ? <AgentToggleButton /> : null}
248
268
  </div>
249
269
  </header>
250
270
 
@@ -127,7 +127,7 @@ const defaultThemeCss = `
127
127
  --border: 217.2 32.6% 17.5%;
128
128
  --primary: 217.2 91.2% 59.8%;
129
129
  --primary-foreground: 222.2 47.4% 11.2%;
130
- --destructive: 0 84% 60%;
130
+ --destructive: 0 91% 71%;
131
131
  --destructive-foreground: 210 40% 98%;
132
132
  }
133
133
  html, body {
@@ -15,9 +15,11 @@ export {
15
15
  type UseSemanticNavigationStateResult,
16
16
  } from "../route-state.js";
17
17
  export {
18
+ COMMAND_MENU_OPEN_EVENT,
18
19
  CommandMenu,
19
20
  openAgentSidebar,
20
21
  openAgentSettings,
22
+ openCommandMenu,
21
23
  submitToAgent,
22
24
  useCommandMenuShortcut,
23
25
  type CommandMenuProps,
@@ -102,7 +102,7 @@ const APP_SUBMENU_CONTENT_CLASS =
102
102
  "z-50 w-72 rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2";
103
103
 
104
104
  const SWITCHER_BUTTON_CLASS =
105
- "flex w-full items-center gap-2 rounded-md border border-border/70 px-2.5 py-1.5 text-xs font-medium text-muted-foreground hover:bg-accent/50 hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-60 cursor-pointer";
105
+ "flex w-full items-center gap-2 rounded-md border-0 bg-accent/50 px-2.5 py-1.5 text-xs font-medium text-muted-foreground hover:bg-accent/70 hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-60 cursor-pointer";
106
106
 
107
107
  const DEFAULT_ORGANIZATION_SETTINGS_PATH = "/settings#organization";
108
108
  const DEFAULT_PROFILE_PATH = "/settings#account";
@@ -151,33 +151,29 @@ function AppMenuLink({
151
151
  onNavigate: () => void;
152
152
  }) {
153
153
  const Icon = appMenuIcon(app);
154
+ const description =
155
+ app.status === "pending"
156
+ ? "Building"
157
+ : app.description?.trim() ||
158
+ (app.isDispatch ? "Workspace hub" : `${app.name} workspace`);
154
159
  return (
155
160
  <a
156
161
  href={app.href}
157
162
  onClick={onNavigate}
158
- className={`flex items-center gap-2 rounded-sm px-2.5 py-2 text-xs outline-none hover:bg-accent focus:bg-accent ${
159
- app.isDispatch ? "border border-primary/20 bg-primary/5" : ""
160
- }`}
163
+ className="flex items-center gap-2 rounded-sm px-2.5 py-2 text-xs outline-none hover:bg-accent focus:bg-accent"
161
164
  >
162
- <span
163
- className={`flex h-7 w-7 shrink-0 items-center justify-center rounded-md ${
164
- app.isDispatch
165
- ? "bg-primary text-primary-foreground"
166
- : "bg-muted text-muted-foreground"
167
- }`}
168
- >
165
+ <span className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground">
169
166
  <Icon className="h-3.5 w-3.5" />
170
167
  </span>
171
168
  <span className="min-w-0 flex-1">
172
169
  <span className="block truncate font-medium text-foreground">
173
170
  {app.name}
174
171
  </span>
175
- <span className="block truncate text-[11px] text-muted-foreground">
176
- {app.isDispatch
177
- ? "Main hub"
178
- : app.status === "pending"
179
- ? "Building"
180
- : "Open app"}
172
+ <span
173
+ className="block truncate text-[11px] text-muted-foreground"
174
+ title={description}
175
+ >
176
+ {description}
181
177
  </span>
182
178
  </span>
183
179
  <IconArrowUpRight className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
@@ -187,14 +183,12 @@ function AppMenuLink({
187
183
 
188
184
  function AppsSubmenu({
189
185
  apps,
190
- isWorkspace,
191
186
  isLoading,
192
187
  dispatchHref,
193
188
  dispatchAllAppsHref,
194
189
  onNavigate,
195
190
  }: {
196
191
  apps: OrgSwitcherAppLink[];
197
- isWorkspace: boolean;
198
192
  isLoading: boolean;
199
193
  dispatchHref: string;
200
194
  dispatchAllAppsHref: string;
@@ -241,17 +235,6 @@ function AppsSubmenu({
241
235
  collisionPadding={12}
242
236
  className={APP_SUBMENU_CONTENT_CLASS}
243
237
  >
244
- <div className="px-2.5 py-1.5">
245
- <div className="text-[10px] uppercase tracking-wide text-muted-foreground">
246
- {isWorkspace ? "Workspace apps" : "Default apps"}
247
- </div>
248
- <div className="mt-0.5 text-[11px] text-muted-foreground">
249
- {isWorkspace
250
- ? "Dispatch is the workspace hub."
251
- : "Dispatch is the home base."}
252
- </div>
253
- </div>
254
-
255
238
  <AppMenuLink app={dispatchApp} onNavigate={onNavigate} />
256
239
 
257
240
  {visibleNonDispatch.length > 0 && (
@@ -269,7 +252,7 @@ function AppsSubmenu({
269
252
  onClick={onNavigate}
270
253
  className="flex items-center gap-2 rounded-sm px-2.5 py-1.5 text-xs text-foreground outline-none hover:bg-accent focus:bg-accent"
271
254
  >
272
- <IconMessageCircle className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
255
+ <IconApps className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
273
256
  <span className="flex-1">
274
257
  {`View ${remainingCount} more in Dispatch`}
275
258
  </span>
@@ -549,7 +532,6 @@ export function OrgSwitcher({
549
532
  <div className="my-1 h-px bg-border" />
550
533
  <AppsSubmenu
551
534
  apps={appLinks.apps}
552
- isWorkspace={appLinks.isWorkspace}
553
535
  isLoading={appLinks.isLoading}
554
536
  dispatchHref={appLinks.dispatchHref}
555
537
  dispatchAllAppsHref={appLinks.dispatchAllAppsHref}
@@ -0,0 +1,24 @@
1
+ import { IconLoader2 } from "@tabler/icons-react";
2
+ import { lazy, Suspense } from "react";
3
+
4
+ const ExtensionsListPage = lazy(() =>
5
+ import("../extensions/ExtensionsListPage.js").then((module) => ({
6
+ default: module.ExtensionsListPage,
7
+ })),
8
+ );
9
+
10
+ export function ExtensionsSettingsContent() {
11
+ return (
12
+ <div className="mx-auto w-full max-w-5xl">
13
+ <Suspense
14
+ fallback={
15
+ <div className="flex min-h-[28rem] items-center justify-center text-muted-foreground">
16
+ <IconLoader2 className="size-5 animate-spin" aria-label="Loading" />
17
+ </div>
18
+ }
19
+ >
20
+ <ExtensionsListPage embedded />
21
+ </Suspense>
22
+ </div>
23
+ );
24
+ }
@@ -29,6 +29,7 @@ import {
29
29
  IconGauge,
30
30
  IconApps,
31
31
  IconUsersGroup,
32
+ IconTool,
32
33
  } from "@tabler/icons-react";
33
34
  import React, {
34
35
  Suspense,
@@ -67,6 +68,7 @@ import {
67
68
  import { AgentsSection } from "./AgentsSection.js";
68
69
  import { AutomationsSection } from "./AutomationsSection.js";
69
70
  import { DemoModeSection } from "./DemoModeSection.js";
71
+ import { ExtensionsSettingsContent } from "./ExtensionsSettingsContent.js";
70
72
  import { SecretsSection } from "./SecretsSection.js";
71
73
  import {
72
74
  SettingsSection,
@@ -3037,6 +3039,14 @@ export function useAgentSettingsTabs(): SettingsTabItem[] {
3037
3039
  />
3038
3040
  ),
3039
3041
  },
3042
+ {
3043
+ id: "extensions",
3044
+ label: "Extensions",
3045
+ icon: IconTool,
3046
+ group: "workspace",
3047
+ keywords: "extensions widgets mini apps tools sandboxed apps",
3048
+ content: <ExtensionsSettingsContent />,
3049
+ },
3040
3050
  ];
3041
3051
  }, [baseProps]);
3042
3052
  }
@@ -3708,6 +3708,9 @@ export default bundle;
3708
3708
  "process.env.AGENT_NATIVE_BUILD_GA_MEASUREMENT_ID": JSON.stringify(
3709
3709
  process.env.GA_MEASUREMENT_ID?.trim() || "",
3710
3710
  ),
3711
+ "process.env.AGENT_NATIVE_BUILD_GTM_CONTAINER_ID": JSON.stringify(
3712
+ process.env.GTM_CONTAINER_ID?.trim() || "",
3713
+ ),
3711
3714
  "process.env.AGENT_NATIVE_BUILD_DEPLOY_CONTEXT": JSON.stringify(
3712
3715
  process.env.CONTEXT?.trim() || "",
3713
3716
  ),
@@ -92,7 +92,7 @@ export function getThemeVars(_isDark?: boolean): string {
92
92
  --muted-foreground: 240 5% 64.9%;
93
93
  --accent: 240 3.7% 15.9%;
94
94
  --accent-foreground: 0 0% 98%;
95
- --destructive: 0 84% 60%;
95
+ --destructive: 0 91% 71%;
96
96
  --destructive-foreground: 0 0% 98%;
97
97
  --border: 240 3.7% 15.9%;
98
98
  --input: 240 3.7% 15.9%;
@@ -172,6 +172,7 @@ const messages = {
172
172
  workspaceControlPlane: "Workspace control plane",
173
173
  workspaceSubtitle_one: "Workspace · {{count}} app",
174
174
  workspaceSubtitle_other: "Workspace · {{count}} apps",
175
+ search: "Search",
175
176
  chats: "Chats",
176
177
  newChat: "New chat",
177
178
  newDispatchChat: "New Dispatch chat",
@@ -310,6 +311,7 @@ const messages = {
310
311
  newTerminal: "New terminal",
311
312
  panelOptions: "Agent panel options",
312
313
  collapseSidebar: "Collapse sidebar",
314
+ expandSidebar: "Expand sidebar",
313
315
  hideChats: "Hide chats",
314
316
  allChats: "All chats",
315
317
  settings: "Settings",
@@ -2,16 +2,21 @@
2
2
  * Opt-in analytics injection for SSR streams.
3
3
  * Supported environment variables:
4
4
  * - `GA_MEASUREMENT_ID` — Google Analytics 4 measurement ID
5
+ * - `GTM_CONTAINER_ID` — Google Tag Manager web container ID
5
6
  *
6
7
  * Netlify configuration-file env vars are build-time only for serverless
7
8
  * functions, so the Vite/Nitro build paths also bake this public value into
8
9
  * SSR bundles.
9
10
  *
10
11
  * Amplitude and Sentry are initialized client-side via their npm packages
11
- * (see `packages/core/src/client/analytics.ts`). Only GA requires script
12
- * tag injection because the gtag.js loader must be a `<script src>`.
12
+ * (see `packages/core/src/client/analytics.ts`). GTM and GA require script
13
+ * tag injection because their loaders must be `<script>` elements.
13
14
  *
14
- * When set, the corresponding script tags are injected before `</head>`.
15
+ * When GTM is set, its head bootstrap is injected before `</head>` and its
16
+ * noscript fallback immediately after `<body>`. GTM takes precedence over GA
17
+ * so pageviews are not double-counted; configure the GA tag inside GTM.
18
+ * When only GA is set, the corresponding script tags are injected before
19
+ * `</head>`.
15
20
  * When not set, the stream passes through untouched (zero overhead).
16
21
  *
17
22
  * Usage in entry.server.tsx:
@@ -22,6 +27,7 @@
22
27
  */
23
28
 
24
29
  declare const __AGENT_NATIVE_BUILD_GA_MEASUREMENT_ID__: string | undefined;
30
+ declare const __AGENT_NATIVE_BUILD_GTM_CONTAINER_ID__: string | undefined;
25
31
 
26
32
  function normalizeMeasurementId(value: string | undefined): string | null {
27
33
  const trimmed = value?.trim();
@@ -34,6 +40,25 @@ function getViteBakedGaMeasurementId(): string | undefined {
34
40
  : undefined;
35
41
  }
36
42
 
43
+ function normalizeContainerId(value: string | undefined): string | null {
44
+ const trimmed = value?.trim().toUpperCase();
45
+ return trimmed && /^GTM-[A-Z0-9]+$/.test(trimmed) ? trimmed : null;
46
+ }
47
+
48
+ function getViteBakedGtmContainerId(): string | undefined {
49
+ return typeof __AGENT_NATIVE_BUILD_GTM_CONTAINER_ID__ === "string"
50
+ ? __AGENT_NATIVE_BUILD_GTM_CONTAINER_ID__
51
+ : undefined;
52
+ }
53
+
54
+ function getGtmContainerId(): string | null {
55
+ return (
56
+ normalizeContainerId(process.env.GTM_CONTAINER_ID) ||
57
+ normalizeContainerId(process.env.AGENT_NATIVE_BUILD_GTM_CONTAINER_ID) ||
58
+ normalizeContainerId(getViteBakedGtmContainerId())
59
+ );
60
+ }
61
+
37
62
  function getGaMeasurementId(): string | null {
38
63
  return (
39
64
  normalizeMeasurementId(process.env.GA_MEASUREMENT_ID) ||
@@ -74,6 +99,37 @@ function getGaScript(): string | null {
74
99
  );
75
100
  }
76
101
 
102
+ function getGtmHeadScript(containerId: string): string {
103
+ const jsId = JSON.stringify(containerId);
104
+ return `<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer',${jsId});</script>`;
105
+ }
106
+
107
+ function getGtmBodyFallback(containerId: string): string {
108
+ const src = encodeURIComponent(containerId);
109
+ return `<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=${src}" height="0" width="0" style="display:none;visibility:hidden" title="Google Tag Manager"></iframe></noscript>`;
110
+ }
111
+
112
+ type AnalyticsInjection = {
113
+ head: string;
114
+ body: string;
115
+ };
116
+
117
+ function getAnalyticsInjection(): AnalyticsInjection | null {
118
+ const containerId = getGtmContainerId();
119
+ if (containerId) {
120
+ return {
121
+ head: getGtmHeadScript(containerId),
122
+ body: getGtmBodyFallback(containerId),
123
+ };
124
+ }
125
+
126
+ const gaScript = getGaScript();
127
+ return gaScript ? { head: gaScript, body: "" } : null;
128
+ }
129
+
130
+ const HEAD_CLOSE_PATTERN = /<\/head>/i;
131
+ const BODY_OPEN_PATTERN = /<body\b[^>]*>/i;
132
+
77
133
  /**
78
134
  * Add the configured analytics scripts to a complete HTML document.
79
135
  *
@@ -82,38 +138,111 @@ function getGaScript(): string | null {
82
138
  * auth guard and need the same injection path.
83
139
  */
84
140
  export function injectAnalyticsIntoHtml(html: string): string {
85
- const script = getGaScript();
86
- if (!script) return html;
87
- const headCloseIdx = html.indexOf("</head>");
88
- if (headCloseIdx === -1) return html;
89
- return html.slice(0, headCloseIdx) + script + html.slice(headCloseIdx);
141
+ const injection = getAnalyticsInjection();
142
+ if (!injection) return html;
143
+
144
+ const headCloseMatch = HEAD_CLOSE_PATTERN.exec(html);
145
+ if (!headCloseMatch || headCloseMatch.index === undefined) return html;
146
+
147
+ let output =
148
+ html.slice(0, headCloseMatch.index) +
149
+ injection.head +
150
+ html.slice(headCloseMatch.index);
151
+
152
+ if (injection.body) {
153
+ const bodyOpenMatch = BODY_OPEN_PATTERN.exec(output);
154
+ if (bodyOpenMatch && bodyOpenMatch.index !== undefined) {
155
+ const bodyEnd = bodyOpenMatch.index + bodyOpenMatch[0].length;
156
+ output =
157
+ output.slice(0, bodyEnd) + injection.body + output.slice(bodyEnd);
158
+ }
159
+ }
160
+
161
+ return output;
90
162
  }
91
163
 
92
- export function wrapWithAnalytics(body: ReadableStream): ReadableStream {
93
- const scripts = [getGaScript()].filter(Boolean).join("");
94
- if (!scripts) return body;
164
+ export function wrapWithAnalytics(
165
+ body: ReadableStream<Uint8Array>,
166
+ ): ReadableStream<Uint8Array> {
167
+ const injection = getAnalyticsInjection();
168
+ if (!injection) return body;
95
169
 
96
170
  const decoder = new TextDecoder();
97
171
  const encoder = new TextEncoder();
98
- let injected = false;
172
+ let pending = "";
173
+ let headInjected = false;
174
+ let bodyInjected = !injection.body;
99
175
 
100
176
  return body.pipeThrough(
101
- new TransformStream({
177
+ new TransformStream<Uint8Array, Uint8Array>({
102
178
  transform(chunk, controller) {
103
- if (injected) {
104
- controller.enqueue(chunk);
105
- return;
179
+ pending += decoder.decode(chunk, { stream: true });
180
+
181
+ if (!headInjected) {
182
+ const headCloseMatch = HEAD_CLOSE_PATTERN.exec(pending);
183
+ if (!headCloseMatch || headCloseMatch.index === undefined) return;
184
+
185
+ const headEnd = headCloseMatch.index + headCloseMatch[0].length;
186
+ controller.enqueue(
187
+ encoder.encode(
188
+ pending.slice(0, headCloseMatch.index) +
189
+ injection.head +
190
+ pending.slice(headCloseMatch.index, headEnd),
191
+ ),
192
+ );
193
+ pending = pending.slice(headEnd);
194
+ headInjected = true;
106
195
  }
107
- const text = decoder.decode(chunk, { stream: true });
108
- const headCloseIdx = text.indexOf("</head>");
109
- if (headCloseIdx !== -1) {
110
- const modified =
111
- text.slice(0, headCloseIdx) + scripts + text.slice(headCloseIdx);
112
- controller.enqueue(encoder.encode(modified));
113
- injected = true;
114
- } else {
115
- controller.enqueue(chunk);
196
+
197
+ if (!bodyInjected) {
198
+ const bodyOpenMatch = BODY_OPEN_PATTERN.exec(pending);
199
+ if (!bodyOpenMatch || bodyOpenMatch.index === undefined) return;
200
+
201
+ const bodyEnd = bodyOpenMatch.index + bodyOpenMatch[0].length;
202
+ controller.enqueue(
203
+ encoder.encode(pending.slice(0, bodyEnd) + injection.body),
204
+ );
205
+ pending = pending.slice(bodyEnd);
206
+ bodyInjected = true;
116
207
  }
208
+
209
+ if (pending) {
210
+ controller.enqueue(encoder.encode(pending));
211
+ pending = "";
212
+ }
213
+ },
214
+ flush(controller) {
215
+ pending += decoder.decode();
216
+
217
+ if (!headInjected) {
218
+ const headCloseMatch = HEAD_CLOSE_PATTERN.exec(pending);
219
+ if (headCloseMatch && headCloseMatch.index !== undefined) {
220
+ const headEnd = headCloseMatch.index + headCloseMatch[0].length;
221
+ controller.enqueue(
222
+ encoder.encode(
223
+ pending.slice(0, headCloseMatch.index) +
224
+ injection.head +
225
+ pending.slice(headCloseMatch.index, headEnd),
226
+ ),
227
+ );
228
+ pending = pending.slice(headEnd);
229
+ headInjected = true;
230
+ }
231
+ }
232
+
233
+ if (headInjected && !bodyInjected) {
234
+ const bodyOpenMatch = BODY_OPEN_PATTERN.exec(pending);
235
+ if (bodyOpenMatch && bodyOpenMatch.index !== undefined) {
236
+ const bodyEnd = bodyOpenMatch.index + bodyOpenMatch[0].length;
237
+ controller.enqueue(
238
+ encoder.encode(pending.slice(0, bodyEnd) + injection.body),
239
+ );
240
+ pending = pending.slice(bodyEnd);
241
+ bodyInjected = true;
242
+ }
243
+ }
244
+
245
+ if (pending) controller.enqueue(encoder.encode(pending));
117
246
  },
118
247
  }),
119
248
  );