@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
@@ -223,7 +223,7 @@ Pattern across all of these: extensions are about **the moment** the user is in
223
223
 
224
224
  The simple path:
225
225
 
226
- 1. **Click "New Extension"** in the sidebar (or just ask in chat).
226
+ 1. Open **Settings Extensions** (or just ask in chat), then click **New Extension**.
227
227
  2. **Describe what you want in one sentence.** "A sticky-note pad for the contact I'm emailing." "A KPI box for trials started this week."
228
228
  3. **The agent writes it and it appears in your Extensions list, ready to use.**
229
229
 
@@ -617,9 +617,23 @@ Extensions are private to the user who created them by default. To share:
617
617
 
618
618
  Shared extensions have their own URLs and plug into the same share dialog as documents, decks, and dashboards. Slot installs are always personal — sharing an extension means others _can_ install it; it doesn't auto-pin it to their UI.
619
619
 
620
- ## Extensions vs. editing the app code {#vs-app-code}
620
+ ## Should I use an extension or edit the app code? {#vs-app-code}
621
621
 
622
- The framework lets the agent edit the app's source code directly — components, routes, styles. So when should you reach for an extension instead?
622
+ The framework lets the agent edit the app's source code directly — components,
623
+ routes, styles, and business logic. Use this question when either path could
624
+ solve the request:
625
+
626
+ - **Start with an extension** for a self-contained, relatively one-off widget:
627
+ a custom visualization or interaction, a dashboard tile, a standalone
628
+ utility, or an add-on in an existing slot. It is fast, requires no source
629
+ change, build, or deploy, and can be private or shared.
630
+ - **Use app code** for a core feature of the template, a change to native UI,
631
+ layout, routes, or business logic, or anything that should be reused broadly
632
+ across dashboards or users. If the host has no suitable slot or the request
633
+ needs a new slot, use code.
634
+ - **Promote repeated extensions.** If people keep rebuilding the same
635
+ extension, or maintaining copies in many places would be worse than one
636
+ shared implementation, move it into app code as a reusable native feature.
623
637
 
624
638
  | | Extension | App code edit |
625
639
  | --------------------- | ------------------------------------------------- | ------------------------------------ |
@@ -630,7 +644,12 @@ The framework lets the agent edit the app's source code directly — components,
630
644
  | **Scope** | One user (or shared with org) | The entire product, every user |
631
645
  | **Best for** | Personal widgets, custom KPIs, per-team utilities | Core features that ship to all users |
632
646
 
633
- Rule of thumb: **if it's for one user or one team, it's an extension.** If every user of the template should get it, ship it as a real feature.
647
+ Rule of thumb: **if an extension can solve the problem, generally start there.**
648
+ Use code when the extension boundary does not fit or when broad reuse and
649
+ product-wide availability justify a native implementation. For example, a
650
+ one-off custom visualization on a dashboard is a good extension; a new pie,
651
+ multi-bar, or line chart type that should be available across dashboards
652
+ belongs in the template code.
634
653
 
635
654
  If what you actually need is a cached, refreshable data source for an existing chart or table — not a new interactive widget — see [Data Programs](/docs/data-programs) instead; it shares this page's sandbox and security posture but has no UI of its own.
636
655
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.120.1",
3
+ "version": "0.120.3",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -390,7 +390,7 @@
390
390
  "yjs": "^13.6.31",
391
391
  "zod": "^4.3.6",
392
392
  "@agent-native/recap-cli": "0.5.1",
393
- "@agent-native/toolkit": "^0.10.4"
393
+ "@agent-native/toolkit": "^0.10.5"
394
394
  },
395
395
  "devDependencies": {
396
396
  "@ai-sdk/anthropic": "^3.0.71",
@@ -6401,6 +6401,10 @@ export async function chainServerDrivenContinuation(opts: {
6401
6401
  terminalEvent: run.events.at(-1)?.event,
6402
6402
  })
6403
6403
  .catch(() => {});
6404
+ run.continuationTerminalEvent = {
6405
+ type: "auto_continue",
6406
+ reason: continuationReason,
6407
+ };
6404
6408
  } catch (chainErr) {
6405
6409
  // Chain dispatch failed — fail loud so the held row goes terminal
6406
6410
  // instead of spinning. The reaper would also catch it, but this is
@@ -41,6 +41,16 @@ export interface ActiveRun {
41
41
  subscribers: Set<(event: RunEvent) => void>;
42
42
  abort: AbortController;
43
43
  abortReason?: string;
44
+ /**
45
+ * Terminal event to emit when a server-driven continuation has been handed
46
+ * off successfully. The continuation runs outside this process, so the
47
+ * normal loop-level auto_continue event is not sent through this run's
48
+ * `send` callback.
49
+ */
50
+ continuationTerminalEvent?: Extract<
51
+ AgentChatEvent,
52
+ { type: "auto_continue" }
53
+ >;
44
54
  startedAt: number;
45
55
  }
46
56
 
@@ -954,7 +964,17 @@ export function startRun(
954
964
  // /runs/active check while we wait for SQL writes to land.
955
965
  let completionError: unknown = null;
956
966
  let terminalPersistenceError: unknown = null;
957
- const terminalEvent = pendingTerminalEvent?.event ?? null;
967
+ const resolveTerminalEventForCompletion = () => {
968
+ const continuationTerminalEvent = run.continuationTerminalEvent
969
+ ? {
970
+ seq: run.events.length,
971
+ event: run.continuationTerminalEvent,
972
+ }
973
+ : null;
974
+ return continuationTerminalEvent ?? pendingTerminalEvent;
975
+ };
976
+ let terminalEventForCompletion = resolveTerminalEventForCompletion();
977
+ let terminalEvent = terminalEventForCompletion?.event ?? null;
958
978
  if (
959
979
  onComplete &&
960
980
  !(run.status === "aborted" && run.abortReason === "no_progress")
@@ -966,12 +986,12 @@ export function startRun(
966
986
  ? "errored"
967
987
  : run.status;
968
988
  const completionRun: ActiveRun =
969
- pendingTerminalEvent || completionStatus !== run.status
989
+ terminalEventForCompletion || completionStatus !== run.status
970
990
  ? {
971
991
  ...run,
972
992
  status: completionStatus,
973
- events: pendingTerminalEvent
974
- ? [...run.events, pendingTerminalEvent]
993
+ events: terminalEventForCompletion
994
+ ? [...run.events, terminalEventForCompletion]
975
995
  : run.events,
976
996
  }
977
997
  : run;
@@ -986,6 +1006,12 @@ export function startRun(
986
1006
  }
987
1007
  }
988
1008
 
1009
+ // Server-driven continuation is installed by onComplete after the
1010
+ // successor has been dispatched. Resolve the terminal event again so
1011
+ // this chunk emits auto_continue instead of a misleading done event.
1012
+ terminalEventForCompletion = resolveTerminalEventForCompletion();
1013
+ terminalEvent = terminalEventForCompletion?.event ?? null;
1014
+
989
1015
  // 2. Compute final status. If the completion callback threw, we'd
990
1016
  // rather mark the run errored than claim success with incomplete
991
1017
  // thread_data.
@@ -1022,18 +1048,18 @@ export function startRun(
1022
1048
  // re-stamp the seq at emit time (max-seq+1) just below.
1023
1049
  const terminalEvent: AgentChatEvent =
1024
1050
  finalStatus === "completed"
1025
- ? (pendingTerminalEvent?.event ?? { type: "done" })
1026
- : pendingTerminalEvent?.event.type === "error" ||
1027
- pendingTerminalEvent?.event.type === "missing_api_key"
1028
- ? pendingTerminalEvent.event
1029
- : pendingTerminalEvent?.event.type === "auto_continue"
1051
+ ? (terminalEventForCompletion?.event ?? { type: "done" })
1052
+ : terminalEventForCompletion?.event.type === "error" ||
1053
+ terminalEventForCompletion?.event.type === "missing_api_key"
1054
+ ? terminalEventForCompletion.event
1055
+ : terminalEventForCompletion?.event.type === "auto_continue"
1030
1056
  ? // The run was checkpointed at a soft-timeout/loop boundary and
1031
1057
  // is recoverable: the partial turn is in agent_run_events and
1032
1058
  // the continuation run will re-attempt the thread_data save.
1033
1059
  // Even though the completion save failed (finalStatus stays
1034
1060
  // "errored" for SQL/diagnostics), re-emit the auto_continue so
1035
1061
  // the client resumes instead of seeing a dead chat.
1036
- pendingTerminalEvent.event
1062
+ terminalEventForCompletion.event
1037
1063
  : {
1038
1064
  type: "error",
1039
1065
  error: completionError
@@ -167,6 +167,7 @@ export interface AgentChatRequest {
167
167
  continuationReason?:
168
168
  | "run_timeout"
169
169
  | "loop_limit"
170
+ | "max_tokens"
170
171
  | "no_progress"
171
172
  | "stream_ended"
172
173
  | "gateway_timeout"
@@ -371,6 +372,7 @@ export type AgentChatEvent =
371
372
  reason:
372
373
  | "run_timeout"
373
374
  | "loop_limit"
375
+ | "max_tokens"
374
376
  | "no_progress"
375
377
  | "stream_ended"
376
378
  | "gateway_timeout"
@@ -1933,7 +1933,7 @@ function renderHtml(sessions, args) {
1933
1933
  return "<!doctype html><html><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>Context X-Ray</title><style>" +
1934
1934
  "@import url(\"https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap\");" +
1935
1935
  ":root{--background:0 0% 100%;--foreground:220 10% 10%;--card:0 0% 100%;--muted:220 10% 95%;--muted-foreground:220 5% 45%;--accent:220 10% 92%;--border:220 10% 90%;--ring:220 10% 55%;--destructive:0 84% 60%;--radius:.5rem;--shadow:0 1px 2px rgba(16,24,40,.06);}" +
1936
- "@media(prefers-color-scheme:dark){:root{--background:220 10% 7%;--foreground:220 8% 92%;--card:220 9% 9%;--muted:220 8% 15%;--muted-foreground:220 6% 64%;--accent:220 8% 17%;--border:220 8% 18%;--ring:220 8% 54%;--destructive:0 84% 60%;--shadow:none;}}" +
1936
+ "@media(prefers-color-scheme:dark){:root{--background:220 10% 7%;--foreground:220 8% 92%;--card:220 9% 9%;--muted:220 8% 15%;--muted-foreground:220 6% 64%;--accent:220 8% 17%;--border:220 8% 18%;--ring:220 8% 54%;--destructive:0 91% 71%;--shadow:none;}}" +
1937
1937
  "*{box-sizing:border-box}html{background:hsl(var(--background))}body{margin:0;background:hsl(var(--background));color:hsl(var(--foreground));font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;font-feature-settings:\"cv02\",\"cv03\",\"cv04\",\"cv11\";line-height:1.45}button{font:inherit;color:inherit}main{max-width:1180px;margin:0 auto;padding:20px 18px 44px}.topbar{border-bottom:1px solid hsl(var(--border));background:hsl(var(--background));position:sticky;top:0;z-index:10}.topbar-inner{max-width:1180px;margin:0 auto;padding:14px 18px;display:flex;align-items:center;justify-content:space-between;gap:16px}.title-row{display:flex;align-items:center;gap:9px}.logo-dot{width:10px;height:10px;border-radius:999px;background:#38bdf8;box-shadow:0 0 0 4px rgba(56,189,248,.12)}h1{font-size:20px;line-height:1.1;margin:0;font-weight:650;letter-spacing:0}h2{font-size:15px;line-height:1.2;margin:0;font-weight:650}h3{font-size:14px;line-height:1.3;margin:0;font-weight:600}p{margin:0}.muted,.eyebrow,.meta,.empty{color:hsl(var(--muted-foreground))}.eyebrow{text-transform:uppercase;letter-spacing:.08em;font-size:11px;font-weight:650}.meta{font-size:12px}.tabs{display:inline-flex;align-items:center;gap:2px;border:1px solid hsl(var(--border));background:hsl(var(--muted)/.35);border-radius:8px;padding:2px}.tab{border:0;background:transparent;border-radius:6px;padding:6px 10px;font-size:12px;line-height:1.1;cursor:pointer}.tab:hover{background:hsl(var(--accent)/.5)}.tab.active{background:hsl(var(--background));box-shadow:var(--shadow)}.stats{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin:18px 0}.card{background:hsl(var(--card));border:1px solid hsl(var(--border));border-radius:8px;padding:14px;box-shadow:var(--shadow)}.stat-value{display:block;font-size:28px;line-height:1.1;font-weight:700;margin-top:6px}.panel{display:none}.panel.active{display:block}.grid{display:grid;grid-template-columns:minmax(0,1.35fr) minmax(280px,.8fr);gap:14px;align-items:start}.grid.equal{grid-template-columns:repeat(2,minmax(0,1fr))}.section-head{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;margin-bottom:12px}.bar{display:flex;overflow:hidden;height:10px;border-radius:999px;background:hsl(var(--muted));margin:10px 0 12px}.bar span{display:block;min-width:2px}.table{width:100%;border-collapse:collapse;font-size:12px}.table th{text-align:left;color:hsl(var(--muted-foreground));font-weight:600;border-bottom:1px solid hsl(var(--border));padding:7px 8px}.table td{border-bottom:1px solid hsl(var(--border));padding:8px;vertical-align:top}.table th:last-child,.table td:last-child{text-align:right}.row-button{width:100%;display:grid;grid-template-columns:minmax(0,1fr) 74px 70px;gap:10px;align-items:center;text-align:left;border:1px solid transparent;background:transparent;border-radius:6px;padding:8px;cursor:pointer}.row-button:hover,.row-button.active{border-color:hsl(var(--border));background:hsl(var(--accent)/.35)}.row-title{font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.row-meta{font-size:12px;color:hsl(var(--muted-foreground));text-align:right}.badge-list{display:flex;flex-wrap:wrap;gap:6px}.badge{display:inline-flex;align-items:center;gap:5px;border:1px solid hsl(var(--border));border-radius:999px;padding:3px 7px;font-size:11px;background:hsl(var(--background));max-width:100%}.badge .dot{width:7px;height:7px;border-radius:999px;flex:0 0 auto}.tips{margin:0;padding-left:20px}.tips li{margin:0 0 8px}.detail{min-height:228px}.detail-list{display:grid;gap:8px;margin-top:10px}.sample{border:1px solid hsl(var(--border));border-radius:8px;padding:10px;background:hsl(var(--muted)/.22)}.sample-top{display:flex;justify-content:space-between;gap:10px;margin-bottom:5px;font-size:11px;color:hsl(var(--muted-foreground))}.sample p{font-size:12px;color:hsl(var(--foreground));overflow-wrap:anywhere}.session-card{border:1px solid hsl(var(--border));border-radius:8px;background:hsl(var(--card));margin-bottom:10px;overflow:hidden}.session-card summary{list-style:none;display:flex;justify-content:space-between;gap:14px;cursor:pointer;padding:13px 14px}.session-card summary::-webkit-details-marker{display:none}.session-body{border-top:1px solid hsl(var(--border));padding:12px 14px}.session-title{font-size:13px;font-weight:650;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.session-path{font-size:12px;color:hsl(var(--muted-foreground));margin-top:3px;overflow-wrap:anywhere}.token-big{font-size:20px;font-weight:700;white-space:nowrap}.mini-label{margin:10px 0 6px;font-size:11px;text-transform:uppercase;letter-spacing:.08em;font-weight:650;color:hsl(var(--muted-foreground))}.footer{margin-top:20px;color:hsl(var(--muted-foreground));font-size:12px}.hidden{display:none!important}@media(max-width:840px){.topbar-inner{align-items:flex-start;flex-direction:column}.stats,.grid,.grid.equal{grid-template-columns:1fr}.tabs{width:100%;overflow:auto}.tab{white-space:nowrap}.row-button{grid-template-columns:minmax(0,1fr) 64px 58px}.session-card summary{align-items:flex-start;flex-direction:column}}" +
1938
1938
  "</style></head><body><header class=\"topbar\"><div class=\"topbar-inner\"><div><div class=\"title-row\"><span class=\"logo-dot\"></span><h1>Context X-Ray</h1></div><p class=\"meta\">Generated " + escapeHtml(report.generatedLabel) + " · mode=" + escapeHtml(report.mode) + " · source=" + escapeHtml(report.source) + " · since=" + escapeHtml(report.since) + "</p></div><nav class=\"tabs\" aria-label=\"Report views\"><button class=\"tab active\" data-tab=\"overview\">Overview</button><button class=\"tab\" data-tab=\"tools\">Tool Calls</button><button class=\"tab\" data-tab=\"mcp\">MCP</button><button class=\"tab\" data-tab=\"metadata\">Metadata</button><button class=\"tab\" data-tab=\"sessions\">Sessions</button></nav></div></header><main><section class=\"stats\" id=\"stats\"></section><section class=\"panel active\" id=\"panel-overview\"></section><section class=\"panel\" id=\"panel-tools\"></section><section class=\"panel\" id=\"panel-mcp\"></section><section class=\"panel\" id=\"panel-metadata\"></section><section class=\"panel\" id=\"panel-sessions\"></section><p class=\"footer\">Reads local transcript and MCP config files only. No transcript content is uploaded.</p></main><script type=\"application/json\" id=\"xray-data\">" + jsonScript(report) + "</script><script>" +
1939
1939
  "(function(){var report=JSON.parse(document.getElementById('xray-data').textContent);var cats=['user','assistant','tool_call','tool_output','reasoning','instructions','attachment','metadata','other'];var labels={user:'User asks',assistant:'Assistant text',tool_call:'Tool calls',tool_output:'Tool output',reasoning:'Reasoning',instructions:'Instructions/context',attachment:'Attachments',metadata:'Metadata',other:'Other'};var colors={user:'#8ba8ff',assistant:'#55b982',tool_call:'#f0a85b',tool_output:'#e06b73',reasoning:'#a77be8',instructions:'#6ac3d5',attachment:'#d6a85a',metadata:'#9aa3ad',other:'#c3c8ce'};function esc(v){return String(v||'').replace(/[&<>\"']/g,function(ch){return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[ch];});}function fmt(n){n=Number(n)||0;if(n>=1000000)return(n/1000000).toFixed(1)+'m';if(n>=1000)return(n/1000).toFixed(1)+'k';return String(n);}function tok(chars){chars=Number(chars)||0;return chars>0?Math.max(1,Math.ceil(chars/4)):0;}function pc(part,total){return total>0?Math.max(0,Math.min(100,(part/total)*100)):0;}function totalCounter(counter){return Object.keys(counter||{}).reduce(function(sum,key){return sum+(Number(counter[key])||0);},0);}function bar(counter){var total=totalCounter(counter);if(!total)return'<div class=\"bar\"></div>';return'<div class=\"bar\">'+cats.map(function(cat){var value=counter[cat]||0;if(!value)return'';return'<span title=\"'+esc(labels[cat])+'\" style=\"width:'+Math.max(1,pc(value,total)).toFixed(2)+'%;background:'+colors[cat]+'\"></span>';}).join('')+'</div>';}function metric(label,value){return'<article class=\"card\"><div class=\"eyebrow\">'+esc(label)+'</div><span class=\"stat-value\">'+esc(value)+'</span></article>';}function tableRows(entries,kind){if(!entries||!entries.length)return'<tr><td>None detected</td><td></td></tr>';return entries.map(function(entry){var value=entry[1];var shown=kind==='chars'?fmt(tok(value)):(kind==='tokens'?fmt(value):String(value));return'<tr><td>'+esc(entry[0])+'</td><td>'+esc(shown)+'</td></tr>';}).join('');}function toolToken(name){var found=(report.toolTokens||[]).filter(function(entry){return entry[0]===name;})[0];return found?found[1]:0;}function renderStats(){var counts=report.sourceCounts||{};document.getElementById('stats').innerHTML=metric('Sessions',report.sessionCount)+metric('Observed/estimated tokens',fmt(report.totalTokens))+metric('Codex',counts.codex||0)+metric('Claude',counts.claude||0);}function renderOverview(){var categoryTotal=totalCounter(report.categories);var categoryRows=cats.map(function(cat){var chars=(report.categories||{})[cat]||0;if(!chars)return'';return'<tr><td><span class=\"badge\"><span class=\"dot\" style=\"background:'+colors[cat]+'\"></span>'+esc(labels[cat])+'</span></td><td>'+fmt(tok(chars))+'</td><td>'+pc(chars,categoryTotal).toFixed(0)+'%</td></tr>';}).join('');document.getElementById('panel-overview').innerHTML='<div class=\"grid\"><section class=\"card\"><div class=\"section-head\"><div><h2>Where The Context Is Going</h2><p class=\"meta\">Approximate contribution by transcript bucket.</p></div></div>'+bar(report.categories)+'<table class=\"table\"><tbody>'+categoryRows+'</tbody></table></section><section class=\"card\"><div class=\"section-head\"><div><h2>Warnings And Optimizations</h2><p class=\"meta\">Promptable changes you control.</p></div></div><ol class=\"tips\">'+(report.recommendations||[]).map(function(tip){return'<li>'+esc(tip)+'</li>';}).join('')+'</ol></section></div><div class=\"grid equal\" style=\"margin-top:14px\"><section class=\"card\"><h2>Top Paths</h2><table class=\"table\"><tbody>'+tableRows(report.paths,'count')+'</tbody></table></section><section class=\"card\"><h2>Metadata Types</h2><table class=\"table\"><tbody>'+tableRows(report.metadata,'chars')+'</tbody></table></section></div>';}function renderTools(){var rows=(report.tools||[]).map(function(entry,index){var name=entry[0];var count=entry[1];return'<button class=\"row-button'+(index===0?' active':'')+'\" data-tool=\"'+esc(name)+'\"><span><span class=\"row-title\">'+esc(name)+'</span><span class=\"meta\">Click to inspect sampled calls</span></span><span class=\"row-meta\">x'+count+'</span><span class=\"row-meta\">'+fmt(toolToken(name))+' tok</span></button>';}).join('')||'<div class=\"empty\">No tool calls detected in these sessions.</div>';document.getElementById('panel-tools').innerHTML='<div class=\"grid\"><section class=\"card\"><div class=\"section-head\"><div><h2>Tool Calls</h2><p class=\"meta\">Calls are clickable; samples are capped so the report stays light.</p></div></div><div>'+rows+'</div></section><aside class=\"card detail\" id=\"tool-detail\"></aside></div>';Array.prototype.forEach.call(document.querySelectorAll('[data-tool]'),function(btn){btn.addEventListener('click',function(){Array.prototype.forEach.call(document.querySelectorAll('[data-tool]'),function(item){item.classList.remove('active');});btn.classList.add('active');renderToolDetail(btn.getAttribute('data-tool'));});});if((report.tools||[]).length)renderToolDetail(report.tools[0][0]);else document.getElementById('tool-detail').innerHTML='<h2>Tool Detail</h2><p class=\"empty\">Nothing to inspect yet.</p>';}function renderToolDetail(name){var events=(report.toolEvents||[]).filter(function(event){return event.tool===name;}).slice(0,30);document.getElementById('tool-detail').innerHTML='<div class=\"section-head\"><div><h2>'+esc(name)+'</h2><p class=\"meta\">'+events.length+' sampled call'+(events.length===1?'':'s')+'</p></div></div><div class=\"detail-list\">'+(events.map(function(event){return'<article class=\"sample\"><div class=\"sample-top\"><span>'+esc(event.source)+' · '+esc(event.sessionTitle||event.sessionId)+'</span><span>'+fmt(event.tokens||0)+' tok</span></div><p>'+esc(event.preview||'No preview captured.')+'</p></article>';}).join('')||'<p class=\"empty\">No sampled call payloads for this tool.</p>')+'</div>';}function renderMcp(){var servers=report.mcpServers||[];var usage=report.mcpUsage||[];var configured=servers.map(function(server){return'<button class=\"row-button\" data-mcp=\"'+esc(server.name)+'\"><span><span class=\"row-title\">'+esc(server.name)+'</span><span class=\"meta\">'+esc(server.source)+' · '+esc(server.target)+'</span></span><span class=\"row-meta\">config</span><span class=\"row-meta\"></span></button>';}).join('')||'<div class=\"empty\">No MCP server config found in the common local config files.</div>';var detected=usage.map(function(entry,index){return'<button class=\"row-button'+(!servers.length&&index===0?' active':'')+'\" data-mcp=\"'+esc(entry[0])+'\"><span><span class=\"row-title\">'+esc(entry[0])+'</span><span class=\"meta\">Detected from mcp__server__tool style names</span></span><span class=\"row-meta\">x'+entry[1]+'</span><span class=\"row-meta\"></span></button>';}).join('')||'<div class=\"empty\">No MCP-prefixed tool calls detected in the selected sessions.</div>';document.getElementById('panel-mcp').innerHTML='<div class=\"grid\"><section class=\"card\"><div class=\"section-head\"><div><h2>MCP Servers</h2><p class=\"meta\">Configured locally plus inferred calls from transcripts.</p></div></div><div class=\"mini-label\">Configured</div>'+configured+'<div class=\"mini-label\">Detected usage</div>'+detected+'</section><aside class=\"card detail\" id=\"mcp-detail\"></aside></div>';Array.prototype.forEach.call(document.querySelectorAll('[data-mcp]'),function(btn){btn.addEventListener('click',function(){Array.prototype.forEach.call(document.querySelectorAll('[data-mcp]'),function(item){item.classList.remove('active');});btn.classList.add('active');renderMcpDetail(btn.getAttribute('data-mcp'));});});if(usage.length)renderMcpDetail(usage[0][0]);else if(servers.length)renderMcpDetail(servers[0].name);else document.getElementById('mcp-detail').innerHTML='<h2>MCP Detail</h2><p class=\"empty\">Install or run sessions with MCP tools to see usage here.</p>';}function renderMcpDetail(name){var server=(report.mcpServers||[]).filter(function(item){return item.name===name;})[0];var tools=(report.mcpTools||[]).filter(function(entry){return entry[0].indexOf(name+' / ')===0;});var events=(report.toolEvents||[]).filter(function(event){return event.mcpServer===name;}).slice(0,25);document.getElementById('mcp-detail').innerHTML='<div class=\"section-head\"><div><h2>'+esc(name)+'</h2><p class=\"meta\">'+(server?esc(server.source+' · '+server.target):'Detected from tool call names')+'</p></div></div><div class=\"mini-label\">Tools</div><table class=\"table\"><tbody>'+tableRows(tools,'count')+'</tbody></table><div class=\"mini-label\">Sample calls</div><div class=\"detail-list\">'+(events.map(function(event){return'<article class=\"sample\"><div class=\"sample-top\"><span>'+esc(event.mcpTool||event.tool)+'</span><span>'+fmt(event.tokens||0)+' tok</span></div><p>'+esc(event.preview||'No preview captured.')+'</p></article>';}).join('')||'<p class=\"empty\">No sampled MCP calls for this server in the selected sessions.</p>')+'</div>';}function renderMetadata(){var rows=(report.metadata||[]).map(function(entry,index){return'<button class=\"row-button'+(index===0?' active':'')+'\" data-meta=\"'+esc(entry[0])+'\"><span><span class=\"row-title\">'+esc(entry[0])+'</span><span class=\"meta\">Click to inspect sampled records</span></span><span class=\"row-meta\">'+fmt(tok(entry[1]))+' tok</span><span class=\"row-meta\">'+fmt(entry[1])+' ch</span></button>';}).join('')||'<div class=\"empty\">No metadata-heavy records detected.</div>';document.getElementById('panel-metadata').innerHTML='<div class=\"grid\"><section class=\"card\"><div class=\"section-head\"><div><h2>Metadata</h2><p class=\"meta\">Breakdown by transcript record type.</p></div></div>'+rows+'</section><aside class=\"card detail\" id=\"metadata-detail\"></aside></div>';Array.prototype.forEach.call(document.querySelectorAll('[data-meta]'),function(btn){btn.addEventListener('click',function(){Array.prototype.forEach.call(document.querySelectorAll('[data-meta]'),function(item){item.classList.remove('active');});btn.classList.add('active');renderMetadataDetail(btn.getAttribute('data-meta'));});});if((report.metadata||[]).length)renderMetadataDetail(report.metadata[0][0]);else document.getElementById('metadata-detail').innerHTML='<h2>Metadata Detail</h2><p class=\"empty\">Nothing to inspect yet.</p>';}function renderMetadataDetail(type){var events=(report.metadataEvents||[]).filter(function(event){return event.type===type;}).slice(0,30);document.getElementById('metadata-detail').innerHTML='<div class=\"section-head\"><div><h2>'+esc(type)+'</h2><p class=\"meta\">'+events.length+' sampled record'+(events.length===1?'':'s')+'</p></div></div><div class=\"detail-list\">'+(events.map(function(event){return'<article class=\"sample\"><div class=\"sample-top\"><span>'+esc(event.source)+' · '+esc(event.sessionTitle||event.sessionId)+'</span><span>'+fmt(event.tokens||0)+' tok</span></div><p>'+esc(event.preview||'No preview captured.')+'</p></article>';}).join('')||'<p class=\"empty\">No sampled records for this metadata type.</p>')+'</div>';}function renderSessions(){document.getElementById('panel-sessions').innerHTML=(report.sessions||[]).map(function(session,index){var catRows=Object.keys(session.categories||{}).sort(function(a,b){return session.categories[b]-session.categories[a];}).map(function(cat){var chars=session.categories[cat];return'<tr><td>'+esc(labels[cat]||cat)+'</td><td>'+fmt(tok(chars))+'</td><td>'+pc(chars,session.totalChars||0).toFixed(0)+'%</td></tr>';}).join('');var tools=(session.tools?Object.keys(session.tools):[]).sort(function(a,b){return session.tools[b]-session.tools[a];}).slice(0,8).map(function(name){return'<span class=\"badge\">'+esc(name)+' x'+session.tools[name]+'</span>';}).join('')||'<span class=\"empty\">none detected</span>';var paths=(session.paths?Object.keys(session.paths):[]).sort(function(a,b){return session.paths[b]-session.paths[a];}).slice(0,8).map(function(name){return'<span class=\"badge\">'+esc(name)+' x'+session.paths[name]+'</span>';}).join('')||'<span class=\"empty\">none detected</span>';return'<details class=\"session-card\"'+(index===0?' open':'')+'><summary><span><span class=\"eyebrow\">'+esc(session.source)+' · '+esc(session.updatedAt||'unknown time')+'</span><span class=\"session-title\">'+esc(session.title||session.sessionId)+'</span><span class=\"session-path\">'+esc(session.cwd||session.path)+'</span></span><span class=\"token-big\">'+fmt(session.tokens)+'</span></summary><div class=\"session-body\">'+bar(session.categories)+'<div class=\"grid equal\"><div><div class=\"mini-label\">Buckets</div><table class=\"table\"><tbody>'+catRows+'</tbody></table></div><div><div class=\"mini-label\">Frequent tools</div><div class=\"badge-list\">'+tools+'</div><div class=\"mini-label\">Repeated paths</div><div class=\"badge-list\">'+paths+'</div></div></div></div></details>';}).join('')||'<section class=\"card\"><p class=\"empty\">No matching sessions found.</p></section>';}function activate(name){Array.prototype.forEach.call(document.querySelectorAll('.tab'),function(tab){tab.classList.toggle('active',tab.getAttribute('data-tab')===name);});Array.prototype.forEach.call(document.querySelectorAll('.panel'),function(panel){panel.classList.toggle('active',panel.id==='panel-'+name);});if(location.hash!=='#'+name)history.replaceState(null,'','#'+name);}Array.prototype.forEach.call(document.querySelectorAll('.tab'),function(tab){tab.addEventListener('click',function(){activate(tab.getAttribute('data-tab'));});});renderStats();renderOverview();renderTools();renderMcp();renderMetadata();renderSessions();var initial=(location.hash||'#overview').slice(1);if(document.getElementById('panel-'+initial))activate(initial);})();" +
package/src/cli/index.ts CHANGED
@@ -9,6 +9,7 @@ import { fileURLToPath } from "url";
9
9
  import * as Sentry from "@sentry/node";
10
10
 
11
11
  import { resolveDeployPostBuildInvocation } from "./deploy-build.js";
12
+ import { createCliTelemetry } from "./telemetry.js";
12
13
 
13
14
  // Resolve version once at module scope — used by both --version and --help
14
15
  let _version = "unknown";
@@ -170,6 +171,12 @@ const BUGS_URL = "https://github.com/BuilderIO/agent-native/issues";
170
171
  const command = process.argv[2];
171
172
  // Filter out bare "--" separators that pnpm inserts between its args and script args
172
173
  const args = process.argv.slice(3).filter((a) => a !== "--");
174
+ const cliTelemetry = createCliTelemetry({
175
+ cli: "core",
176
+ cliVersion: _version,
177
+ command: command ?? "none",
178
+ interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY),
179
+ });
173
180
 
174
181
  function parseScaffoldArgs(argv: string[]): {
175
182
  name?: string;
@@ -203,25 +210,34 @@ function parseScaffoldArgs(argv: string[]): {
203
210
  // Track CLI usage (best-effort, non-blocking)
204
211
  function trackCli(event: string, props?: Record<string, unknown>): void {
205
212
  try {
206
- void import("../tracking/registry.js")
207
- .then((m) => m.track(event, { command, ...props }))
208
- .catch(() => undefined);
209
- void import("../tracking/providers.js")
210
- .then((m) => m.registerBuiltinProviders())
211
- .catch(() => undefined);
213
+ cliTelemetry.track(event, { command, ...props });
214
+ } catch {}
215
+ }
216
+
217
+ function captureCliException(
218
+ error: unknown,
219
+ context?: Parameters<typeof cliTelemetry.captureException>[1],
220
+ ): void {
221
+ try {
222
+ cliTelemetry.captureException(error, context);
212
223
  } catch {}
213
224
  }
214
225
 
226
+ function flushTelemetryAndExit(code: number): void {
227
+ void Promise.allSettled([cliTelemetry.flush(), Sentry.flush(2000)]).finally(
228
+ () => process.exit(code),
229
+ );
230
+ }
231
+
215
232
  // Global error handler — show feedback link on unhandled crashes
216
233
  process.on("uncaughtException", (err) => {
217
234
  console.error(`\n Unexpected error: ${err.message}\n`);
218
235
  console.error(` Report this bug: ${BUGS_URL}`);
219
236
  console.error(` Send feedback: ${FEEDBACK_URL}\n`);
220
237
  trackCli("cli.crash", { error: err.message });
238
+ captureCliException(err, { handled: false, tags: { source: "process" } });
221
239
  Sentry.captureException(err);
222
- void Sentry.flush(2000)
223
- .catch(() => undefined)
224
- .finally(() => process.exit(1));
240
+ flushTelemetryAndExit(1);
225
241
  });
226
242
 
227
243
  process.on("unhandledRejection", (reason: any) => {
@@ -229,16 +245,18 @@ process.on("unhandledRejection", (reason: any) => {
229
245
  console.error(` Report this bug: ${BUGS_URL}`);
230
246
  console.error(` Send feedback: ${FEEDBACK_URL}\n`);
231
247
  trackCli("cli.crash", { error: reason?.message ?? String(reason) });
248
+ captureCliException(reason, {
249
+ handled: false,
250
+ tags: { source: "unhandled-rejection" },
251
+ });
232
252
  Sentry.captureException(reason);
233
- void Sentry.flush(2000)
234
- .catch(() => undefined)
235
- .finally(() => process.exit(1));
253
+ flushTelemetryAndExit(1);
236
254
  });
237
255
 
238
256
  // Surface a self-heal hint when an interrupted `npx @agent-native/core@latest ...`
239
257
  // leaves a half-extracted package in the npx cache and a follow-up run fails
240
258
  // to load one of our own sub-modules.
241
- function handleScaffoldImportError(err: any): never {
259
+ function handleScaffoldImportError(err: any): void {
242
260
  const msg = err?.message ?? String(err);
243
261
  const looksLikeCorruptCache =
244
262
  err?.code === "ERR_MODULE_NOT_FOUND" ||
@@ -255,9 +273,12 @@ function handleScaffoldImportError(err: any): never {
255
273
  console.error(`\n Failed to load the scaffolder: ${msg}\n`);
256
274
  }
257
275
  trackCli("cli.scaffold.import_error", { error: msg });
276
+ captureCliException(err, {
277
+ handled: false,
278
+ tags: { source: "scaffold-import" },
279
+ });
258
280
  Sentry.captureException(err);
259
- Sentry.flush(2000).finally(() => process.exit(1));
260
- throw err;
281
+ flushTelemetryAndExit(1);
261
282
  }
262
283
 
263
284
  function findBinUpwards(binName: string): string | undefined {
@@ -525,7 +546,17 @@ function runBuildStep(
525
546
  stage: "spawn",
526
547
  },
527
548
  });
528
- Sentry.flush(2000).finally(() => process.exit(1));
549
+ captureCliException(err, {
550
+ handled: false,
551
+ tags: {
552
+ source: "build-step",
553
+ buildStep: opts.label,
554
+ ...(template ? { template } : {}),
555
+ ...(app ? { app } : {}),
556
+ },
557
+ extra: { stage: "spawn" },
558
+ });
559
+ flushTelemetryAndExit(1);
529
560
  });
530
561
 
531
562
  child.on("exit", (code, signal) => {
@@ -557,8 +588,18 @@ function runBuildStep(
557
588
  stdoutTail: stdoutBuf,
558
589
  },
559
590
  });
591
+ captureCliException(err, {
592
+ handled: false,
593
+ tags: {
594
+ source: "build-step",
595
+ buildStep: opts.label,
596
+ ...(template ? { template } : {}),
597
+ ...(app ? { app } : {}),
598
+ },
599
+ extra: { exitCode, signal: signal ?? null },
600
+ });
560
601
  // Don't throw — see comment on runBuildStep above.
561
- Sentry.flush(2000).finally(() => process.exit(exitCode));
602
+ flushTelemetryAndExit(exitCode);
562
603
  });
563
604
  });
564
605
  }
@@ -690,8 +731,12 @@ switch (command) {
690
731
  // implies a programming error in the orchestration above. Capture
691
732
  // and exit so the global unhandledRejection handler doesn't double-
692
733
  // report with a generic title.
734
+ captureCliException(err, {
735
+ handled: false,
736
+ tags: { source: "orchestration" },
737
+ });
693
738
  Sentry.captureException(err);
694
- Sentry.flush(2000).finally(() => process.exit(1));
739
+ flushTelemetryAndExit(1);
695
740
  });
696
741
  break;
697
742
  }
package/src/cli/skills.ts CHANGED
@@ -4454,6 +4454,11 @@ export async function runSkills(
4454
4454
  error: error instanceof Error ? error.message : String(error),
4455
4455
  durationMs: Date.now() - startedAt,
4456
4456
  });
4457
+ telemetry.captureException(error, {
4458
+ handled: false,
4459
+ tags: { source: "skills-command", command: parsed.command },
4460
+ extra: { durationMs: Date.now() - startedAt },
4461
+ });
4457
4462
  throw error;
4458
4463
  } finally {
4459
4464
  await telemetry.flush();
@@ -38,9 +38,17 @@ export interface CliTelemetryOptions {
38
38
 
39
39
  export interface CliTelemetry {
40
40
  track(event: string, properties?: Record<string, unknown>): void;
41
+ captureException(error: unknown, context?: CliExceptionContext): void;
41
42
  flush(): Promise<void>;
42
43
  }
43
44
 
45
+ export interface CliExceptionContext {
46
+ handled?: boolean;
47
+ level?: "fatal" | "error" | "warning" | "info" | "debug";
48
+ tags?: Record<string, string | number | boolean | null | undefined>;
49
+ extra?: Record<string, unknown>;
50
+ }
51
+
44
52
  function resolvePublicKey(): string {
45
53
  const fromEnv = process.env.AGENT_NATIVE_ANALYTICS_PUBLIC_KEY?.trim();
46
54
  return fromEnv || EMBEDDED_PUBLIC_KEY;
@@ -60,6 +68,110 @@ function telemetryDisabled(): boolean {
60
68
  );
61
69
  }
62
70
 
71
+ const MAX_EXCEPTION_MESSAGE_LENGTH = 1000;
72
+ const MAX_EXCEPTION_STACK_LENGTH = 8000;
73
+ const MAX_EXCEPTION_TAGS = 30;
74
+ const MAX_EXCEPTION_EXTRA_KEYS = 30;
75
+ const MAX_EXCEPTION_VALUE_LENGTH = 1000;
76
+ const SECRET_RE = /\b(?:bearer|basic)\s+[^\s]+/gi;
77
+ const SECRET_KEY_RE =
78
+ /(?:authorization|cookie|set[-_]?cookie|token|secret|password|passwd|pwd|api[-_]?key|apikey|credential)/i;
79
+
80
+ function redactExceptionText(value: string): string {
81
+ return value
82
+ .replace(SECRET_RE, (match) => `${match.split(/\s+/, 1)[0]} <redacted>`)
83
+ .replace(
84
+ /([A-Za-z0-9_$.-]*(?:authorization|cookie|token|secret|password|passwd|pwd|api[-_]?key|apikey|credential)[A-Za-z0-9_$.-]*\s*[:=]\s*)([^\s,;}]+)/gi,
85
+ "$1<redacted>",
86
+ );
87
+ }
88
+
89
+ function boundedExceptionText(value: unknown, max: number): string {
90
+ const text =
91
+ typeof value === "string" ? value : String(value ?? "Unknown error");
92
+ const safe = redactExceptionText(text);
93
+ return safe.length > max ? safe.slice(0, max) : safe;
94
+ }
95
+
96
+ function safeExceptionValue(value: unknown, depth = 2): unknown {
97
+ if (
98
+ value == null ||
99
+ typeof value === "boolean" ||
100
+ typeof value === "number"
101
+ ) {
102
+ return value;
103
+ }
104
+ if (typeof value === "string") {
105
+ return boundedExceptionText(value, MAX_EXCEPTION_VALUE_LENGTH);
106
+ }
107
+ if (depth <= 0)
108
+ return boundedExceptionText(value, MAX_EXCEPTION_VALUE_LENGTH);
109
+ if (Array.isArray(value)) {
110
+ return value
111
+ .slice(0, 20)
112
+ .map((item) => safeExceptionValue(item, depth - 1));
113
+ }
114
+ if (typeof value === "object") {
115
+ const out: Record<string, unknown> = {};
116
+ for (const [key, child] of Object.entries(value)) {
117
+ if (Object.keys(out).length >= MAX_EXCEPTION_EXTRA_KEYS) break;
118
+ const safeKey = boundedExceptionText(key, 100);
119
+ out[safeKey] = SECRET_KEY_RE.test(safeKey)
120
+ ? "<redacted>"
121
+ : safeExceptionValue(child, depth - 1);
122
+ }
123
+ return out;
124
+ }
125
+ return boundedExceptionText(value, MAX_EXCEPTION_VALUE_LENGTH);
126
+ }
127
+
128
+ function captureException(
129
+ error: unknown,
130
+ context: CliExceptionContext,
131
+ trackEvent: (event: string, properties?: Record<string, unknown>) => void,
132
+ ): void {
133
+ const exception =
134
+ error instanceof Error
135
+ ? {
136
+ type: boundedExceptionText(error.name || "Error", 200),
137
+ message: boundedExceptionText(
138
+ error.message || error.name || "Error",
139
+ MAX_EXCEPTION_MESSAGE_LENGTH,
140
+ ),
141
+ stack: error.stack
142
+ ? boundedExceptionText(error.stack, MAX_EXCEPTION_STACK_LENGTH)
143
+ : undefined,
144
+ }
145
+ : {
146
+ type: "Error",
147
+ message: boundedExceptionText(error, MAX_EXCEPTION_MESSAGE_LENGTH),
148
+ stack: undefined,
149
+ };
150
+ const tags: Record<string, string> = {};
151
+ for (const [key, value] of Object.entries(context.tags ?? {})) {
152
+ if (Object.keys(tags).length >= MAX_EXCEPTION_TAGS || value == null) break;
153
+ const safeKey = boundedExceptionText(key, 100);
154
+ tags[safeKey] = SECRET_KEY_RE.test(safeKey)
155
+ ? "<redacted>"
156
+ : boundedExceptionText(value, 200);
157
+ }
158
+ const extra = safeExceptionValue(context.extra);
159
+ trackEvent("$exception", {
160
+ app: "agent-native-cli",
161
+ template: "cli",
162
+ runtime: "cli",
163
+ source: "cli",
164
+ exceptionType: exception.type,
165
+ exceptionMessage: exception.message,
166
+ ...(exception.stack ? { exceptionStack: exception.stack } : {}),
167
+ handled: context.handled ?? false,
168
+ level: context.level ?? "error",
169
+ occurredAt: new Date().toISOString(),
170
+ ...(Object.keys(tags).length ? { exceptionTags: tags } : {}),
171
+ ...(extra && typeof extra === "object" ? { exceptionExtra: extra } : {}),
172
+ });
173
+ }
174
+
63
175
  /**
64
176
  * Read (or lazily create) a stable per-machine install id, shared across both
65
177
  * skills CLIs so one developer counts once. Best-effort: an unwritable home
@@ -132,5 +244,10 @@ export function createCliTelemetry(options: CliTelemetryOptions): CliTelemetry {
132
244
  ]);
133
245
  }
134
246
 
135
- return { track, flush };
247
+ return {
248
+ track,
249
+ captureException: (error, context = {}) =>
250
+ captureException(error, context, track),
251
+ flush,
252
+ };
136
253
  }
@@ -2745,6 +2745,12 @@ export interface AgentSidebarProps {
2745
2745
  * page-level AgentChatSurface can morph into it on navigation.
2746
2746
  */
2747
2747
  chatViewTransition?: boolean;
2748
+ /**
2749
+ * Mark the initial panel mount as the destination of a page-to-sidebar chat
2750
+ * handoff. This suppresses only the drawer's initial entry animation; normal
2751
+ * sidebar open/close transitions remain enabled.
2752
+ */
2753
+ chatViewTransitionHandoff?: boolean;
2748
2754
  /** Namespace for persisted chat state. Use the same key as AgentChatHome. */
2749
2755
  storageKey?: string;
2750
2756
  /** Open the sidebar when a chat run is active or reconnects. */
@@ -2784,6 +2790,7 @@ export function AgentSidebar({
2784
2790
  animateMobile = true,
2785
2791
  animateDesktop = true,
2786
2792
  chatViewTransition = false,
2793
+ chatViewTransitionHandoff = false,
2787
2794
  storageKey,
2788
2795
  openOnChatRunning = false,
2789
2796
  onFullscreenRequest,
@@ -3308,6 +3315,9 @@ export function AgentSidebar({
3308
3315
  data-agent-sidebar-position={position}
3309
3316
  data-agent-sidebar-state={panelOpen ? "open" : "closed"}
3310
3317
  data-agent-sidebar-resizing={isResizing ? "true" : undefined}
3318
+ data-agent-sidebar-chat-handoff={
3319
+ chatViewTransitionHandoff ? "true" : undefined
3320
+ }
3311
3321
  style={
3312
3322
  chatViewTransition
3313
3323
  ? getAgentChatViewTransitionStyle(panelStyle)
@@ -576,6 +576,14 @@ CommandMenu.Separator = CommandSeparator;
576
576
 
577
577
  // ─── Keyboard Hook ──────────────────────────────────────────────────────────
578
578
 
579
+ export const COMMAND_MENU_OPEN_EVENT = "agent-native:open-command-menu";
580
+
581
+ export function openCommandMenu() {
582
+ if (typeof window !== "undefined") {
583
+ window.dispatchEvent(new Event(COMMAND_MENU_OPEN_EVENT));
584
+ }
585
+ }
586
+
579
587
  /**
580
588
  * Hook to handle Cmd+K (or Ctrl+K) to open the command menu
581
589
  */
@@ -601,10 +609,14 @@ export function useCommandMenuShortcut(
601
609
  onOpen();
602
610
  }
603
611
  };
612
+ const handleOpenRequest = () => onOpen();
604
613
  const useCapture = Boolean(options.allowContentEditable);
605
614
  document.addEventListener("keydown", handleKeyDown, useCapture);
606
- return () =>
615
+ window.addEventListener(COMMAND_MENU_OPEN_EVENT, handleOpenRequest);
616
+ return () => {
607
617
  document.removeEventListener("keydown", handleKeyDown, useCapture);
618
+ window.removeEventListener(COMMAND_MENU_OPEN_EVENT, handleOpenRequest);
619
+ };
608
620
  }, [onOpen, options.allowContentEditable]);
609
621
  }
610
622