@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
@@ -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
  );
@@ -97,6 +97,7 @@ import {
97
97
  MCP_EMBED_CORS_ALLOW_HEADERS,
98
98
  shouldAllowMcpEmbedCredentials,
99
99
  } from "../shared/mcp-embed-headers.js";
100
+ import { captureException } from "../tracking/error-capture.js";
100
101
  import { track } from "../tracking/index.js";
101
102
  import { registerBuiltinProviders } from "../tracking/providers.js";
102
103
  import { validateTrackPayload } from "../tracking/route.js";
@@ -140,7 +141,7 @@ import {
140
141
  type BuilderRelayCredentials,
141
142
  type BuilderPreviewRelayState,
142
143
  } from "./builder-browser.js";
143
- import { captureError } from "./capture-error.js";
144
+ import { captureError, registerErrorCaptureProvider } from "./capture-error.js";
144
145
  import {
145
146
  getAllowedCorsOrigin,
146
147
  readCorsAllowedOrigins,
@@ -1197,6 +1198,14 @@ export function createCoreRoutesPlugin(
1197
1198
  // already registered the same key win.
1198
1199
  registerFrameworkSecrets();
1199
1200
  registerBuiltinProviders();
1201
+ registerErrorCaptureProvider("agent-native-analytics", (error, context) =>
1202
+ captureException(error, {
1203
+ ...context,
1204
+ handled: false,
1205
+ runtime: "node",
1206
+ source: "server",
1207
+ }),
1208
+ );
1200
1209
  registerBuiltinNotificationChannels();
1201
1210
 
1202
1211
  try {
@@ -602,33 +602,24 @@ function registerMiddleware(
602
602
  status,
603
603
  error: err,
604
604
  });
605
- // Forward 5xx to server-side Sentry — Nitro's own `error` hook may not
606
- // fire here because we convert the throw into a normal JSON response,
607
- // and a console.error alone is invisible in deployed environments.
608
- // 4xx are user-input errors (validation, auth) and aren't worth
609
- // alerting on. Lazy-loaded so the framework-request-handler module
610
- // doesn't pull @sentry/node into bundles that don't need it.
605
+ // Forward 5xx to the configured server error providers — Nitro's own
606
+ // `error` hook may not fire here because we convert the throw into a
607
+ // normal JSON response, and a console.error alone is invisible in
608
+ // deployed environments. 4xx are user-input errors (validation, auth)
609
+ // and aren't worth alerting on.
611
610
  if (status >= 500) {
612
- // Static `import` would create a cycle (sentry.ts imports auth.ts
613
- // which imports… eventually, framework-request-handler.ts).
614
- import("./sentry.js")
615
- .then(({ captureRouteError, isServerSentryEnabled }) => {
616
- if (!isServerSentryEnabled()) return;
617
- captureRouteError(err, {
618
- route: reqPath,
619
- method: event.method,
620
- userAgent: (() => {
621
- try {
622
- return event.headers?.get("user-agent") ?? undefined;
623
- } catch {
624
- return undefined;
625
- }
626
- })(),
627
- });
628
- })
629
- .catch(() => {
630
- // Sentry is observability — never let it break a response path.
631
- });
611
+ captureError(err, {
612
+ route: reqPath,
613
+ method: event.method,
614
+ tags: { status_code: String(status) },
615
+ userAgent: (() => {
616
+ try {
617
+ return event.headers?.get("user-agent") ?? undefined;
618
+ } catch {
619
+ return undefined;
620
+ }
621
+ })(),
622
+ });
632
623
  }
633
624
  try {
634
625
  setResponseStatus(event, status);
@@ -310,6 +310,10 @@
310
310
  opacity: 1;
311
311
  }
312
312
 
313
+ /* A named chat surface already morphs from its old geometry during a
314
+ full-page-chat handoff. Override only the initial style of that panel so it
315
+ does not slide in from the right underneath the morph. Keeping the normal
316
+ rules intact preserves ordinary sidebar open/close animation. */
313
317
  @starting-style {
314
318
  .agent-sidebar-panel[data-agent-sidebar-animation="desktop"][data-agent-sidebar-state="open"] {
315
319
  width: 0;
@@ -330,6 +334,15 @@
330
334
  .agent-sidebar-backdrop[data-agent-sidebar-animation="mobile"][data-agent-sidebar-state="open"] {
331
335
  opacity: 0;
332
336
  }
337
+
338
+ .agent-native-chat-view-transition.agent-sidebar-panel[data-agent-sidebar-animation="desktop"][data-agent-sidebar-chat-handoff="true"] {
339
+ width: var(--agent-sidebar-width);
340
+ }
341
+
342
+ .agent-native-chat-view-transition.agent-sidebar-panel[data-agent-sidebar-animation="desktop"][data-agent-sidebar-chat-handoff="true"]
343
+ > .agent-sidebar-panel-inner {
344
+ transform: translateX(0);
345
+ }
333
346
  }
334
347
 
335
348
  @media (prefers-reduced-motion: reduce) {
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  AgentSidebar,
3
3
  focusAgentChat,
4
+ isAgentChatHomeHandoffActive,
4
5
  navigateWithAgentChatViewTransition,
5
6
  useAgentChatHomeHandoff,
6
7
  useAgentChatHomeHandoffLinks,
@@ -57,6 +58,7 @@ export function Layout({ children }: LayoutProps) {
57
58
  activePath: location.pathname,
58
59
  enabled: !isChatRoute,
59
60
  });
61
+ const chatHomeHandoffPending = isAgentChatHomeHandoffActive("chat");
60
62
  useAgentChatHomeHandoffLinks({
61
63
  storageKey: "chat",
62
64
  isChatPath: (pathname) => pathname === "/" || pathname.startsWith("/chat/"),
@@ -164,6 +166,7 @@ export function Layout({ children }: LayoutProps) {
164
166
  <AgentSidebar
165
167
  position="right"
166
168
  chatViewTransition
169
+ chatViewTransitionHandoff={chatHomeHandoffPending}
167
170
  storageKey="chat"
168
171
  browserTabId={TAB_ID}
169
172
  openOnChatRunning={chatHomeHandoffActive}
@@ -4,10 +4,11 @@ import {
4
4
  type ChatThreadSummary,
5
5
  } from "@agent-native/core/client/agent-chat";
6
6
  import { appPath } from "@agent-native/core/client/api-path";
7
- import { ExtensionsSidebarSection } from "@agent-native/core/client/extensions";
8
- import { useT } from "@agent-native/core/client/i18n";
7
+ import { LanguagePicker, useT } from "@agent-native/core/client/i18n";
8
+ import { openCommandMenu } from "@agent-native/core/client/navigation";
9
9
  import { OrgSwitcher } from "@agent-native/core/client/org";
10
10
  import { FeedbackButton } from "@agent-native/core/client/ui";
11
+ import { SidebarFooterActions } from "@agent-native/toolkit/app-shell";
11
12
  import {
12
13
  ChatHistoryRail,
13
14
  type ChatHistoryItem,
@@ -17,6 +18,7 @@ import {
17
18
  IconLayoutSidebarLeftCollapse,
18
19
  IconLayoutSidebarLeftExpand,
19
20
  IconMessageCircle,
21
+ IconSearch,
20
22
  IconSettings,
21
23
  } from "@tabler/icons-react";
22
24
  import { useEffect, useMemo } from "react";
@@ -38,6 +40,9 @@ const navItems = [
38
40
  href: "/",
39
41
  view: "chat",
40
42
  },
43
+ ];
44
+
45
+ const bottomNavItems = [
41
46
  {
42
47
  icon: IconHierarchy2,
43
48
  labelKey: "settings.agentTitle",
@@ -124,7 +129,7 @@ function chatThreadPath(threadId: string) {
124
129
  return `/chat/${encodeURIComponent(threadId)}`;
125
130
  }
126
131
 
127
- function ChatThreadsSection() {
132
+ function ChatThreadsSection({ open }: { open: boolean }) {
128
133
  const navigate = useNavigate();
129
134
  const location = useLocation();
130
135
  const t = useT();
@@ -228,36 +233,42 @@ function ChatThreadsSection() {
228
233
  }
229
234
 
230
235
  return (
231
- <div className="mt-2 ms-4">
232
- <ChatHistoryRail
233
- items={chatItems}
234
- activeId={displayedActiveThreadId}
235
- onSelect={(threadId) => openThread(threadId)}
236
- onNewChat={() => void handleNewChat()}
237
- railLabels={{
238
- newChat: t("chat.newChat"),
239
- showMore: t("chat.chats"),
240
- showLess: t("chat.chats"),
241
- }}
242
- renameMaxLength={160}
243
- onTogglePin={(threadId) => {
244
- const thread = visibleThreads.find((item) => item.id === threadId);
245
- if (thread) void pinThread(threadId, !thread.pinnedAt);
246
- }}
247
- onRename={handleRenameThread}
248
- onDelete={(threadId) => void handleArchiveThread(threadId)}
249
- labels={{
250
- options: (item) =>
251
- t("chat.optionsFor", { title: item.titleText ?? "" }),
252
- renameInput: (item) =>
253
- t("chat.renameThread", { title: item.titleText ?? "" }),
254
- rename: t("chat.renameChat"),
255
- pin: t("chat.pinChat"),
256
- unpin: t("chat.unpinChat"),
257
- delete: t("chat.archiveChat"),
258
- }}
259
- className="min-w-0"
260
- />
236
+ <div
237
+ className="an-chat-history-rail__collapse"
238
+ data-state={open ? "open" : "closed"}
239
+ aria-hidden={!open}
240
+ >
241
+ <div className="ms-4">
242
+ <ChatHistoryRail
243
+ items={chatItems}
244
+ activeId={displayedActiveThreadId}
245
+ onSelect={(threadId) => openThread(threadId)}
246
+ onNewChat={() => void handleNewChat()}
247
+ railLabels={{
248
+ newChat: t("chat.newChat"),
249
+ showMore: t("chat.chats"),
250
+ showLess: t("chat.chats"),
251
+ }}
252
+ renameMaxLength={160}
253
+ onTogglePin={(threadId) => {
254
+ const thread = visibleThreads.find((item) => item.id === threadId);
255
+ if (thread) void pinThread(threadId, !thread.pinnedAt);
256
+ }}
257
+ onRename={handleRenameThread}
258
+ onDelete={(threadId) => void handleArchiveThread(threadId)}
259
+ labels={{
260
+ options: (item) =>
261
+ t("chat.optionsFor", { title: item.titleText ?? "" }),
262
+ renameInput: (item) =>
263
+ t("chat.renameThread", { title: item.titleText ?? "" }),
264
+ rename: t("chat.renameChat"),
265
+ pin: t("chat.pinChat"),
266
+ unpin: t("chat.unpinChat"),
267
+ delete: t("chat.archiveChat"),
268
+ }}
269
+ className="min-w-0"
270
+ />
271
+ </div>
261
272
  </div>
262
273
  );
263
274
  }
@@ -279,14 +290,14 @@ export function Sidebar({
279
290
  cn(
280
291
  "flex items-center text-sm transition-colors",
281
292
  collapsed
282
- ? "relative h-10 w-full justify-center rounded-none border-s-2 px-0"
293
+ ? "relative h-10 w-full justify-center rounded-none px-0"
283
294
  : "h-9 rounded-md gap-3 px-3",
284
295
  isActive
285
296
  ? collapsed
286
- ? "border-s-sidebar-accent-foreground/80 bg-sidebar-accent text-sidebar-accent-foreground"
297
+ ? "bg-sidebar-accent text-sidebar-accent-foreground"
287
298
  : "bg-sidebar-accent text-sidebar-accent-foreground"
288
299
  : collapsed
289
- ? "border-s-transparent text-sidebar-foreground/70 hover:bg-sidebar-accent/55 hover:text-sidebar-accent-foreground"
300
+ ? "text-sidebar-foreground/70 hover:bg-sidebar-accent/55 hover:text-sidebar-accent-foreground"
290
301
  : "text-sidebar-foreground hover:bg-sidebar-accent/65 hover:text-sidebar-accent-foreground",
291
302
  );
292
303
  const collapseButton = collapsible ? (
@@ -315,6 +326,31 @@ export function Sidebar({
315
326
  </TooltipContent>
316
327
  </Tooltip>
317
328
  ) : null;
329
+ const searchButton = (
330
+ <Tooltip>
331
+ <TooltipTrigger asChild>
332
+ <button
333
+ type="button"
334
+ onClick={openCommandMenu}
335
+ aria-label={t("root.commandSearch")}
336
+ className="flex size-8 items-center justify-center rounded-md text-sidebar-foreground/65 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
337
+ >
338
+ <IconSearch className="size-4" />
339
+ </button>
340
+ </TooltipTrigger>
341
+ <TooltipContent side="right">{t("root.commandSearch")}</TooltipContent>
342
+ </Tooltip>
343
+ );
344
+ const translateButton = (
345
+ <LanguagePicker variant="ghost-icon" label={t("settings.languageLabel")} />
346
+ );
347
+ const feedbackButton = (
348
+ <FeedbackButton
349
+ variant={collapsed ? "icon" : "sidebar"}
350
+ side="right"
351
+ className={collapsed ? "h-8 w-8" : "min-w-0"}
352
+ />
353
+ );
318
354
 
319
355
  return (
320
356
  <aside
@@ -409,8 +445,8 @@ export function Sidebar({
409
445
  ) : (
410
446
  link
411
447
  )}
412
- {!collapsed && item.view === "chat" && isChatRoute ? (
413
- <ChatThreadsSection />
448
+ {!collapsed && item.view === "chat" ? (
449
+ <ChatThreadsSection open={isChatRoute} />
414
450
  ) : null}
415
451
  </div>
416
452
  );
@@ -419,11 +455,38 @@ export function Sidebar({
419
455
  </nav>
420
456
 
421
457
  <div className={cn("mt-auto shrink-0", collapsed && "py-2")}>
422
- {!collapsed ? (
423
- <div className="px-2 py-1">
424
- <ExtensionsSidebarSection />
425
- </div>
426
- ) : null}
458
+ <nav
459
+ className={cn(
460
+ "grid",
461
+ collapsed ? "gap-0 px-1 py-1" : "gap-1 px-2 py-1",
462
+ )}
463
+ >
464
+ {bottomNavItems.map((item) => {
465
+ const Icon = item.icon;
466
+ const isActive = location.pathname.startsWith(item.href);
467
+ const link = (
468
+ <Link
469
+ to={item.href}
470
+ className={navClass({ isActive })}
471
+ aria-current={isActive ? "page" : undefined}
472
+ aria-label={collapsed ? t(item.labelKey) : undefined}
473
+ >
474
+ <Icon className="size-4 shrink-0" />
475
+ <span className={collapsed ? "sr-only" : "truncate"}>
476
+ {t(item.labelKey)}
477
+ </span>
478
+ </Link>
479
+ );
480
+ return collapsed ? (
481
+ <Tooltip key={item.href}>
482
+ <TooltipTrigger asChild>{link}</TooltipTrigger>
483
+ <TooltipContent side="right">{t(item.labelKey)}</TooltipContent>
484
+ </Tooltip>
485
+ ) : (
486
+ <div key={item.href}>{link}</div>
487
+ );
488
+ })}
489
+ </nav>
427
490
 
428
491
  <div className={cn(collapsed ? "px-1 py-1" : "px-3 py-2")}>
429
492
  <OrgSwitcher
@@ -436,14 +499,13 @@ export function Sidebar({
436
499
  />
437
500
  </div>
438
501
 
439
- {!collapsed ? (
440
- <div className="flex items-center justify-end gap-1 px-3 py-2">
441
- <FeedbackButton className="min-w-0 flex-1" side="right" />
442
- {collapseButton}
443
- </div>
444
- ) : collapseButton ? (
445
- <div className="flex justify-center px-1 py-1">{collapseButton}</div>
446
- ) : null}
502
+ <SidebarFooterActions
503
+ collapsed={collapsed}
504
+ feedback={feedbackButton}
505
+ translate={translateButton}
506
+ search={searchButton}
507
+ collapse={collapseButton}
508
+ />
447
509
  </div>
448
510
  </aside>
449
511
  );
@@ -22,7 +22,7 @@
22
22
  --muted-foreground: 0 0% 45%;
23
23
  --accent: 0 0% 95%;
24
24
  --accent-foreground: 0 0% 15%;
25
- --destructive: 0 84% 60%;
25
+ --destructive: 0 91% 71%;
26
26
  --destructive-foreground: 0 0% 98%;
27
27
  --border: 0 0% 90%;
28
28
  --input: 0 0% 90%;
@@ -1,4 +1,4 @@
1
- import { ExtensionsListPage } from "@agent-native/core/client/extensions";
1
+ import { Navigate } from "react-router";
2
2
 
3
3
  import { APP_TITLE } from "@/lib/app-config";
4
4
 
@@ -7,5 +7,5 @@ export function meta() {
7
7
  }
8
8
 
9
9
  export default function ExtensionsRoute() {
10
- return <ExtensionsListPage />;
10
+ return <Navigate to="/settings#extensions" replace />;
11
11
  }
@@ -6,5 +6,6 @@ functions = "templates/chat/.netlify/functions-internal"
6
6
 
7
7
  [build.environment]
8
8
  GA_MEASUREMENT_ID = "G-ESF7FYXGN9"
9
+ GTM_CONTAINER_ID = "GTM-N3WSTXZ"
9
10
  NITRO_PRESET = "netlify"
10
11
  NPM_CONFIG_PRODUCTION = "false"
@@ -52,7 +52,7 @@
52
52
  --muted-foreground: 0 0% 60%;
53
53
  --accent: 0 0% 18%;
54
54
  --accent-foreground: 0 0% 90%;
55
- --destructive: 0 84% 60%;
55
+ --destructive: 0 91% 71%;
56
56
  --destructive-foreground: 0 0% 98%;
57
57
  --border: 0 0% 24%;
58
58
  --input: 0 0% 24%;
@@ -76,6 +76,22 @@ Full source-code customization is a core Agent Native capability. Extensions
76
76
  are the fast, sandboxed, no-deploy layer—not the limit of what the app can
77
77
  become.
78
78
 
79
+ Use this decision rule when either path could solve the request:
80
+
81
+ - Start with an extension for a self-contained, relatively one-off widget,
82
+ custom visualization or interaction, dashboard tile, standalone utility, or
83
+ add-on in an existing slot.
84
+ - Use app code for a core template feature, native UI/layout/routes/business
85
+ logic, a new slot, or behavior that should be reused broadly across dashboards
86
+ or users.
87
+ - If the same extension keeps getting rebuilt, promote it into app code as one
88
+ reusable native feature instead of maintaining copies.
89
+
90
+ As a rule of thumb, if an extension can solve the problem, generally start
91
+ there. An isolated custom dashboard visualization belongs in an extension; a
92
+ new chart type that should be available across dashboards belongs in the
93
+ template code.
94
+
79
95
  **When a user asks to "make an extension", "create an extension", or "build
80
96
  a ... extension" (or the older phrasings "make a tool" / "create a tool"):**
81
97