@agent-native/core 0.129.1 → 0.130.0

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 (596) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +78 -0
  3. package/corpus/core/docs/content/cloneable-saas.mdx +114 -0
  4. package/corpus/core/docs/content/creating-templates.mdx +28 -2
  5. package/corpus/core/docs/content/syncing-template-changes.mdx +7 -0
  6. package/corpus/core/docs/content/template-clips-developers.mdx +12 -5
  7. package/corpus/core/docs/content/template-dispatch-developers.mdx +1 -1
  8. package/corpus/core/docs/content/template-dispatch.mdx +1 -1
  9. package/corpus/core/package.json +1 -1
  10. package/corpus/core/src/action-ui.ts +1 -0
  11. package/corpus/core/src/action.ts +5 -1
  12. package/corpus/core/src/agent/engine/ai-sdk-engine.ts +15 -5
  13. package/corpus/core/src/agent/harness/runner.ts +5 -0
  14. package/corpus/core/src/agent/production-agent.ts +33 -0
  15. package/corpus/core/src/agent/run-loop-with-resume.ts +5 -0
  16. package/corpus/core/src/agent/run-manager.ts +126 -1
  17. package/corpus/core/src/agent/thread-data-builder.ts +47 -2
  18. package/corpus/core/src/agent/types.ts +2 -0
  19. package/corpus/core/src/chat-threads/store.ts +4 -5
  20. package/corpus/core/src/cli/create.ts +1139 -65
  21. package/corpus/core/src/cli/design-connect.ts +3 -7
  22. package/corpus/core/src/cli/index.ts +5 -3
  23. package/corpus/core/src/cli/skills-content/design-visual-edit-skill.ts +83 -47
  24. package/corpus/core/src/client/AssistantChat.tsx +27 -16
  25. package/corpus/core/src/client/agent-chat-adapter.ts +24 -0
  26. package/corpus/core/src/client/blocks/library/wireframe-kit.tsx +17 -2
  27. package/corpus/core/src/client/chat/index.ts +1 -0
  28. package/corpus/core/src/client/chat/message-components.tsx +104 -1
  29. package/corpus/core/src/client/chat/run-recovery.tsx +15 -3
  30. package/corpus/core/src/client/chat/widgets/DataTableWidget.tsx +10 -29
  31. package/corpus/core/src/client/chat/widgets/WorkspaceFileWidget.tsx +71 -0
  32. package/corpus/core/src/client/chat/widgets/builtin-tool-renderers.tsx +22 -0
  33. package/corpus/core/src/client/chat/widgets/workspace-file-result.ts +49 -0
  34. package/corpus/core/src/client/embed-auth.ts +2 -0
  35. package/corpus/core/src/client/org/InvitationBanner.tsx +14 -1
  36. package/corpus/core/src/client/org/OrgSwitcher.tsx +23 -0
  37. package/corpus/core/src/client/org/TeamPage.tsx +130 -0
  38. package/corpus/core/src/client/org/WorkspaceNotice.tsx +85 -0
  39. package/corpus/core/src/client/org/hooks.ts +14 -0
  40. package/corpus/core/src/client/org/index.ts +2 -0
  41. package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +27 -40
  42. package/corpus/core/src/client/resources/ResourcesPanel.tsx +134 -51
  43. package/corpus/core/src/client/resources/mcp-integration-catalog.ts +7 -0
  44. package/corpus/core/src/client/resources/use-resources.ts +6 -0
  45. package/corpus/core/src/client/use-action.ts +3 -1
  46. package/corpus/core/src/client/widgets/index.ts +1 -0
  47. package/corpus/core/src/coding-tools/run-code.ts +2 -1
  48. package/corpus/core/src/db/client.ts +28 -4
  49. package/corpus/core/src/deploy/build.ts +31 -3
  50. package/corpus/core/src/eject/remote-mcp-presets.ts +1 -1
  51. package/corpus/core/src/index.browser.ts +1 -0
  52. package/corpus/core/src/index.ts +1 -0
  53. package/corpus/core/src/integrations/google-docs-poller.ts +3 -0
  54. package/corpus/core/src/integrations/webhook-handler.ts +28 -11
  55. package/corpus/core/src/jobs/scheduler.ts +4 -0
  56. package/corpus/core/src/localization/default-messages.ts +3 -2
  57. package/corpus/core/src/mcp/build-server.ts +20 -2
  58. package/corpus/core/src/observability/traces.ts +48 -12
  59. package/corpus/core/src/org/handlers.ts +52 -1
  60. package/corpus/core/src/org/migrations.ts +4 -0
  61. package/corpus/core/src/org/plugin.ts +14 -0
  62. package/corpus/core/src/org/schema.ts +1 -0
  63. package/corpus/core/src/org/types.ts +8 -0
  64. package/corpus/core/src/org/workspace-url.ts +74 -0
  65. package/corpus/core/src/resources/handlers.ts +35 -5
  66. package/corpus/core/src/scripts/runner.ts +183 -5
  67. package/corpus/core/src/server/action-routes.ts +32 -2
  68. package/corpus/core/src/server/agent-chat-plugin.ts +29 -0
  69. package/corpus/core/src/server/agent-teams.ts +10 -1
  70. package/corpus/core/src/server/auth.ts +33 -7
  71. package/corpus/core/src/server/embed-route.ts +9 -0
  72. package/corpus/core/src/server/embed-session.ts +62 -3
  73. package/corpus/core/src/server/open-route.ts +20 -6
  74. package/corpus/core/src/server/prompts/framework-core-compact.ts +1 -1
  75. package/corpus/core/src/server/prompts/framework-core.ts +1 -0
  76. package/corpus/core/src/server/request-context.ts +36 -1
  77. package/corpus/core/src/shared/embed-auth.ts +1 -0
  78. package/corpus/core/src/shared/html-document.ts +115 -0
  79. package/corpus/core/src/shared/index.ts +1 -0
  80. package/corpus/core/src/sharing/access.ts +8 -1
  81. package/corpus/core/src/sharing/registry.ts +11 -2
  82. package/corpus/core/src/workspace-files/actions.ts +100 -0
  83. package/corpus/core/src/workspace-files/tool.ts +4 -0
  84. package/corpus/templates/analytics/.agents/skills/analysis-workspace/SKILL.md +4 -0
  85. package/corpus/templates/analytics/.agents/skills/hubspot/SKILL.md +9 -1
  86. package/corpus/templates/analytics/AGENTS.md +17 -24
  87. package/corpus/templates/analytics/actions/data-source-status.ts +11 -1
  88. package/corpus/templates/analytics/app/i18n-data.ts +34 -0
  89. package/corpus/templates/analytics/app/lib/data-source-status.ts +86 -0
  90. package/corpus/templates/analytics/app/lib/native-mcp-exclusions.ts +9 -0
  91. package/corpus/templates/analytics/app/pages/DataSources.tsx +184 -20
  92. package/corpus/templates/analytics/changelog/2026-07-28-native-analytics-data-sources-no-longer-show-duplicate-mc.md +6 -0
  93. package/corpus/templates/analytics/changelog/2026-07-29-exports-now-appear-in-chat-with-a-direct-download-instead-of.md +6 -0
  94. package/corpus/templates/analytics/changelog/2026-07-29-queued-chat-prompts-no-longer-resend-after-analytics-navigat.md +6 -0
  95. package/corpus/templates/analytics/changelog/2026-07-29-scheduled-dashboard-emails-load-every-panel-reliably-without.md +6 -0
  96. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +6 -3
  97. package/corpus/templates/analytics/server/lib/credential-keys.ts +1 -1
  98. package/corpus/templates/analytics/server/lib/hubspot.ts +1 -1
  99. package/corpus/templates/analytics/server/lib/provider-credentials.ts +55 -1
  100. package/corpus/templates/analytics/server/plugins/agent-chat.ts +123 -27
  101. package/corpus/templates/analytics/server/routes/[...page].get.ts +2 -7
  102. package/corpus/templates/analytics/vite.config.ts +7 -0
  103. package/corpus/templates/brain/actions/list-connection-providers.ts +100 -2
  104. package/corpus/templates/brain/app/lib/brain.ts +10 -0
  105. package/corpus/templates/brain/app/routes/sources.tsx +15 -4
  106. package/corpus/templates/brain/changelog/2026-07-29-brain-automatically-retries-failed-source-syncs-and-guides-y.md +6 -0
  107. package/corpus/templates/brain/jobs/process-ingest-queue.ts +13 -0
  108. package/corpus/templates/brain/server/jobs/sync-sources.ts +27 -22
  109. package/corpus/templates/brain/server/plugins/agent-chat.ts +2 -1
  110. package/corpus/templates/brain/server/routes/api/brain/queue/run.post.ts +7 -1
  111. package/corpus/templates/clips/AGENTS.md +1 -1
  112. package/corpus/templates/clips/actions/create-recording-agent-link.ts +11 -1
  113. package/corpus/templates/clips/actions/update-comment.ts +68 -0
  114. package/corpus/templates/clips/app/components/editor/editor-layout.tsx +0 -1
  115. package/corpus/templates/clips/app/components/player/comments-panel.tsx +221 -65
  116. package/corpus/templates/clips/app/components/player/video-player.tsx +101 -27
  117. package/corpus/templates/clips/app/i18n/en-US.ts +2 -1
  118. package/corpus/templates/clips/app/routes/bug-report.done.tsx +48 -27
  119. package/corpus/templates/clips/app/routes/bug-report.tsx +43 -4
  120. package/corpus/templates/clips/app/routes/record.tsx +2 -0
  121. package/corpus/templates/clips/changelog/2026-07-29-clip-playback-now-recovers-instead-of-getting-stuck-when-a-b.md +6 -0
  122. package/corpus/templates/clips/changelog/2026-07-29-comments-can-now-be-edited-after-posting.md +6 -0
  123. package/corpus/templates/clips/changelog/2026-07-29-download-actions-now-use-a-shorter-clearer-label.md +6 -0
  124. package/corpus/templates/clips/changelog/2026-07-29-embedded-bug-reports-now-return-a-temporary-agent-readable.md +6 -0
  125. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +1 -1
  126. package/corpus/templates/clips/desktop/src-tauri/src/system_audio.rs +21 -1
  127. package/corpus/templates/clips/shared/bug-report.ts +99 -0
  128. package/corpus/templates/content/actions/_content-database-personal-view.ts +7 -1
  129. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +5 -2
  130. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +20 -8
  131. package/corpus/templates/content/changelog/2026-07-29-missing-databases-no-longer-trigger-repeated-personal-view-e.md +6 -0
  132. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +83 -47
  133. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +474 -55
  134. package/corpus/templates/design/.generated/bridge/embedded-wheel.generated.ts +3 -0
  135. package/corpus/templates/design/.generated/bridge/hit-test.generated.ts +18 -1
  136. package/corpus/templates/design/.generated/bridge/source-location.generated.ts +348 -0
  137. package/corpus/templates/design/actions/add-localhost-screens.ts +2 -7
  138. package/corpus/templates/design/actions/apply-visual-edit.ts +7 -1
  139. package/corpus/templates/design/actions/connect-localhost.ts +5 -9
  140. package/corpus/templates/design/actions/create-component.ts +16 -13
  141. package/corpus/templates/design/actions/grant-localhost-write-consent.ts +2 -7
  142. package/corpus/templates/design/actions/list-design-source-capabilities.ts +4 -7
  143. package/corpus/templates/design/actions/list-local-files.ts +26 -50
  144. package/corpus/templates/design/actions/list-localhost-connections.ts +2 -7
  145. package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +2 -2
  146. package/corpus/templates/design/actions/open-visual-edit.ts +234 -135
  147. package/corpus/templates/design/actions/read-local-file.ts +26 -50
  148. package/corpus/templates/design/actions/request-localhost-write-consent.ts +2 -7
  149. package/corpus/templates/design/actions/write-local-file.ts +31 -73
  150. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +307 -133
  151. package/corpus/templates/design/app/components/design/EditPanel.tsx +94 -22
  152. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +137 -60
  153. package/corpus/templates/design/app/components/design/ResponsiveInteractBar.tsx +75 -14
  154. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +755 -97
  155. package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +8 -0
  156. package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +24 -1
  157. package/corpus/templates/design/app/components/design/bridge/source-location.bridge.ts +530 -0
  158. package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbenchLoader.tsx +278 -0
  159. package/corpus/templates/design/app/components/design/code-workbench/editor/MonacoHost.tsx +32 -12
  160. package/corpus/templates/design/app/components/design/code-workbench/editor/monaco-setup.ts +14 -3
  161. package/corpus/templates/design/app/components/design/code-workbench/explorer/ExplorerView.tsx +87 -24
  162. package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +36 -0
  163. package/corpus/templates/design/app/components/design/code-workbench/store.tsx +2 -1
  164. package/corpus/templates/design/app/components/design/code-workbench/workspace/localhost-provider.ts +48 -8
  165. package/corpus/templates/design/app/components/design/design-canvas/content-size-report.ts +3 -13
  166. package/corpus/templates/design/app/components/design/design-canvas/embedded-frame.ts +4 -2
  167. package/corpus/templates/design/app/components/design/design-canvas/hit-test.ts +3 -13
  168. package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +3 -1
  169. package/corpus/templates/design/app/components/design/edit-panel/inspect-code-source.ts +93 -0
  170. package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +4 -2
  171. package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +35 -0
  172. package/corpus/templates/design/app/components/design/multi-screen/iframe-targeting.ts +24 -0
  173. package/corpus/templates/design/app/components/design/multi-screen/types.ts +9 -0
  174. package/corpus/templates/design/app/components/design/types.ts +29 -0
  175. package/corpus/templates/design/app/components/layout/Layout.tsx +7 -4
  176. package/corpus/templates/design/app/hooks/use-navigation-state.ts +3 -0
  177. package/corpus/templates/design/app/i18n-data.ts +153 -46
  178. package/corpus/templates/design/app/i18n-responsive-interact.ts +12 -12
  179. package/corpus/templates/design/app/lib/design-editor-route.ts +23 -0
  180. package/corpus/templates/design/app/pages/VisualEdit.tsx +19 -6
  181. package/corpus/templates/design/app/pages/design-editor/action-error.ts +19 -0
  182. package/corpus/templates/design/app/pages/design-editor/canvas-primitive-insert.ts +29 -0
  183. package/corpus/templates/design/app/pages/design-editor/clone-and-pen-edit.ts +6 -0
  184. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +277 -15
  185. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +75 -9
  186. package/corpus/templates/design/app/pages/design-editor/layer-state-scope.ts +28 -0
  187. package/corpus/templates/design/app/pages/design-editor/live-screen-layer-drop.ts +41 -0
  188. package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +496 -41
  189. package/corpus/templates/design/app/pages/design-editor/pending-live-edit-unload-guard.ts +27 -0
  190. package/corpus/templates/design/app/pages/design-editor/pending-structure-verification.ts +10 -0
  191. package/corpus/templates/design/app/pages/design-editor/react-semantic-handoff.ts +168 -9
  192. package/corpus/templates/design/app/pages/design-editor/responsive-interact.ts +41 -3
  193. package/corpus/templates/design/app/pages/design-editor/screen-command-utils.ts +5 -0
  194. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +42 -13
  195. package/corpus/templates/design/app/pages/design-editor/source-location.ts +180 -0
  196. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +17 -0
  197. package/corpus/templates/design/app/public-routes.ts +1 -0
  198. package/corpus/templates/design/app/routes/visual-edit.$id.tsx +15 -0
  199. package/corpus/templates/design/changelog/2026-06-29-screen-overview-is-easier-to-find-and-named-screens-open-dir.md +1 -1
  200. package/corpus/templates/design/changelog/2026-07-28-deleting-a-selected-element-now-removes-it-from-the-live-pre.md +6 -0
  201. package/corpus/templates/design/changelog/2026-07-28-deleting-an-element-on-a-connected-localhost-screen-now-queu.md +6 -0
  202. package/corpus/templates/design/changelog/2026-07-28-interact-mode-now-shows-a-responsive-device-preview-with-pre.md +6 -0
  203. package/corpus/templates/design/changelog/2026-07-28-layer-hide-and-lock-now-apply-to-the-live-preview-instead-of.md +6 -0
  204. package/corpus/templates/design/changelog/2026-07-28-layers-panel-selections-on-a-connected-localhost-screen-can-.md +6 -0
  205. package/corpus/templates/design/changelog/2026-07-28-locked-layers-now-show-a-subtle-dashed-outline-in-the-live-p.md +6 -0
  206. package/corpus/templates/design/changelog/2026-07-28-the-apply-design-updates-button-now-counts-pending-live-text.md +6 -0
  207. package/corpus/templates/design/changelog/2026-07-28-the-design-canvas-no-longer-stalls-on-a-render-loop-while-a-.md +6 -0
  208. package/corpus/templates/design/changelog/2026-07-28-visual-edit-on-a-local-dev-server-no-longer-requires-signing.md +6 -0
  209. package/corpus/templates/design/changelog/2026-07-28-visual-edits-on-a-react-19-app-no-longer-report-a-source-lin.md +6 -0
  210. package/corpus/templates/design/changelog/2026-07-29-an-edit-that-cannot-be-written-to-source-now-names-the-reaso.md +6 -0
  211. package/corpus/templates/design/changelog/2026-07-29-applying-a-primitive-dropped-onto-a-connected-localhost-scre.md +6 -0
  212. package/corpus/templates/design/changelog/2026-07-29-changing-a-style-in-the-inspector-now-updates-a-connected-lo.md +6 -0
  213. package/corpus/templates/design/changelog/2026-07-29-choosing-edit-or-annotate-from-a-focused-screen-now-returns-.md +6 -0
  214. package/corpus/templates/design/changelog/2026-07-29-concurrent-source-edits-now-return-a-clear-conflict-response.md +6 -0
  215. package/corpus/templates/design/changelog/2026-07-29-creating-a-component-from-an-element-that-repeats-in-the-sou.md +6 -0
  216. package/corpus/templates/design/changelog/2026-07-29-deleting-an-element-you-just-dropped-onto-a-live-screen-no-l.md +6 -0
  217. package/corpus/templates/design/changelog/2026-07-29-dragging-a-layer-across-screens-no-longer-dies-when-the-poin.md +6 -0
  218. package/corpus/templates/design/changelog/2026-07-29-dragging-an-element-from-a-stored-screen-into-a-live-localho.md +6 -0
  219. package/corpus/templates/design/changelog/2026-07-29-drawing-a-box-on-the-canvas-and-dragging-it-into-a-connected.md +6 -0
  220. package/corpus/templates/design/changelog/2026-07-29-fixed-a-loading-screen-flicker-when-reopening-designs-with-a.md +6 -0
  221. package/corpus/templates/design/changelog/2026-07-29-interact-mode-has-edit-and-annotate-buttons-again-so-you-can.md +6 -0
  222. package/corpus/templates/design/changelog/2026-07-29-layer-groups-can-be-dropped-onto-live-localhost-screens.md +6 -0
  223. package/corpus/templates/design/changelog/2026-07-29-localhost-source-errors-now-say-what-actually-went-wrong-whi.md +6 -0
  224. package/corpus/templates/design/changelog/2026-07-29-opening-or-refreshing-a-live-localhost-screen-in-single-scre.md +6 -0
  225. package/corpus/templates/design/changelog/2026-07-29-redo-after-undoing-a-drop-onto-a-live-screen-puts-the-elemen.md +6 -0
  226. package/corpus/templates/design/changelog/2026-07-29-shapes-can-be-drawn-directly-onto-live-localhost-screens.md +6 -0
  227. package/corpus/templates/design/changelog/2026-07-29-shapes-drawn-on-the-canvas-board-now-appear-immediately-inst.md +6 -0
  228. package/corpus/templates/design/changelog/2026-07-29-style-edits-on-a-running-localhost-screen-now-preview-live-a.md +6 -0
  229. package/corpus/templates/design/changelog/2026-07-29-the-apply-design-updates-control-now-appears-as-a-clean-conn.md +6 -0
  230. package/corpus/templates/design/changelog/2026-07-29-visual-edits-on-a-mapped-component-instance-now-tell-the-age.md +6 -0
  231. package/corpus/templates/design/server/lib/design-data-access.ts +21 -7
  232. package/corpus/templates/design/server/lib/localhost-connection.ts +240 -0
  233. package/corpus/templates/design/server/routes/[...page].get.ts +2 -5
  234. package/corpus/templates/design/server/source-workspace.ts +2 -0
  235. package/corpus/templates/design/shared/code-layer.ts +43 -0
  236. package/corpus/templates/design/shared/html-content.ts +26 -0
  237. package/corpus/templates/design/shared/html-integrity.ts +21 -1
  238. package/corpus/templates/design/shared/local-jsx-visual-edit.ts +15 -0
  239. package/corpus/templates/design/shared/source-mode.ts +76 -0
  240. package/corpus/templates/dispatch/changelog/2026-07-29-workspace-members-without-admin-access-now-see-a-clear-permi.md +6 -0
  241. package/corpus/templates/dispatch/server/lib/usage-metrics.ts +2 -1
  242. package/corpus/templates/plan/app/lib/plan-annotation-runtime.ts +3 -4
  243. package/corpus/templates/plan/server/routes/[...page].get.ts +2 -5
  244. package/corpus/templates/slides/actions/patch-deck.ts +29 -17
  245. package/corpus/toolkit/CHANGELOG.md +6 -0
  246. package/corpus/toolkit/package.json +1 -1
  247. package/corpus/toolkit/src/composer/ComposerPlusMenu.tsx +3 -2
  248. package/dist/action-ui.d.ts +1 -0
  249. package/dist/action-ui.d.ts.map +1 -1
  250. package/dist/action-ui.js +1 -0
  251. package/dist/action-ui.js.map +1 -1
  252. package/dist/action.d.ts +5 -1
  253. package/dist/action.d.ts.map +1 -1
  254. package/dist/action.js.map +1 -1
  255. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  256. package/dist/agent/engine/ai-sdk-engine.js +13 -5
  257. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  258. package/dist/agent/harness/runner.d.ts.map +1 -1
  259. package/dist/agent/harness/runner.js +5 -0
  260. package/dist/agent/harness/runner.js.map +1 -1
  261. package/dist/agent/production-agent.d.ts +16 -0
  262. package/dist/agent/production-agent.d.ts.map +1 -1
  263. package/dist/agent/production-agent.js +18 -1
  264. package/dist/agent/production-agent.js.map +1 -1
  265. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  266. package/dist/agent/run-loop-with-resume.js +6 -0
  267. package/dist/agent/run-loop-with-resume.js.map +1 -1
  268. package/dist/agent/run-manager.d.ts +14 -0
  269. package/dist/agent/run-manager.d.ts.map +1 -1
  270. package/dist/agent/run-manager.js +91 -1
  271. package/dist/agent/run-manager.js.map +1 -1
  272. package/dist/agent/thread-data-builder.d.ts +3 -0
  273. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  274. package/dist/agent/thread-data-builder.js +35 -3
  275. package/dist/agent/thread-data-builder.js.map +1 -1
  276. package/dist/agent/types.d.ts +2 -0
  277. package/dist/agent/types.d.ts.map +1 -1
  278. package/dist/agent/types.js.map +1 -1
  279. package/dist/chat-threads/store.d.ts.map +1 -1
  280. package/dist/chat-threads/store.js +4 -6
  281. package/dist/chat-threads/store.js.map +1 -1
  282. package/dist/cli/create.d.ts +66 -6
  283. package/dist/cli/create.d.ts.map +1 -1
  284. package/dist/cli/create.js +765 -66
  285. package/dist/cli/create.js.map +1 -1
  286. package/dist/cli/design-connect.d.ts.map +1 -1
  287. package/dist/cli/design-connect.js +2 -7
  288. package/dist/cli/design-connect.js.map +1 -1
  289. package/dist/cli/index.js +5 -3
  290. package/dist/cli/index.js.map +1 -1
  291. package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
  292. package/dist/cli/skills-content/design-visual-edit-skill.d.ts.map +1 -1
  293. package/dist/cli/skills-content/design-visual-edit-skill.js +83 -47
  294. package/dist/cli/skills-content/design-visual-edit-skill.js.map +1 -1
  295. package/dist/client/AssistantChat.d.ts.map +1 -1
  296. package/dist/client/AssistantChat.js +16 -9
  297. package/dist/client/AssistantChat.js.map +1 -1
  298. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  299. package/dist/client/agent-chat-adapter.js +21 -0
  300. package/dist/client/agent-chat-adapter.js.map +1 -1
  301. package/dist/client/blocks/library/wireframe-kit.d.ts +2 -0
  302. package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -1
  303. package/dist/client/blocks/library/wireframe-kit.js +8 -2
  304. package/dist/client/blocks/library/wireframe-kit.js.map +1 -1
  305. package/dist/client/chat/index.d.ts +1 -1
  306. package/dist/client/chat/index.d.ts.map +1 -1
  307. package/dist/client/chat/index.js +1 -1
  308. package/dist/client/chat/index.js.map +1 -1
  309. package/dist/client/chat/message-components.d.ts +17 -0
  310. package/dist/client/chat/message-components.d.ts.map +1 -1
  311. package/dist/client/chat/message-components.js +24 -2
  312. package/dist/client/chat/message-components.js.map +1 -1
  313. package/dist/client/chat/run-recovery.d.ts +6 -0
  314. package/dist/client/chat/run-recovery.d.ts.map +1 -1
  315. package/dist/client/chat/run-recovery.js +13 -3
  316. package/dist/client/chat/run-recovery.js.map +1 -1
  317. package/dist/client/chat/widgets/DataTableWidget.d.ts.map +1 -1
  318. package/dist/client/chat/widgets/DataTableWidget.js +2 -3
  319. package/dist/client/chat/widgets/DataTableWidget.js.map +1 -1
  320. package/dist/client/chat/widgets/WorkspaceFileWidget.d.ts +5 -0
  321. package/dist/client/chat/widgets/WorkspaceFileWidget.d.ts.map +1 -0
  322. package/dist/client/chat/widgets/WorkspaceFileWidget.js +34 -0
  323. package/dist/client/chat/widgets/WorkspaceFileWidget.js.map +1 -0
  324. package/dist/client/chat/widgets/builtin-tool-renderers.d.ts.map +1 -1
  325. package/dist/client/chat/widgets/builtin-tool-renderers.js +13 -1
  326. package/dist/client/chat/widgets/builtin-tool-renderers.js.map +1 -1
  327. package/dist/client/chat/widgets/workspace-file-result.d.ts +12 -0
  328. package/dist/client/chat/widgets/workspace-file-result.d.ts.map +1 -0
  329. package/dist/client/chat/widgets/workspace-file-result.js +34 -0
  330. package/dist/client/chat/widgets/workspace-file-result.js.map +1 -0
  331. package/dist/client/embed-auth.d.ts.map +1 -1
  332. package/dist/client/embed-auth.js +2 -1
  333. package/dist/client/embed-auth.js.map +1 -1
  334. package/dist/client/org/InvitationBanner.d.ts +5 -2
  335. package/dist/client/org/InvitationBanner.d.ts.map +1 -1
  336. package/dist/client/org/InvitationBanner.js +9 -2
  337. package/dist/client/org/InvitationBanner.js.map +1 -1
  338. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  339. package/dist/client/org/OrgSwitcher.js +3 -2
  340. package/dist/client/org/OrgSwitcher.js.map +1 -1
  341. package/dist/client/org/TeamPage.d.ts.map +1 -1
  342. package/dist/client/org/TeamPage.js +27 -3
  343. package/dist/client/org/TeamPage.js.map +1 -1
  344. package/dist/client/org/WorkspaceNotice.d.ts +18 -0
  345. package/dist/client/org/WorkspaceNotice.d.ts.map +1 -0
  346. package/dist/client/org/WorkspaceNotice.js +56 -0
  347. package/dist/client/org/WorkspaceNotice.js.map +1 -0
  348. package/dist/client/org/hooks.d.ts +1 -0
  349. package/dist/client/org/hooks.d.ts.map +1 -1
  350. package/dist/client/org/hooks.js +12 -0
  351. package/dist/client/org/hooks.js.map +1 -1
  352. package/dist/client/org/index.d.ts +2 -1
  353. package/dist/client/org/index.d.ts.map +1 -1
  354. package/dist/client/org/index.js +2 -1
  355. package/dist/client/org/index.js.map +1 -1
  356. package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
  357. package/dist/client/resources/McpIntegrationDialog.js +8 -12
  358. package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
  359. package/dist/client/resources/ResourcesPanel.d.ts +3 -0
  360. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  361. package/dist/client/resources/ResourcesPanel.js +49 -20
  362. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  363. package/dist/client/resources/mcp-integration-catalog.d.ts +1 -0
  364. package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
  365. package/dist/client/resources/mcp-integration-catalog.js +3 -0
  366. package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
  367. package/dist/client/resources/use-resources.d.ts +1 -0
  368. package/dist/client/resources/use-resources.d.ts.map +1 -1
  369. package/dist/client/resources/use-resources.js +3 -0
  370. package/dist/client/resources/use-resources.js.map +1 -1
  371. package/dist/client/use-action.d.ts +3 -1
  372. package/dist/client/use-action.d.ts.map +1 -1
  373. package/dist/client/use-action.js +3 -1
  374. package/dist/client/use-action.js.map +1 -1
  375. package/dist/client/widgets/index.d.ts +1 -1
  376. package/dist/client/widgets/index.d.ts.map +1 -1
  377. package/dist/client/widgets/index.js +1 -1
  378. package/dist/client/widgets/index.js.map +1 -1
  379. package/dist/coding-tools/run-code.js +2 -1
  380. package/dist/coding-tools/run-code.js.map +1 -1
  381. package/dist/collab/awareness.d.ts +2 -2
  382. package/dist/collab/awareness.d.ts.map +1 -1
  383. package/dist/collab/routes.d.ts +1 -1
  384. package/dist/db/client.d.ts +1 -0
  385. package/dist/db/client.d.ts.map +1 -1
  386. package/dist/db/client.js +24 -3
  387. package/dist/db/client.js.map +1 -1
  388. package/dist/deploy/build.d.ts.map +1 -1
  389. package/dist/deploy/build.js +25 -3
  390. package/dist/deploy/build.js.map +1 -1
  391. package/dist/eject/remote-mcp-presets.js +1 -1
  392. package/dist/eject/remote-mcp-presets.js.map +1 -1
  393. package/dist/index.browser.d.ts +1 -1
  394. package/dist/index.browser.d.ts.map +1 -1
  395. package/dist/index.browser.js +1 -1
  396. package/dist/index.browser.js.map +1 -1
  397. package/dist/index.d.ts +1 -1
  398. package/dist/index.d.ts.map +1 -1
  399. package/dist/index.js +1 -1
  400. package/dist/index.js.map +1 -1
  401. package/dist/integrations/google-docs-poller.d.ts.map +1 -1
  402. package/dist/integrations/google-docs-poller.js +4 -1
  403. package/dist/integrations/google-docs-poller.js.map +1 -1
  404. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  405. package/dist/integrations/webhook-handler.js +23 -11
  406. package/dist/integrations/webhook-handler.js.map +1 -1
  407. package/dist/jobs/scheduler.js +4 -0
  408. package/dist/jobs/scheduler.js.map +1 -1
  409. package/dist/localization/default-messages.d.ts +3 -2
  410. package/dist/localization/default-messages.d.ts.map +1 -1
  411. package/dist/localization/default-messages.js +3 -2
  412. package/dist/localization/default-messages.js.map +1 -1
  413. package/dist/mcp/build-server.d.ts.map +1 -1
  414. package/dist/mcp/build-server.js +10 -1
  415. package/dist/mcp/build-server.js.map +1 -1
  416. package/dist/notifications/routes.d.ts +1 -1
  417. package/dist/observability/traces.d.ts.map +1 -1
  418. package/dist/observability/traces.js +27 -7
  419. package/dist/observability/traces.js.map +1 -1
  420. package/dist/org/handlers.d.ts +15 -0
  421. package/dist/org/handlers.d.ts.map +1 -1
  422. package/dist/org/handlers.js +45 -1
  423. package/dist/org/handlers.js.map +1 -1
  424. package/dist/org/migrations.d.ts.map +1 -1
  425. package/dist/org/migrations.js +4 -0
  426. package/dist/org/migrations.js.map +1 -1
  427. package/dist/org/plugin.d.ts +1 -0
  428. package/dist/org/plugin.d.ts.map +1 -1
  429. package/dist/org/plugin.js +10 -1
  430. package/dist/org/plugin.js.map +1 -1
  431. package/dist/org/schema.d.ts +19 -0
  432. package/dist/org/schema.d.ts.map +1 -1
  433. package/dist/org/schema.js +1 -0
  434. package/dist/org/schema.js.map +1 -1
  435. package/dist/org/types.d.ts +8 -0
  436. package/dist/org/types.d.ts.map +1 -1
  437. package/dist/org/types.js.map +1 -1
  438. package/dist/org/workspace-url.d.ts +32 -0
  439. package/dist/org/workspace-url.d.ts.map +1 -0
  440. package/dist/org/workspace-url.js +63 -0
  441. package/dist/org/workspace-url.js.map +1 -0
  442. package/dist/progress/routes.d.ts +1 -1
  443. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  444. package/dist/provider-api/actions/provider-api.d.ts +7 -7
  445. package/dist/resources/handlers.d.ts +2 -3
  446. package/dist/resources/handlers.d.ts.map +1 -1
  447. package/dist/resources/handlers.js +25 -5
  448. package/dist/resources/handlers.js.map +1 -1
  449. package/dist/scripts/runner.d.ts +17 -0
  450. package/dist/scripts/runner.d.ts.map +1 -1
  451. package/dist/scripts/runner.js +130 -5
  452. package/dist/scripts/runner.js.map +1 -1
  453. package/dist/secrets/routes.d.ts +9 -9
  454. package/dist/server/action-routes.d.ts.map +1 -1
  455. package/dist/server/action-routes.js +24 -2
  456. package/dist/server/action-routes.js.map +1 -1
  457. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  458. package/dist/server/agent-chat-plugin.js +26 -1
  459. package/dist/server/agent-chat-plugin.js.map +1 -1
  460. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  461. package/dist/server/agent-teams.d.ts.map +1 -1
  462. package/dist/server/agent-teams.js +10 -1
  463. package/dist/server/agent-teams.js.map +1 -1
  464. package/dist/server/auth.d.ts +22 -0
  465. package/dist/server/auth.d.ts.map +1 -1
  466. package/dist/server/auth.js +33 -7
  467. package/dist/server/auth.js.map +1 -1
  468. package/dist/server/embed-route.d.ts.map +1 -1
  469. package/dist/server/embed-route.js +6 -1
  470. package/dist/server/embed-route.js.map +1 -1
  471. package/dist/server/embed-session.d.ts +7 -0
  472. package/dist/server/embed-session.d.ts.map +1 -1
  473. package/dist/server/embed-session.js +46 -4
  474. package/dist/server/embed-session.js.map +1 -1
  475. package/dist/server/open-route.d.ts.map +1 -1
  476. package/dist/server/open-route.js +17 -7
  477. package/dist/server/open-route.js.map +1 -1
  478. package/dist/server/prompts/framework-core-compact.js +1 -1
  479. package/dist/server/prompts/framework-core-compact.js.map +1 -1
  480. package/dist/server/prompts/framework-core.d.ts.map +1 -1
  481. package/dist/server/prompts/framework-core.js +1 -0
  482. package/dist/server/prompts/framework-core.js.map +1 -1
  483. package/dist/server/request-context.d.ts +26 -0
  484. package/dist/server/request-context.d.ts.map +1 -1
  485. package/dist/server/request-context.js +18 -1
  486. package/dist/server/request-context.js.map +1 -1
  487. package/dist/shared/embed-auth.d.ts +1 -0
  488. package/dist/shared/embed-auth.d.ts.map +1 -1
  489. package/dist/shared/embed-auth.js +1 -0
  490. package/dist/shared/embed-auth.js.map +1 -1
  491. package/dist/shared/html-document.d.ts +12 -0
  492. package/dist/shared/html-document.d.ts.map +1 -0
  493. package/dist/shared/html-document.js +92 -0
  494. package/dist/shared/html-document.js.map +1 -0
  495. package/dist/shared/index.d.ts +1 -0
  496. package/dist/shared/index.d.ts.map +1 -1
  497. package/dist/shared/index.js +1 -0
  498. package/dist/shared/index.js.map +1 -1
  499. package/dist/sharing/access.d.ts +1 -0
  500. package/dist/sharing/access.d.ts.map +1 -1
  501. package/dist/sharing/access.js +8 -2
  502. package/dist/sharing/access.js.map +1 -1
  503. package/dist/sharing/registry.d.ts +3 -0
  504. package/dist/sharing/registry.d.ts.map +1 -1
  505. package/dist/sharing/registry.js.map +1 -1
  506. package/dist/workspace-files/actions.d.ts +28 -0
  507. package/dist/workspace-files/actions.d.ts.map +1 -0
  508. package/dist/workspace-files/actions.js +75 -0
  509. package/dist/workspace-files/actions.js.map +1 -0
  510. package/dist/workspace-files/tool.d.ts.map +1 -1
  511. package/dist/workspace-files/tool.js +4 -0
  512. package/dist/workspace-files/tool.js.map +1 -1
  513. package/docs/content/cloneable-saas.mdx +114 -0
  514. package/docs/content/creating-templates.mdx +28 -2
  515. package/docs/content/syncing-template-changes.mdx +7 -0
  516. package/docs/content/template-clips-developers.mdx +12 -5
  517. package/docs/content/template-dispatch-developers.mdx +1 -1
  518. package/docs/content/template-dispatch.mdx +1 -1
  519. package/package.json +2 -2
  520. package/src/action-ui.ts +1 -0
  521. package/src/action.ts +5 -1
  522. package/src/agent/engine/ai-sdk-engine.ts +15 -5
  523. package/src/agent/harness/runner.ts +5 -0
  524. package/src/agent/production-agent.ts +33 -0
  525. package/src/agent/run-loop-with-resume.ts +5 -0
  526. package/src/agent/run-manager.ts +126 -1
  527. package/src/agent/thread-data-builder.ts +47 -2
  528. package/src/agent/types.ts +2 -0
  529. package/src/chat-threads/store.ts +4 -5
  530. package/src/cli/create.ts +1139 -65
  531. package/src/cli/design-connect.ts +3 -7
  532. package/src/cli/index.ts +5 -3
  533. package/src/cli/skills-content/design-visual-edit-skill.ts +83 -47
  534. package/src/client/AssistantChat.tsx +27 -16
  535. package/src/client/agent-chat-adapter.ts +24 -0
  536. package/src/client/blocks/library/wireframe-kit.tsx +17 -2
  537. package/src/client/chat/index.ts +1 -0
  538. package/src/client/chat/message-components.tsx +104 -1
  539. package/src/client/chat/run-recovery.tsx +15 -3
  540. package/src/client/chat/widgets/DataTableWidget.tsx +10 -29
  541. package/src/client/chat/widgets/WorkspaceFileWidget.tsx +71 -0
  542. package/src/client/chat/widgets/builtin-tool-renderers.tsx +22 -0
  543. package/src/client/chat/widgets/workspace-file-result.ts +49 -0
  544. package/src/client/embed-auth.ts +2 -0
  545. package/src/client/org/InvitationBanner.tsx +14 -1
  546. package/src/client/org/OrgSwitcher.tsx +23 -0
  547. package/src/client/org/TeamPage.tsx +130 -0
  548. package/src/client/org/WorkspaceNotice.tsx +85 -0
  549. package/src/client/org/hooks.ts +14 -0
  550. package/src/client/org/index.ts +2 -0
  551. package/src/client/resources/McpIntegrationDialog.tsx +27 -40
  552. package/src/client/resources/ResourcesPanel.tsx +134 -51
  553. package/src/client/resources/mcp-integration-catalog.ts +7 -0
  554. package/src/client/resources/use-resources.ts +6 -0
  555. package/src/client/use-action.ts +3 -1
  556. package/src/client/widgets/index.ts +1 -0
  557. package/src/coding-tools/run-code.ts +2 -1
  558. package/src/db/client.ts +28 -4
  559. package/src/deploy/build.ts +31 -3
  560. package/src/eject/remote-mcp-presets.ts +1 -1
  561. package/src/index.browser.ts +1 -0
  562. package/src/index.ts +1 -0
  563. package/src/integrations/google-docs-poller.ts +3 -0
  564. package/src/integrations/webhook-handler.ts +28 -11
  565. package/src/jobs/scheduler.ts +4 -0
  566. package/src/localization/default-messages.ts +3 -2
  567. package/src/mcp/build-server.ts +20 -2
  568. package/src/observability/traces.ts +48 -12
  569. package/src/org/handlers.ts +52 -1
  570. package/src/org/migrations.ts +4 -0
  571. package/src/org/plugin.ts +14 -0
  572. package/src/org/schema.ts +1 -0
  573. package/src/org/types.ts +8 -0
  574. package/src/org/workspace-url.ts +74 -0
  575. package/src/resources/handlers.ts +35 -5
  576. package/src/scripts/runner.ts +183 -5
  577. package/src/server/__snapshots__/agent-chat-plugin.surface.spec.ts.snap +2 -1
  578. package/src/server/action-routes.ts +32 -2
  579. package/src/server/agent-chat-plugin.ts +29 -0
  580. package/src/server/agent-teams.ts +10 -1
  581. package/src/server/auth.ts +33 -7
  582. package/src/server/embed-route.ts +9 -0
  583. package/src/server/embed-session.ts +62 -3
  584. package/src/server/open-route.ts +20 -6
  585. package/src/server/prompts/framework-core-compact.ts +1 -1
  586. package/src/server/prompts/framework-core.ts +1 -0
  587. package/src/server/request-context.ts +36 -1
  588. package/src/shared/embed-auth.ts +1 -0
  589. package/src/shared/html-document.ts +115 -0
  590. package/src/shared/index.ts +1 -0
  591. package/src/sharing/access.ts +8 -1
  592. package/src/sharing/registry.ts +11 -2
  593. package/src/workspace-files/actions.ts +100 -0
  594. package/src/workspace-files/tool.ts +4 -0
  595. package/corpus/templates/design/changelog/2026-07-28-interact-mode-can-preview-designs-in-responsive-device-sizes.md +0 -6
  596. package/corpus/templates/design/changelog/2026-07-28-interact-mode-now-opens-a-full-screen-responsive-preview-wit.md +0 -6
@@ -172,7 +172,9 @@ interface DataSourceStatusSummary {
172
172
  externalSourceLabels: string[];
173
173
  availableExternalSources: Array<{
174
174
  aliases: string[];
175
- configured: boolean;
175
+ configured: boolean | null;
176
+ label?: string;
177
+ setupLink?: string;
176
178
  }>;
177
179
  setupLink: string;
178
180
  }
@@ -242,7 +244,7 @@ function hasMissingRequestedExternalSource(
242
244
  const configuredAliases = [
243
245
  ...configuredSourceLabels.map((label) => [label]),
244
246
  ...availableExternalSources
245
- .filter(({ configured }) => configured)
247
+ .filter(({ configured }) => configured === true)
246
248
  .map(({ aliases }) => aliases),
247
249
  ];
248
250
  const sourceAliases = [
@@ -256,12 +258,21 @@ function hasMissingRequestedExternalSource(
256
258
  .filter(({ terms }) =>
257
259
  terms.some((term) => containsNormalizedPhrase(userText, term)),
258
260
  )
259
- .some(
260
- ({ aliases }) =>
261
- !configuredAliases.some((configured) =>
262
- sourceAliasesOverlap(configured, aliases),
263
- ),
264
- );
261
+ .some(({ aliases }) => {
262
+ const matchingStatuses = availableExternalSources.filter((source) =>
263
+ sourceAliasesOverlap(source.aliases, aliases),
264
+ );
265
+ if (
266
+ matchingStatuses.some(
267
+ ({ configured }) => configured === true || configured === null,
268
+ )
269
+ ) {
270
+ return false;
271
+ }
272
+ return !configuredAliases.some((configured) =>
273
+ sourceAliasesOverlap(configured, aliases),
274
+ );
275
+ });
265
276
  }
266
277
 
267
278
  function dataSourceStatusSummary(
@@ -270,7 +281,7 @@ function dataSourceStatusSummary(
270
281
  const externalSourceLabels = new Set<string>();
271
282
  const availableExternalSources = new Map<
272
283
  string,
273
- { aliases: string[]; configured: boolean }
284
+ DataSourceStatusSummary["availableExternalSources"][number]
274
285
  >();
275
286
  let checked = false;
276
287
  let setupLink = ANALYTICS_DATA_SOURCES_LINK;
@@ -278,7 +289,8 @@ function dataSourceStatusSummary(
278
289
  const addAvailableExternalSource = (
279
290
  provider: unknown,
280
291
  label: unknown,
281
- configured: boolean,
292
+ configured: boolean | null,
293
+ providerSetupLink?: unknown,
282
294
  ) => {
283
295
  const aliases = [provider, label]
284
296
  .filter((value): value is string => typeof value === "string")
@@ -288,11 +300,35 @@ function dataSourceStatusSummary(
288
300
  if (!key) return;
289
301
  const existing = availableExternalSources.get(key);
290
302
  if (existing) {
291
- existing.configured ||= configured;
303
+ existing.configured =
304
+ existing.configured === true || configured === true
305
+ ? true
306
+ : existing.configured === null || configured === null
307
+ ? null
308
+ : false;
292
309
  existing.aliases = [...new Set([...existing.aliases, ...aliases])];
310
+ if (!existing.label && typeof label === "string" && label.trim()) {
311
+ existing.label = label.trim();
312
+ }
313
+ if (
314
+ !existing.setupLink &&
315
+ typeof providerSetupLink === "string" &&
316
+ providerSetupLink.trim()
317
+ ) {
318
+ existing.setupLink = providerSetupLink.trim();
319
+ }
293
320
  return;
294
321
  }
295
- availableExternalSources.set(key, { aliases, configured });
322
+ availableExternalSources.set(key, {
323
+ aliases,
324
+ configured,
325
+ ...(typeof label === "string" && label.trim()
326
+ ? { label: label.trim() }
327
+ : {}),
328
+ ...(typeof providerSetupLink === "string" && providerSetupLink.trim()
329
+ ? { setupLink: providerSetupLink.trim() }
330
+ : {}),
331
+ });
296
332
  };
297
333
 
298
334
  for (const result of toolResults ?? []) {
@@ -373,7 +409,12 @@ function dataSourceStatusSummary(
373
409
  if (typeof label === "string" && label.trim()) {
374
410
  externalSourceLabels.add(label.trim());
375
411
  }
376
- addAvailableExternalSource(record.provider, label, true);
412
+ addAvailableExternalSource(
413
+ record.provider,
414
+ label,
415
+ true,
416
+ record.setupLink,
417
+ );
377
418
  }
378
419
 
379
420
  // Backward compatibility for status responses that predate the compact
@@ -393,12 +434,15 @@ function dataSourceStatusSummary(
393
434
  .toLowerCase();
394
435
  if (providerId === "first-party") continue;
395
436
  const label = record.label ?? record.provider;
437
+ const configured =
438
+ typeof record.configured === "boolean" ? record.configured : null;
396
439
  addAvailableExternalSource(
397
440
  record.provider,
398
441
  label,
399
- record.configured === true,
442
+ configured,
443
+ record.setupLink,
400
444
  );
401
- if (record.configured !== true) continue;
445
+ if (configured !== true) continue;
402
446
  if (typeof label === "string" && label.trim()) {
403
447
  externalSourceLabels.add(label.trim());
404
448
  }
@@ -418,8 +462,17 @@ function dataSourceStatusSummary(
418
462
  const record = provider as Record<string, unknown>;
419
463
  const providerId = record.id ?? record.provider;
420
464
  const label = record.label ?? providerId;
465
+ const grantState =
466
+ typeof record.grantState === "string" ? record.grantState : null;
421
467
  const configured =
422
- record.configured === true || record.grantState === "connected";
468
+ record.configured === true || grantState === "connected"
469
+ ? true
470
+ : record.configured === false ||
471
+ grantState === "granted" ||
472
+ grantState === "needs_grant" ||
473
+ grantState === "not_connected"
474
+ ? false
475
+ : null;
423
476
  addAvailableExternalSource(providerId, label, configured);
424
477
  if (configured && typeof label === "string" && label.trim()) {
425
478
  externalSourceLabels.add(label.trim());
@@ -435,6 +488,34 @@ function dataSourceStatusSummary(
435
488
  };
436
489
  }
437
490
 
491
+ function requestedExternalSourceSetup(
492
+ userText: string,
493
+ summary: DataSourceStatusSummary,
494
+ ): { label: string; setupLink: string } | null {
495
+ let source:
496
+ | DataSourceStatusSummary["availableExternalSources"][number]
497
+ | undefined;
498
+ let bestMatchLength = -1;
499
+ for (const candidate of summary.availableExternalSources) {
500
+ if (candidate.configured !== false || !candidate.setupLink) continue;
501
+ const matchLength = Math.max(
502
+ -1,
503
+ ...candidate.aliases
504
+ .filter((alias) => containsNormalizedPhrase(userText, alias))
505
+ .map((alias) => normalizeSourceLabel(alias).length),
506
+ );
507
+ if (matchLength > bestMatchLength) {
508
+ source = candidate;
509
+ bestMatchLength = matchLength;
510
+ }
511
+ }
512
+ if (!source?.setupLink) return null;
513
+ return {
514
+ label: source.label ?? source.aliases[0] ?? "data source",
515
+ setupLink: source.setupLink,
516
+ };
517
+ }
518
+
438
519
  function includesDataSourcesLink(text: string, setupLink: string): boolean {
439
520
  const normalizedSetupLink = setupLink.trim().replace(/&amp;/g, "&");
440
521
  if (!normalizedSetupLink) return false;
@@ -475,8 +556,23 @@ export function realDataFinalGuard(
475
556
  const incompleteEvidence = hasIncompleteDataEvidence(context.toolResults);
476
557
  const dataQueryAttempted = hasDataQueryAttempt(context.toolResults);
477
558
  const sourceStatus = dataSourceStatusSummary(context.toolResults);
559
+ const requestedSourceSetup = requestedExternalSourceSetup(
560
+ userText,
561
+ sourceStatus,
562
+ );
563
+ const setupLink = requestedSourceSetup?.setupLink ?? sourceStatus.setupLink;
564
+ const setupLabel = requestedSourceSetup
565
+ ? `Connect ${requestedSourceSetup.label}`
566
+ : "Connect data sources";
567
+ const setupMarkdown = `[${setupLabel}](${setupLink})`;
568
+ const hasUnknownExternalSourceStatus =
569
+ sourceStatus.availableExternalSources.some(
570
+ ({ configured }) => configured === null,
571
+ );
478
572
  const noConnectedExternalSources =
479
- sourceStatus.checked && sourceStatus.externalSourceLabels.length === 0;
573
+ sourceStatus.checked &&
574
+ sourceStatus.externalSourceLabels.length === 0 &&
575
+ !hasUnknownExternalSourceStatus;
480
576
  const externalSourceRequest = looksLikeExternalSourceRequest(userText);
481
577
  const missingRequestedExternalSource = hasMissingRequestedExternalSource(
482
578
  userText,
@@ -601,11 +697,11 @@ export function realDataFinalGuard(
601
697
  }
602
698
  if (
603
699
  needsDataSourceLink &&
604
- !includesDataSourcesLink(context.text, sourceStatus.setupLink)
700
+ !includesDataSourcesLink(context.text, setupLink)
605
701
  ) {
606
702
  return {
607
- retryMessage: `The response correctly explains that the requested live data is unavailable, but it needs a contextual next step. Explain which external source is missing, keep the conversation open, and include this exact markdown link: [Connect data sources](${sourceStatus.setupLink}). Do not use the generic no-grounded-data fallback.`,
608
- fallbackMessage: `I can help with that once the relevant source is connected. [Connect data sources](${sourceStatus.setupLink})`,
703
+ retryMessage: `The response correctly explains that the requested live data is unavailable, but it needs a contextual next step. Explain which external source is missing, keep the conversation open, and include this exact markdown link: ${setupMarkdown}. Do not use the generic no-grounded-data fallback.`,
704
+ fallbackMessage: `I can help with that once the relevant source is connected. ${setupMarkdown}`,
609
705
  maxRetries: 2,
610
706
  };
611
707
  }
@@ -615,11 +711,11 @@ export function realDataFinalGuard(
615
711
  if (failedQueryMessage) {
616
712
  if (
617
713
  needsDataSourceLink &&
618
- !includesDataSourcesLink(context.text, sourceStatus.setupLink)
714
+ !includesDataSourcesLink(context.text, setupLink)
619
715
  ) {
620
716
  return {
621
- retryMessage: `${failedQueryMessage} Explain which external source is missing and include this exact markdown link: [Connect data sources](${sourceStatus.setupLink}).`,
622
- fallbackMessage: `${failedQueryMessage} [Connect data sources](${sourceStatus.setupLink})`,
717
+ retryMessage: `${failedQueryMessage} Explain which external source is missing and include this exact markdown link: ${setupMarkdown}.`,
718
+ fallbackMessage: `${failedQueryMessage} ${setupMarkdown}`,
623
719
  maxRetries: 2,
624
720
  };
625
721
  }
@@ -635,8 +731,8 @@ export function realDataFinalGuard(
635
731
  (noConnectedExternalSources && externalSourceRequest))
636
732
  ) {
637
733
  return {
638
- retryMessage: `The requested external source is not connected. Explain what is missing in the context of the user's question and include this exact markdown link: [Connect data sources](${sourceStatus.setupLink}). Do not use the generic no-grounded-data fallback.`,
639
- fallbackMessage: `I can help with that once the relevant source is connected. [Connect data sources](${sourceStatus.setupLink})`,
734
+ retryMessage: `The requested external source is not connected. Explain what is missing in the context of the user's question and include this exact markdown link: ${setupMarkdown}. Do not use the generic no-grounded-data fallback.`,
735
+ fallbackMessage: `I can help with that once the relevant source is connected. ${setupMarkdown}`,
640
736
  maxRetries: 2,
641
737
  expandToolSurface: true,
642
738
  };
@@ -655,8 +751,8 @@ export function realDataFinalGuard(
655
751
  }
656
752
  if (noConnectedExternalSources) {
657
753
  return {
658
- retryMessage: `The user asked for live analytics, but data-source-status found no connected external providers. The built-in first-party source is still available for first-party Analytics data. If this request needs an external source, respond naturally in the context of the user's question, explain what is missing, and include [Connect data sources](${sourceStatus.setupLink}). Do not use a generic canned no-data response.`,
659
- fallbackMessage: `I can help with that once the relevant source is connected. [Connect data sources](${sourceStatus.setupLink})`,
754
+ retryMessage: `The user asked for live analytics, but data-source-status found no connected external providers. The built-in first-party source is still available for first-party Analytics data. If this request needs an external source, respond naturally in the context of the user's question, explain what is missing, and include ${setupMarkdown}. Do not use a generic canned no-data response.`,
755
+ fallbackMessage: `I can help with that once the relevant source is connected. ${setupMarkdown}`,
660
756
  maxRetries: 2,
661
757
  expandToolSurface: true,
662
758
  };
@@ -2,6 +2,7 @@ import { AGENT_ACCESS_PARAM } from "@agent-native/core/server";
2
2
  import { createH3SSRHandler } from "@agent-native/core/server/ssr-handler";
3
3
  import {
4
4
  buildAgentReadableResourceDiscovery,
5
+ injectDocumentMarkup,
5
6
  renderAgentReadableResourceDiscoveryScript,
6
7
  } from "@agent-native/core/shared";
7
8
  import {
@@ -140,13 +141,7 @@ function injectAgentDiscovery(html: string, script: string): string {
140
141
  if (scriptId && html.includes(`id="${scriptId}"`)) {
141
142
  return html;
142
143
  }
143
- if (html.includes("</head>")) {
144
- return html.replace("</head>", `${script}</head>`);
145
- }
146
- if (html.includes("</body>")) {
147
- return html.replace("</body>", `${script}</body>`);
148
- }
149
- return `${html}${script}`;
144
+ return injectDocumentMarkup(html, script, { target: "head" });
150
145
  }
151
146
 
152
147
  export default defineEventHandler(async (event) => {
@@ -2,6 +2,8 @@ import { agentNative } from "@agent-native/core/vite";
2
2
  import { reactRouter } from "@react-router/dev/vite";
3
3
  import { defineConfig } from "vite";
4
4
 
5
+ import { ANALYTICS_NATIVE_MCP_PRESET_EXCLUSIONS } from "./app/lib/native-mcp-exclusions";
6
+
5
7
  const reactRouterPlugins = reactRouter as unknown as () => any[];
6
8
  const agentNativePlugins = agentNative as unknown as (
7
9
  options?: Parameters<typeof agentNative>[0],
@@ -14,6 +16,11 @@ export default defineConfig({
14
16
  // shiki only runs in AssistantChat's useEffect — keep it out of the
15
17
  // CF Pages Functions bundle (25 MiB limit).
16
18
  ssrStubs: ["shiki"],
19
+ // Native data-source actions own these providers in Analytics; showing
20
+ // their MCP presets would create a second, conflicting setup path.
21
+ mcpIntegrations: {
22
+ defaults: { exclude: [...ANALYTICS_NATIVE_MCP_PRESET_EXCLUSIONS] },
23
+ },
17
24
  }),
18
25
  ],
19
26
  });
@@ -30,6 +30,59 @@ const SUPPORTED_SOURCE_PROVIDERS = new Set([
30
30
  "github",
31
31
  ]);
32
32
 
33
+ function dispatchIntegrationsHref(providerId: string) {
34
+ const params = new URLSearchParams({
35
+ provider: providerId,
36
+ appId: APP_ID,
37
+ returnTo: "ask",
38
+ });
39
+ return `/dispatch/integrations?${params.toString()}`;
40
+ }
41
+
42
+ function providerApiConfigured({
43
+ credentialHealth,
44
+ providerApi,
45
+ workspace,
46
+ }: {
47
+ credentialHealth: Awaited<ReturnType<typeof credentialHealthForProvider>>;
48
+ providerApi: ReturnType<typeof listProviderApiCatalog>[number] | null;
49
+ workspace: WorkspaceConnectionProviderAppSummary;
50
+ }): boolean | null {
51
+ if (!providerApi) return null;
52
+ if (workspace.hasActiveWorkspaceConnection) return true;
53
+ if (providerApi.auth === "none") return true;
54
+
55
+ const availableKeys = new Set(
56
+ credentialHealth.details
57
+ .filter((detail) => detail.available)
58
+ .map((detail) => detail.key),
59
+ );
60
+
61
+ // Jira's legacy fallback is one complete Basic-auth tuple. The catalog keys
62
+ // are individually optional because OAuth is preferred, so the generic
63
+ // required-key count cannot prove that an unconnected Jira provider is ready.
64
+ if (providerApi.id === "jira") {
65
+ return ["JIRA_BASE_URL", "JIRA_USER_EMAIL", "JIRA_API_TOKEN"].every((key) =>
66
+ availableKeys.has(key),
67
+ );
68
+ }
69
+
70
+ if (
71
+ providerApi.auth.startsWith("oauth-bearer:") &&
72
+ !providerApi.auth.includes("-or-")
73
+ ) {
74
+ return false;
75
+ }
76
+ if (providerApi.credentialKeys.length === 0) return false;
77
+ if (
78
+ providerApi.auth.includes("-or-api-key-header:") ||
79
+ providerApi.auth.includes("-or-bearer-key:")
80
+ ) {
81
+ return providerApi.credentialKeys.some((key) => availableKeys.has(key));
82
+ }
83
+ return providerApi.credentialKeys.every((key) => availableKeys.has(key));
84
+ }
85
+
33
86
  async function credentialHealthForProvider(
34
87
  provider: WorkspaceConnectionProviderCatalogForAppItem,
35
88
  ): Promise<{
@@ -100,14 +153,48 @@ async function credentialHealthForProvider(
100
153
 
101
154
  function providerHealthForProvider({
102
155
  credentialHealth,
156
+ providerApi,
157
+ providerApiIsConfigured,
103
158
  sourceProviderSupported,
104
159
  workspace,
105
160
  }: {
106
161
  credentialHealth: Awaited<ReturnType<typeof credentialHealthForProvider>>;
162
+ providerApi: ReturnType<typeof listProviderApiCatalog>[number] | null;
163
+ providerApiIsConfigured: boolean | null;
107
164
  sourceProviderSupported: boolean;
108
165
  workspace: WorkspaceConnectionProviderAppSummary;
109
166
  }) {
167
+ if (providerApi && providerApiIsConfigured === false) {
168
+ if (workspace.grantState === "needs_grant") {
169
+ return {
170
+ status: "needs_grant" as const,
171
+ message: workspace.grantAvailabilityMessage,
172
+ };
173
+ }
174
+ if (
175
+ workspace.hasGrantedWorkspaceConnection &&
176
+ !workspace.hasActiveWorkspaceConnection
177
+ ) {
178
+ return {
179
+ status: "unhealthy" as const,
180
+ message:
181
+ "Brain has a grant, but the shared connection needs reauth or repair.",
182
+ };
183
+ }
184
+ return {
185
+ status: "missing_credentials" as const,
186
+ message:
187
+ "Connect this provider before Brain makes an on-demand API request.",
188
+ };
189
+ }
110
190
  if (!sourceProviderSupported) {
191
+ if (providerApi) {
192
+ return {
193
+ status: "ready" as const,
194
+ message:
195
+ "Authenticated provider API access is ready for on-demand Brain queries.",
196
+ };
197
+ }
111
198
  return {
112
199
  status: "unsupported" as const,
113
200
  message:
@@ -175,7 +262,7 @@ async function listWorkspaceConnectionsForCatalog(): Promise<{
175
262
 
176
263
  export default defineAction({
177
264
  description:
178
- "List reusable connection provider metadata relevant to Brain sources, including workspace connection grants for the Brain app.",
265
+ "Check reusable Brain source and provider API readiness before using a provider. Each provider reports whether authenticated access is configured and includes a focused setupLink. When a requested provider is unavailable, explain the missing connection and return its setupLink instead of attempting provider-api-request.",
179
266
  schema: z.object({}),
180
267
  http: { method: "GET" },
181
268
  readOnly: true,
@@ -206,8 +293,13 @@ export default defineAction({
206
293
  const workspaceConnection = provider.workspaceConnection;
207
294
  const credentialHealth = await credentialHealthForProvider(provider);
208
295
  const providerApi = isProviderApiId(provider.id)
209
- ? listProviderApiCatalog(provider.id)[0]
296
+ ? (listProviderApiCatalog(provider.id)[0] ?? null)
210
297
  : null;
298
+ const providerApiIsConfigured = providerApiConfigured({
299
+ credentialHealth,
300
+ providerApi,
301
+ workspace: workspaceConnection,
302
+ });
211
303
  return {
212
304
  id: provider.id,
213
305
  label: provider.label,
@@ -222,9 +314,15 @@ export default defineAction({
222
314
  configuredSourceCount,
223
315
  hasConfiguredSources: configuredSourceCount > 0,
224
316
  sourceProviderSupported,
317
+ configured:
318
+ providerApiIsConfigured ??
319
+ (sourceProviderSupported ? credentialHealth.available : null),
320
+ setupLink: dispatchIntegrationsHref(provider.id),
225
321
  credentialHealth,
226
322
  providerHealth: providerHealthForProvider({
227
323
  credentialHealth,
324
+ providerApi,
325
+ providerApiIsConfigured,
228
326
  sourceProviderSupported,
229
327
  workspace: workspaceConnection,
230
328
  }),
@@ -549,8 +549,18 @@ export interface BrainConnectionProvider {
549
549
  configuredSourceCount: number;
550
550
  hasConfiguredSources: boolean;
551
551
  sourceProviderSupported: boolean;
552
+ configured?: boolean | null;
553
+ setupLink?: string;
552
554
  credentialHealth?: BrainCredentialHealth;
553
555
  providerHealth?: BrainProviderHealth;
556
+ rawProviderApi?: {
557
+ available: boolean;
558
+ actionNames: string[];
559
+ docsUrls: string[];
560
+ specUrls: string[];
561
+ auth: string | null;
562
+ examples: unknown[];
563
+ };
554
564
  workspaceConnection?: BrainWorkspaceConnectionSummary;
555
565
  }
556
566
 
@@ -1115,6 +1115,14 @@ function ProviderCatalog({
1115
1115
  const readinessCallout = providerReadinessCallout(provider, t);
1116
1116
  const ReadinessIcon = readinessCallout.icon;
1117
1117
  const readinessItems = providerReadinessItems(provider, t);
1118
+ const providerNeedsSetup =
1119
+ provider.configured !== true &&
1120
+ provider.rawProviderApi?.available === true &&
1121
+ (provider.providerHealth?.status === "needs_grant" ||
1122
+ provider.providerHealth?.status === "unhealthy" ||
1123
+ provider.providerHealth?.status === "missing_credentials");
1124
+ const providerSetupHref =
1125
+ provider.setupLink ?? dispatchIntegrationsHref(provider.id);
1118
1126
  return (
1119
1127
  <div
1120
1128
  key={provider.id}
@@ -1378,7 +1386,8 @@ function ProviderCatalog({
1378
1386
  {t("sources.noSharedWorkspaceConnection")}
1379
1387
  </p>
1380
1388
  )}
1381
- {!provider.sourceProviderSupported ? (
1389
+ {!provider.sourceProviderSupported &&
1390
+ provider.rawProviderApi?.available !== true ? (
1382
1391
  <p className="text-xs leading-5 text-muted-foreground">
1383
1392
  {t("sources.connectionMetadataOnlyDetail")}
1384
1393
  </p>
@@ -1400,11 +1409,13 @@ function ProviderCatalog({
1400
1409
  <IconSettings2 className="size-4" />
1401
1410
  {expanded ? t("sources.hideDetails") : t("sources.details")}
1402
1411
  </Button>
1403
- {grantState === "needs_grant" ? (
1412
+ {grantState === "needs_grant" || providerNeedsSetup ? (
1404
1413
  <Button size="sm" variant="outline" asChild>
1405
- <a href={dispatchIntegrationsHref(provider.id)}>
1414
+ <a href={providerSetupHref}>
1406
1415
  <IconExternalLink className="size-4" />
1407
- {t("sources.grantInDispatch")}
1416
+ {grantState === "needs_grant"
1417
+ ? t("sources.grantInDispatch")
1418
+ : t("sources.connectProvider")}
1408
1419
  </a>
1409
1420
  </Button>
1410
1421
  ) : null}
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-29
4
+ ---
5
+
6
+ Brain automatically retries failed source syncs, drains search indexing backlogs faster, and guides you to connect provider APIs when setup is missing.
@@ -30,6 +30,7 @@ export type DistillationAgentRunner = (
30
30
  export interface ProcessBrainIngestQueueOptions {
31
31
  limit?: number;
32
32
  runDistillation?: boolean;
33
+ maxDistillations?: number;
33
34
  distillationRunner?: DistillationAgentRunner;
34
35
  }
35
36
 
@@ -331,9 +332,20 @@ export async function processBrainIngestQueueOnce(
331
332
  const processed: string[] = [];
332
333
  const deferred: string[] = [];
333
334
  const failed: string[] = [];
335
+ const maxDistillations = Math.max(
336
+ 0,
337
+ Math.floor(options.maxDistillations ?? Number.POSITIVE_INFINITY),
338
+ );
339
+ let distillationsStarted = 0;
334
340
  for (const row of rows) {
335
341
  const payload = parseJson<Record<string, unknown>>(row.payloadJson, {});
336
342
  if (row.operation === "distill") {
343
+ if (
344
+ options.runDistillation &&
345
+ distillationsStarted >= maxDistillations
346
+ ) {
347
+ continue;
348
+ }
337
349
  if (!options.runDistillation) {
338
350
  const claimToken = await claimForHeadlessRunner(row, payload);
339
351
  if (!claimToken) continue;
@@ -367,6 +379,7 @@ export async function processBrainIngestQueueOnce(
367
379
  };
368
380
  const claimToken = await claimForHeadlessRunner(row, nextPayload);
369
381
  if (!claimToken) continue;
382
+ distillationsStarted += 1;
370
383
 
371
384
  try {
372
385
  const runner =
@@ -1,10 +1,10 @@
1
1
  import { runWithRequestContext } from "@agent-native/core/server/request-context";
2
2
  import { accessFilter } from "@agent-native/core/sharing";
3
- import { and, eq, ne } from "drizzle-orm";
3
+ import { and, inArray, ne } from "drizzle-orm";
4
4
 
5
5
  import type { BrainSourceProvider } from "../../shared/types.js";
6
6
  import { getDb, schema } from "../db/index.js";
7
- import { nowIso, parseJson } from "../lib/brain.js";
7
+ import { parseJson } from "../lib/brain.js";
8
8
  import { runConnectorSync } from "../lib/connectors.js";
9
9
 
10
10
  const DEFAULT_POLL_MINUTES = 60;
@@ -13,6 +13,7 @@ let skippingLogged = false;
13
13
  let running = false;
14
14
 
15
15
  type SourceRow = typeof schema.brainSources.$inferSelect;
16
+ const RETRYABLE_SOURCE_STATUSES: SourceRow["status"][] = ["active", "error"];
16
17
 
17
18
  function configuredPollMinutes(source: SourceRow): number {
18
19
  const config = parseJson<Record<string, unknown>>(source.configJson, {});
@@ -56,30 +57,34 @@ function retryAfterAt(source: SourceRow): number | null {
56
57
  return Number.isFinite(retryAt) ? retryAt : null;
57
58
  }
58
59
 
60
+ function sourceSyncDueAt(source: SourceRow, nowMs: number): number | null {
61
+ if (!RETRYABLE_SOURCE_STATUSES.includes(source.status)) return null;
62
+ if (!isAutoSyncEnabled(source)) return null;
63
+
64
+ const pollIntervalMs = configuredPollMinutes(source) * 60 * 1000;
65
+ let pollAt = nowMs;
66
+ if (source.status === "error") {
67
+ const failedAt = Date.parse(source.updatedAt);
68
+ if (Number.isFinite(failedAt)) pollAt = failedAt + pollIntervalMs;
69
+ } else if (source.lastSyncedAt) {
70
+ const lastSynced = Date.parse(source.lastSyncedAt);
71
+ if (Number.isFinite(lastSynced)) pollAt = lastSynced + pollIntervalMs;
72
+ }
73
+
74
+ return Math.max(pollAt, retryAfterAt(source) ?? Number.NEGATIVE_INFINITY);
75
+ }
76
+
59
77
  export function isBrainSourceDue(
60
78
  source: SourceRow,
61
79
  nowMs = Date.now(),
62
80
  ): boolean {
63
- if (source.status !== "active") return false;
64
- if (!isAutoSyncEnabled(source)) return false;
65
- const retryAt = retryAfterAt(source);
66
- if (retryAt && retryAt > nowMs) return false;
67
- if (!source.lastSyncedAt) return true;
68
- const lastSynced = Date.parse(source.lastSyncedAt);
69
- if (!Number.isFinite(lastSynced)) return true;
70
- return nowMs - lastSynced >= configuredPollMinutes(source) * 60 * 1000;
81
+ const dueAt = sourceSyncDueAt(source, nowMs);
82
+ return dueAt !== null && dueAt <= nowMs;
71
83
  }
72
84
 
73
85
  export function nextBrainSourceSyncAt(source: SourceRow): string | null {
74
- if (source.status !== "active" || !isAutoSyncEnabled(source)) return null;
75
- const retryAt = retryAfterAt(source);
76
- if (retryAt) return new Date(retryAt).toISOString();
77
- if (!source.lastSyncedAt) return nowIso();
78
- const lastSynced = Date.parse(source.lastSyncedAt);
79
- if (!Number.isFinite(lastSynced)) return nowIso();
80
- return new Date(
81
- lastSynced + configuredPollMinutes(source) * 60 * 1000,
82
- ).toISOString();
86
+ const dueAt = sourceSyncDueAt(source, Date.now());
87
+ return dueAt === null ? null : new Date(dueAt).toISOString();
83
88
  }
84
89
 
85
90
  export async function listDueBrainSources(
@@ -90,15 +95,15 @@ export async function listDueBrainSources(
90
95
  ) {
91
96
  const db = getDb();
92
97
  const where = options.system
93
- ? // guard:allow-unscoped — system scheduler enumerates active sources,
98
+ ? // guard:allow-unscoped — system scheduler enumerates retryable sources,
94
99
  // then re-enters each row's owner/org context before syncing.
95
100
  and(
96
- eq(schema.brainSources.status, "active"),
101
+ inArray(schema.brainSources.status, RETRYABLE_SOURCE_STATUSES),
97
102
  ne(schema.brainSources.provider, "manual"),
98
103
  )
99
104
  : and(
100
105
  accessFilter(schema.brainSources, schema.brainSourceShares),
101
- eq(schema.brainSources.status, "active"),
106
+ inArray(schema.brainSources.status, RETRYABLE_SOURCE_STATUSES),
102
107
  ne(schema.brainSources.provider, "manual"),
103
108
  );
104
109
  const rows = await db
@@ -24,6 +24,7 @@ const INITIAL_TOOL_NAMES = [
24
24
  "write-knowledge",
25
25
  "list-sources",
26
26
  "get-source",
27
+ "list-connection-providers",
27
28
  "create-source",
28
29
  "sync-source",
29
30
  "enqueue-distillation",
@@ -56,7 +57,7 @@ Important rules:
56
57
  - Source policy matters: strict means answer from reviewed knowledge only; balanced means raw captures are fallback context when reviewed knowledge is thin; exploratory means raw captures and sources may be surfaced as clearly labeled leads.
57
58
  - Company-tier knowledge may create a proposal instead of publishing immediately, depending on settings.
58
59
  - Slack and Granola sources are configurable v1 connectors. Generic transcript import is always available.
59
- - Source/read actions are convenience readers, not provider capability limits. For ad hoc provider analysis that needs an endpoint, filter, payload, pagination mode, or API version not modeled by a Brain action, call provider-api-catalog/provider-api-docs, then provider-api-request against the provider's real HTTP API. Use connectionId for a specific shared grant and accountId for a specific OAuth account.
60
+ - Source/read actions are convenience readers, not provider capability limits. Before any provider API request, call list-connection-providers and inspect the matching provider. If configured is not true, do not attempt the request; explain that the connection needs setup or repair and include setupLink. Jira is queried on demand through the provider API rather than indexed as a Brain source. For ad hoc provider analysis that needs an endpoint, filter, payload, pagination mode, or API version not modeled by a Brain action, call provider-api-catalog/provider-api-docs, then provider-api-request against the provider's real HTTP API. Use connectionId for a specific shared grant and accountId for a specific OAuth account.
60
61
  - For broad searches, joins, classification, source-corpus counts, or absence claims across provider records, fetch every relevant page or an explicitly bounded cohort, stage/save large responses with stageAs/saveToFile/fetchAllPages, then use query-staged-dataset or run-code to reduce the corpus. Report source, filters, row counts, pagination, truncation, and gaps.`,
61
62
  a2aMessageFallback: async ({ text }) => tryAnswerBrainA2AQuestion(text),
62
63
  mentionProviders: async () => {