@agent-native/core 0.108.0 → 0.109.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 (368) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +25 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/a2a/client.ts +162 -17
  5. package/corpus/core/src/a2a/correlation.ts +50 -0
  6. package/corpus/core/src/a2a/handlers.ts +200 -14
  7. package/corpus/core/src/a2a/index.ts +7 -1
  8. package/corpus/core/src/a2a/invoke.ts +77 -1
  9. package/corpus/core/src/a2a/server.ts +13 -1
  10. package/corpus/core/src/a2a/task-store.ts +146 -6
  11. package/corpus/core/src/a2a/types.ts +32 -0
  12. package/corpus/core/src/action.ts +5 -2
  13. package/corpus/core/src/agent/production-agent.ts +33 -4
  14. package/corpus/core/src/client/AssistantChat.tsx +648 -603
  15. package/corpus/core/src/client/MultiTabAssistantChat.tsx +31 -4
  16. package/corpus/core/src/client/agent-chat-adapter.ts +23 -37
  17. package/corpus/core/src/client/agent-sidebar-state.ts +4 -0
  18. package/corpus/core/src/client/analytics.ts +84 -0
  19. package/corpus/core/src/client/chat/message-components.tsx +94 -22
  20. package/corpus/core/src/client/chat/tool-call-display.tsx +170 -47
  21. package/corpus/core/src/client/chat/use-agent-chat-lifecycle-tracking.ts +74 -0
  22. package/corpus/core/src/client/chat-thread-url.ts +11 -0
  23. package/corpus/core/src/client/error-capture.ts +12 -0
  24. package/corpus/core/src/client/extensions/ExtensionSlot.tsx +37 -1
  25. package/corpus/core/src/client/index.ts +2 -0
  26. package/corpus/core/src/client/route-chunk-recovery.ts +20 -8
  27. package/corpus/core/src/client/session-replay.ts +31 -0
  28. package/corpus/core/src/client/use-run-stuck-detection.ts +27 -1
  29. package/corpus/core/src/db/client.ts +55 -0
  30. package/corpus/core/src/extensions/actions.ts +2 -14
  31. package/corpus/core/src/extensions/store.ts +1 -1
  32. package/corpus/core/src/localization/default-messages.ts +3 -0
  33. package/corpus/core/src/mcp/build-server.ts +2 -2
  34. package/corpus/core/src/observability/traces.ts +172 -19
  35. package/corpus/core/src/progress/actions.ts +4 -2
  36. package/corpus/core/src/provider-api/index.ts +205 -105
  37. package/corpus/core/src/scripts/call-agent.ts +190 -19
  38. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +112 -25
  39. package/corpus/core/src/server/agent-chat-plugin.ts +136 -4
  40. package/corpus/core/src/styles/agent-conversation.css +7 -0
  41. package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +20 -0
  42. package/corpus/core/src/templates/default/app/i18n/de-DE.ts +20 -0
  43. package/corpus/core/src/templates/default/app/i18n/en-US.ts +20 -0
  44. package/corpus/core/src/templates/default/app/i18n/es-ES.ts +20 -0
  45. package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +21 -0
  46. package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +19 -0
  47. package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +20 -0
  48. package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +19 -0
  49. package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +20 -0
  50. package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +19 -0
  51. package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +19 -0
  52. package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +49 -0
  53. package/corpus/core/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  54. package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
  55. package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  56. package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
  57. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +29 -10
  58. package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +54 -23
  59. package/corpus/templates/analytics/.builder/skills/apollo/SKILL.md +19 -41
  60. package/corpus/templates/analytics/.builder/skills/commonroom/SKILL.md +20 -35
  61. package/corpus/templates/analytics/.builder/skills/github/SKILL.md +23 -67
  62. package/corpus/templates/analytics/.builder/skills/pylon/SKILL.md +25 -43
  63. package/corpus/templates/analytics/AGENTS.md +22 -13
  64. package/corpus/templates/analytics/actions/account-deep-dive.ts +1 -0
  65. package/corpus/templates/analytics/actions/configure-gong-native-insights.ts +29 -0
  66. package/corpus/templates/analytics/actions/content-calendar-schema.ts +8 -4
  67. package/corpus/templates/analytics/actions/content-calendar.ts +12 -4
  68. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -1
  69. package/corpus/templates/analytics/actions/gong-calls.ts +113 -22
  70. package/corpus/templates/analytics/actions/gong-native-insights.ts +166 -0
  71. package/corpus/templates/analytics/actions/hubspot-deals.ts +190 -46
  72. package/corpus/templates/analytics/actions/pylon-issues.ts +123 -0
  73. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
  74. package/corpus/templates/analytics/actions/slack-messages.ts +179 -27
  75. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +48 -152
  76. package/corpus/templates/analytics/app/components/ui/chart.tsx +1 -1
  77. package/corpus/templates/analytics/app/hooks/use-chart-tooltip-flip.ts +21 -6
  78. package/corpus/templates/analytics/app/i18n/zh-TW.ts +13 -0
  79. package/corpus/templates/analytics/app/i18n-data.ts +134 -0
  80. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +181 -30
  81. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +6 -0
  82. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +4 -3
  83. package/corpus/templates/analytics/changelog/2026-07-17-analytics-now-includes-a-default-alert-for-spikes-in-stuck-agent-chats.md +6 -0
  84. package/corpus/templates/analytics/changelog/2026-07-17-dashboard-editors-can-add-shared-extensions-or-opt-into-per-.md +6 -0
  85. package/corpus/templates/analytics/changelog/2026-07-17-dashboard-extensions-show-a-loading-skeleton.md +6 -0
  86. package/corpus/templates/analytics/changelog/2026-07-17-errors-now-group-repeat-failures-consistently-and-keep-priva.md +6 -0
  87. package/corpus/templates/analytics/changelog/2026-07-17-gong-transcript-reviews-now-batch-bounded-call-windows-for-f.md +6 -0
  88. package/corpus/templates/analytics/changelog/2026-07-17-hubspot-deal-filters-now-run-in-hubspot-before-paging-result.md +6 -0
  89. package/corpus/templates/analytics/changelog/2026-07-17-notion-content-calendars-now-discover-the-matching-database-.md +6 -0
  90. package/corpus/templates/analytics/changelog/2026-07-17-pylon-dashboard-reads-now-use-the-paginated-issue-search-api.md +6 -0
  91. package/corpus/templates/analytics/changelog/2026-07-17-slack-reads-no-longer-join-channels-and-report-pagination-coverage.md +6 -0
  92. package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +23 -14
  93. package/corpus/templates/analytics/docs/schemas/tracked-events.md +5 -1
  94. package/corpus/templates/analytics/server/handlers/notion.ts +14 -3
  95. package/corpus/templates/analytics/server/handlers/slack.ts +182 -29
  96. package/corpus/templates/analytics/server/jobs/analytics-alerts.ts +3 -3
  97. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +2 -6
  98. package/corpus/templates/analytics/server/lib/analytics-alerts.ts +209 -87
  99. package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +6 -2
  100. package/corpus/templates/analytics/server/lib/error-capture.ts +75 -8
  101. package/corpus/templates/analytics/server/lib/gong-native-policy.ts +72 -0
  102. package/corpus/templates/analytics/server/lib/gong.ts +54 -66
  103. package/corpus/templates/analytics/server/lib/hubspot.ts +40 -3
  104. package/corpus/templates/analytics/server/lib/notion.ts +83 -8
  105. package/corpus/templates/analytics/server/lib/real-data-actions.ts +4 -0
  106. package/corpus/templates/analytics/server/lib/slack.ts +242 -90
  107. package/corpus/templates/analytics/server/plugins/agent-chat.ts +3 -3
  108. package/corpus/templates/analytics/server/routes/api/pylon/accounts.get.ts +42 -1
  109. package/corpus/templates/analytics/server/routes/api/pylon/issues.get.ts +71 -1
  110. package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +44 -4
  111. package/corpus/templates/clips/actions/finalize-recording.ts +541 -62
  112. package/corpus/templates/clips/app/components/library/bulk-action-toolbar.tsx +19 -1
  113. package/corpus/templates/clips/app/components/library/create-folder-dialog.tsx +123 -0
  114. package/corpus/templates/clips/app/components/library/library-grid.tsx +42 -4
  115. package/corpus/templates/clips/app/components/library/recording-card.tsx +30 -0
  116. package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +17 -2
  117. package/corpus/templates/clips/app/components/player/video-player.tsx +14 -2
  118. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +2 -2
  119. package/corpus/templates/clips/app/entry.client.tsx +6 -1
  120. package/corpus/templates/clips/app/i18n/ar-SA.ts +12 -1
  121. package/corpus/templates/clips/app/i18n/de-DE.ts +12 -1
  122. package/corpus/templates/clips/app/i18n/en-US.ts +12 -1
  123. package/corpus/templates/clips/app/i18n/es-ES.ts +11 -1
  124. package/corpus/templates/clips/app/i18n/fr-FR.ts +11 -1
  125. package/corpus/templates/clips/app/i18n/hi-IN.ts +10 -1
  126. package/corpus/templates/clips/app/i18n/ja-JP.ts +12 -1
  127. package/corpus/templates/clips/app/i18n/ko-KR.ts +11 -1
  128. package/corpus/templates/clips/app/i18n/pt-BR.ts +11 -1
  129. package/corpus/templates/clips/app/i18n/zh-CN.ts +11 -1
  130. package/corpus/templates/clips/app/i18n/zh-TW.ts +11 -1
  131. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +72 -1
  132. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -1
  133. package/corpus/templates/clips/app/routes/record.tsx +3 -3
  134. package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -3
  135. package/corpus/templates/clips/changelog/2026-07-17-choose-which-workspace-receives-new-clips-recordings-and-des.md +6 -0
  136. package/corpus/templates/clips/changelog/2026-07-17-clips-now-retries-storage-verification-in-the-background-ins.md +6 -0
  137. package/corpus/templates/clips/changelog/2026-07-17-create-folders-directly-from-the-move-menu.md +6 -0
  138. package/corpus/templates/clips/changelog/2026-07-17-failed-desktop-uploads-now-offer-a-direct-way-to-reopen-clip.md +6 -0
  139. package/corpus/templates/clips/changelog/2026-07-17-fixed-broken-thumbnail-icons-appearing-over-playable-clip-em.md +6 -0
  140. package/corpus/templates/clips/changelog/2026-07-17-playback-comments-stay-readable-at-faster-playback-speeds.md +6 -0
  141. package/corpus/templates/clips/chrome-extension/src/finalize-recovery.ts +3 -0
  142. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +3 -3
  143. package/corpus/templates/clips/desktop/src/app.tsx +19 -7
  144. package/corpus/templates/clips/desktop/src/lib/recorder.ts +111 -13
  145. package/corpus/templates/clips/desktop/src/lib/upload-verification.ts +16 -7
  146. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -4
  147. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/live_upload.rs +32 -15
  148. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +45 -18
  149. package/corpus/templates/clips/server/jobs/media-verification.ts +130 -0
  150. package/corpus/templates/clips/server/lib/builder-media-compression.ts +15 -0
  151. package/corpus/templates/clips/server/lib/media-verification-state.ts +38 -0
  152. package/corpus/templates/clips/server/lib/player-thumbnail-url.ts +31 -0
  153. package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +10 -3
  154. package/corpus/templates/clips/server/plugins/auth.ts +5 -5
  155. package/corpus/templates/clips/server/plugins/calendar-jobs.ts +2 -0
  156. package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +12 -2
  157. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +6 -1
  158. package/corpus/templates/clips/server/routes/api/thumbnail/[recordingId].get.ts +340 -0
  159. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +24 -7
  160. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +91 -7
  161. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/status.get.ts +14 -0
  162. package/corpus/templates/clips/shared/finalize-recovery.ts +61 -2
  163. package/corpus/templates/clips/shared/share-meta.ts +1 -1
  164. package/corpus/templates/content/app/entry.client.tsx +6 -1
  165. package/corpus/templates/dispatch/AGENTS.md +5 -0
  166. package/corpus/templates/dispatch/changelog/2026-07-17-apps-page-links-to-other-available-apps.md +6 -0
  167. package/corpus/templates/dispatch/changelog/2026-07-17-curated-template-remixes.md +6 -0
  168. package/corpus/templates/mail/app/entry.client.tsx +6 -1
  169. package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +11 -7
  170. package/corpus/templates/slides/.env.example +0 -1
  171. package/corpus/templates/slides/AGENTS.md +4 -0
  172. package/corpus/templates/slides/DEVELOPING.md +2 -2
  173. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +1 -1
  174. package/corpus/templates/slides/actions/logo-config.ts +6 -7
  175. package/corpus/templates/slides/actions/search-images.ts +11 -39
  176. package/corpus/templates/slides/actions/search-logos.ts +5 -52
  177. package/corpus/templates/slides/app/components/editor/ImageSearchPanel.tsx +1 -1
  178. package/corpus/templates/slides/app/components/editor/LogoSearchPanel.tsx +16 -26
  179. package/corpus/templates/slides/app/entry.client.tsx +6 -1
  180. package/corpus/templates/slides/server/lib/media-search-providers.ts +216 -0
  181. package/corpus/templates/slides/server/register-secrets.ts +30 -0
  182. package/dist/a2a/client.d.ts +47 -1
  183. package/dist/a2a/client.d.ts.map +1 -1
  184. package/dist/a2a/client.js +94 -12
  185. package/dist/a2a/client.js.map +1 -1
  186. package/dist/a2a/correlation.d.ts +10 -0
  187. package/dist/a2a/correlation.d.ts.map +1 -0
  188. package/dist/a2a/correlation.js +40 -0
  189. package/dist/a2a/correlation.js.map +1 -0
  190. package/dist/a2a/handlers.d.ts.map +1 -1
  191. package/dist/a2a/handlers.js +147 -15
  192. package/dist/a2a/handlers.js.map +1 -1
  193. package/dist/a2a/index.d.ts +4 -4
  194. package/dist/a2a/index.d.ts.map +1 -1
  195. package/dist/a2a/index.js +2 -2
  196. package/dist/a2a/index.js.map +1 -1
  197. package/dist/a2a/invoke.d.ts +29 -2
  198. package/dist/a2a/invoke.d.ts.map +1 -1
  199. package/dist/a2a/invoke.js +33 -1
  200. package/dist/a2a/invoke.js.map +1 -1
  201. package/dist/a2a/server.d.ts.map +1 -1
  202. package/dist/a2a/server.js +14 -1
  203. package/dist/a2a/server.js.map +1 -1
  204. package/dist/a2a/task-store.d.ts +12 -1
  205. package/dist/a2a/task-store.d.ts.map +1 -1
  206. package/dist/a2a/task-store.js +96 -6
  207. package/dist/a2a/task-store.js.map +1 -1
  208. package/dist/a2a/types.d.ts +27 -0
  209. package/dist/a2a/types.d.ts.map +1 -1
  210. package/dist/a2a/types.js.map +1 -1
  211. package/dist/action.d.ts +5 -2
  212. package/dist/action.d.ts.map +1 -1
  213. package/dist/action.js.map +1 -1
  214. package/dist/agent/production-agent.d.ts +14 -0
  215. package/dist/agent/production-agent.d.ts.map +1 -1
  216. package/dist/agent/production-agent.js +19 -3
  217. package/dist/agent/production-agent.js.map +1 -1
  218. package/dist/client/AssistantChat.d.ts +14 -1
  219. package/dist/client/AssistantChat.d.ts.map +1 -1
  220. package/dist/client/AssistantChat.js +158 -136
  221. package/dist/client/AssistantChat.js.map +1 -1
  222. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  223. package/dist/client/MultiTabAssistantChat.js +27 -4
  224. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  225. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  226. package/dist/client/agent-chat-adapter.js +21 -39
  227. package/dist/client/agent-chat-adapter.js.map +1 -1
  228. package/dist/client/agent-sidebar-state.d.ts +1 -0
  229. package/dist/client/agent-sidebar-state.d.ts.map +1 -1
  230. package/dist/client/agent-sidebar-state.js +4 -0
  231. package/dist/client/agent-sidebar-state.js.map +1 -1
  232. package/dist/client/analytics.d.ts +14 -0
  233. package/dist/client/analytics.d.ts.map +1 -1
  234. package/dist/client/analytics.js +67 -0
  235. package/dist/client/analytics.js.map +1 -1
  236. package/dist/client/chat/message-components.d.ts +8 -0
  237. package/dist/client/chat/message-components.d.ts.map +1 -1
  238. package/dist/client/chat/message-components.js +62 -19
  239. package/dist/client/chat/message-components.js.map +1 -1
  240. package/dist/client/chat/tool-call-display.d.ts +6 -0
  241. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  242. package/dist/client/chat/tool-call-display.js +83 -14
  243. package/dist/client/chat/tool-call-display.js.map +1 -1
  244. package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts +8 -0
  245. package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts.map +1 -0
  246. package/dist/client/chat/use-agent-chat-lifecycle-tracking.js +51 -0
  247. package/dist/client/chat/use-agent-chat-lifecycle-tracking.js.map +1 -0
  248. package/dist/client/chat-thread-url.d.ts +2 -0
  249. package/dist/client/chat-thread-url.d.ts.map +1 -0
  250. package/dist/client/chat-thread-url.js +12 -0
  251. package/dist/client/chat-thread-url.js.map +1 -0
  252. package/dist/client/error-capture.d.ts.map +1 -1
  253. package/dist/client/error-capture.js +7 -0
  254. package/dist/client/error-capture.js.map +1 -1
  255. package/dist/client/extensions/ExtensionSlot.d.ts +3 -1
  256. package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
  257. package/dist/client/extensions/ExtensionSlot.js +28 -3
  258. package/dist/client/extensions/ExtensionSlot.js.map +1 -1
  259. package/dist/client/index.d.ts +1 -1
  260. package/dist/client/index.d.ts.map +1 -1
  261. package/dist/client/index.js +1 -1
  262. package/dist/client/index.js.map +1 -1
  263. package/dist/client/route-chunk-recovery.d.ts.map +1 -1
  264. package/dist/client/route-chunk-recovery.js +14 -9
  265. package/dist/client/route-chunk-recovery.js.map +1 -1
  266. package/dist/client/session-replay.d.ts +15 -0
  267. package/dist/client/session-replay.d.ts.map +1 -1
  268. package/dist/client/session-replay.js +20 -0
  269. package/dist/client/session-replay.js.map +1 -1
  270. package/dist/client/use-run-stuck-detection.d.ts.map +1 -1
  271. package/dist/client/use-run-stuck-detection.js +25 -1
  272. package/dist/client/use-run-stuck-detection.js.map +1 -1
  273. package/dist/db/client.d.ts +7 -0
  274. package/dist/db/client.d.ts.map +1 -1
  275. package/dist/db/client.js +33 -0
  276. package/dist/db/client.js.map +1 -1
  277. package/dist/extensions/actions.d.ts.map +1 -1
  278. package/dist/extensions/actions.js +2 -10
  279. package/dist/extensions/actions.js.map +1 -1
  280. package/dist/extensions/store.js +1 -1
  281. package/dist/extensions/store.js.map +1 -1
  282. package/dist/localization/default-messages.d.ts +3 -0
  283. package/dist/localization/default-messages.d.ts.map +1 -1
  284. package/dist/localization/default-messages.js +3 -0
  285. package/dist/localization/default-messages.js.map +1 -1
  286. package/dist/mcp/build-server.d.ts +2 -0
  287. package/dist/mcp/build-server.d.ts.map +1 -1
  288. package/dist/mcp/build-server.js +2 -2
  289. package/dist/mcp/build-server.js.map +1 -1
  290. package/dist/notifications/routes.d.ts +2 -2
  291. package/dist/observability/routes.d.ts +5 -5
  292. package/dist/observability/traces.d.ts +9 -0
  293. package/dist/observability/traces.d.ts.map +1 -1
  294. package/dist/observability/traces.js +137 -19
  295. package/dist/observability/traces.js.map +1 -1
  296. package/dist/progress/actions.d.ts.map +1 -1
  297. package/dist/progress/actions.js +3 -2
  298. package/dist/progress/actions.js.map +1 -1
  299. package/dist/progress/routes.d.ts +1 -1
  300. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  301. package/dist/provider-api/index.d.ts.map +1 -1
  302. package/dist/provider-api/index.js +91 -8
  303. package/dist/provider-api/index.js.map +1 -1
  304. package/dist/scripts/call-agent.d.ts.map +1 -1
  305. package/dist/scripts/call-agent.js +140 -17
  306. package/dist/scripts/call-agent.js.map +1 -1
  307. package/dist/secrets/routes.d.ts +9 -9
  308. package/dist/server/agent-chat/action-filters-a2a.d.ts +24 -2
  309. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
  310. package/dist/server/agent-chat/action-filters-a2a.js +62 -7
  311. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
  312. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  313. package/dist/server/agent-chat-plugin.js +118 -5
  314. package/dist/server/agent-chat-plugin.js.map +1 -1
  315. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  316. package/dist/server/transcribe-voice.d.ts +1 -1
  317. package/dist/styles/agent-conversation.css +7 -0
  318. package/dist/templates/default/app/i18n/ar-SA.ts +20 -0
  319. package/dist/templates/default/app/i18n/de-DE.ts +20 -0
  320. package/dist/templates/default/app/i18n/en-US.ts +20 -0
  321. package/dist/templates/default/app/i18n/es-ES.ts +20 -0
  322. package/dist/templates/default/app/i18n/fr-FR.ts +21 -0
  323. package/dist/templates/default/app/i18n/hi-IN.ts +19 -0
  324. package/dist/templates/default/app/i18n/ja-JP.ts +20 -0
  325. package/dist/templates/default/app/i18n/ko-KR.ts +19 -0
  326. package/dist/templates/default/app/i18n/pt-BR.ts +20 -0
  327. package/dist/templates/default/app/i18n/zh-CN.ts +19 -0
  328. package/dist/templates/default/app/i18n/zh-TW.ts +19 -0
  329. package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +49 -0
  330. package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  331. package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
  332. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  333. package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
  334. package/package.json +1 -1
  335. package/src/templates/default/app/i18n/ar-SA.ts +20 -0
  336. package/src/templates/default/app/i18n/de-DE.ts +20 -0
  337. package/src/templates/default/app/i18n/en-US.ts +20 -0
  338. package/src/templates/default/app/i18n/es-ES.ts +20 -0
  339. package/src/templates/default/app/i18n/fr-FR.ts +21 -0
  340. package/src/templates/default/app/i18n/hi-IN.ts +19 -0
  341. package/src/templates/default/app/i18n/ja-JP.ts +20 -0
  342. package/src/templates/default/app/i18n/ko-KR.ts +19 -0
  343. package/src/templates/default/app/i18n/pt-BR.ts +20 -0
  344. package/src/templates/default/app/i18n/zh-CN.ts +19 -0
  345. package/src/templates/default/app/i18n/zh-TW.ts +19 -0
  346. package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +49 -0
  347. package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  348. package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
  349. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  350. package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
  351. package/corpus/templates/analytics/server/handlers/github.ts +0 -200
  352. package/corpus/templates/analytics/server/handlers/pylon.ts +0 -43
  353. package/corpus/templates/analytics/server/lib/apollo.ts +0 -167
  354. package/corpus/templates/analytics/server/lib/commonroom.ts +0 -149
  355. package/corpus/templates/analytics/server/lib/github.ts +0 -660
  356. package/corpus/templates/analytics/server/lib/mixpanel.ts +0 -156
  357. package/corpus/templates/analytics/server/lib/posthog.ts +0 -194
  358. package/corpus/templates/analytics/server/lib/pylon.ts +0 -109
  359. package/corpus/templates/analytics/server/routes/api/github/graphql.post.ts +0 -1
  360. package/corpus/templates/analytics/server/routes/api/github/issue.get.ts +0 -1
  361. package/corpus/templates/analytics/server/routes/api/github/org-prs.get.ts +0 -1
  362. package/corpus/templates/analytics/server/routes/api/github/pr.get.ts +0 -1
  363. package/corpus/templates/analytics/server/routes/api/github/prs.get.ts +0 -1
  364. package/corpus/templates/analytics/server/routes/api/github/search.get.ts +0 -1
  365. package/corpus/templates/slides/actions/fetch-logos.ts +0 -90
  366. package/corpus/templates/slides/actions/image-search.ts +0 -64
  367. package/corpus/templates/slides/actions/import-github.ts +0 -182
  368. package/corpus/templates/slides/actions/logo-lookup.ts +0 -113
@@ -9,6 +9,9 @@ export type Workspace = "primary" | "secondary";
9
9
  const cache = new Map<string, { data: unknown; ts: number }>();
10
10
  const CACHE_TTL_MS = 2 * 60 * 1000; // 2 minutes
11
11
  const MAX_CACHE = 200;
12
+ const MAX_CHANNEL_PAGES = 10;
13
+ const MAX_USER_PAGES = 10;
14
+ const SLACK_PAGE_SIZE = 200;
12
15
 
13
16
  async function getToken(workspace: Workspace): Promise<string> {
14
17
  const envKey =
@@ -131,6 +134,41 @@ export interface SlackTeamInfo {
131
134
  icon?: { image_68?: string };
132
135
  }
133
136
 
137
+ export interface SlackPaginationMetadata {
138
+ cursor_type: "response_metadata" | "latest_ts" | "page" | "none";
139
+ request_cursor?: string;
140
+ next_cursor?: string;
141
+ provider_next_cursor?: string;
142
+ page?: number;
143
+ pages?: number;
144
+ next_page?: number;
145
+ }
146
+
147
+ export interface SlackCoverageMetadata {
148
+ requested: number;
149
+ fetched: number;
150
+ returned: number;
151
+ total?: number;
152
+ pages_fetched: number;
153
+ coverage_complete: boolean;
154
+ truncated: boolean;
155
+ truncation_reasons: string[];
156
+ }
157
+
158
+ export interface SlackAuthorCoverageMetadata {
159
+ requested_users: number;
160
+ resolved_users: number;
161
+ unresolved_user_ids: string[];
162
+ requested_bots: number;
163
+ resolved_bots: number;
164
+ unresolved_bot_ids: string[];
165
+ directory_pages_fetched: number;
166
+ directory_next_cursor?: string;
167
+ coverage_complete: boolean;
168
+ truncated: boolean;
169
+ truncation_reasons: string[];
170
+ }
171
+
134
172
  // User cache (keyed by workspace + userId)
135
173
  const userCache = new Map<string, SlackUser>();
136
174
 
@@ -165,18 +203,26 @@ export async function getTeamInfo(
165
203
  }
166
204
  }
167
205
 
168
- export async function listChannels(
206
+ export async function listChannelsWithCoverage(
169
207
  workspace: Workspace,
170
- ): Promise<SlackChannel[]> {
208
+ requestCursor?: string,
209
+ ): Promise<{
210
+ channels: SlackChannel[];
211
+ total: number;
212
+ truncated: boolean;
213
+ pagination: SlackPaginationMetadata;
214
+ coverage: SlackCoverageMetadata;
215
+ }> {
171
216
  const all: SlackChannel[] = [];
172
- let cursor: string | undefined;
217
+ let cursor = requestCursor;
218
+ let pagesFetched = 0;
173
219
 
174
- // Paginate through all channels
175
- for (let i = 0; i < 10; i++) {
220
+ // Paginate through the bounded channel directory.
221
+ for (let i = 0; i < MAX_CHANNEL_PAGES; i++) {
176
222
  const params: Record<string, string> = {
177
223
  types: "public_channel",
178
224
  exclude_archived: "true",
179
- limit: "200",
225
+ limit: String(SLACK_PAGE_SIZE),
180
226
  };
181
227
  if (cursor) params.cursor = cursor;
182
228
 
@@ -186,17 +232,46 @@ export async function listChannels(
186
232
  }>(workspace, "conversations.list", params, !cursor); // cache first page only
187
233
 
188
234
  all.push(...(data.channels || []));
235
+ pagesFetched += 1;
189
236
  cursor = data.response_metadata?.next_cursor;
190
237
  if (!cursor) break;
191
238
  }
192
239
 
193
- return all;
240
+ const truncated = Boolean(cursor);
241
+ return {
242
+ channels: all,
243
+ total: all.length,
244
+ truncated,
245
+ pagination: {
246
+ cursor_type: "response_metadata",
247
+ ...(requestCursor ? { request_cursor: requestCursor } : {}),
248
+ ...(cursor ? { next_cursor: cursor } : {}),
249
+ },
250
+ coverage: {
251
+ requested: MAX_CHANNEL_PAGES * SLACK_PAGE_SIZE,
252
+ fetched: all.length,
253
+ returned: all.length,
254
+ pages_fetched: pagesFetched,
255
+ coverage_complete: !truncated,
256
+ truncated,
257
+ truncation_reasons: truncated ? ["page_cap"] : [],
258
+ },
259
+ };
260
+ }
261
+
262
+ export async function listChannels(
263
+ workspace: Workspace,
264
+ ): Promise<SlackChannel[]> {
265
+ return (await listChannelsWithCoverage(workspace)).channels;
194
266
  }
195
267
 
196
268
  export interface ChannelHistoryResult {
197
269
  messages: SlackMessage[];
198
270
  has_more: boolean;
199
271
  next_cursor?: string; // timestamp of last message
272
+ truncated: boolean;
273
+ pagination: SlackPaginationMetadata;
274
+ coverage: SlackCoverageMetadata;
200
275
  }
201
276
 
202
277
  export async function getChannelHistory(
@@ -215,55 +290,38 @@ export async function getChannelHistory(
215
290
  const data = await slackApi<{
216
291
  messages: SlackMessage[];
217
292
  has_more?: boolean;
293
+ response_metadata?: { next_cursor?: string };
218
294
  }>(workspace, "conversations.history", params, false);
219
295
  const messages = data.messages || [];
296
+ const nextCursor =
297
+ messages.length > 0 ? messages[messages.length - 1].ts : undefined;
298
+ const providerNextCursor = data.response_metadata?.next_cursor || undefined;
299
+ const hasMore = Boolean(data.has_more || providerNextCursor);
220
300
  return {
221
301
  messages,
222
- has_more: !!data.has_more,
223
- next_cursor:
224
- messages.length > 0 ? messages[messages.length - 1].ts : undefined,
302
+ has_more: hasMore,
303
+ next_cursor: nextCursor,
304
+ truncated: hasMore,
305
+ pagination: {
306
+ cursor_type: "latest_ts",
307
+ ...(cursor ? { request_cursor: cursor } : {}),
308
+ ...(nextCursor ? { next_cursor: nextCursor } : {}),
309
+ ...(providerNextCursor
310
+ ? { provider_next_cursor: providerNextCursor }
311
+ : {}),
312
+ },
313
+ coverage: {
314
+ requested: Math.min(limit, SLACK_PAGE_SIZE),
315
+ fetched: messages.length,
316
+ returned: messages.length,
317
+ pages_fetched: 1,
318
+ coverage_complete: !hasMore,
319
+ truncated: hasMore,
320
+ truncation_reasons: hasMore ? ["provider_has_more"] : [],
321
+ },
225
322
  };
226
323
  } catch (err: any) {
227
324
  if (err.message?.includes("not_in_channel")) {
228
- // Try to auto-join the channel (requires channels:join scope)
229
- try {
230
- const token = await getToken(workspace);
231
- const joinRes = await fetch(
232
- "https://slack.com/api/conversations.join",
233
- {
234
- method: "POST",
235
- headers: {
236
- Authorization: `Bearer ${token}`,
237
- "Content-Type": "application/json",
238
- },
239
- body: JSON.stringify({ channel: channelId }),
240
- },
241
- );
242
- const joinData = await joinRes.json();
243
- if (joinData.ok) {
244
- // Joined successfully, retry history
245
- const data = await slackApi<{
246
- messages: SlackMessage[];
247
- has_more?: boolean;
248
- }>(
249
- workspace,
250
- "conversations.history",
251
- {
252
- channel: channelId,
253
- limit: String(Math.min(limit, 200)),
254
- },
255
- false,
256
- );
257
- const msgs = data.messages || [];
258
- return {
259
- messages: msgs,
260
- has_more: !!data.has_more,
261
- next_cursor: msgs.length > 0 ? msgs[msgs.length - 1].ts : undefined,
262
- };
263
- }
264
- } catch {
265
- // join failed, fall through to friendly error
266
- }
267
325
  throw new Error(
268
326
  "Bot is not in this channel. Please invite the bot to the channel in Slack: " +
269
327
  "open the channel, click the channel name, go to Integrations > Add apps, " +
@@ -275,28 +333,35 @@ export async function getChannelHistory(
275
333
  }
276
334
 
277
335
  export async function searchMessages(
278
- workspace: Workspace,
279
- query: string,
280
- count = 50,
281
- ): Promise<{ messages: SlackMessage[]; total: number }> {
282
- // search.messages requires a user token, but we'll try with bot token
283
- // If it fails, we'll fall back to channel history filtering
284
- const data = await slackApi<{
285
- messages: { matches: SlackMessage[]; total: number };
286
- }>(
287
- workspace,
288
- "search.messages",
289
- {
290
- query,
291
- count: String(Math.min(count, 100)),
292
- sort: "timestamp",
293
- sort_dir: "desc",
294
- },
295
- false,
296
- );
336
+ _workspace: Workspace,
337
+ _query: string,
338
+ _count = 50,
339
+ ): Promise<{
340
+ messages: SlackMessage[];
341
+ total: number;
342
+ unsupported: true;
343
+ truncated: boolean;
344
+ pagination: SlackPaginationMetadata;
345
+ coverage: SlackCoverageMetadata;
346
+ guidance: string;
347
+ }> {
297
348
  return {
298
- messages: data.messages?.matches || [],
299
- total: data.messages?.total || 0,
349
+ messages: [],
350
+ total: 0,
351
+ unsupported: true,
352
+ truncated: true,
353
+ pagination: { cursor_type: "none" },
354
+ coverage: {
355
+ requested: 0,
356
+ fetched: 0,
357
+ returned: 0,
358
+ pages_fetched: 0,
359
+ coverage_complete: false,
360
+ truncated: true,
361
+ truncation_reasons: ["bot_token_global_search_unsupported"],
362
+ },
363
+ guidance:
364
+ "Slack search.messages is unavailable with the configured bot credential. Use conversations.history through the shared Slack corpus recipe for a known channel.",
300
365
  };
301
366
  }
302
367
 
@@ -304,10 +369,7 @@ export async function getUserInfo(
304
369
  workspace: Workspace,
305
370
  userId: string,
306
371
  ): Promise<SlackUser> {
307
- const cacheKey = scopedCredentialCacheKey(
308
- `${workspace}:${userId}`,
309
- workspace === "secondary" ? "SLACK_BOT_TOKEN_2" : "SLACK_BOT_TOKEN",
310
- );
372
+ const cacheKey = slackUserCacheKey(workspace, userId);
311
373
  const cached = userCache.get(cacheKey);
312
374
  if (cached) return cached;
313
375
 
@@ -351,38 +413,81 @@ export async function resolveUsers(
351
413
  userIds: string[],
352
414
  messages?: SlackMessage[],
353
415
  ): Promise<Record<string, SlackUser>> {
416
+ return (await resolveUsersWithCoverage(workspace, userIds, messages)).users;
417
+ }
418
+
419
+ export async function resolveUsersWithCoverage(
420
+ workspace: Workspace,
421
+ userIds: string[],
422
+ messages?: SlackMessage[],
423
+ ): Promise<{
424
+ users: Record<string, SlackUser>;
425
+ coverage: SlackAuthorCoverageMetadata;
426
+ }> {
354
427
  const unique = [...new Set(userIds)];
355
428
  const results: Record<string, SlackUser> = {};
429
+ const unresolvedUsers = new Set(unique);
430
+ let directoryPagesFetched = 0;
431
+ let directoryNextCursor: string | undefined;
432
+ let directoryError = false;
433
+
434
+ for (const id of unique) {
435
+ const cacheKey = slackUserCacheKey(workspace, id);
436
+ const cached = userCache.get(cacheKey);
437
+ if (!cached) continue;
438
+ results[id] = cached;
439
+ unresolvedUsers.delete(id);
440
+ }
356
441
 
357
- await Promise.all(
358
- unique.map(async (id) => {
359
- try {
360
- results[id] = await getUserInfo(workspace, id);
361
- } catch {
362
- results[id] = {
363
- id,
364
- name: id,
365
- real_name: id,
366
- profile: { display_name: id, image_48: "", image_72: "" },
367
- };
442
+ try {
443
+ while (unresolvedUsers.size > 0 && directoryPagesFetched < MAX_USER_PAGES) {
444
+ const params: Record<string, string> = {
445
+ limit: String(SLACK_PAGE_SIZE),
446
+ };
447
+ if (directoryNextCursor) params.cursor = directoryNextCursor;
448
+ const data = await slackApi<{
449
+ members: SlackUser[];
450
+ response_metadata?: { next_cursor?: string };
451
+ }>(workspace, "users.list", params, true);
452
+ directoryPagesFetched += 1;
453
+
454
+ for (const user of data.members || []) {
455
+ userCache.set(slackUserCacheKey(workspace, user.id), user);
456
+ if (!unresolvedUsers.has(user.id)) continue;
457
+ results[user.id] = user;
458
+ unresolvedUsers.delete(user.id);
368
459
  }
369
- }),
370
- );
460
+
461
+ directoryNextCursor = data.response_metadata?.next_cursor || undefined;
462
+ if (!directoryNextCursor) break;
463
+ }
464
+ } catch {
465
+ directoryError = true;
466
+ }
467
+
468
+ const unresolvedUserIds = [...unresolvedUsers];
469
+ for (const id of unresolvedUserIds) {
470
+ results[id] = fallbackSlackUser(id);
471
+ }
371
472
 
372
473
  // Resolve bot users from messages that have bot_id but no user
474
+ let resolvedBots = 0;
475
+ const unresolvedBotIds: string[] = [];
476
+ const botIds: string[] = [];
373
477
  if (messages) {
374
- const botIds = [
478
+ botIds.push(
375
479
  ...new Set(
376
480
  messages
377
481
  .filter((m) => m.bot_id && !results[m.bot_id])
378
482
  .map((m) => m.bot_id!),
379
483
  ),
380
- ];
484
+ );
381
485
 
382
486
  await Promise.all(
383
487
  botIds.map(async (botId) => {
384
488
  try {
385
489
  const bot = await getBotInfo(workspace, botId);
490
+ resolvedBots += 1;
386
491
  results[botId] = {
387
492
  id: botId,
388
493
  name: bot.name,
@@ -394,6 +499,7 @@ export async function resolveUsers(
394
499
  },
395
500
  };
396
501
  } catch {
502
+ unresolvedBotIds.push(botId);
397
503
  // Use the username from the message if available
398
504
  const msg = messages.find((m) => m.bot_id === botId);
399
505
  results[botId] = {
@@ -411,7 +517,53 @@ export async function resolveUsers(
411
517
  );
412
518
  }
413
519
 
414
- return results;
520
+ const directoryTruncated =
521
+ unresolvedUsers.size > 0 && Boolean(directoryNextCursor);
522
+ const coverageComplete =
523
+ unresolvedUserIds.length === 0 && unresolvedBotIds.length === 0;
524
+ const truncationReasons = [
525
+ ...(directoryTruncated ? ["user_directory_page_cap"] : []),
526
+ ...(directoryError ? ["user_directory_error"] : []),
527
+ ...(unresolvedUserIds.length > 0 && !directoryTruncated && !directoryError
528
+ ? ["users_not_found"]
529
+ : []),
530
+ ...(unresolvedBotIds.length > 0 ? ["bots_not_found"] : []),
531
+ ];
532
+
533
+ return {
534
+ users: results,
535
+ coverage: {
536
+ requested_users: unique.length,
537
+ resolved_users: unique.length - unresolvedUserIds.length,
538
+ unresolved_user_ids: unresolvedUserIds,
539
+ requested_bots: botIds.length,
540
+ resolved_bots: resolvedBots,
541
+ unresolved_bot_ids: unresolvedBotIds,
542
+ directory_pages_fetched: directoryPagesFetched,
543
+ ...(directoryNextCursor
544
+ ? { directory_next_cursor: directoryNextCursor }
545
+ : {}),
546
+ coverage_complete: coverageComplete,
547
+ truncated: !coverageComplete,
548
+ truncation_reasons: truncationReasons,
549
+ },
550
+ };
551
+ }
552
+
553
+ function slackUserCacheKey(workspace: Workspace, userId: string): string {
554
+ return scopedCredentialCacheKey(
555
+ `${workspace}:${userId}`,
556
+ workspace === "secondary" ? "SLACK_BOT_TOKEN_2" : "SLACK_BOT_TOKEN",
557
+ );
558
+ }
559
+
560
+ function fallbackSlackUser(id: string): SlackUser {
561
+ return {
562
+ id,
563
+ name: id,
564
+ real_name: id,
565
+ profile: { display_name: id, image_48: "", image_72: "" },
566
+ };
415
567
  }
416
568
 
417
569
  /**
@@ -687,7 +687,7 @@ export default createAgentChatPlugin({
687
687
  connectorCatalog: [...ANALYTICS_CONNECTOR_CATALOG],
688
688
  externalAgents: {
689
689
  // Keep the direct MCP surface deliberately curated. External agents
690
- // should use ask_app for multi-step investigation; these six actions are
690
+ // should use ask_app for multi-step investigation; cataloged actions are
691
691
  // bounded fallback reads for callers that already know what they need.
692
692
  authenticatedReads: "off",
693
693
  writes: "ask_app_only",
@@ -704,8 +704,8 @@ export default createAgentChatPlugin({
704
704
  analyticsSourceGuidanceOpening() +
705
705
  "DASHBOARD CREATION RULE — You may create dashboards, analyses, SQL panels, or other resources only when the user explicitly asks you to (e.g. 'build me a dashboard for...', 'create a new analysis', 'add a chart for...'). Never create any resource proactively during research, trend analysis, or answering questions. If you think a dashboard would be useful, suggest it and wait for explicit confirmation before creating anything. Never add new items to the sidebar or modify existing dashboards without an explicit user directive. " +
706
706
  "DASHBOARD MUTATION RULE — For dashboard edits, default to `mutate-dashboard` with the typed `dashboard.*` script API so the main payload is a string and avoids native-array serialization traps. It can move panels by id, edit titles/SQL/config, insert, duplicate, remove, and patch dashboard fields in one atomic save. The script API is constrained: no variables/imports/loops/functions, only JSON-compatible arguments on documented dashboard methods. Do not count shifting `/panels/<index>` positions for ordinary dashboard edits unless the user specifically asks for low-level JSON-pointer operations. " +
707
- 'DASHBOARD EXTENSION BOX RULE — Analytics dashboards support extension boxes. Insert `chartType: "extension"` panels with `config.extensionSlotId` set to `analytics.dashboard.<dashboard-id>.panel.<panel-id>`, then call `add-extension-slot-target` and `install-extension` with that same id. The install is per-user; the extension box stays on the shared dashboard and receives dashboard/panel/current-filter context. Use `get-sql-dashboard` panel summaries to inspect an existing box; `config.extensionId` is only the legacy direct-embed format. ' +
708
- "EXTENSION DATA-REPAIR RULE — When fixing data in an existing extension-backed dashboard or migrated surface such as Risk Meeting, inspect the current dashboard and extension first, then use `update-extension` `patches`/`edits` that change only the data-loading seam. Preserve the existing layout, CSS, copy, and interactions; never reconstruct the full HTML body for a data-only fix. Full-body replacement is blocked unless `allowFullReplacement=true`, which is reserved for an explicit visual rewrite or a complete replacement body supplied by the user. If a focused edit fails, change the target instead of retrying identical arguments. " +
707
+ 'DASHBOARD EXTENSION BOX RULE — Analytics dashboards support extension boxes. For ordinary requests such as "put X in this dashboard," insert a `chartType: "extension"` panel with `config.extensionId`; this author-selected embed is shared with the dashboard, appears in scheduled reports, and receives dashboard/panel/current-filter context. Use `config.extensionSlotId` only when the user explicitly asks for a personal/per-viewer slot. Slot ids use `analytics.dashboard.<dashboard-id>.panel.<panel-id>` and require `add-extension-slot-target` plus `install-extension`; installs are per-user, so viewers can see different content and report identities may see an empty slot. Use `get-sql-dashboard` panel summaries to inspect an existing box. ' +
708
+ "EXTENSION DATA-REPAIR RULE — When fixing data in an existing extension-backed dashboard or migrated surface such as Risk Meeting, inspect the current dashboard and extension first, then use `update-extension` `patches`/`edits` that change only the data-loading seam. Preserve the existing layout, CSS, copy, and interactions; never reconstruct the full HTML body for a data-only fix. Full-body replacement is blocked unless `allowFullReplacement=true`. A request that combines a visual rewrite such as compacting, removing sections, renaming, or changing padding with a data repair is a broad rewrite; after inspecting the current extension, use `allowFullReplacement=true` for the complete replacement. If a focused edit fails, change the target instead of retrying identical arguments. " +
709
709
  'FIRST-PARTY DASHBOARD TIME RULE — AI-generated `source: "first-party"` panels are dashboard-time-bound by default: set `config.timeScope` to `dashboard` and include a matching dashboard time predicate. `{{timeRange}}` requires a matching `filters` entry with `id: "timeRange"` and `type: "select"`; `{{<id>Start}}`/`{{<id>End}}` require a matching `type: "date-range"` filter with that id. Allowed `timeScope` values are `dashboard`, `fixed-window`, `cohort-history`, and `all-time`; use `all-time` only when the user requests full available history and put all-time, lifetime, or historical in the title or description. Server validation rejects unbound first-party SQL. ' +
710
710
  "DASHBOARD READ RULE — `get-sql-dashboard` is compact by default: use its `panels` summaries plus `layout.panelOrder`, `layout.firstPanelIds`, and `layout.groups[].rows[].rowNumber/panelIds` for orientation and verification. Pass `includeConfig: true` only when you truly need full panel SQL/config. " +
711
711
  'DASHBOARD REORDER RULE — For simple chart/section moves, use `mutate-dashboard` code such as `dashboard.panels(["panel-a","panel-b"]).moveToTop();`. For visible placement requests like "second row" or "next to return rates", use row-aware placement such as `dashboard.insertPanel({...}).nextTo("retention-over-time")`, `.atRow(2)`, or `dashboard.panel("panel-a").moveNextTo("panel-b")`; these keep panels in the intended rendered row and expand/rebalance that row when needed. Never count shifting `/panels/<index>` positions for ordinary \'move this chart\' requests. Use `get-sql-dashboard.layout.groups[].rows` as proof of visible row placement, not only flat `panelOrder`. ' +
@@ -1 +1,42 @@
1
- export { handlePylonAccounts as default } from "../../../handlers/pylon";
1
+ import { defineEventHandler, getQuery, setResponseStatus } from "h3";
2
+
3
+ import {
4
+ requireCredential,
5
+ runApiHandlerWithContext,
6
+ } from "../../../lib/credentials";
7
+ import { executeProviderApiRequest } from "../../../lib/provider-api";
8
+
9
+ export default defineEventHandler((event) =>
10
+ runApiHandlerWithContext(event, async () => {
11
+ const missing = await requireCredential(event, "PYLON_API_KEY", "Pylon");
12
+ if (missing) return missing;
13
+ try {
14
+ const query = getQuery(event);
15
+ const search =
16
+ typeof query.query === "string" && query.query.trim()
17
+ ? query.query
18
+ : undefined;
19
+ const result = (await executeProviderApiRequest({
20
+ provider: "pylon",
21
+ method: "GET",
22
+ path: "/accounts",
23
+ ...(search ? { query: { query: search } } : {}),
24
+ })) as { response?: { json?: unknown } };
25
+ const body = result.response?.json;
26
+ const accounts =
27
+ Array.isArray(body) || !body || typeof body !== "object"
28
+ ? Array.isArray(body)
29
+ ? body
30
+ : []
31
+ : Array.isArray((body as { data?: unknown }).data)
32
+ ? (body as { data: unknown[] }).data
33
+ : [];
34
+ return { accounts, total: accounts.length };
35
+ } catch (error) {
36
+ setResponseStatus(event, 500);
37
+ return {
38
+ error: error instanceof Error ? error.message : String(error),
39
+ };
40
+ }
41
+ }),
42
+ );
@@ -1 +1,71 @@
1
- export { handlePylonIssues as default } from "../../../handlers/pylon";
1
+ import { defineEventHandler, getQuery, setResponseStatus } from "h3";
2
+
3
+ import pylonIssues from "../../../../actions/pylon-issues";
4
+ import {
5
+ requireCredential,
6
+ runApiHandlerWithContext,
7
+ } from "../../../lib/credentials";
8
+ import { executeProviderApiRequest } from "../../../lib/provider-api";
9
+
10
+ function queryString(value: unknown): string | undefined {
11
+ return typeof value === "string" && value.trim() ? value : undefined;
12
+ }
13
+
14
+ function responseItems(value: unknown): unknown[] {
15
+ if (Array.isArray(value)) return value;
16
+ if (value && typeof value === "object" && "data" in value) {
17
+ const data = (value as { data?: unknown }).data;
18
+ return Array.isArray(data) ? data : [];
19
+ }
20
+ return [];
21
+ }
22
+
23
+ export default defineEventHandler((event) =>
24
+ runApiHandlerWithContext(event, async () => {
25
+ const missing = await requireCredential(event, "PYLON_API_KEY", "Pylon");
26
+ if (missing) return missing;
27
+ try {
28
+ const query = getQuery(event);
29
+ const accountId = queryString(query.account_id);
30
+ const state = queryString(query.state);
31
+ const search = queryString(query.query);
32
+
33
+ if (accountId || state || search) {
34
+ const now = new Date();
35
+ const start = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1_000);
36
+ const response = (await executeProviderApiRequest({
37
+ provider: "pylon",
38
+ method: "GET",
39
+ path: "/issues",
40
+ query: {
41
+ ...(accountId ? { account_id: accountId } : {}),
42
+ ...(state ? { state } : {}),
43
+ ...(search ? { query: search } : {}),
44
+ start_time: start.toISOString(),
45
+ end_time: now.toISOString(),
46
+ },
47
+ })) as { response?: { json?: unknown } };
48
+ const issues = responseItems(response.response?.json);
49
+ return { issues, total: issues.length };
50
+ }
51
+
52
+ const days = queryString(query.days);
53
+ const parsedDays = days == null ? 371 : Number(days);
54
+ if (!Number.isInteger(parsedDays) || parsedDays < 1 || parsedDays > 730) {
55
+ setResponseStatus(event, 400);
56
+ return { error: "days must be an integer between 1 and 730" };
57
+ }
58
+ const result = await pylonIssues.run({
59
+ days: parsedDays,
60
+ pageSize: 500,
61
+ maxPages: 20,
62
+ });
63
+ return result;
64
+ } catch (error) {
65
+ setResponseStatus(event, 500);
66
+ return {
67
+ error: error instanceof Error ? error.message : String(error),
68
+ };
69
+ }
70
+ }),
71
+ );
@@ -6,6 +6,7 @@ import {
6
6
  resolveCredential,
7
7
  withRequestContextFromEvent,
8
8
  } from "../../lib/credentials";
9
+ import { executeProviderApiRequest } from "../../lib/provider-api";
9
10
  import {
10
11
  CLAY_ANALYTICS_CREDENTIAL_KEYS,
11
12
  HUBSPOT_ANALYTICS_CREDENTIAL_KEYS,
@@ -13,6 +14,32 @@ import {
13
14
  resolveAnalyticsProviderCredential,
14
15
  } from "../../lib/provider-credentials";
15
16
 
17
+ type ProviderApiConnectionResponse = {
18
+ response?: {
19
+ ok?: boolean;
20
+ status?: number;
21
+ text?: string;
22
+ json?: unknown;
23
+ };
24
+ };
25
+
26
+ function providerApiConnectionResult(
27
+ provider: string,
28
+ result: unknown,
29
+ ): { ok: boolean; error?: string } {
30
+ const response = (result as ProviderApiConnectionResponse).response;
31
+ if (response?.ok) return { ok: true };
32
+
33
+ const detail =
34
+ response?.text?.trim() ||
35
+ (response?.json === undefined ? "" : JSON.stringify(response.json));
36
+ const status = response?.status ?? "unknown";
37
+ return {
38
+ ok: false,
39
+ error: `${provider} API error ${status}${detail ? `: ${detail}` : ""}`,
40
+ };
41
+ }
42
+
16
43
  export default defineEventHandler(async (event) => {
17
44
  const body = await readBody(event);
18
45
  const { source } = body as { source?: string };
@@ -66,8 +93,17 @@ export default defineEventHandler(async (event) => {
66
93
  const sa = await resolveCredential("MIXPANEL_SERVICE_ACCOUNT", ctx);
67
94
  if (!projectId || !sa)
68
95
  return { ok: false, error: "Missing credentials" };
69
- const { testConnection } = await import("../../lib/mixpanel");
70
- return await testConnection();
96
+ const result = await executeProviderApiRequest({
97
+ provider: "mixpanel",
98
+ method: "GET",
99
+ path: "/events/top",
100
+ query: {
101
+ type: "general",
102
+ limit: 1,
103
+ project_id: "{projectId}",
104
+ },
105
+ });
106
+ return providerApiConnectionResult("Mixpanel", result);
71
107
  }
72
108
 
73
109
  case "posthog": {
@@ -75,8 +111,12 @@ export default defineEventHandler(async (event) => {
75
111
  const projectId = await resolveCredential("POSTHOG_PROJECT_ID", ctx);
76
112
  if (!apiKey || !projectId)
77
113
  return { ok: false, error: "Missing credentials" };
78
- const { testConnection } = await import("../../lib/posthog");
79
- return await testConnection();
114
+ const result = await executeProviderApiRequest({
115
+ provider: "posthog",
116
+ method: "GET",
117
+ path: "/api/projects/{projectId}/",
118
+ });
119
+ return providerApiConnectionResult("PostHog", result);
80
120
  }
81
121
 
82
122
  case "postgresql": {