@agent-native/core 0.69.0 → 0.70.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (336) hide show
  1. package/README.md +15 -15
  2. package/corpus/README.md +2 -2
  3. package/corpus/core/CHANGELOG.md +109 -0
  4. package/corpus/core/docs/design/durable-agent-runs.md +217 -0
  5. package/corpus/core/package.json +1 -1
  6. package/corpus/core/src/action.ts +89 -0
  7. package/corpus/core/src/agent/model-config.ts +0 -2
  8. package/corpus/core/src/agent/run-loop-with-resume.ts +48 -0
  9. package/corpus/core/src/changelog/parse.ts +245 -0
  10. package/corpus/core/src/cli/changelog.ts +199 -0
  11. package/corpus/core/src/cli/index.ts +19 -0
  12. package/corpus/core/src/cli/recap.ts +24 -1
  13. package/corpus/core/src/cli/skills.ts +74 -47
  14. package/corpus/core/src/client/AgentPanel.tsx +5 -3
  15. package/corpus/core/src/client/AssistantChat.tsx +8 -0
  16. package/corpus/core/src/client/CommandMenu.tsx +183 -75
  17. package/corpus/core/src/client/agent-chat-adapter.ts +44 -7
  18. package/corpus/core/src/client/analytics.ts +181 -0
  19. package/corpus/core/src/client/changelog/Changelog.tsx +321 -0
  20. package/corpus/core/src/client/client-surface.ts +41 -0
  21. package/corpus/core/src/client/composer/TiptapComposer.tsx +123 -12
  22. package/corpus/core/src/client/feedback-context.ts +4 -0
  23. package/corpus/core/src/client/index.ts +12 -0
  24. package/corpus/core/src/client/mcp-apps/McpAppRenderer.tsx +54 -0
  25. package/corpus/core/src/client/settings/useBuilderStatus.ts +82 -20
  26. package/corpus/core/src/client/sse-event-processor.ts +7 -1
  27. package/corpus/core/src/mcp/build-server.ts +57 -1
  28. package/corpus/core/src/mcp/embed-app.ts +197 -7
  29. package/corpus/core/src/mcp/oauth-route.ts +109 -13
  30. package/corpus/core/src/server/attribution.ts +211 -0
  31. package/corpus/core/src/server/auth.ts +6 -0
  32. package/corpus/core/src/server/better-auth-instance.ts +49 -5
  33. package/corpus/core/src/server/builder-browser.ts +27 -1
  34. package/corpus/core/src/server/core-routes-plugin.ts +136 -0
  35. package/corpus/core/src/server/google-oauth.ts +19 -6
  36. package/corpus/core/src/server/onboarding-html.ts +35 -0
  37. package/corpus/core/src/shared/mcp-embed-headers.ts +1 -1
  38. package/corpus/core/src/styles/agent-conversation.css +21 -0
  39. package/corpus/core/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
  40. package/corpus/core/src/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +72 -0
  41. package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
  42. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +22 -0
  43. package/corpus/templates/analytics/AGENTS.md +8 -1
  44. package/corpus/templates/analytics/CHANGELOG.md +10 -0
  45. package/corpus/templates/analytics/actions/install-dashboard-template.ts +99 -4
  46. package/corpus/templates/analytics/actions/open-traffic-dashboard.ts +1 -1
  47. package/corpus/templates/analytics/actions/update-dashboard.ts +39 -8
  48. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +30 -3
  49. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +180 -144
  50. package/corpus/templates/analytics/app/components/layout/Header.tsx +2 -3
  51. package/corpus/templates/analytics/app/components/layout/Layout.tsx +7 -5
  52. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +221 -215
  53. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +6 -6
  54. package/corpus/templates/analytics/app/lib/demo-dashboard-path.ts +1 -1
  55. package/corpus/templates/analytics/app/lib/last-opened.ts +2 -1
  56. package/corpus/templates/analytics/app/pages/Settings.tsx +4 -0
  57. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +3 -3
  58. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +2 -2
  59. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +32 -2
  60. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +101 -99
  61. package/corpus/templates/analytics/app/pages/overview/OverviewPage.tsx +1 -1
  62. package/corpus/templates/analytics/app/routes/adhoc.$id.tsx +18 -5
  63. package/corpus/templates/analytics/app/routes/catalog.tsx +1 -1
  64. package/corpus/templates/analytics/app/routes/dashboards.$id.tsx +9 -0
  65. package/corpus/templates/analytics/app/routes/traffic.tsx +1 -1
  66. package/corpus/templates/analytics/changelog/2026-06-23-long-dashboard-and-analysis-names-in-the-sidebar-now-truncat.md +6 -0
  67. package/corpus/templates/analytics/changelog/2026-06-23-open-any-dashboard-chart-full-screen-in-a-modal-from-the-pan.md +6 -0
  68. package/corpus/templates/analytics/changelog/2026-06-23-the-dashboards-and-analyses-sidebar-settings-buttons-now-sta.md +6 -0
  69. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +145 -0
  70. package/corpus/templates/analytics/server/db/index.ts +1 -1
  71. package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +9 -2
  72. package/corpus/templates/analytics/server/lib/demo-dashboards.ts +1 -1
  73. package/corpus/templates/analytics/server/plugins/agent-chat.ts +2 -2
  74. package/corpus/templates/analytics/server/plugins/core-routes.ts +6 -6
  75. package/corpus/templates/assets/CHANGELOG.md +10 -0
  76. package/corpus/templates/assets/actions/generate-image.ts +24 -0
  77. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +2 -2
  78. package/corpus/templates/assets/app/global.css +17 -1
  79. package/corpus/templates/assets/app/root.tsx +7 -1
  80. package/corpus/templates/assets/app/routes/_index.tsx +94 -14
  81. package/corpus/templates/assets/app/routes/settings.tsx +6 -0
  82. package/corpus/templates/assets/changelog/2026-06-23-chat-dates-in-the-sidebar-no-longer-wrap-onto-two-lines.md +6 -0
  83. package/corpus/templates/assets/changelog/2026-06-23-clicking-image-video-or-refine-on-the-start-screen-now-drops.md +6 -0
  84. package/corpus/templates/assets/changelog/2026-06-23-pick-your-image-generation-model-right-from-the-chat-model-m.md +6 -0
  85. package/corpus/templates/brain/CHANGELOG.md +10 -0
  86. package/corpus/templates/brain/app/root.tsx +7 -1
  87. package/corpus/templates/brain/app/routes/settings.tsx +8 -1
  88. package/corpus/templates/calendar/CHANGELOG.md +10 -0
  89. package/corpus/templates/calendar/app/pages/Settings.tsx +4 -0
  90. package/corpus/templates/calendar/app/root.tsx +7 -1
  91. package/corpus/templates/chat/CHANGELOG.md +10 -0
  92. package/corpus/templates/chat/app/root.tsx +7 -1
  93. package/corpus/templates/clips/CHANGELOG.md +10 -0
  94. package/corpus/templates/clips/app/components/library/library-grid.tsx +1 -20
  95. package/corpus/templates/clips/app/components/player/share-dialog.tsx +33 -7
  96. package/corpus/templates/clips/app/components/player/sign-in-prompt-dialog.tsx +8 -0
  97. package/corpus/templates/clips/app/components/player/video-player.tsx +150 -20
  98. package/corpus/templates/clips/app/components/recorder/countdown-overlay.tsx +72 -48
  99. package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +7 -11
  100. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +31 -0
  101. package/corpus/templates/clips/app/components/sharing/slack-share-hint.tsx +71 -0
  102. package/corpus/templates/clips/app/lib/countdown-audio-cue.ts +35 -17
  103. package/corpus/templates/clips/app/root.tsx +7 -1
  104. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +15 -1
  105. package/corpus/templates/clips/app/routes/record.tsx +78 -5
  106. package/corpus/templates/clips/app/routes/share.$shareId.tsx +86 -5
  107. package/corpus/templates/clips/changelog/2026-06-23-clips-shared-in-slack-no-longer-show-a-could-not-start-playb.md +6 -0
  108. package/corpus/templates/clips/changelog/2026-06-23-made-the-play-button-on-shared-and-embedded-clips-scale-with.md +6 -0
  109. package/corpus/templates/clips/changelog/2026-06-23-public-clip-share-links-now-show-whether-they-ll-play-inline.md +6 -0
  110. package/corpus/templates/clips/changelog/2026-06-23-removed-select-button-from-library-hover-a-clip-to-select-it.md +6 -0
  111. package/corpus/templates/clips/changelog/2026-06-23-screen-camera-recordings-now-keep-the-presenter-s-face-in-th.md +6 -0
  112. package/corpus/templates/clips/changelog/2026-06-23-shared-video-links-now-play-for-anyone-without-signing-in.md +6 -0
  113. package/corpus/templates/clips/changelog/2026-06-23-skip-or-cancel-the-recording-countdown-with-buttons-beside-t.md +6 -0
  114. package/corpus/templates/clips/changelog/2026-06-23-the-desktop-camera-bubble-now-looks-sharp-the-instant-it-ope.md +6 -0
  115. package/corpus/templates/clips/changelog/2026-06-23-the-desktop-recording-widget-now-grows-downward-only-when-yo.md +6 -0
  116. package/corpus/templates/clips/changelog/2026-06-23-the-recording-start-sound-is-now-a-softer-more-modern-chime.md +6 -0
  117. package/corpus/templates/clips/chrome-extension/public/manifest.json +17 -8
  118. package/corpus/templates/clips/chrome-extension/src/background.ts +769 -180
  119. package/corpus/templates/clips/chrome-extension/src/content-script.ts +177 -0
  120. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +466 -329
  121. package/corpus/templates/clips/chrome-extension/src/overlay.css +377 -0
  122. package/corpus/templates/clips/chrome-extension/src/overlay.html +12 -0
  123. package/corpus/templates/clips/chrome-extension/src/overlay.ts +330 -0
  124. package/corpus/templates/clips/chrome-extension/src/permission.html +227 -0
  125. package/corpus/templates/clips/chrome-extension/src/permission.ts +105 -0
  126. package/corpus/templates/clips/chrome-extension/src/popup.html +3 -0
  127. package/corpus/templates/clips/chrome-extension/src/popup.ts +50 -2
  128. package/corpus/templates/clips/chrome-extension/src/styles.css +50 -0
  129. package/corpus/templates/clips/chrome-extension/vite.config.ts +3 -0
  130. package/corpus/templates/clips/desktop/src/lib/audio-cue.ts +41 -24
  131. package/corpus/templates/clips/desktop/src/lib/bubble-webrtc.ts +119 -2
  132. package/corpus/templates/clips/desktop/src/lib/recorder.ts +20 -0
  133. package/corpus/templates/clips/desktop/src/main.tsx +3 -0
  134. package/corpus/templates/clips/desktop/src/overlays/countdown.tsx +21 -2
  135. package/corpus/templates/clips/desktop/src/overlays/region-record-border.tsx +76 -0
  136. package/corpus/templates/clips/desktop/src/styles.css +119 -2
  137. package/corpus/templates/clips/desktop/src-tauri/capabilities/default.json +2 -1
  138. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +140 -1
  139. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -0
  140. package/corpus/templates/clips/desktop/src-tauri/src/util.rs +4 -1
  141. package/corpus/templates/clips/server/routes/api/video/[recordingId].get.ts +85 -6
  142. package/corpus/templates/clips/shared/share-attribution.ts +79 -0
  143. package/corpus/templates/content/AGENTS.md +20 -3
  144. package/corpus/templates/content/CHANGELOG.md +10 -0
  145. package/corpus/templates/content/actions/_database-utils.ts +15 -0
  146. package/corpus/templates/content/actions/_property-utils.ts +371 -4
  147. package/corpus/templates/content/actions/configure-document-property.ts +35 -1
  148. package/corpus/templates/content/actions/create-content-database.ts +5 -1
  149. package/corpus/templates/content/actions/delete-document-property.ts +52 -2
  150. package/corpus/templates/content/actions/duplicate-document-property.ts +34 -17
  151. package/corpus/templates/content/actions/reorder-document-property.ts +79 -0
  152. package/corpus/templates/content/actions/set-document-property.ts +39 -0
  153. package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +806 -0
  154. package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +226 -68
  155. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +59 -30
  156. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +25 -1
  157. package/corpus/templates/content/app/components/editor/blockFieldSaveController.ts +180 -0
  158. package/corpus/templates/content/app/components/editor/blockFieldSaveRegistry.ts +179 -0
  159. package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +244 -0
  160. package/corpus/templates/content/app/components/editor/previewDocumentSaveRegistry.ts +132 -0
  161. package/corpus/templates/content/app/global.css +9 -0
  162. package/corpus/templates/content/app/hooks/use-document-properties.ts +21 -0
  163. package/corpus/templates/content/app/root.tsx +7 -1
  164. package/corpus/templates/content/server/db/schema.ts +30 -0
  165. package/corpus/templates/content/server/plugins/db.ts +87 -0
  166. package/corpus/templates/content/shared/api.ts +7 -0
  167. package/corpus/templates/content/shared/properties.ts +109 -0
  168. package/corpus/templates/design/CHANGELOG.md +10 -0
  169. package/corpus/templates/design/actions/generate-design.ts +4 -0
  170. package/corpus/templates/design/app/root.tsx +7 -1
  171. package/corpus/templates/design/app/routes/settings.tsx +10 -2
  172. package/corpus/templates/dispatch/CHANGELOG.md +10 -0
  173. package/corpus/templates/dispatch/app/root.tsx +7 -1
  174. package/corpus/templates/forms/.agents/skills/form-responses/SKILL.md +10 -0
  175. package/corpus/templates/forms/CHANGELOG.md +10 -0
  176. package/corpus/templates/forms/actions/export-responses.ts +6 -0
  177. package/corpus/templates/forms/actions/list-responses.ts +2 -0
  178. package/corpus/templates/forms/actions/response-insights.ts +2 -0
  179. package/corpus/templates/forms/app/pages/ResponsesPage.tsx +138 -1
  180. package/corpus/templates/forms/app/root.tsx +7 -1
  181. package/corpus/templates/forms/changelog/2026-06-23-response-tables-now-show-the-page-each-submission-came-from-.md +6 -0
  182. package/corpus/templates/forms/changelog/2026-06-23-response-tables-now-show-whether-feedback-came-from-the-web-.md +6 -0
  183. package/corpus/templates/forms/server/db/schema.ts +7 -0
  184. package/corpus/templates/forms/server/handlers/submissions.ts +19 -2
  185. package/corpus/templates/forms/server/lib/integrations.ts +76 -2
  186. package/corpus/templates/forms/server/plugins/db.ts +20 -0
  187. package/corpus/templates/forms/shared/types.ts +12 -0
  188. package/corpus/templates/macros/CHANGELOG.md +10 -0
  189. package/corpus/templates/macros/app/root.tsx +7 -1
  190. package/corpus/templates/mail/CHANGELOG.md +10 -0
  191. package/corpus/templates/mail/app/components/layout/CommandPalette.tsx +3 -0
  192. package/corpus/templates/mail/app/pages/SettingsPage.tsx +27 -0
  193. package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +31 -17
  194. package/corpus/templates/plan/.agents/skills/visual-plan/references/wireframe.md +7 -4
  195. package/corpus/templates/plan/.agents/skills/visual-recap/SKILL.md +34 -24
  196. package/corpus/templates/plan/.agents/skills/visual-recap/references/wireframe.md +7 -4
  197. package/corpus/templates/plan/AGENTS.md +4 -0
  198. package/corpus/templates/plan/CHANGELOG.md +10 -0
  199. package/corpus/templates/plan/actions/view-screen.ts +5 -0
  200. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +98 -1
  201. package/corpus/templates/plan/app/components/plan/wireframe/html-artboard.css +3 -1
  202. package/corpus/templates/plan/app/pages/PlansPage.tsx +107 -7
  203. package/corpus/templates/plan/app/root.tsx +7 -1
  204. package/corpus/templates/plan/changelog/2026-06-23-large-diagrams-in-a-plan-now-scroll-within-their-block-inste.md +6 -0
  205. package/corpus/templates/plan/shared/share-attribution.ts +72 -0
  206. package/corpus/templates/slides/CHANGELOG.md +10 -0
  207. package/corpus/templates/slides/app/root.tsx +7 -1
  208. package/corpus/templates/videos/CHANGELOG.md +4 -151
  209. package/corpus/templates/videos/app/root.tsx +7 -1
  210. package/dist/action.js +87 -0
  211. package/dist/action.js.map +1 -1
  212. package/dist/agent/engine/builder-engine.d.ts +1 -1
  213. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  214. package/dist/agent/model-config.d.ts +2 -2
  215. package/dist/agent/model-config.d.ts.map +1 -1
  216. package/dist/agent/model-config.js +0 -2
  217. package/dist/agent/model-config.js.map +1 -1
  218. package/dist/agent/run-loop-with-resume.d.ts +13 -0
  219. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  220. package/dist/agent/run-loop-with-resume.js +44 -0
  221. package/dist/agent/run-loop-with-resume.js.map +1 -1
  222. package/dist/changelog/parse.d.ts +70 -0
  223. package/dist/changelog/parse.d.ts.map +1 -0
  224. package/dist/changelog/parse.js +200 -0
  225. package/dist/changelog/parse.js.map +1 -0
  226. package/dist/cli/changelog.d.ts +4 -0
  227. package/dist/cli/changelog.d.ts.map +1 -0
  228. package/dist/cli/changelog.js +166 -0
  229. package/dist/cli/changelog.js.map +1 -0
  230. package/dist/cli/index.js +18 -0
  231. package/dist/cli/index.js.map +1 -1
  232. package/dist/cli/recap.d.ts.map +1 -1
  233. package/dist/cli/recap.js +22 -1
  234. package/dist/cli/recap.js.map +1 -1
  235. package/dist/cli/skills.d.ts +3 -3
  236. package/dist/cli/skills.d.ts.map +1 -1
  237. package/dist/cli/skills.js +74 -47
  238. package/dist/cli/skills.js.map +1 -1
  239. package/dist/client/AgentPanel.d.ts.map +1 -1
  240. package/dist/client/AgentPanel.js +5 -3
  241. package/dist/client/AgentPanel.js.map +1 -1
  242. package/dist/client/AssistantChat.d.ts +6 -1
  243. package/dist/client/AssistantChat.d.ts.map +1 -1
  244. package/dist/client/AssistantChat.js +2 -2
  245. package/dist/client/AssistantChat.js.map +1 -1
  246. package/dist/client/CommandMenu.d.ts +17 -1
  247. package/dist/client/CommandMenu.d.ts.map +1 -1
  248. package/dist/client/CommandMenu.js +49 -13
  249. package/dist/client/CommandMenu.js.map +1 -1
  250. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  251. package/dist/client/agent-chat-adapter.js +43 -6
  252. package/dist/client/agent-chat-adapter.js.map +1 -1
  253. package/dist/client/analytics.d.ts +18 -0
  254. package/dist/client/analytics.d.ts.map +1 -1
  255. package/dist/client/analytics.js +177 -0
  256. package/dist/client/analytics.js.map +1 -1
  257. package/dist/client/changelog/Changelog.d.ts +47 -0
  258. package/dist/client/changelog/Changelog.d.ts.map +1 -0
  259. package/dist/client/changelog/Changelog.js +138 -0
  260. package/dist/client/changelog/Changelog.js.map +1 -0
  261. package/dist/client/client-surface.d.ts +17 -0
  262. package/dist/client/client-surface.d.ts.map +1 -0
  263. package/dist/client/client-surface.js +24 -0
  264. package/dist/client/client-surface.js.map +1 -0
  265. package/dist/client/composer/TiptapComposer.d.ts +26 -1
  266. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  267. package/dist/client/composer/TiptapComposer.js +27 -5
  268. package/dist/client/composer/TiptapComposer.js.map +1 -1
  269. package/dist/client/feedback-context.d.ts +3 -0
  270. package/dist/client/feedback-context.d.ts.map +1 -1
  271. package/dist/client/feedback-context.js +2 -0
  272. package/dist/client/feedback-context.js.map +1 -1
  273. package/dist/client/index.d.ts +3 -1
  274. package/dist/client/index.d.ts.map +1 -1
  275. package/dist/client/index.js +3 -1
  276. package/dist/client/index.js.map +1 -1
  277. package/dist/client/mcp-apps/McpAppRenderer.d.ts +1 -0
  278. package/dist/client/mcp-apps/McpAppRenderer.d.ts.map +1 -1
  279. package/dist/client/mcp-apps/McpAppRenderer.js +42 -1
  280. package/dist/client/mcp-apps/McpAppRenderer.js.map +1 -1
  281. package/dist/client/settings/useBuilderStatus.d.ts +2 -0
  282. package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
  283. package/dist/client/settings/useBuilderStatus.js +58 -10
  284. package/dist/client/settings/useBuilderStatus.js.map +1 -1
  285. package/dist/client/sse-event-processor.d.ts.map +1 -1
  286. package/dist/client/sse-event-processor.js +7 -1
  287. package/dist/client/sse-event-processor.js.map +1 -1
  288. package/dist/mcp/build-server.d.ts +21 -0
  289. package/dist/mcp/build-server.d.ts.map +1 -1
  290. package/dist/mcp/build-server.js +43 -1
  291. package/dist/mcp/build-server.js.map +1 -1
  292. package/dist/mcp/embed-app.d.ts.map +1 -1
  293. package/dist/mcp/embed-app.js +197 -7
  294. package/dist/mcp/embed-app.js.map +1 -1
  295. package/dist/mcp/oauth-route.d.ts.map +1 -1
  296. package/dist/mcp/oauth-route.js +95 -12
  297. package/dist/mcp/oauth-route.js.map +1 -1
  298. package/dist/server/attribution.d.ts +83 -0
  299. package/dist/server/attribution.d.ts.map +1 -0
  300. package/dist/server/attribution.js +178 -0
  301. package/dist/server/attribution.js.map +1 -0
  302. package/dist/server/auth.d.ts.map +1 -1
  303. package/dist/server/auth.js +7 -0
  304. package/dist/server/auth.js.map +1 -1
  305. package/dist/server/better-auth-instance.d.ts +9 -1
  306. package/dist/server/better-auth-instance.d.ts.map +1 -1
  307. package/dist/server/better-auth-instance.js +32 -2
  308. package/dist/server/better-auth-instance.js.map +1 -1
  309. package/dist/server/builder-browser.d.ts +4 -0
  310. package/dist/server/builder-browser.d.ts.map +1 -1
  311. package/dist/server/builder-browser.js +20 -1
  312. package/dist/server/builder-browser.js.map +1 -1
  313. package/dist/server/core-routes-plugin.d.ts +25 -0
  314. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  315. package/dist/server/core-routes-plugin.js +101 -0
  316. package/dist/server/core-routes-plugin.js.map +1 -1
  317. package/dist/server/google-oauth.d.ts.map +1 -1
  318. package/dist/server/google-oauth.js +16 -2
  319. package/dist/server/google-oauth.js.map +1 -1
  320. package/dist/server/onboarding-html.d.ts.map +1 -1
  321. package/dist/server/onboarding-html.js +35 -0
  322. package/dist/server/onboarding-html.js.map +1 -1
  323. package/dist/shared/mcp-embed-headers.js +1 -1
  324. package/dist/shared/mcp-embed-headers.js.map +1 -1
  325. package/dist/styles/agent-conversation.css +21 -0
  326. package/dist/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
  327. package/dist/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +72 -0
  328. package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
  329. package/docs/design/durable-agent-runs.md +217 -0
  330. package/package.json +1 -1
  331. package/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
  332. package/src/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +72 -0
  333. package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
  334. package/corpus/templates/analytics/app/pages/About.tsx +0 -108
  335. package/corpus/templates/analytics/app/routes/about.tsx +0 -9
  336. /package/corpus/templates/analytics/app/routes/{dashboards.tsx → dashboards._index.tsx} +0 -0
@@ -1191,6 +1191,7 @@ ${
1191
1191
  }
1192
1192
  }
1193
1193
  function __anFinishOAuthExchange(ret, flowId, sessionToken) {
1194
+ __anGoogleSignInInFlight = false;
1194
1195
  if (__anIsBuilderPreview()) {
1195
1196
  if (sessionToken) {
1196
1197
  __anSetOAuthDebug('OAuth exchange redeemed; applying session bridge to embedded app', flowId);
@@ -1361,6 +1362,8 @@ ${identitySsoScript}
1361
1362
  }
1362
1363
  var __anOAuthPollTimer = null;
1363
1364
  var __anOAuthPollCount = 0;
1365
+ var __anGoogleSignInInFlight = false;
1366
+ var __anGoogleRecoverBound = false;
1364
1367
  function __anNewOAuthFlowId() {
1365
1368
  try {
1366
1369
  if (window.crypto && typeof window.crypto.randomUUID === 'function') {
@@ -1401,6 +1404,34 @@ ${identitySsoScript}
1401
1404
  err.textContent = message;
1402
1405
  err.classList.add('show');
1403
1406
  btn.disabled = false;
1407
+ __anGoogleSignInInFlight = false;
1408
+ }
1409
+ function __anRecoverGoogleSignInAfterReturn() {
1410
+ // The user left for the Google sign-in window and came back. If the flow
1411
+ // never completed (e.g. they closed the window to switch profiles), the
1412
+ // button is stuck disabled with no error path firing for up to 5 minutes.
1413
+ // Re-enable it so they can retry. Wait briefly first so a genuinely
1414
+ // in-flight exchange can still finish and navigate without a flicker.
1415
+ if (!__anGoogleSignInInFlight) return;
1416
+ setTimeout(function() {
1417
+ if (!__anGoogleSignInInFlight) return;
1418
+ var btn = document.getElementById('google-btn');
1419
+ if (!btn || !btn.disabled) return;
1420
+ if (__anOAuthPollTimer) {
1421
+ clearInterval(__anOAuthPollTimer);
1422
+ __anOAuthPollTimer = null;
1423
+ }
1424
+ btn.disabled = false;
1425
+ __anGoogleSignInInFlight = false;
1426
+ }, 1200);
1427
+ }
1428
+ function __anBindGoogleRecover() {
1429
+ if (__anGoogleRecoverBound) return;
1430
+ __anGoogleRecoverBound = true;
1431
+ window.addEventListener('focus', __anRecoverGoogleSignInAfterReturn);
1432
+ document.addEventListener('visibilitychange', function() {
1433
+ if (document.visibilityState === 'visible') __anRecoverGoogleSignInAfterReturn();
1434
+ });
1404
1435
  }
1405
1436
  function __anHandlePopupOAuthFailure(ret, btn, err, flowId, redirectReason, builderFrameMessage) {
1406
1437
  if (__anIsBuilderPreview() && __anIsInFrame()) {
@@ -2013,6 +2044,8 @@ ${
2013
2044
  var err = document.getElementById('google-err');
2014
2045
  var ret = __anGetReturnPath();
2015
2046
  btn.disabled = true;
2047
+ __anGoogleSignInInFlight = true;
2048
+ __anBindGoogleRecover();
2016
2049
  err.classList.remove('show');
2017
2050
  if (__anResolveAuthFlow() === 'popup') {
2018
2051
  __anStartPopupOAuth(ret, btn, err);
@@ -2037,11 +2070,13 @@ ${
2037
2070
  err.textContent = data.message || 'Google OAuth is not configured.';
2038
2071
  err.classList.add('show');
2039
2072
  btn.disabled = false;
2073
+ __anGoogleSignInInFlight = false;
2040
2074
  }
2041
2075
  } catch (e) {
2042
2076
  err.textContent = 'Failed to connect. Please try again.';
2043
2077
  err.classList.add('show');
2044
2078
  btn.disabled = false;
2079
+ __anGoogleSignInInFlight = false;
2045
2080
  }
2046
2081
  }`
2047
2082
  : ""
@@ -4,7 +4,7 @@ export const EMBED_TRANSPLANT_HEADER = "x-agent-native-embed-transplant";
4
4
 
5
5
  const CLAUDE_MCP_CONTENT_HOST_RE = /^[a-f0-9]{32}\.claudemcpcontent\.com$/i;
6
6
  const CHATGPT_MCP_SANDBOX_HOST_RE =
7
- /^[^.]+\.web-sandbox\.oaiusercontent\.com$/i;
7
+ /^(?:[^.]+\.)?web-sandbox\.oaiusercontent\.com$/i;
8
8
 
9
9
  export function isLocalMcpEmbedOrigin(
10
10
  origin: string | null | undefined,
@@ -325,6 +325,27 @@
325
325
  font-size: 12px;
326
326
  }
327
327
 
328
+ .agent-mcp-app__error {
329
+ flex-direction: column;
330
+ text-align: center;
331
+ }
332
+
333
+ .agent-mcp-app__open {
334
+ min-height: 28px;
335
+ border: 1px solid hsl(var(--destructive) / 0.35);
336
+ border-radius: calc(var(--radius) - 2px);
337
+ background: hsl(var(--background));
338
+ color: hsl(var(--foreground));
339
+ cursor: pointer;
340
+ font: inherit;
341
+ font-weight: 600;
342
+ padding: 0 10px;
343
+ }
344
+
345
+ .agent-mcp-app__open:hover {
346
+ background: hsl(var(--muted));
347
+ }
348
+
328
349
  .agent-mcp-app__error,
329
350
  .agent-mcp-app--error {
330
351
  color: hsl(var(--destructive));
@@ -0,0 +1,111 @@
1
+ ---
2
+ name: changelog
3
+ description: >-
4
+ How to keep each app's user-facing changelog. Use when you ship a change a
5
+ user would notice (a new feature, a visible improvement, a bug fix), when
6
+ wiring the in-app "What's new" surface into a template, or when releasing
7
+ pending changelog entries.
8
+ scope: dev
9
+ metadata:
10
+ internal: true
11
+ ---
12
+
13
+ # Changelog — user-facing "What's new"
14
+
15
+ Every template app keeps a `CHANGELOG.md` of **user-facing** changes that
16
+ renders in-app via the command menu (Cmd+K → "What's new") and on the settings
17
+ page. The flow mirrors changesets so it survives many agents working in
18
+ parallel: each change drops a small **pending entry file**, and a later
19
+ **release** rolls all pending files into a dated `CHANGELOG.md` section.
20
+
21
+ ## When to add an entry
22
+
23
+ Add an entry whenever you ship something a user of that app would notice:
24
+
25
+ - a new capability or surface,
26
+ - a visible improvement (speed, layout, copy, defaults),
27
+ - a bug fix that affects behavior they'd see.
28
+
29
+ Do **not** add entries for refactors, internal tooling, tests, dependency
30
+ bumps, or anything invisible to the end user. The changelog is product notes,
31
+ not a commit log — write it the way you'd describe the change to a customer.
32
+
33
+ ## How to add an entry
34
+
35
+ From the app directory (the template you changed):
36
+
37
+ ```bash
38
+ agent-native changelog add "Recordings can be trimmed before sharing" --type added
39
+ agent-native changelog add "Faster transcript search" --type improved
40
+ agent-native changelog add "Fixed a crash when opening an empty folder" --type fixed
41
+ ```
42
+
43
+ `--type` is one of `added`, `improved`, `fixed`, `changed`, `removed`,
44
+ `security` (aliases like `feature`, `bugfix`, `enhancement` are accepted). This
45
+ writes `changelog/<date>-<slug>.md` — one file per change, so parallel work
46
+ never conflicts. You can also hand-write that file; the frontmatter is just:
47
+
48
+ ```md
49
+ ---
50
+ type: added
51
+ date: 2026-06-23
52
+ ---
53
+ Recordings can be trimmed before sharing.
54
+ ```
55
+
56
+ ## Writing good entries
57
+
58
+ - One user-facing sentence, present tense, no internal jargon or file names.
59
+ - Lead with the benefit ("Recordings can be trimmed…"), not the mechanism.
60
+ - Markdown is allowed (bold, links) but keep it short — it renders as a bullet.
61
+
62
+ ## Releasing
63
+
64
+ `release` stamps every pending entry into `CHANGELOG.md` under a dated
65
+ `## <date>` section (grouped by type) and deletes the pending files:
66
+
67
+ ```bash
68
+ agent-native changelog release # uses today's date
69
+ agent-native changelog list # preview pending + released
70
+ ```
71
+
72
+ Releasing is usually done at deploy/merge time. The in-app surface reads
73
+ `CHANGELOG.md`, so only released entries are visible to users — pending entries
74
+ stay invisible until rolled up.
75
+
76
+ ## Wiring the in-app surface (once per template)
77
+
78
+ Templates already get the rendering for free from `@agent-native/core`. To
79
+ expose it in an app:
80
+
81
+ 1. **Command menu** — pass the app's own changelog to `CommandMenu`:
82
+
83
+ ```tsx
84
+ import changelog from "../CHANGELOG.md?raw";
85
+ // ...
86
+ <CommandMenu open={cmdkOpen} onOpenChange={setCmdkOpen} changelog={changelog}>
87
+ {/* existing groups */}
88
+ </CommandMenu>
89
+ ```
90
+
91
+ This adds a "What's new" entry with an unseen-release dot and an in-app
92
+ dialog — no other wiring needed.
93
+
94
+ 2. **Settings** (optional) — drop the card on the settings page:
95
+
96
+ ```tsx
97
+ import { ChangelogSettingsCard } from "@agent-native/core/client";
98
+ import changelog from "../CHANGELOG.md?raw";
99
+ // ...
100
+ <ChangelogSettingsCard markdown={changelog} />
101
+ ```
102
+
103
+ `CHANGELOG.md?raw` is inlined by Vite at build time, so this works on every
104
+ host with no server route or runtime file access.
105
+
106
+ ## Checklist
107
+
108
+ - [ ] Shipped a user-visible change? Run `agent-native changelog add "…"`.
109
+ - [ ] New template UI? Pass `changelog` to its `CommandMenu` and seed a
110
+ `CHANGELOG.md`.
111
+ - [ ] Releasing/deploying? `agent-native changelog release` rolls pending → dated.
@@ -0,0 +1,72 @@
1
+ ---
2
+ name: reliable-mutations
3
+ description: >-
4
+ How the agent must perform writes so they actually persist under the hosted
5
+ ~40s run budget. Use whenever you create, update, delete, or batch-write app
6
+ data — especially "do this for many items" loops, or any task where the user
7
+ expects N things to end up saved.
8
+ ---
9
+
10
+ # Reliable Mutations
11
+
12
+ ## Rule
13
+
14
+ Make a change in **one atomic call** when the action supports it, then **verify
15
+ the persisted end state and report concrete proof** (counts/ids). Never drive a
16
+ multi-step change by looping many small writes, and never report success from a
17
+ tool ✓ alone.
18
+
19
+ ## Why
20
+
21
+ Hosted agent runs have a ~40s soft budget (it exists to hand off cleanly under
22
+ the upstream gateway/function walls — it is correct and is not raisable; see the
23
+ durable-agent-runs design doc). When you loop many sequential writes inside one
24
+ turn, the budget can cut you off mid-loop. The run resumes in a new chunk, but
25
+ the resume often re-does earlier steps instead of advancing, so the loop churns
26
+ and the *saved* result ends up partial — or empty — even though each individual
27
+ tool call appeared to succeed. The user gets told "done" while the data says
28
+ otherwise. One atomic call commits or fails as a unit; verification turns a
29
+ hopeful ✓ into a fact.
30
+
31
+ ## How
32
+
33
+ 1. **Prefer a single atomic call.** If an action accepts the whole set (add
34
+ many, set all, bulk update), pass the full batch in one call so it commits
35
+ atomically. Check the action surface for a batch/plural form before reaching
36
+ for a loop.
37
+ 2. **Do not loop many small writes under the run budget.** A sequence of N
38
+ per-item writes in one turn will race the ~40s cutoff and can leave partial
39
+ or no state. If no batch action exists, that is a gap in the action layer —
40
+ add or extend an action that accepts the batch (see the `actions` skill)
41
+ rather than papering over it with a loop.
42
+ 3. **Verify the end state after writing.** Re-read the data (a list/read action,
43
+ a count query) and confirm the result matches intent — the right number of
44
+ rows, the expected ids/fields. Do this before you tell the user it worked.
45
+ 4. **Report proof-of-done, not vibes.** State concrete evidence: "saved 12 of 12
46
+ panels (ids …)" or "updated 5 rows". Do not infer success from the presence
47
+ of a tool ✓ on an individual call.
48
+ 5. **On a time-budget cutoff, fail loud.** If the turn is cut before the change
49
+ is fully committed and verified, say so explicitly and report what *did*
50
+ persist (M of N) and what remains. Never round a partial or unverified write
51
+ up to "done".
52
+
53
+ ## Don't
54
+
55
+ - Don't loop `for each item: write(item)` for a large set in a single hosted
56
+ turn.
57
+ - Don't claim completion because every tool call returned ✓ — a ✓ on an aborted
58
+ chunk does not mean the row was committed.
59
+ - Don't silently shrink the scope ("I added a few of them") and present it as the
60
+ finished task.
61
+ - Don't try to "fix" this by asking for a longer run timeout — the budget is
62
+ correct; restructure the write instead.
63
+
64
+ ## Related
65
+
66
+ - `actions` — define or extend a batch/atomic action when only per-item writes
67
+ exist.
68
+ - `storing-data` — where app data lives and how reads/writes are scoped.
69
+ - `performance` — avoid query waterfalls when verifying end state.
70
+ - Design doc: `packages/core/docs/design/durable-agent-runs.md` — the real
71
+ ceiling fix (checkpointed and durable runs); this skill is the agent-facing
72
+ mitigation that reduces how often the ceiling is hit.
@@ -31,7 +31,11 @@ Fire an analytics event.
31
31
  ```ts
32
32
  import { track } from "@agent-native/core/tracking";
33
33
 
34
- track("meal.logged", { mealName: "Salad", calories: 350 }, { userId: "user@example.com" });
34
+ track(
35
+ "meal.logged",
36
+ { mealName: "Salad", calories: 350 },
37
+ { userId: "user@example.com" },
38
+ );
35
39
  ```
36
40
 
37
41
  ### `identify(userId, traits?)`
@@ -73,13 +77,13 @@ Flush all providers (call before process exit).
73
77
 
74
78
  Set the env var and the provider auto-registers at startup. No SDK dependencies -- all providers use raw HTTP.
75
79
 
76
- | Provider | Env vars |
77
- | ---------- | --------------------------------------------------------- |
78
- | PostHog | `POSTHOG_API_KEY` (required), `POSTHOG_HOST` (optional, defaults to `https://us.i.posthog.com`) |
79
- | Mixpanel | `MIXPANEL_TOKEN` |
80
- | Amplitude | `AMPLITUDE_API_KEY` |
80
+ | Provider | Env vars |
81
+ | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
82
+ | PostHog | `POSTHOG_API_KEY` (required), `POSTHOG_HOST` (optional, defaults to `https://us.i.posthog.com`) |
83
+ | Mixpanel | `MIXPANEL_TOKEN` |
84
+ | Amplitude | `AMPLITUDE_API_KEY` |
81
85
  | Agent Native Analytics | `AGENT_NATIVE_ANALYTICS_PUBLIC_KEY` (server), `AGENT_NATIVE_ANALYTICS_ENDPOINT` (optional, defaults to `https://analytics.agent-native.com/track`) |
82
- | Webhook | `TRACKING_WEBHOOK_URL` (required), `TRACKING_WEBHOOK_AUTH` (optional, sent as `Authorization` header) |
86
+ | Webhook | `TRACKING_WEBHOOK_URL` (required), `TRACKING_WEBHOOK_AUTH` (optional, sent as `Authorization` header) |
83
87
 
84
88
  Multiple providers can be active simultaneously. All receive every event.
85
89
 
@@ -106,10 +110,35 @@ Every browser-side `trackEvent()` POST to the Agent Native Analytics `/track` en
106
110
 
107
111
  These fields land in the `analytics_events.anonymous_id`, `analytics_events.session_id`, and `analytics_events.user_id` columns in the analytics template. Storage access is wrapped in try/catch — private-browsing / blocked-storage clients silently degrade to NULL rather than crashing the page.
108
112
 
113
+ ### Referral / viral attribution (first-touch)
114
+
115
+ `configureTracking()` also captures an anonymous visitor's **first-touch** referral context once, on first page load, and persists it across the signup boundary so the server-side `signup` event records where the user came from. This powers virality metrics for every template (Clips share links, Plans public pages, etc.).
116
+
117
+ **Share-link params** (set by whatever generates the link; read client-side only):
118
+
119
+ - `ref` — referral source bucket, e.g. `clip_share`, `plan_share`
120
+ - `via` — the referrer's stable user id (the clip/plan owner)
121
+ - `utm_source`, `utm_medium`, `utm_campaign`, `utm_content`, `utm_term`
122
+
123
+ **Client persistence** (first-write-wins — an existing value is never overwritten):
124
+
125
+ - `localStorage` key `an_attribution` and first-party cookie `an_ft` (`path=/; max-age=2592000; SameSite=Lax`, not HttpOnly — non-sensitive, written by client JS).
126
+ - Both store the same URL-encoded compact JSON (empty fields omitted, each value capped at 120 chars): `{ ref, via, utm_source, utm_medium, utm_campaign, utm_content, utm_term, landing_path, landing_referrer, landed_at }`. `landing_referrer` is the **host only** of `document.referrer` (scrubbed; same-origin referrers are dropped).
127
+ - `getFirstTouchAttribution()` (from `@agent-native/core/client`) returns the parsed object or `null`.
128
+
129
+ **Signup event enrichment** (server-side, from the `an_ft` cookie on the signup/OAuth-callback request, derived in `packages/core/src/server/attribution.ts`):
130
+
131
+ - `referral_source` — `ref` if present, else derived: `/share/…` → `clip_share`; a plan public path (`/p/`, `/plan/`, `/share-plan/`) → `plan_share`; a non-empty external referring host → `external`; otherwise `direct`.
132
+ - `referrer_user` (= `via`), `referral_medium` (= `utm_medium`), `referral_campaign` (= `utm_campaign`)
133
+ - `utm_source`, `utm_medium`, `utm_campaign`, `utm_content`, `utm_term` (raw passthrough)
134
+ - `first_touch_path` (= `landing_path`), `landing_referrer`
135
+
136
+ Attribution parsing is fully defensive and never blocks signup — a missing/malformed cookie falls back to `referral_source: "direct"`.
137
+
109
138
  Other framework-level baseline events:
110
139
 
111
140
  - `session status` from `useSession()`, with `signed_in`
112
- - `signup` from Better Auth user creation, with `auth_provider` and `auth_user_id`
141
+ - `signup` from Better Auth user creation, with `auth_provider`, `auth_user_id`, and first-touch referral attribution (`referral_source`, `referrer_user`, `referral_medium`, `referral_campaign`, `utm_*`, `first_touch_path`, `landing_referrer` — see "Referral / viral attribution" above)
113
142
  - `builder connect clicked` and `builder connect popup blocked` from browser Connect Builder CTAs
114
143
  - `builder connect started`, `builder connect succeeded`, `builder connect failed`, `builder disconnect succeeded`, and `builder disconnect failed` from the Builder connection routes, with LLM connection context when resolvable
115
144
 
@@ -121,7 +150,10 @@ For new lifecycle events, call `track()` server-side when the server is the sour
121
150
  interface TrackingProvider {
122
151
  name: string;
123
152
  track(event: TrackingEvent): void | Promise<void>;
124
- identify?(userId: string, traits?: Record<string, unknown>): void | Promise<void>;
153
+ identify?(
154
+ userId: string,
155
+ traits?: Record<string, unknown>,
156
+ ): void | Promise<void>;
125
157
  flush?(): void | Promise<void>;
126
158
  }
127
159
 
@@ -142,11 +174,11 @@ interface TrackingEvent {
142
174
 
143
175
  ## Key Files
144
176
 
145
- | File | Purpose |
146
- | ---------------------------------------------- | ------------------------------------------- |
147
- | `packages/core/src/tracking/registry.ts` | `track()`, `identify()`, `registerTrackingProvider()`, `flushTracking()` |
148
- | `packages/core/src/tracking/providers.ts` | Built-in providers (PostHog, Mixpanel, Amplitude, Agent Native Analytics, Webhook) and `registerBuiltinProviders()` |
149
- | `packages/core/src/tracking/types.ts` | `TrackingEvent` and `TrackingProvider` interfaces |
177
+ | File | Purpose |
178
+ | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
179
+ | `packages/core/src/tracking/registry.ts` | `track()`, `identify()`, `registerTrackingProvider()`, `flushTracking()` |
180
+ | `packages/core/src/tracking/providers.ts` | Built-in providers (PostHog, Mixpanel, Amplitude, Agent Native Analytics, Webhook) and `registerBuiltinProviders()` |
181
+ | `packages/core/src/tracking/types.ts` | `TrackingEvent` and `TrackingProvider` interfaces |
150
182
 
151
183
  ## Related Skills
152
184
 
@@ -174,6 +174,28 @@ pnpm action update-dashboard --dashboardId weekly-metrics --config '<full json>'
174
174
 
175
175
  After a mutation, navigate to the dashboard if the user is elsewhere. The app syncs through the framework's polling/query invalidation path.
176
176
 
177
+ ## Reliable Bulk Edits
178
+
179
+ This is the dashboard-specific application of the framework-wide `reliable-mutations` skill — read that for the general rule (one atomic write, verify end state, report proof-of-done).
180
+
181
+ Hosted agent runs have a **~40s budget**. Many sequential `update-dashboard` calls (one per panel, plus schema-discovery calls) will blow that budget and leave the dashboard in a partial state — earlier inserts looked like they succeeded (✓), but nothing actually persisted. Avoid this:
182
+
183
+ - **Batch ALL changes into ONE `update-dashboard` call.** A single `update-dashboard` is atomic: it applies every op to an in-memory config, validates all panel SQL, then upserts once. Never loop the action.
184
+ - To add N panels, pass N ops in one call: `ops: [{op:"insert", path:"/panels/-", value:<panel>}, … ]` (`/panels/-` appends to the end).
185
+ - The `ops` format needs no discovery: each op is `{ op, path, from?, value? }`, `op ∈ set | replace | remove | insert | move | move-before`, and `path` is a JSON Pointer (e.g. `/panels/3`, `/panels/3/title`, `/name`).
186
+ - **To add a shipped template's panels, prefer `install-dashboard-template` with `mergePanels: true`** and the existing `dashboardId`. It appends only the template panels whose id is not already present (preserving existing panels and order) in one atomic save — you don't author each panel yourself.
187
+ - **Always verify the returned proof-of-done and report it.** `update-dashboard` returns `panelCount`, `appliedOps`, and a `summary` string; `install-dashboard-template --mergePanels` returns `addedPanelIds`, `skippedExistingIds`, and `panelCount`. Tell the user the resulting panel count instead of assuming success.
188
+
189
+ ```bash
190
+ # Add several panels in ONE atomic call (never one call per panel)
191
+ pnpm action update-dashboard --dashboardId weekly-metrics \
192
+ --ops '[{"op":"insert","path":"/panels/-","value":{"id":"p1","title":"A","source":"first-party","chartType":"metric","width":1,"sql":"SELECT COUNT(*) AS value FROM analytics_events"}},
193
+ {"op":"insert","path":"/panels/-","value":{"id":"p2","title":"B","source":"first-party","chartType":"metric","width":1,"sql":"SELECT COUNT(DISTINCT user_id) AS value FROM analytics_events"}}]'
194
+
195
+ # Append a template's panels to an existing dashboard in one call
196
+ pnpm action install-dashboard-template --templateId skills-cli-funnel --dashboardId weekly-metrics --mergePanels true
197
+ ```
198
+
177
199
  ## Archiving vs deleting
178
200
 
179
201
  Dashboards have a soft-delete state. The default user-facing destructive action is **Archive** (recoverable). Hard delete still exists, but lives behind a "Delete permanently" confirm in both the page header and the sidebar dropdown — and in the agent surface, behind the older `delete-dashboard` action. Archived rows stay in the `dashboards` table with `archived_at` set, are hidden from the default sidebar list, and remain accessible by id (so deep links in chat history keep working) until explicitly purged.
@@ -87,7 +87,14 @@ details live in `.agents/skills/`.
87
87
  `id`, category, data sources, panel count, and installed dashboard IDs.
88
88
  - `install-dashboard-template` installs a catalog template into normal
89
89
  SQL-backed dashboards. Required: `templateId`. Optional: `dashboardId`,
90
- `name`, `overwrite`, and `forceNew`.
90
+ `name`, `overwrite`, `forceNew`, and `mergePanels`.
91
+ - To add a template's panels to an existing dashboard, call
92
+ `install-dashboard-template` with `mergePanels: true` and the existing
93
+ `dashboardId`. It appends only the template panels whose id is not already
94
+ present (preserving existing panels and order) in one atomic save and returns
95
+ `{ addedPanelIds, skippedExistingIds, panelCount }`. Prefer this over looping
96
+ `update-dashboard` to add many panels — sequential calls time out on the ~40s
97
+ hosted run budget.
91
98
  - Node Exporter ships as `node-exporter-macos` for Darwin/Homebrew
92
99
  `node_exporter` scrapes and `node-exporter-full` for the Linux-focused
93
100
  Grafana 1860 revision 45 full dashboard converted into native Analytics
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ All notable user-facing changes to Agent-Native Analytics are documented here. Open it any
4
+ time from the command menu (Cmd+K → "What's new") or from Settings.
5
+
6
+ ## 2026-06-23
7
+
8
+ ### Added
9
+
10
+ - See what's new right inside Agent-Native Analytics — a changelog now lives in the command menu (Cmd+K) and in Settings.
@@ -43,7 +43,8 @@ function uniqueConstraintMessage(err: unknown): boolean {
43
43
 
44
44
  export default defineAction({
45
45
  description:
46
- "Install a dashboard template from the Analytics catalog into the user's SQL-backed dashboards. Use list-dashboard-templates first when choosing a template.",
46
+ "Install a dashboard template from the Analytics catalog into the user's SQL-backed dashboards. Use list-dashboard-templates first when choosing a template. " +
47
+ "To ADD a template's panels to an EXISTING dashboard in ONE call (the preferred way to bulk-add panels), pass `mergePanels: true` with the `dashboardId` of the existing dashboard: it appends every template panel whose id is not already present, preserves all existing panels and their order, and saves once. This avoids looping update-dashboard, which times out on the ~40s hosted run budget.",
47
48
  schema: z.object({
48
49
  templateId: z
49
50
  .string()
@@ -52,7 +53,7 @@ export default defineAction({
52
53
  .string()
53
54
  .optional()
54
55
  .describe(
55
- "Optional dashboard id to write. Omit to reuse an existing installed copy or create a unique id.",
56
+ "Optional dashboard id to write. Omit to reuse an existing installed copy or create a unique id. Required when mergePanels is true.",
56
57
  ),
57
58
  name: z
58
59
  .string()
@@ -70,6 +71,12 @@ export default defineAction({
70
71
  .describe(
71
72
  "If true, create another copy even when this template is installed.",
72
73
  ),
74
+ mergePanels: z
75
+ .boolean()
76
+ .optional()
77
+ .describe(
78
+ "If true AND a dashboard already exists at dashboardId, APPEND this template's panels (only the ones whose id is not already present) to the existing dashboard in one atomic save, preserving all existing panels and their order. Returns { addedPanelIds, skippedExistingIds, panelCount }. Non-destructive; does not change overwrite/forceNew behavior.",
79
+ ),
73
80
  }),
74
81
  mcpApp: {
75
82
  compactCatalog: true,
@@ -90,6 +97,94 @@ export default defineAction({
90
97
  if (!entry)
91
98
  throw new Error(`Unknown dashboard template: ${args.templateId}`);
92
99
 
100
+ // Append/merge mode: add this template's panels to an existing dashboard
101
+ // in ONE atomic save instead of looping update-dashboard (which times out
102
+ // on the ~40s hosted run budget). Non-destructive: existing panels and
103
+ // their order are preserved; only template panels with a new id are added.
104
+ if (args.mergePanels) {
105
+ const targetId = args.dashboardId?.trim();
106
+ if (!targetId) {
107
+ throw new Error(
108
+ "mergePanels=true requires dashboardId (the existing dashboard to append the template's panels to).",
109
+ );
110
+ }
111
+ const target = await getDashboard(targetId, ctx);
112
+ if (!target) {
113
+ throw new Error(
114
+ `Dashboard "${targetId}" not found (or you don't have access). mergePanels appends to an existing dashboard — install the template normally first, or omit mergePanels to create a new copy.`,
115
+ );
116
+ }
117
+
118
+ const targetConfig = target.config as Record<string, unknown>;
119
+ const existingPanels = Array.isArray(targetConfig.panels)
120
+ ? (targetConfig.panels as Array<Record<string, unknown>>)
121
+ : [];
122
+ const existingIds = new Set(
123
+ existingPanels
124
+ .map((panel) => (typeof panel?.id === "string" ? panel.id : null))
125
+ .filter((id): id is string => !!id),
126
+ );
127
+
128
+ const seedConfig = cloneDashboardConfig(entry);
129
+ const seedPanels = Array.isArray(seedConfig.panels)
130
+ ? (seedConfig.panels as unknown as Array<Record<string, unknown>>)
131
+ : [];
132
+
133
+ const addedPanelIds: string[] = [];
134
+ const skippedExistingIds: string[] = [];
135
+ const appended: Array<Record<string, unknown>> = [];
136
+ for (const panel of seedPanels) {
137
+ const id = typeof panel?.id === "string" ? panel.id : null;
138
+ if (id && existingIds.has(id)) {
139
+ skippedExistingIds.push(id);
140
+ continue;
141
+ }
142
+ appended.push(panel);
143
+ if (id) {
144
+ addedPanelIds.push(id);
145
+ existingIds.add(id);
146
+ }
147
+ }
148
+
149
+ const mergedConfig: Record<string, unknown> = {
150
+ ...targetConfig,
151
+ panels: [...existingPanels, ...appended],
152
+ };
153
+ const panelCount = (mergedConfig.panels as unknown[]).length;
154
+
155
+ if (appended.length > 0) {
156
+ const saved = await upsertDashboard(
157
+ targetId,
158
+ target.kind,
159
+ mergedConfig,
160
+ ctx,
161
+ );
162
+ await syncToCollab(targetId, mergedConfig);
163
+ targetConfig.name = saved.title;
164
+ }
165
+
166
+ return {
167
+ templateId: entry.id,
168
+ templateName: entry.name,
169
+ dashboardId: targetId,
170
+ name: target.title,
171
+ merged: true,
172
+ addedPanelIds,
173
+ skippedExistingIds,
174
+ panelCount,
175
+ urlPath: `/dashboards/${targetId}`,
176
+ deepLink: buildDeepLink({
177
+ app: "analytics",
178
+ view: "adhoc",
179
+ params: { dashboardId: targetId },
180
+ }),
181
+ message:
182
+ appended.length > 0
183
+ ? `Added ${addedPanelIds.length} panel(s) from "${entry.name}" to "${target.title}"; ${skippedExistingIds.length} already present. Dashboard now has ${panelCount} panel(s).`
184
+ : `No new panels to add from "${entry.name}" — all ${skippedExistingIds.length} template panel id(s) already present. Dashboard has ${panelCount} panel(s).`,
185
+ };
186
+ }
187
+
93
188
  const installed = (await listDashboardCatalog(ctx)).find(
94
189
  (template) => template.id === entry.id,
95
190
  );
@@ -100,7 +195,7 @@ export default defineAction({
100
195
  dashboardId: existingInstall.id,
101
196
  name: existingInstall.name,
102
197
  alreadyInstalled: true,
103
- urlPath: `/adhoc/${existingInstall.id}`,
198
+ urlPath: `/dashboards/${existingInstall.id}`,
104
199
  deepLink: buildDeepLink({
105
200
  app: "analytics",
106
201
  view: "adhoc",
@@ -144,7 +239,7 @@ export default defineAction({
144
239
  name: dashboard.title,
145
240
  alreadyInstalled: false,
146
241
  overwritten: !!existing,
147
- urlPath: `/adhoc/${dashboardId}`,
242
+ urlPath: `/dashboards/${dashboardId}`,
148
243
  deepLink: buildDeepLink({
149
244
  app: "analytics",
150
245
  view: "adhoc",
@@ -2,7 +2,7 @@ import { defineAction, embedApp } from "@agent-native/core";
2
2
  import { buildDeepLink } from "@agent-native/core/server";
3
3
  import { z } from "zod";
4
4
 
5
- const TRAFFIC_DASHBOARD_PATH = "/adhoc/agent-native-templates-first-party";
5
+ const TRAFFIC_DASHBOARD_PATH = "/dashboards/agent-native-templates-first-party";
6
6
  const TRAFFIC_DASHBOARD_ID = "agent-native-templates-first-party";
7
7
 
8
8
  function trafficDashboardDeepLink(): string {