@agent-native/core 0.145.4 → 0.145.6

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 (398) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +18 -0
  3. package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  4. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +17 -1
  5. package/corpus/templates/analytics/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  6. package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +1 -0
  7. package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +22 -3
  8. package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +76 -23
  9. package/corpus/templates/analytics/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  10. package/corpus/templates/analytics/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  11. package/corpus/templates/analytics/AGENTS.md +2 -1
  12. package/corpus/templates/analytics/actions/account-deep-dive.ts +83 -47
  13. package/corpus/templates/analytics/actions/create-dashboard-folder.ts +27 -0
  14. package/corpus/templates/analytics/actions/gong-calls.ts +3 -3
  15. package/corpus/templates/analytics/actions/list-dashboard-folders.ts +26 -0
  16. package/corpus/templates/analytics/actions/list-sql-dashboards.ts +1 -0
  17. package/corpus/templates/analytics/actions/set-dashboard-folder.ts +26 -0
  18. package/corpus/templates/analytics/app/components/ProviderCorpusJobNotifier.tsx +18 -3
  19. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +6 -4
  20. package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -0
  21. package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +12 -2
  22. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +35 -20
  23. package/corpus/templates/analytics/app/global.css +17 -0
  24. package/corpus/templates/analytics/app/hooks/use-dashboard-revisions.ts +29 -15
  25. package/corpus/templates/analytics/app/hooks/use-dashboard-views.ts +15 -3
  26. package/corpus/templates/analytics/app/i18n-data.ts +296 -0
  27. package/corpus/templates/analytics/app/lib/prefetch-keys.ts +23 -2
  28. package/corpus/templates/analytics/app/pages/DashboardOverview.tsx +642 -0
  29. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +66 -31
  30. package/corpus/templates/analytics/app/root.tsx +4 -0
  31. package/corpus/templates/analytics/app/routes/dashboards._index.tsx +5 -1
  32. package/corpus/templates/analytics/changelog/2026-08-07-added-a-dashboards-overview-with-personal-and-shared-folders.md +6 -0
  33. package/corpus/templates/analytics/changelog/2026-08-07-analytics-tracking-and-chat-startup-no-longer-emit-avoidable.md +6 -0
  34. package/corpus/templates/analytics/changelog/2026-08-07-dashboard-panels-now-load-custom-api-data-programs-reliably.md +6 -0
  35. package/corpus/templates/analytics/changelog/2026-08-07-gong-searches-conserve-api-quota-and-report-incomplete-coverage.md +6 -0
  36. package/corpus/templates/analytics/changelog/2026-08-07-searchable-dashboards-make-personal-and-shared-folders-easie.md +6 -0
  37. package/corpus/templates/analytics/netlify.toml +3 -0
  38. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +112 -0
  39. package/corpus/templates/analytics/server/db/index.ts +12 -0
  40. package/corpus/templates/analytics/server/db/schema.ts +14 -0
  41. package/corpus/templates/analytics/server/jobs/analytics-rollup-backfill.ts +4 -0
  42. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +1 -0
  43. package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +85 -15
  44. package/corpus/templates/analytics/server/lib/dashboard-folders-store.ts +168 -0
  45. package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +9 -4
  46. package/corpus/templates/analytics/server/lib/dashboards-store.ts +116 -1
  47. package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +4 -8
  48. package/corpus/templates/analytics/server/lib/gong.ts +139 -78
  49. package/corpus/templates/analytics/server/plugins/db.ts +55 -15
  50. package/corpus/templates/analytics/server/plugins/session-replay-retention-jobs.ts +6 -2
  51. package/corpus/templates/analytics/server/routes/api/session-replay/retention.post.ts +65 -0
  52. package/corpus/templates/assets/.agents/skills/actions/SKILL.md +18 -0
  53. package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  54. package/corpus/templates/assets/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  55. package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +1 -0
  56. package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +76 -23
  57. package/corpus/templates/assets/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  58. package/corpus/templates/assets/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  59. package/corpus/templates/brain/.agents/skills/actions/SKILL.md +18 -0
  60. package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  61. package/corpus/templates/brain/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  62. package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +1 -0
  63. package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +76 -23
  64. package/corpus/templates/brain/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  65. package/corpus/templates/brain/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  66. package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +18 -0
  67. package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  68. package/corpus/templates/calendar/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  69. package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +1 -0
  70. package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +76 -23
  71. package/corpus/templates/calendar/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  72. package/corpus/templates/calendar/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  73. package/corpus/templates/chat/.agents/skills/actions/SKILL.md +18 -0
  74. package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  75. package/corpus/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  76. package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +1 -0
  77. package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +76 -23
  78. package/corpus/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  79. package/corpus/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  80. package/corpus/templates/chat/.env.example +3 -0
  81. package/corpus/templates/chat/AGENTS.md +4 -0
  82. package/corpus/templates/clips/.agents/skills/actions/SKILL.md +18 -0
  83. package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  84. package/corpus/templates/clips/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  85. package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +1 -0
  86. package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +76 -23
  87. package/corpus/templates/clips/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  88. package/corpus/templates/clips/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  89. package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +4 -0
  90. package/corpus/templates/clips/actions/request-transcript.ts +52 -3
  91. package/corpus/templates/clips/app/components/editor/editor-layout.tsx +8 -3
  92. package/corpus/templates/clips/app/components/editor/waveform.tsx +2 -1
  93. package/corpus/templates/clips/app/components/library/search-bar.tsx +1 -1
  94. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +3 -10
  95. package/corpus/templates/clips/app/global.css +9 -0
  96. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -0
  97. package/corpus/templates/clips/changelog/2026-08-07-screen-recordings-now-capture-tab-and-system-audio-even-when.md +6 -0
  98. package/corpus/templates/clips/changelog/2026-08-07-transcription-now-retries-transient-cloud-failures-automatic.md +6 -0
  99. package/corpus/templates/clips/desktop/src-tauri/src/silence_detector.rs +10 -11
  100. package/corpus/templates/clips/server/db/schema.ts +7 -0
  101. package/corpus/templates/clips/server/plugins/db.ts +8 -0
  102. package/corpus/templates/clips/shared/recording-capture.ts +38 -0
  103. package/corpus/templates/clips/shared/transcript-failure.ts +89 -0
  104. package/corpus/templates/content/.agents/skills/actions/SKILL.md +18 -0
  105. package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  106. package/corpus/templates/content/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  107. package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +1 -0
  108. package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +76 -23
  109. package/corpus/templates/content/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  110. package/corpus/templates/content/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  111. package/corpus/templates/content/.env.example +9 -3
  112. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +1 -0
  113. package/corpus/templates/content/changelog/2026-08-07-collapsed-sidebar-utility-buttons-stay-anchored-at-the-botto.md +6 -0
  114. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  115. package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +76 -23
  116. package/corpus/templates/crm/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  117. package/corpus/templates/crm/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  118. package/corpus/templates/design/.agents/skills/actions/SKILL.md +18 -0
  119. package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  120. package/corpus/templates/design/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  121. package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +1 -0
  122. package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +76 -23
  123. package/corpus/templates/design/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  124. package/corpus/templates/design/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  125. package/corpus/templates/design/actions/view-screen.ts +1 -0
  126. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +14 -1
  127. package/corpus/templates/design/changelog/2026-08-07-cmd-c-now-copies-selected-text-in-the-agent-panel-instead-of.md +6 -0
  128. package/corpus/templates/design/changelog/2026-08-07-real-time-voice-can-now-read-the-current-selection-and-edit-.md +6 -0
  129. package/corpus/templates/design/server/lib/reprompt-action-guard.ts +7 -3
  130. package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +18 -0
  131. package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  132. package/corpus/templates/dispatch/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  133. package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +1 -0
  134. package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +76 -23
  135. package/corpus/templates/dispatch/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  136. package/corpus/templates/dispatch/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  137. package/corpus/templates/factory/.agents/skills/actions/SKILL.md +18 -0
  138. package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  139. package/corpus/templates/factory/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  140. package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +1 -0
  141. package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +76 -23
  142. package/corpus/templates/factory/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  143. package/corpus/templates/factory/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  144. package/corpus/templates/factory/actions/babysit-agent-native-pull-request.ts +279 -0
  145. package/corpus/templates/factory/actions/get-factory-automation-health.ts +23 -4
  146. package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +1 -1
  147. package/corpus/templates/factory/app/routes/factory.tsx +21 -3
  148. package/corpus/templates/factory/changelog/2026-08-07-factory-can-keep-builder-bot-pull-requests-moving-by-request.md +6 -0
  149. package/corpus/templates/factory/server/lib/require-factory-automation.ts +1 -0
  150. package/corpus/templates/factory/server/plugins/agent-chat.ts +4 -1
  151. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +81 -12
  152. package/corpus/templates/factory/server/triage/github-client.ts +31 -0
  153. package/corpus/templates/factory/server/triage/pr-babysit.ts +75 -1
  154. package/corpus/templates/forms/.agents/skills/actions/SKILL.md +18 -0
  155. package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  156. package/corpus/templates/forms/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  157. package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +1 -0
  158. package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +76 -23
  159. package/corpus/templates/forms/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  160. package/corpus/templates/forms/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  161. package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  162. package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +1 -0
  163. package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +76 -23
  164. package/corpus/templates/macros/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  165. package/corpus/templates/macros/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  166. package/corpus/templates/mail/.agents/skills/actions/SKILL.md +18 -0
  167. package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  168. package/corpus/templates/mail/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  169. package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +1 -0
  170. package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +76 -23
  171. package/corpus/templates/mail/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  172. package/corpus/templates/mail/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  173. package/corpus/templates/plan/.agents/skills/actions/SKILL.md +18 -0
  174. package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  175. package/corpus/templates/plan/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  176. package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +1 -0
  177. package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +76 -23
  178. package/corpus/templates/plan/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  179. package/corpus/templates/plan/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  180. package/corpus/templates/plan/app/pages/PlansPage.tsx +2 -1
  181. package/corpus/templates/plan/changelog/2026-08-07-inline-help-icons-now-stay-visually-balanced-with-nearby-tex.md +6 -0
  182. package/corpus/templates/slides/.agents/skills/actions/SKILL.md +18 -0
  183. package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  184. package/corpus/templates/slides/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  185. package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +1 -0
  186. package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +76 -23
  187. package/corpus/templates/slides/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  188. package/corpus/templates/slides/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  189. package/corpus/templates/slides/.env.example +5 -0
  190. package/corpus/templates/slides/changelog/2026-08-07-fixed-generated-slides-briefly-disappearing-while-they-are-b.md +6 -0
  191. package/corpus/templates/slides/server/plugins/collab.ts +20 -8
  192. package/corpus/templates/tasks/.agents/skills/actions/SKILL.md +18 -0
  193. package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  194. package/corpus/templates/tasks/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  195. package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +1 -0
  196. package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +76 -23
  197. package/corpus/templates/tasks/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  198. package/corpus/templates/tasks/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  199. package/corpus/templates/tasks/.env.example +3 -0
  200. package/dist/agent/production-agent.js +24 -3
  201. package/dist/client/AgentPanel.d.ts +6 -0
  202. package/dist/client/AgentPanel.js +176 -30
  203. package/dist/client/AssistantChat.d.ts +2 -0
  204. package/dist/client/AssistantChat.js +4 -1
  205. package/dist/client/ConnectBuilderCard.js +6 -11
  206. package/dist/client/MultiTabAssistantChat.js +1 -1
  207. package/dist/client/RuntimeConfigNotice.d.ts +1 -0
  208. package/dist/client/RuntimeConfigNotice.js +94 -0
  209. package/dist/client/agent-chat/index.d.ts +1 -1
  210. package/dist/client/agent-chat/index.js +1 -1
  211. package/dist/client/agent-chat-adapter.js +85 -4
  212. package/dist/client/agent-page/AgentTabsPage.js +1 -1
  213. package/dist/client/agent-sidebar-state.d.ts +6 -0
  214. package/dist/client/agent-sidebar-state.js +25 -0
  215. package/dist/client/app-providers.js +2 -1
  216. package/dist/client/assistant-ui-recovery.js +1 -1
  217. package/dist/client/chat/index.d.ts +1 -1
  218. package/dist/client/chat/index.js +1 -1
  219. package/dist/client/chat/markdown-renderer.d.ts +2 -1
  220. package/dist/client/chat/markdown-renderer.js +48 -2
  221. package/dist/client/chat/message-components.d.ts +6 -0
  222. package/dist/client/chat/message-components.js +182 -53
  223. package/dist/client/chat/tool-call-display.d.ts +16 -4
  224. package/dist/client/chat/tool-call-display.js +225 -18
  225. package/dist/client/extensions/ExtensionsSidebarSection.js +1 -1
  226. package/dist/client/frame-protocol.d.ts +4 -0
  227. package/dist/client/i18n.js +9 -0
  228. package/dist/client/integrations/IntegrationsPanel.js +2 -5
  229. package/dist/client/onboarding/FirstRunOnboarding.js +2 -3
  230. package/dist/client/org/TeamPage.js +49 -6
  231. package/dist/client/org/hooks.d.ts +7 -2
  232. package/dist/client/org/hooks.js +11 -4
  233. package/dist/client/resources/McpConnectionSuggestion.js +2 -3
  234. package/dist/client/resources/McpIntegrationDialog.js +2 -16
  235. package/dist/client/resources/McpIntegrationLogo.d.ts +11 -0
  236. package/dist/client/resources/McpIntegrationLogo.js +14 -0
  237. package/dist/client/resources/ResourceTree.js +1 -1
  238. package/dist/client/resources/mcp-integration-logos.d.ts +1 -0
  239. package/dist/client/resources/mcp-integration-logos.js +47 -18
  240. package/dist/client/settings/useBuilderStatus.js +6 -0
  241. package/dist/client/ui/index.d.ts +1 -0
  242. package/dist/client/ui/index.js +1 -0
  243. package/dist/collab/struct-routes.d.ts +1 -1
  244. package/dist/config.d.ts +26 -3
  245. package/dist/config.js +106 -14
  246. package/dist/db/ddl-guard.d.ts +15 -2
  247. package/dist/db/ddl-guard.js +53 -5
  248. package/dist/jobs/scheduler.js +7 -0
  249. package/dist/localization/default-messages.d.ts +17 -0
  250. package/dist/localization/default-messages.js +17 -0
  251. package/dist/mcp/oauth-client-metadata.js +5 -1
  252. package/dist/mcp/oauth-route.d.ts +5 -4
  253. package/dist/mcp/oauth-route.js +25 -9
  254. package/dist/mcp/server.d.ts +1 -1
  255. package/dist/mcp/server.js +9 -10
  256. package/dist/notifications/routes.d.ts +3 -3
  257. package/dist/org/handlers.d.ts +1 -0
  258. package/dist/org/handlers.js +17 -2
  259. package/dist/provider-api/actions/custom-provider-registration.d.ts +9 -9
  260. package/dist/provider-api/actions/provider-api.d.ts +7 -7
  261. package/dist/provider-api/corpus-jobs.d.ts +12 -2
  262. package/dist/provider-api/corpus-jobs.js +31 -1
  263. package/dist/provider-api/index.d.ts +2 -0
  264. package/dist/provider-api/index.js +7 -1
  265. package/dist/secrets/routes.d.ts +6 -6
  266. package/dist/server/agent-chat/recurring-jobs-runtime.d.ts +1 -1
  267. package/dist/server/agent-chat/recurring-jobs-runtime.js +14 -2
  268. package/dist/server/agent-chat/script-entries.js +12 -1
  269. package/dist/server/agent-chat-plugin.js +2 -2
  270. package/dist/server/auth.d.ts +1 -0
  271. package/dist/server/auth.js +85 -1
  272. package/dist/server/better-auth-instance.d.ts +9 -0
  273. package/dist/server/better-auth-instance.js +25 -11
  274. package/dist/server/core-routes-plugin.d.ts +7 -0
  275. package/dist/server/core-routes-plugin.js +51 -5
  276. package/dist/server/create-server.js +23 -2
  277. package/dist/server/db-pressure.d.ts +38 -0
  278. package/dist/server/db-pressure.js +147 -0
  279. package/dist/server/index.d.ts +1 -0
  280. package/dist/server/index.js +1 -0
  281. package/dist/server/legacy-auth-migration.d.ts +10 -0
  282. package/dist/server/legacy-auth-migration.js +37 -0
  283. package/dist/server/onboarding-html.js +206 -2
  284. package/dist/server/poll.d.ts +26 -0
  285. package/dist/server/poll.js +108 -13
  286. package/dist/server/realtime-voice.d.ts +2 -1
  287. package/dist/server/realtime-voice.js +38 -56
  288. package/dist/server/short-lived-token.d.ts +43 -0
  289. package/dist/server/short-lived-token.js +74 -0
  290. package/dist/server/ssr-handler.js +4 -1
  291. package/dist/shared/index.d.ts +1 -0
  292. package/dist/shared/index.js +1 -0
  293. package/dist/shared/runtime-config.d.ts +44 -0
  294. package/dist/shared/runtime-config.js +284 -0
  295. package/dist/styles/agent-native.css +48 -1
  296. package/dist/templates/chat/.agents/skills/actions/SKILL.md +18 -0
  297. package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  298. package/dist/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  299. package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +1 -0
  300. package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +76 -23
  301. package/dist/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  302. package/dist/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  303. package/dist/templates/chat/.env.example +3 -0
  304. package/dist/templates/chat/AGENTS.md +4 -0
  305. package/dist/templates/default/.agents/skills/actions/SKILL.md +18 -0
  306. package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  307. package/dist/templates/default/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  308. package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +1 -0
  309. package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +76 -23
  310. package/dist/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  311. package/dist/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  312. package/dist/templates/default/AGENTS.md +6 -1
  313. package/dist/templates/default/app/i18n/ar-SA.ts +6 -0
  314. package/dist/templates/default/app/i18n/de-DE.ts +6 -0
  315. package/dist/templates/default/app/i18n/en-US.ts +6 -0
  316. package/dist/templates/default/app/i18n/es-ES.ts +6 -0
  317. package/dist/templates/default/app/i18n/fr-FR.ts +6 -0
  318. package/dist/templates/default/app/i18n/hi-IN.ts +6 -0
  319. package/dist/templates/default/app/i18n/ja-JP.ts +6 -0
  320. package/dist/templates/default/app/i18n/ko-KR.ts +6 -0
  321. package/dist/templates/default/app/i18n/pt-BR.ts +6 -0
  322. package/dist/templates/default/app/i18n/zh-CN.ts +6 -0
  323. package/dist/templates/default/app/i18n/zh-TW.ts +6 -0
  324. package/dist/templates/headless/.agents/skills/actions/SKILL.md +18 -0
  325. package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  326. package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +76 -23
  327. package/dist/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  328. package/dist/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  329. package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +18 -0
  330. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  331. package/dist/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  332. package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +1 -0
  333. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +76 -23
  334. package/dist/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  335. package/dist/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  336. package/dist/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +4 -0
  337. package/dist/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +8 -0
  338. package/dist/templates/workspace-core/AGENTS.md +7 -2
  339. package/dist/templates/workspace-root/AGENTS.md +5 -0
  340. package/dist/vite/client.d.ts +3 -3
  341. package/dist/vite/client.js +47 -1
  342. package/dist/vite/index.d.ts +1 -1
  343. package/docs/content/agent-native-config.mdx +240 -139
  344. package/docs/content/authentication.mdx +17 -0
  345. package/docs/content/deployment.mdx +19 -14
  346. package/docs/content/drop-in-agent.mdx +19 -2
  347. package/docs/content/environment-variables.mdx +63 -38
  348. package/docs/content/getting-started-actions.mdx +15 -6
  349. package/docs/content/getting-started-database.mdx +14 -10
  350. package/docs/content/getting-started-pages.mdx +32 -35
  351. package/docs/content/getting-started.mdx +7 -6
  352. package/package.json +2 -2
  353. package/src/templates/chat/.agents/skills/actions/SKILL.md +18 -0
  354. package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  355. package/src/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  356. package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +1 -0
  357. package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +76 -23
  358. package/src/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  359. package/src/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  360. package/src/templates/chat/.env.example +3 -0
  361. package/src/templates/chat/AGENTS.md +4 -0
  362. package/src/templates/default/.agents/skills/actions/SKILL.md +18 -0
  363. package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  364. package/src/templates/default/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  365. package/src/templates/default/.agents/skills/frontend-design/SKILL.md +1 -0
  366. package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +76 -23
  367. package/src/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  368. package/src/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  369. package/src/templates/default/AGENTS.md +6 -1
  370. package/src/templates/default/app/i18n/ar-SA.ts +6 -0
  371. package/src/templates/default/app/i18n/de-DE.ts +6 -0
  372. package/src/templates/default/app/i18n/en-US.ts +6 -0
  373. package/src/templates/default/app/i18n/es-ES.ts +6 -0
  374. package/src/templates/default/app/i18n/fr-FR.ts +6 -0
  375. package/src/templates/default/app/i18n/hi-IN.ts +6 -0
  376. package/src/templates/default/app/i18n/ja-JP.ts +6 -0
  377. package/src/templates/default/app/i18n/ko-KR.ts +6 -0
  378. package/src/templates/default/app/i18n/pt-BR.ts +6 -0
  379. package/src/templates/default/app/i18n/zh-CN.ts +6 -0
  380. package/src/templates/default/app/i18n/zh-TW.ts +6 -0
  381. package/src/templates/headless/.agents/skills/actions/SKILL.md +18 -0
  382. package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  383. package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +76 -23
  384. package/src/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  385. package/src/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  386. package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +18 -0
  387. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  388. package/src/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  389. package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +1 -0
  390. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +76 -23
  391. package/src/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  392. package/src/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  393. package/src/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +4 -0
  394. package/src/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +8 -0
  395. package/src/templates/workspace-core/AGENTS.md +7 -2
  396. package/src/templates/workspace-root/AGENTS.md +5 -0
  397. package/corpus/templates/dispatch/app/routes/admin.apps.$appId.tsx +0 -1
  398. package/corpus/templates/dispatch/app/routes/admin.apps.tsx +0 -1
@@ -0,0 +1,168 @@
1
+ import { recordChange } from "@agent-native/core/server";
2
+ import { accessFilter, assertAccess } from "@agent-native/core/sharing";
3
+ import { desc, eq } from "drizzle-orm";
4
+
5
+ import { getDb, schema } from "../db/index.js";
6
+ import { type DashboardRecord, getDashboard } from "./dashboards-store.js";
7
+
8
+ export type DashboardFolderScope = "personal" | "shared";
9
+
10
+ export interface DashboardFolderContext {
11
+ email: string;
12
+ orgId: string | null;
13
+ }
14
+
15
+ export interface DashboardFolderRecord {
16
+ id: string;
17
+ name: string;
18
+ scope: DashboardFolderScope;
19
+ ownerEmail: string;
20
+ orgId: string | null;
21
+ visibility: "private" | "org" | "public";
22
+ createdAt: string;
23
+ updatedAt: string;
24
+ }
25
+
26
+ function nowIso(): string {
27
+ return new Date().toISOString();
28
+ }
29
+
30
+ function toFolder(row: any): DashboardFolderRecord {
31
+ return {
32
+ id: row.id,
33
+ name: row.name,
34
+ scope: row.scope,
35
+ ownerEmail: row.ownerEmail,
36
+ orgId: row.orgId ?? null,
37
+ visibility: row.visibility,
38
+ createdAt: row.createdAt,
39
+ updatedAt: row.updatedAt,
40
+ };
41
+ }
42
+
43
+ export async function listDashboardFolders(
44
+ ctx: DashboardFolderContext,
45
+ ): Promise<DashboardFolderRecord[]> {
46
+ const rows = await (getDb() as any)
47
+ .select()
48
+ .from(schema.dashboardFolders)
49
+ .where(
50
+ accessFilter(schema.dashboardFolders, schema.dashboardFolderShares, {
51
+ userEmail: ctx.email,
52
+ orgId: ctx.orgId ?? undefined,
53
+ }),
54
+ )
55
+ .orderBy(desc(schema.dashboardFolders.updatedAt));
56
+ return rows.map(toFolder);
57
+ }
58
+
59
+ export async function createDashboardFolder(
60
+ name: string,
61
+ scope: DashboardFolderScope,
62
+ ctx: DashboardFolderContext,
63
+ ): Promise<DashboardFolderRecord> {
64
+ const trimmedName = name.trim();
65
+ if (!trimmedName) throw new Error("folder name is required");
66
+ if (scope === "shared" && !ctx.orgId) {
67
+ throw new Error("an active organization is required for shared folders");
68
+ }
69
+ const id = crypto.randomUUID();
70
+ const now = nowIso();
71
+ const folderOrgId = scope === "shared" ? ctx.orgId : null;
72
+ await (getDb() as any).insert(schema.dashboardFolders).values({
73
+ id,
74
+ name: trimmedName,
75
+ scope,
76
+ createdAt: now,
77
+ updatedAt: now,
78
+ ownerEmail: ctx.email,
79
+ orgId: folderOrgId,
80
+ visibility: scope === "shared" ? "org" : "private",
81
+ });
82
+ recordChange({
83
+ source: "dashboard-folders",
84
+ type: "change",
85
+ key: id,
86
+ ...(scope === "shared" && ctx.orgId
87
+ ? { orgId: ctx.orgId }
88
+ : { owner: ctx.email }),
89
+ });
90
+ return {
91
+ id,
92
+ name: trimmedName,
93
+ scope,
94
+ ownerEmail: ctx.email,
95
+ orgId: folderOrgId,
96
+ visibility: scope === "shared" ? "org" : "private",
97
+ createdAt: now,
98
+ updatedAt: now,
99
+ };
100
+ }
101
+
102
+ async function getFolder(
103
+ id: string,
104
+ ctx: DashboardFolderContext,
105
+ ): Promise<DashboardFolderRecord> {
106
+ await assertAccess("dashboard-folder", id, "viewer", {
107
+ userEmail: ctx.email,
108
+ orgId: ctx.orgId ?? undefined,
109
+ });
110
+ const [row] = await (getDb() as any)
111
+ .select()
112
+ .from(schema.dashboardFolders)
113
+ .where(eq(schema.dashboardFolders.id, id))
114
+ .limit(1);
115
+ if (!row) throw new Error("dashboard folder not found");
116
+ return toFolder(row);
117
+ }
118
+
119
+ export async function assignDashboardToFolder(
120
+ dashboardId: string,
121
+ folderId: string | null,
122
+ ctx: DashboardFolderContext,
123
+ ): Promise<DashboardRecord> {
124
+ const dashboard = await getDashboard(dashboardId, ctx);
125
+ if (!dashboard) throw new Error("dashboard not found or inaccessible");
126
+ await assertAccess("dashboard", dashboardId, "editor", {
127
+ userEmail: ctx.email,
128
+ orgId: ctx.orgId ?? undefined,
129
+ });
130
+
131
+ if (folderId) {
132
+ const folder = await getFolder(folderId, ctx);
133
+ if (folder.scope === "personal") {
134
+ if (
135
+ dashboard.visibility !== "private" ||
136
+ dashboard.ownerEmail.toLowerCase() !== ctx.email.toLowerCase()
137
+ ) {
138
+ throw new Error("personal folders require an owned private dashboard");
139
+ }
140
+ } else if (
141
+ dashboard.visibility !== "org" ||
142
+ !ctx.orgId ||
143
+ dashboard.orgId !== ctx.orgId ||
144
+ folder.orgId !== ctx.orgId
145
+ ) {
146
+ throw new Error("shared folders require an org-visible dashboard");
147
+ }
148
+ }
149
+
150
+ await (getDb() as any)
151
+ .update(schema.dashboards)
152
+ .set({ folderId, updatedAt: nowIso(), updatedBy: ctx.email })
153
+ .where(eq(schema.dashboards.id, dashboardId));
154
+ recordChange({
155
+ source: "dashboards",
156
+ type: "change",
157
+ key: dashboardId,
158
+ ...((dashboard.visibility === "org" && dashboard.orgId
159
+ ? { orgId: dashboard.orgId }
160
+ : { owner: dashboard.ownerEmail }) as {
161
+ owner?: string;
162
+ orgId?: string;
163
+ }),
164
+ });
165
+ const updated = await getDashboard(dashboardId, ctx);
166
+ if (!updated) throw new Error("dashboard disappeared after folder update");
167
+ return updated;
168
+ }
@@ -1,6 +1,9 @@
1
1
  import type { CredentialContext } from "@agent-native/core/credentials";
2
2
  import { resolveCredential } from "@agent-native/core/credentials";
3
- import { runDataProgram } from "@agent-native/core/data-programs";
3
+ import {
4
+ getInitializedDataProgramsAppId,
5
+ runDataProgram,
6
+ } from "@agent-native/core/data-programs";
4
7
  import type { MissingKeyResponse } from "@agent-native/core/server";
5
8
 
6
9
  import { getUserSegmentation, queryEvents } from "./amplitude";
@@ -12,6 +15,7 @@ import {
12
15
  runPrometheusPanel,
13
16
  serializePanelDescriptorInput,
14
17
  } from "./prometheus";
18
+ import { ANALYTICS_APP_ID } from "./provider-credentials";
15
19
 
16
20
  export const DASHBOARD_PANEL_SOURCES = [
17
21
  "bigquery",
@@ -25,8 +29,6 @@ export const DASHBOARD_PANEL_SOURCES = [
25
29
 
26
30
  export type DashboardPanelSource = (typeof DASHBOARD_PANEL_SOURCES)[number];
27
31
 
28
- const ANALYTICS_DATA_PROGRAM_APP_ID = "analytics";
29
-
30
32
  export interface DashboardPanelQueryResult {
31
33
  rows: Record<string, unknown>[];
32
34
  schema: { name: string; type: string }[];
@@ -360,7 +362,10 @@ async function runProgramPanel(
360
362
  const descriptor = parseProgramDescriptor(raw);
361
363
  const result = await runDataProgram({
362
364
  programId: descriptor.programId,
363
- appId: ANALYTICS_DATA_PROGRAM_APP_ID,
365
+ // Use the same app scope that registered the agent's data-program actions.
366
+ // Standalone template dev can derive that scope from the runtime package
367
+ // even when APP_NAME is not explicitly set.
368
+ appId: getInitializedDataProgramsAppId() ?? ANALYTICS_APP_ID,
364
369
  params: descriptor.params,
365
370
  ctx: { userEmail: ctx.userEmail, orgId: ctx.orgId ?? null },
366
371
  triggeredBy: "panel_view",
@@ -28,7 +28,7 @@ import {
28
28
  resolveAccess,
29
29
  type ShareRole,
30
30
  } from "@agent-native/core/sharing";
31
- import { and, desc, eq, isNotNull, isNull, sql } from "drizzle-orm";
31
+ import { and, desc, eq, inArray, isNotNull, isNull, sql } from "drizzle-orm";
32
32
 
33
33
  import { getDb, schema } from "../db/index.js";
34
34
 
@@ -62,10 +62,12 @@ export interface DashboardSummaryRecord {
62
62
  id: string;
63
63
  kind: DashboardKind;
64
64
  name: string;
65
+ description: string | null;
65
66
  configName: string | null;
66
67
  catalogTemplateId: string | null;
67
68
  demoId: string | null;
68
69
  parentId: string | null;
70
+ folderId: string | null;
69
71
  ownerEmail: string;
70
72
  orgId: string | null;
71
73
  visibility: "private" | "org" | "public";
@@ -76,6 +78,17 @@ export interface DashboardSummaryRecord {
76
78
  hiddenBy: string | null;
77
79
  }
78
80
 
81
+ /** Hydrated dashboard row for catalog ranking only. */
82
+ export interface DashboardCatalogRecord {
83
+ id: string;
84
+ kind: DashboardKind;
85
+ title: string;
86
+ description: string | null;
87
+ config: Record<string, unknown>;
88
+ }
89
+
90
+ const MAX_CATALOG_DASHBOARD_HYDRATION = 24;
91
+
79
92
  export interface DashboardRevisionRecord {
80
93
  id: string;
81
94
  dashboardId: string;
@@ -281,6 +294,13 @@ function rowToDashboardRevision(row: any): DashboardRevisionRecord {
281
294
  };
282
295
  }
283
296
 
297
+ function configDescriptionFromValue(
298
+ value: Record<string, unknown>,
299
+ ): string | null {
300
+ const description = value["description"];
301
+ return typeof description === "string" ? description : null;
302
+ }
303
+
284
304
  function configFromSettings(data: Record<string, unknown>): {
285
305
  title: string;
286
306
  config: Record<string, unknown>;
@@ -564,6 +584,11 @@ export async function listDashboardSummaries(
564
584
  : sql<
565
585
  string | null
566
586
  >`json_extract(${schema.dashboards.config}, '$.parentId')`;
587
+ const description = isPostgres()
588
+ ? sql<string | null>`(${schema.dashboards.config}::jsonb ->> 'description')`
589
+ : sql<
590
+ string | null
591
+ >`json_extract(${schema.dashboards.config}, '$.description')`;
567
592
  const configName = isPostgres()
568
593
  ? sql<string | null>`(${schema.dashboards.config}::jsonb ->> 'name')`
569
594
  : sql<string | null>`json_extract(${schema.dashboards.config}, '$.name')`;
@@ -586,10 +611,12 @@ export async function listDashboardSummaries(
586
611
  id: schema.dashboards.id,
587
612
  kind: schema.dashboards.kind,
588
613
  name: schema.dashboards.title,
614
+ description,
589
615
  ...(includeCatalogMetadata
590
616
  ? { configName, catalogTemplateId, demoId }
591
617
  : {}),
592
618
  parentId,
619
+ folderId: schema.dashboards.folderId,
593
620
  ownerEmail: schema.dashboards.ownerEmail,
594
621
  orgId: schema.dashboards.orgId,
595
622
  visibility: schema.dashboards.visibility,
@@ -603,11 +630,13 @@ export async function listDashboardSummaries(
603
630
  .where(where);
604
631
  const out: DashboardSummaryRecord[] = rows.map((row: any) => ({
605
632
  ...row,
633
+ description: typeof row.description === "string" ? row.description : null,
606
634
  configName: typeof row.configName === "string" ? row.configName : null,
607
635
  catalogTemplateId:
608
636
  typeof row.catalogTemplateId === "string" ? row.catalogTemplateId : null,
609
637
  demoId: typeof row.demoId === "string" ? row.demoId : null,
610
638
  parentId: typeof row.parentId === "string" ? row.parentId : null,
639
+ folderId: typeof row.folderId === "string" ? row.folderId : null,
611
640
  orgId: row.orgId ?? null,
612
641
  archivedAt: row.archivedAt ?? null,
613
642
  hiddenAt: row.hiddenAt ?? null,
@@ -656,8 +685,10 @@ export async function listDashboardSummaries(
656
685
  id,
657
686
  kind,
658
687
  name: title,
688
+ description: configDescriptionFromValue(config),
659
689
  ...catalogMetadata,
660
690
  parentId: typeof config.parentId === "string" ? config.parentId : null,
691
+ folderId: null,
661
692
  ownerEmail: ctx.email,
662
693
  orgId,
663
694
  visibility,
@@ -676,6 +707,90 @@ export async function listDashboardSummaries(
676
707
  return out;
677
708
  }
678
709
 
710
+ /**
711
+ * Hydrate a bounded set of dashboard ids for catalog ranking.
712
+ *
713
+ * This is the catalog-specific path: it reads only the id, kind, title,
714
+ * description, and config needed for ranking, and only for explicit ids that
715
+ * were already shortlisted from the metadata path.
716
+ */
717
+ export async function loadDashboardCatalogDashboards(
718
+ ctx: AccessCtx,
719
+ ids: readonly string[],
720
+ dbOverride?: any,
721
+ ): Promise<DashboardCatalogRecord[]> {
722
+ const db = (dbOverride ?? getDb()) as any;
723
+ const uniqueIds = [
724
+ ...new Set(ids.map((id) => id.trim()).filter(Boolean)),
725
+ ].slice(0, MAX_CATALOG_DASHBOARD_HYDRATION);
726
+ if (!uniqueIds.length) return [];
727
+
728
+ const description = isPostgres()
729
+ ? sql<string | null>`(${schema.dashboards.config}::jsonb ->> 'description')`
730
+ : sql<
731
+ string | null
732
+ >`json_extract(${schema.dashboards.config}, '$.description')`;
733
+ const archived = isNull(schema.dashboards.archivedAt);
734
+ const visible = isNull(schema.dashboards.hiddenAt);
735
+ const where = and(
736
+ accessFilter(schema.dashboards, schema.dashboardShares, {
737
+ userEmail: ctx.email,
738
+ orgId: ctx.orgId ?? undefined,
739
+ }),
740
+ inArray(schema.dashboards.id, uniqueIds),
741
+ archived,
742
+ visible,
743
+ );
744
+
745
+ // guard:allow-heavy-dashboard-list-read - bounded explicit ids shortlisted from metadata
746
+ const sqlRows = await db
747
+ .select({
748
+ id: schema.dashboards.id,
749
+ kind: schema.dashboards.kind,
750
+ title: schema.dashboards.title,
751
+ description,
752
+ config: schema.dashboards.config,
753
+ })
754
+ .from(schema.dashboards)
755
+ .where(where);
756
+
757
+ const byId = new Map<string, DashboardCatalogRecord>(
758
+ sqlRows.map((row: any) => {
759
+ const catalogRow: DashboardCatalogRecord = {
760
+ id: row.id,
761
+ kind: row.kind,
762
+ title: row.title,
763
+ description:
764
+ typeof row.description === "string" ? row.description : null,
765
+ config:
766
+ typeof row.config === "string" ? JSON.parse(row.config) : row.config,
767
+ };
768
+ return [row.id, catalogRow];
769
+ }),
770
+ );
771
+
772
+ const out: DashboardCatalogRecord[] = [];
773
+ for (const id of uniqueIds) {
774
+ const row = byId.get(id);
775
+ if (row) {
776
+ out.push(row);
777
+ continue;
778
+ }
779
+
780
+ const legacy = await findLegacyDashboard(id, ctx);
781
+ if (!legacy) continue;
782
+ const { title, config } = configFromSettings(legacy.data);
783
+ out.push({
784
+ id,
785
+ kind: legacy.kind,
786
+ title,
787
+ description: configDescriptionFromValue(config),
788
+ config,
789
+ });
790
+ }
791
+ return out;
792
+ }
793
+
679
794
  /**
680
795
  * Reject a name that would collide with another dashboard visible to the
681
796
  * caller. Archived and hidden dashboards are intentionally excluded because
@@ -2,10 +2,7 @@ import { isPostgres } from "@agent-native/core/db";
2
2
  import { sql } from "@agent-native/core/db/schema";
3
3
 
4
4
  import { getDb, schema } from "../db/index.js";
5
- import {
6
- FIRST_PARTY_ANALYTICS_ROLLUP_LOCK_KEY,
7
- FIRST_PARTY_ANALYTICS_ROLLUP_LOCK_SQL,
8
- } from "./analytics-rollup-lock.js";
5
+ import { FIRST_PARTY_ANALYTICS_ROLLUP_LOCK_KEY } from "./analytics-rollup-lock.js";
9
6
 
10
7
  /**
11
8
  * The normalized subset emitted by first-party analytics ingest. Keeping this
@@ -151,10 +148,9 @@ export async function upsertFirstPartyAnalyticsRollups(
151
148
  // snapshot. Holding it through ingest's rollup increment prevents the
152
149
  // backfill's monotonic upsert from losing a concurrently committed
153
150
  // event.
154
- await tx.execute({
155
- sql: FIRST_PARTY_ANALYTICS_ROLLUP_LOCK_SQL,
156
- args: [FIRST_PARTY_ANALYTICS_ROLLUP_LOCK_KEY],
157
- });
151
+ await tx.execute(
152
+ sql`SELECT pg_advisory_xact_lock(hashtextextended(${FIRST_PARTY_ANALYTICS_ROLLUP_LOCK_KEY}, 0::bigint))`,
153
+ );
158
154
  }
159
155
  const dailyRows = [...dailyRollups.values()];
160
156
  await tx
@@ -1,19 +1,14 @@
1
1
  // Gong sales call intelligence API helper
2
2
  // Fetches calls, transcripts, and users
3
3
 
4
- import { resolveCredential } from "./credentials";
5
- import {
6
- requireRequestCredentialContext,
7
- scopedCredentialCacheKey,
8
- } from "./credentials-context";
4
+ import { scopedCredentialCacheKey } from "./credentials-context";
9
5
  import {
10
6
  DEFAULT_GONG_CALL_LIMIT,
11
7
  limitGongCalls,
12
8
  normalizeGongCallLimit,
13
9
  } from "./gong-limits";
14
- import { resolveAnalyticsGongCredentials } from "./provider-credentials";
10
+ import { executeProviderApiRequest } from "./provider-api";
15
11
 
16
- const DEFAULT_API_BASE = "https://api.gong.io/v2";
17
12
  const MAX_GONG_SEARCH_PAGES = 50;
18
13
  const MAX_GONG_CALL_LIST_PAGES = 50;
19
14
  const MAX_GONG_EXHAUSTIVE_RECORDS = 500;
@@ -24,38 +19,101 @@ const cache = new Map<string, { data: unknown; ts: number }>();
24
19
  const CACHE_TTL_MS = 10 * 60 * 1000;
25
20
  const MAX_CACHE = 120;
26
21
 
27
- async function getAuthHeader(): Promise<string> {
28
- const ctx = requireRequestCredentialContext("GONG_ACCESS_KEY");
29
- const credentials = await resolveAnalyticsGongCredentials({ ctx });
30
- if (!credentials)
31
- throw new Error("GONG_ACCESS_KEY and GONG_ACCESS_SECRET not configured");
32
- return `Basic ${Buffer.from(
33
- `${credentials.accessKey}:${credentials.accessSecret}`,
34
- ).toString("base64")}`;
35
- }
36
-
37
- async function getApiBase(): Promise<string> {
38
- const ctx = requireRequestCredentialContext("GONG_ACCESS_KEY");
39
- const configured = await resolveCredential("GONG_API_BASE", ctx);
40
- return (configured || DEFAULT_API_BASE).replace(/\/+$/, "");
41
- }
42
-
43
22
  export interface GongRequestOptions {
44
23
  signal?: AbortSignal;
45
24
  deadlineAt?: number;
46
25
  }
47
26
 
48
- function requestSignal(options?: GongRequestOptions): AbortSignal {
49
- const remainingMs = options?.deadlineAt
27
+ function requestTimeoutMs(options?: GongRequestOptions): number {
28
+ return options?.deadlineAt
50
29
  ? Math.max(
51
30
  1,
52
31
  Math.min(GONG_API_REQUEST_TIMEOUT_MS, options.deadlineAt - Date.now()),
53
32
  )
54
33
  : GONG_API_REQUEST_TIMEOUT_MS;
55
- const timeoutSignal = AbortSignal.timeout(remainingMs);
56
- return options?.signal
57
- ? AbortSignal.any([options.signal, timeoutSignal])
58
- : timeoutSignal;
34
+ }
35
+
36
+ interface GongProviderResponse {
37
+ response: {
38
+ ok: boolean;
39
+ status: number;
40
+ headers?: Record<string, string>;
41
+ json?: unknown;
42
+ text?: string;
43
+ };
44
+ }
45
+
46
+ function splitGongPath(path: string): {
47
+ path: string;
48
+ query?: Record<string, string>;
49
+ } {
50
+ const separator = path.indexOf("?");
51
+ if (separator < 0) return { path };
52
+ const query = Object.fromEntries(
53
+ new URLSearchParams(path.slice(separator + 1)).entries(),
54
+ );
55
+ return {
56
+ path: path.slice(0, separator),
57
+ ...(Object.keys(query).length > 0 ? { query } : {}),
58
+ };
59
+ }
60
+
61
+ function responseHeader(
62
+ headers: Record<string, string> | undefined,
63
+ name: string,
64
+ ): string | undefined {
65
+ const lowerName = name.toLowerCase();
66
+ return Object.entries(headers ?? {}).find(
67
+ ([key]) => key.toLowerCase() === lowerName,
68
+ )?.[1];
69
+ }
70
+
71
+ function responseDetail(response: GongProviderResponse["response"]): string {
72
+ if (typeof response.text === "string" && response.text.trim()) {
73
+ return response.text.replace(/\s+/g, " ").trim().slice(0, 2_000);
74
+ }
75
+ if (response.json !== undefined) {
76
+ return JSON.stringify(response.json).slice(0, 2_000);
77
+ }
78
+ return "";
79
+ }
80
+
81
+ function gongApiError(response: GongProviderResponse["response"]): Error {
82
+ const requestId =
83
+ responseHeader(response.headers, "x-request-id") ??
84
+ responseHeader(response.headers, "request-id");
85
+ const retryAfter = responseHeader(response.headers, "retry-after");
86
+ const metadata = [
87
+ requestId ? `requestId ${requestId}` : "",
88
+ response.status === 429 && retryAfter ? `retry-after ${retryAfter}` : "",
89
+ ]
90
+ .filter(Boolean)
91
+ .join(", ");
92
+ const detail = responseDetail(response);
93
+ return new Error(
94
+ `Gong API error ${response.status}${metadata ? ` (${metadata})` : ""}${detail ? `: ${detail}` : ""}`,
95
+ );
96
+ }
97
+
98
+ async function executeGongRequest<T>(options: {
99
+ method: "GET" | "POST";
100
+ path: string;
101
+ body?: unknown;
102
+ requestOptions?: GongRequestOptions;
103
+ }): Promise<T> {
104
+ const request = splitGongPath(options.path);
105
+ const result = (await executeProviderApiRequest({
106
+ provider: "gong",
107
+ method: options.method,
108
+ path: request.path,
109
+ ...(request.query ? { query: request.query } : {}),
110
+ ...(options.body !== undefined ? { body: options.body } : {}),
111
+ timeoutMs: requestTimeoutMs(options.requestOptions),
112
+ signal: options.requestOptions?.signal,
113
+ })) as GongProviderResponse;
114
+
115
+ if (!result.response.ok) throw gongApiError(result.response);
116
+ return result.response.json as T;
59
117
  }
60
118
 
61
119
  async function apiGet<T>(
@@ -69,21 +127,12 @@ async function apiGet<T>(
69
127
  return cached.data as T;
70
128
  }
71
129
 
72
- const res = await fetch(`${await getApiBase()}${path}`, {
73
- headers: {
74
- Authorization: await getAuthHeader(),
75
- "Content-Type": "application/json",
76
- },
77
- signal: requestSignal(options),
130
+ const data = await executeGongRequest<T>({
131
+ method: "GET",
132
+ path,
133
+ requestOptions: options,
78
134
  });
79
135
 
80
- if (!res.ok) {
81
- const text = await res.text();
82
- throw new Error(`Gong API error ${res.status}: ${text}`);
83
- }
84
-
85
- const data = await res.json();
86
-
87
136
  if (cache.size >= MAX_CACHE) {
88
137
  const oldest = cache.keys().next().value;
89
138
  if (oldest) cache.delete(oldest);
@@ -108,23 +157,13 @@ async function apiPost<T>(
108
157
  return cached.data as T;
109
158
  }
110
159
 
111
- const res = await fetch(`${await getApiBase()}${path}`, {
160
+ const data = await executeGongRequest<T>({
112
161
  method: "POST",
113
- headers: {
114
- Authorization: await getAuthHeader(),
115
- "Content-Type": "application/json",
116
- },
117
- body: JSON.stringify(body),
118
- signal: requestSignal(options),
162
+ path,
163
+ body,
164
+ requestOptions: options,
119
165
  });
120
166
 
121
- if (!res.ok) {
122
- const text = await res.text();
123
- throw new Error(`Gong API error ${res.status}: ${text}`);
124
- }
125
-
126
- const data = await res.json();
127
-
128
167
  if (cache.size >= MAX_CACHE) {
129
168
  const oldest = cache.keys().next().value;
130
169
  if (oldest) cache.delete(oldest);
@@ -298,29 +337,9 @@ export async function getCall(
298
337
  return data.calls?.[0] ?? null;
299
338
  }
300
339
 
301
- export async function getCallDetail(
302
- callId: string,
303
- options?: GongRequestOptions,
304
- ): Promise<GongCallDetail | null> {
305
- const body = {
306
- filter: { callIds: [callId] },
307
- contentSelector: {
308
- exposedFields: {
309
- parties: true,
310
- content: { brief: true, keyPoints: true, outline: true },
311
- },
312
- },
313
- };
314
- const data = await apiPost<{ calls?: any[] }>(
315
- "/calls/extensive",
316
- body,
317
- `detail:${callId}`,
318
- options,
319
- );
320
- const call = data.calls?.[0];
321
- if (!call) return null;
340
+ function normalizeCallDetail(call: any, fallbackId: string): GongCallDetail {
322
341
  return {
323
- id: call.metaData?.id ?? callId,
342
+ id: call.metaData?.id ?? fallbackId,
324
343
  title: call.metaData?.title || "Untitled",
325
344
  url: call.metaData?.url || "",
326
345
  started: call.metaData?.started || "",
@@ -340,6 +359,48 @@ export async function getCallDetail(
340
359
  };
341
360
  }
342
361
 
362
+ export async function getCallDetails(
363
+ callIds: string[],
364
+ options?: GongRequestOptions,
365
+ ): Promise<GongCallDetail[]> {
366
+ const ids = Array.from(
367
+ new Set(
368
+ callIds
369
+ .map((id) => (typeof id === "string" ? id.trim() : ""))
370
+ .filter(Boolean),
371
+ ),
372
+ );
373
+ if (!ids.length) return [];
374
+
375
+ const body = {
376
+ filter: { callIds: ids },
377
+ contentSelector: {
378
+ exposedFields: {
379
+ parties: true,
380
+ content: { brief: true, keyPoints: true, outline: true },
381
+ },
382
+ },
383
+ };
384
+ const data = await apiPost<{ calls?: any[] }>(
385
+ "/calls/extensive",
386
+ body,
387
+ `details:${ids.join(",")}`,
388
+ options,
389
+ );
390
+ return (data.calls ?? []).map((call, index) =>
391
+ normalizeCallDetail(call, ids[index] ?? ""),
392
+ );
393
+ }
394
+
395
+ export async function getCallDetail(
396
+ callId: string,
397
+ options?: GongRequestOptions,
398
+ ): Promise<GongCallDetail | null> {
399
+ const details = await getCallDetails([callId], options);
400
+ const detail = details[0];
401
+ return detail === undefined ? null : detail;
402
+ }
403
+
343
404
  export async function getCallTranscripts(
344
405
  callIds: string[],
345
406
  options?: GongRequestOptions,