@agent-native/core 0.145.4 → 0.145.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (398) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +18 -0
  3. package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  4. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +17 -1
  5. package/corpus/templates/analytics/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  6. package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +1 -0
  7. package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +22 -3
  8. package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +76 -23
  9. package/corpus/templates/analytics/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  10. package/corpus/templates/analytics/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  11. package/corpus/templates/analytics/AGENTS.md +2 -1
  12. package/corpus/templates/analytics/actions/account-deep-dive.ts +83 -47
  13. package/corpus/templates/analytics/actions/create-dashboard-folder.ts +27 -0
  14. package/corpus/templates/analytics/actions/gong-calls.ts +3 -3
  15. package/corpus/templates/analytics/actions/list-dashboard-folders.ts +26 -0
  16. package/corpus/templates/analytics/actions/list-sql-dashboards.ts +1 -0
  17. package/corpus/templates/analytics/actions/set-dashboard-folder.ts +26 -0
  18. package/corpus/templates/analytics/app/components/ProviderCorpusJobNotifier.tsx +18 -3
  19. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +6 -4
  20. package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -0
  21. package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +12 -2
  22. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +35 -20
  23. package/corpus/templates/analytics/app/global.css +17 -0
  24. package/corpus/templates/analytics/app/hooks/use-dashboard-revisions.ts +29 -15
  25. package/corpus/templates/analytics/app/hooks/use-dashboard-views.ts +15 -3
  26. package/corpus/templates/analytics/app/i18n-data.ts +296 -0
  27. package/corpus/templates/analytics/app/lib/prefetch-keys.ts +23 -2
  28. package/corpus/templates/analytics/app/pages/DashboardOverview.tsx +642 -0
  29. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +66 -31
  30. package/corpus/templates/analytics/app/root.tsx +4 -0
  31. package/corpus/templates/analytics/app/routes/dashboards._index.tsx +5 -1
  32. package/corpus/templates/analytics/changelog/2026-08-07-added-a-dashboards-overview-with-personal-and-shared-folders.md +6 -0
  33. package/corpus/templates/analytics/changelog/2026-08-07-analytics-tracking-and-chat-startup-no-longer-emit-avoidable.md +6 -0
  34. package/corpus/templates/analytics/changelog/2026-08-07-dashboard-panels-now-load-custom-api-data-programs-reliably.md +6 -0
  35. package/corpus/templates/analytics/changelog/2026-08-07-gong-searches-conserve-api-quota-and-report-incomplete-coverage.md +6 -0
  36. package/corpus/templates/analytics/changelog/2026-08-07-searchable-dashboards-make-personal-and-shared-folders-easie.md +6 -0
  37. package/corpus/templates/analytics/netlify.toml +3 -0
  38. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +112 -0
  39. package/corpus/templates/analytics/server/db/index.ts +12 -0
  40. package/corpus/templates/analytics/server/db/schema.ts +14 -0
  41. package/corpus/templates/analytics/server/jobs/analytics-rollup-backfill.ts +4 -0
  42. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +1 -0
  43. package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +85 -15
  44. package/corpus/templates/analytics/server/lib/dashboard-folders-store.ts +168 -0
  45. package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +9 -4
  46. package/corpus/templates/analytics/server/lib/dashboards-store.ts +116 -1
  47. package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +4 -8
  48. package/corpus/templates/analytics/server/lib/gong.ts +139 -78
  49. package/corpus/templates/analytics/server/plugins/db.ts +55 -15
  50. package/corpus/templates/analytics/server/plugins/session-replay-retention-jobs.ts +6 -2
  51. package/corpus/templates/analytics/server/routes/api/session-replay/retention.post.ts +65 -0
  52. package/corpus/templates/assets/.agents/skills/actions/SKILL.md +18 -0
  53. package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  54. package/corpus/templates/assets/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  55. package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +1 -0
  56. package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +76 -23
  57. package/corpus/templates/assets/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  58. package/corpus/templates/assets/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  59. package/corpus/templates/brain/.agents/skills/actions/SKILL.md +18 -0
  60. package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  61. package/corpus/templates/brain/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  62. package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +1 -0
  63. package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +76 -23
  64. package/corpus/templates/brain/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  65. package/corpus/templates/brain/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  66. package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +18 -0
  67. package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  68. package/corpus/templates/calendar/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  69. package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +1 -0
  70. package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +76 -23
  71. package/corpus/templates/calendar/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  72. package/corpus/templates/calendar/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  73. package/corpus/templates/chat/.agents/skills/actions/SKILL.md +18 -0
  74. package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  75. package/corpus/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  76. package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +1 -0
  77. package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +76 -23
  78. package/corpus/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  79. package/corpus/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  80. package/corpus/templates/chat/.env.example +3 -0
  81. package/corpus/templates/chat/AGENTS.md +4 -0
  82. package/corpus/templates/clips/.agents/skills/actions/SKILL.md +18 -0
  83. package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  84. package/corpus/templates/clips/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  85. package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +1 -0
  86. package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +76 -23
  87. package/corpus/templates/clips/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  88. package/corpus/templates/clips/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  89. package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +4 -0
  90. package/corpus/templates/clips/actions/request-transcript.ts +52 -3
  91. package/corpus/templates/clips/app/components/editor/editor-layout.tsx +8 -3
  92. package/corpus/templates/clips/app/components/editor/waveform.tsx +2 -1
  93. package/corpus/templates/clips/app/components/library/search-bar.tsx +1 -1
  94. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +3 -10
  95. package/corpus/templates/clips/app/global.css +9 -0
  96. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -0
  97. package/corpus/templates/clips/changelog/2026-08-07-screen-recordings-now-capture-tab-and-system-audio-even-when.md +6 -0
  98. package/corpus/templates/clips/changelog/2026-08-07-transcription-now-retries-transient-cloud-failures-automatic.md +6 -0
  99. package/corpus/templates/clips/desktop/src-tauri/src/silence_detector.rs +10 -11
  100. package/corpus/templates/clips/server/db/schema.ts +7 -0
  101. package/corpus/templates/clips/server/plugins/db.ts +8 -0
  102. package/corpus/templates/clips/shared/recording-capture.ts +38 -0
  103. package/corpus/templates/clips/shared/transcript-failure.ts +89 -0
  104. package/corpus/templates/content/.agents/skills/actions/SKILL.md +18 -0
  105. package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  106. package/corpus/templates/content/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  107. package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +1 -0
  108. package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +76 -23
  109. package/corpus/templates/content/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  110. package/corpus/templates/content/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  111. package/corpus/templates/content/.env.example +9 -3
  112. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +1 -0
  113. package/corpus/templates/content/changelog/2026-08-07-collapsed-sidebar-utility-buttons-stay-anchored-at-the-botto.md +6 -0
  114. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  115. package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +76 -23
  116. package/corpus/templates/crm/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  117. package/corpus/templates/crm/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  118. package/corpus/templates/design/.agents/skills/actions/SKILL.md +18 -0
  119. package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  120. package/corpus/templates/design/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  121. package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +1 -0
  122. package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +76 -23
  123. package/corpus/templates/design/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  124. package/corpus/templates/design/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  125. package/corpus/templates/design/actions/view-screen.ts +1 -0
  126. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +14 -1
  127. package/corpus/templates/design/changelog/2026-08-07-cmd-c-now-copies-selected-text-in-the-agent-panel-instead-of.md +6 -0
  128. package/corpus/templates/design/changelog/2026-08-07-real-time-voice-can-now-read-the-current-selection-and-edit-.md +6 -0
  129. package/corpus/templates/design/server/lib/reprompt-action-guard.ts +7 -3
  130. package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +18 -0
  131. package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  132. package/corpus/templates/dispatch/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  133. package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +1 -0
  134. package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +76 -23
  135. package/corpus/templates/dispatch/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  136. package/corpus/templates/dispatch/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  137. package/corpus/templates/factory/.agents/skills/actions/SKILL.md +18 -0
  138. package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  139. package/corpus/templates/factory/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  140. package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +1 -0
  141. package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +76 -23
  142. package/corpus/templates/factory/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  143. package/corpus/templates/factory/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  144. package/corpus/templates/factory/actions/babysit-agent-native-pull-request.ts +279 -0
  145. package/corpus/templates/factory/actions/get-factory-automation-health.ts +23 -4
  146. package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +1 -1
  147. package/corpus/templates/factory/app/routes/factory.tsx +21 -3
  148. package/corpus/templates/factory/changelog/2026-08-07-factory-can-keep-builder-bot-pull-requests-moving-by-request.md +6 -0
  149. package/corpus/templates/factory/server/lib/require-factory-automation.ts +1 -0
  150. package/corpus/templates/factory/server/plugins/agent-chat.ts +4 -1
  151. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +81 -12
  152. package/corpus/templates/factory/server/triage/github-client.ts +31 -0
  153. package/corpus/templates/factory/server/triage/pr-babysit.ts +75 -1
  154. package/corpus/templates/forms/.agents/skills/actions/SKILL.md +18 -0
  155. package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  156. package/corpus/templates/forms/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  157. package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +1 -0
  158. package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +76 -23
  159. package/corpus/templates/forms/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  160. package/corpus/templates/forms/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  161. package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  162. package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +1 -0
  163. package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +76 -23
  164. package/corpus/templates/macros/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  165. package/corpus/templates/macros/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  166. package/corpus/templates/mail/.agents/skills/actions/SKILL.md +18 -0
  167. package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  168. package/corpus/templates/mail/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  169. package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +1 -0
  170. package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +76 -23
  171. package/corpus/templates/mail/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  172. package/corpus/templates/mail/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  173. package/corpus/templates/plan/.agents/skills/actions/SKILL.md +18 -0
  174. package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  175. package/corpus/templates/plan/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  176. package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +1 -0
  177. package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +76 -23
  178. package/corpus/templates/plan/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  179. package/corpus/templates/plan/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  180. package/corpus/templates/plan/app/pages/PlansPage.tsx +2 -1
  181. package/corpus/templates/plan/changelog/2026-08-07-inline-help-icons-now-stay-visually-balanced-with-nearby-tex.md +6 -0
  182. package/corpus/templates/slides/.agents/skills/actions/SKILL.md +18 -0
  183. package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  184. package/corpus/templates/slides/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  185. package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +1 -0
  186. package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +76 -23
  187. package/corpus/templates/slides/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  188. package/corpus/templates/slides/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  189. package/corpus/templates/slides/.env.example +5 -0
  190. package/corpus/templates/slides/changelog/2026-08-07-fixed-generated-slides-briefly-disappearing-while-they-are-b.md +6 -0
  191. package/corpus/templates/slides/server/plugins/collab.ts +20 -8
  192. package/corpus/templates/tasks/.agents/skills/actions/SKILL.md +18 -0
  193. package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  194. package/corpus/templates/tasks/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  195. package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +1 -0
  196. package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +76 -23
  197. package/corpus/templates/tasks/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  198. package/corpus/templates/tasks/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  199. package/corpus/templates/tasks/.env.example +3 -0
  200. package/dist/agent/production-agent.js +24 -3
  201. package/dist/client/AgentPanel.d.ts +6 -0
  202. package/dist/client/AgentPanel.js +176 -30
  203. package/dist/client/AssistantChat.d.ts +2 -0
  204. package/dist/client/AssistantChat.js +4 -1
  205. package/dist/client/ConnectBuilderCard.js +6 -11
  206. package/dist/client/MultiTabAssistantChat.js +1 -1
  207. package/dist/client/RuntimeConfigNotice.d.ts +1 -0
  208. package/dist/client/RuntimeConfigNotice.js +94 -0
  209. package/dist/client/agent-chat/index.d.ts +1 -1
  210. package/dist/client/agent-chat/index.js +1 -1
  211. package/dist/client/agent-chat-adapter.js +85 -4
  212. package/dist/client/agent-page/AgentTabsPage.js +1 -1
  213. package/dist/client/agent-sidebar-state.d.ts +6 -0
  214. package/dist/client/agent-sidebar-state.js +25 -0
  215. package/dist/client/app-providers.js +2 -1
  216. package/dist/client/assistant-ui-recovery.js +1 -1
  217. package/dist/client/chat/index.d.ts +1 -1
  218. package/dist/client/chat/index.js +1 -1
  219. package/dist/client/chat/markdown-renderer.d.ts +2 -1
  220. package/dist/client/chat/markdown-renderer.js +48 -2
  221. package/dist/client/chat/message-components.d.ts +6 -0
  222. package/dist/client/chat/message-components.js +182 -53
  223. package/dist/client/chat/tool-call-display.d.ts +16 -4
  224. package/dist/client/chat/tool-call-display.js +225 -18
  225. package/dist/client/extensions/ExtensionsSidebarSection.js +1 -1
  226. package/dist/client/frame-protocol.d.ts +4 -0
  227. package/dist/client/i18n.js +9 -0
  228. package/dist/client/integrations/IntegrationsPanel.js +2 -5
  229. package/dist/client/onboarding/FirstRunOnboarding.js +2 -3
  230. package/dist/client/org/TeamPage.js +49 -6
  231. package/dist/client/org/hooks.d.ts +7 -2
  232. package/dist/client/org/hooks.js +11 -4
  233. package/dist/client/resources/McpConnectionSuggestion.js +2 -3
  234. package/dist/client/resources/McpIntegrationDialog.js +2 -16
  235. package/dist/client/resources/McpIntegrationLogo.d.ts +11 -0
  236. package/dist/client/resources/McpIntegrationLogo.js +14 -0
  237. package/dist/client/resources/ResourceTree.js +1 -1
  238. package/dist/client/resources/mcp-integration-logos.d.ts +1 -0
  239. package/dist/client/resources/mcp-integration-logos.js +47 -18
  240. package/dist/client/settings/useBuilderStatus.js +6 -0
  241. package/dist/client/ui/index.d.ts +1 -0
  242. package/dist/client/ui/index.js +1 -0
  243. package/dist/collab/struct-routes.d.ts +1 -1
  244. package/dist/config.d.ts +26 -3
  245. package/dist/config.js +106 -14
  246. package/dist/db/ddl-guard.d.ts +15 -2
  247. package/dist/db/ddl-guard.js +53 -5
  248. package/dist/jobs/scheduler.js +7 -0
  249. package/dist/localization/default-messages.d.ts +17 -0
  250. package/dist/localization/default-messages.js +17 -0
  251. package/dist/mcp/oauth-client-metadata.js +5 -1
  252. package/dist/mcp/oauth-route.d.ts +5 -4
  253. package/dist/mcp/oauth-route.js +25 -9
  254. package/dist/mcp/server.d.ts +1 -1
  255. package/dist/mcp/server.js +9 -10
  256. package/dist/notifications/routes.d.ts +3 -3
  257. package/dist/org/handlers.d.ts +1 -0
  258. package/dist/org/handlers.js +17 -2
  259. package/dist/provider-api/actions/custom-provider-registration.d.ts +9 -9
  260. package/dist/provider-api/actions/provider-api.d.ts +7 -7
  261. package/dist/provider-api/corpus-jobs.d.ts +12 -2
  262. package/dist/provider-api/corpus-jobs.js +31 -1
  263. package/dist/provider-api/index.d.ts +2 -0
  264. package/dist/provider-api/index.js +7 -1
  265. package/dist/secrets/routes.d.ts +6 -6
  266. package/dist/server/agent-chat/recurring-jobs-runtime.d.ts +1 -1
  267. package/dist/server/agent-chat/recurring-jobs-runtime.js +14 -2
  268. package/dist/server/agent-chat/script-entries.js +12 -1
  269. package/dist/server/agent-chat-plugin.js +2 -2
  270. package/dist/server/auth.d.ts +1 -0
  271. package/dist/server/auth.js +85 -1
  272. package/dist/server/better-auth-instance.d.ts +9 -0
  273. package/dist/server/better-auth-instance.js +25 -11
  274. package/dist/server/core-routes-plugin.d.ts +7 -0
  275. package/dist/server/core-routes-plugin.js +51 -5
  276. package/dist/server/create-server.js +23 -2
  277. package/dist/server/db-pressure.d.ts +38 -0
  278. package/dist/server/db-pressure.js +147 -0
  279. package/dist/server/index.d.ts +1 -0
  280. package/dist/server/index.js +1 -0
  281. package/dist/server/legacy-auth-migration.d.ts +10 -0
  282. package/dist/server/legacy-auth-migration.js +37 -0
  283. package/dist/server/onboarding-html.js +206 -2
  284. package/dist/server/poll.d.ts +26 -0
  285. package/dist/server/poll.js +108 -13
  286. package/dist/server/realtime-voice.d.ts +2 -1
  287. package/dist/server/realtime-voice.js +38 -56
  288. package/dist/server/short-lived-token.d.ts +43 -0
  289. package/dist/server/short-lived-token.js +74 -0
  290. package/dist/server/ssr-handler.js +4 -1
  291. package/dist/shared/index.d.ts +1 -0
  292. package/dist/shared/index.js +1 -0
  293. package/dist/shared/runtime-config.d.ts +44 -0
  294. package/dist/shared/runtime-config.js +284 -0
  295. package/dist/styles/agent-native.css +48 -1
  296. package/dist/templates/chat/.agents/skills/actions/SKILL.md +18 -0
  297. package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  298. package/dist/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  299. package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +1 -0
  300. package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +76 -23
  301. package/dist/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  302. package/dist/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  303. package/dist/templates/chat/.env.example +3 -0
  304. package/dist/templates/chat/AGENTS.md +4 -0
  305. package/dist/templates/default/.agents/skills/actions/SKILL.md +18 -0
  306. package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  307. package/dist/templates/default/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  308. package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +1 -0
  309. package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +76 -23
  310. package/dist/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  311. package/dist/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  312. package/dist/templates/default/AGENTS.md +6 -1
  313. package/dist/templates/default/app/i18n/ar-SA.ts +6 -0
  314. package/dist/templates/default/app/i18n/de-DE.ts +6 -0
  315. package/dist/templates/default/app/i18n/en-US.ts +6 -0
  316. package/dist/templates/default/app/i18n/es-ES.ts +6 -0
  317. package/dist/templates/default/app/i18n/fr-FR.ts +6 -0
  318. package/dist/templates/default/app/i18n/hi-IN.ts +6 -0
  319. package/dist/templates/default/app/i18n/ja-JP.ts +6 -0
  320. package/dist/templates/default/app/i18n/ko-KR.ts +6 -0
  321. package/dist/templates/default/app/i18n/pt-BR.ts +6 -0
  322. package/dist/templates/default/app/i18n/zh-CN.ts +6 -0
  323. package/dist/templates/default/app/i18n/zh-TW.ts +6 -0
  324. package/dist/templates/headless/.agents/skills/actions/SKILL.md +18 -0
  325. package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  326. package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +76 -23
  327. package/dist/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  328. package/dist/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  329. package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +18 -0
  330. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  331. package/dist/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  332. package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +1 -0
  333. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +76 -23
  334. package/dist/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  335. package/dist/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  336. package/dist/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +4 -0
  337. package/dist/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +8 -0
  338. package/dist/templates/workspace-core/AGENTS.md +7 -2
  339. package/dist/templates/workspace-root/AGENTS.md +5 -0
  340. package/dist/vite/client.d.ts +3 -3
  341. package/dist/vite/client.js +47 -1
  342. package/dist/vite/index.d.ts +1 -1
  343. package/docs/content/agent-native-config.mdx +240 -139
  344. package/docs/content/authentication.mdx +17 -0
  345. package/docs/content/deployment.mdx +19 -14
  346. package/docs/content/drop-in-agent.mdx +19 -2
  347. package/docs/content/environment-variables.mdx +63 -38
  348. package/docs/content/getting-started-actions.mdx +15 -6
  349. package/docs/content/getting-started-database.mdx +14 -10
  350. package/docs/content/getting-started-pages.mdx +32 -35
  351. package/docs/content/getting-started.mdx +7 -6
  352. package/package.json +2 -2
  353. package/src/templates/chat/.agents/skills/actions/SKILL.md +18 -0
  354. package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  355. package/src/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  356. package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +1 -0
  357. package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +76 -23
  358. package/src/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  359. package/src/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  360. package/src/templates/chat/.env.example +3 -0
  361. package/src/templates/chat/AGENTS.md +4 -0
  362. package/src/templates/default/.agents/skills/actions/SKILL.md +18 -0
  363. package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  364. package/src/templates/default/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  365. package/src/templates/default/.agents/skills/frontend-design/SKILL.md +1 -0
  366. package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +76 -23
  367. package/src/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  368. package/src/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  369. package/src/templates/default/AGENTS.md +6 -1
  370. package/src/templates/default/app/i18n/ar-SA.ts +6 -0
  371. package/src/templates/default/app/i18n/de-DE.ts +6 -0
  372. package/src/templates/default/app/i18n/en-US.ts +6 -0
  373. package/src/templates/default/app/i18n/es-ES.ts +6 -0
  374. package/src/templates/default/app/i18n/fr-FR.ts +6 -0
  375. package/src/templates/default/app/i18n/hi-IN.ts +6 -0
  376. package/src/templates/default/app/i18n/ja-JP.ts +6 -0
  377. package/src/templates/default/app/i18n/ko-KR.ts +6 -0
  378. package/src/templates/default/app/i18n/pt-BR.ts +6 -0
  379. package/src/templates/default/app/i18n/zh-CN.ts +6 -0
  380. package/src/templates/default/app/i18n/zh-TW.ts +6 -0
  381. package/src/templates/headless/.agents/skills/actions/SKILL.md +18 -0
  382. package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  383. package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +76 -23
  384. package/src/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  385. package/src/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  386. package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +18 -0
  387. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  388. package/src/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +45 -47
  389. package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +1 -0
  390. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +76 -23
  391. package/src/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
  392. package/src/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
  393. package/src/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +4 -0
  394. package/src/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +8 -0
  395. package/src/templates/workspace-core/AGENTS.md +7 -2
  396. package/src/templates/workspace-root/AGENTS.md +5 -0
  397. package/corpus/templates/dispatch/app/routes/admin.apps.$appId.tsx +0 -1
  398. package/corpus/templates/dispatch/app/routes/admin.apps.tsx +0 -1
@@ -0,0 +1,279 @@
1
+ import { defineAction } from "@agent-native/core/action";
2
+ import { and, eq } from "drizzle-orm";
3
+ import { z } from "zod";
4
+
5
+ import { resolveConnectorSecret } from "../server/connectors/credentials.js";
6
+ import { getDb } from "../server/db/index.js";
7
+ import { triageConfig, triageItems } from "../server/db/schema.js";
8
+ import { requireFactoryAutomation } from "../server/lib/require-factory-automation.js";
9
+ import {
10
+ requireWorkspaceMember,
11
+ workspaceMemberIdentityFromContext,
12
+ } from "../server/lib/require-workspace-member.js";
13
+ import { createAiServicesGitReadClient } from "../server/triage/ai-services-git.js";
14
+ import { createGitHubClient } from "../server/triage/github-client.js";
15
+ import {
16
+ metadataString,
17
+ parseTriageMetadata,
18
+ serializeTriageMetadata,
19
+ } from "../server/triage/metadata.js";
20
+ import {
21
+ babysitFingerprint,
22
+ DEFAULT_BABYSIT_BOT_AUTHORS,
23
+ reconcileBabysitState,
24
+ shouldBabysitBuilderBotPullRequest,
25
+ } from "../server/triage/pr-babysit.js";
26
+ import { detectOwnerOwnedArea } from "../server/triage/pr-policy.js";
27
+
28
+ const QUIET_PERIOD_MS = 20 * 60_000;
29
+ const MIN_COMMENT_INTERVAL_MS = 90_000;
30
+ const BUILDER_BOT_REQUEST =
31
+ "@builderio-bot look at latest PR feedback and fix anything you agree with. Be skeptical. Reply to every comment (directly on the comment thread of each comment) if you fixed it or not and why. then check back every 2 minutes on a loop and see if any new feedback posted, until at least 20 minutes go by without any new feedback posted we want to address, including making sure CI passes too and no merge conflicts (make sure code is mergeable)";
32
+
33
+ function requiredAiServicesEnv(
34
+ name: "BUILDER_AI_SERVICES_URL" | "BUILDER_PROJECT_ID",
35
+ ): string {
36
+ const value =
37
+ name === "BUILDER_AI_SERVICES_URL"
38
+ ? process.env.BUILDER_AI_SERVICES_URL // guard:allow-env-credential - non-secret deployment endpoint
39
+ : process.env.BUILDER_PROJECT_ID; // guard:allow-env-credential - non-secret deployment project id
40
+ if (!value) throw new Error(`${name} is required for PR babysitting.`);
41
+ return value;
42
+ }
43
+
44
+ function parseTimestamp(value: string | undefined): number | null {
45
+ if (!value) return null;
46
+ const parsed = Date.parse(value);
47
+ return Number.isFinite(parsed) ? parsed : null;
48
+ }
49
+
50
+ function repositoryRef(value: string): { owner: string; repo: string } {
51
+ const match = /^([^/\s]+)\/([^/\s]+)$/.exec(value.trim());
52
+ if (!match)
53
+ throw new Error("Repository must use the owner/repository format.");
54
+ return { owner: match[1], repo: match[2] };
55
+ }
56
+
57
+ async function updateBabysitMetadata(
58
+ itemId: string,
59
+ orgId: string,
60
+ patch: Record<string, unknown>,
61
+ ): Promise<void> {
62
+ const db = getDb();
63
+ const item = (
64
+ await db
65
+ .select({ metadataJson: triageItems.metadataJson })
66
+ .from(triageItems)
67
+ .where(and(eq(triageItems.id, itemId), eq(triageItems.orgId, orgId)))
68
+ .limit(1)
69
+ )[0];
70
+ if (!item) throw new Error("Factory item disappeared during PR babysitting.");
71
+ const metadata = parseTriageMetadata(item.metadataJson);
72
+ Object.assign(metadata, patch);
73
+ await db
74
+ .update(triageItems)
75
+ .set({
76
+ metadataJson: serializeTriageMetadata(metadata),
77
+ updatedAt: new Date().toISOString(),
78
+ })
79
+ .where(and(eq(triageItems.id, itemId), eq(triageItems.orgId, orgId)));
80
+ }
81
+
82
+ export default defineAction({
83
+ description:
84
+ "Watch one builder-io-bot pull request, post the bounded feedback-fix request when CI, mergeability, or review feedback needs work, and stop after 20 quiet minutes. The action never merges or approves.",
85
+ schema: z.object({
86
+ itemId: z.string().min(1),
87
+ }),
88
+ http: false,
89
+ run: async ({ itemId }, context) => {
90
+ const { userEmail, orgId } = await requireWorkspaceMember(
91
+ workspaceMemberIdentityFromContext(context),
92
+ );
93
+ await requireFactoryAutomation(context, { userEmail, orgId }, "prBabysit");
94
+
95
+ const db = getDb();
96
+ const item = (
97
+ await db
98
+ .select()
99
+ .from(triageItems)
100
+ .where(and(eq(triageItems.id, itemId), eq(triageItems.orgId, orgId)))
101
+ .limit(1)
102
+ )[0];
103
+ if (!item) throw new Error("Factory item not found for PR babysitting.");
104
+ if (
105
+ item.source !== "github" ||
106
+ !item.repository ||
107
+ !item.pullRequestNumber
108
+ ) {
109
+ return {
110
+ ok: true,
111
+ action: "skipped",
112
+ reason: "Item is not a pull request.",
113
+ };
114
+ }
115
+
116
+ const configuredRepository = (
117
+ await db
118
+ .select({ repository: triageConfig.repository })
119
+ .from(triageConfig)
120
+ .where(and(eq(triageConfig.id, orgId), eq(triageConfig.orgId, orgId)))
121
+ .limit(1)
122
+ )[0]?.repository;
123
+ if (
124
+ !configuredRepository ||
125
+ configuredRepository.trim() !== item.repository.trim()
126
+ ) {
127
+ throw new Error(
128
+ "PR babysitting is restricted to the configured Factory repository.",
129
+ );
130
+ }
131
+
132
+ const repository = repositoryRef(item.repository);
133
+ const github = createGitHubClient({ ownerEmail: userEmail, orgId });
134
+ const pullRequest = await github.getPullRequestSummary(
135
+ repository,
136
+ item.pullRequestNumber,
137
+ );
138
+ if (pullRequest.state !== "open" || pullRequest.draft) {
139
+ await updateBabysitMetadata(itemId, orgId, {
140
+ prBabysitState: "closed-or-draft",
141
+ prBabysitLastCheckedAt: new Date().toISOString(),
142
+ });
143
+ return { ok: true, action: "skipped", reason: "PR is closed or draft." };
144
+ }
145
+
146
+ const ownerOwnedArea = detectOwnerOwnedArea([
147
+ item.repository,
148
+ pullRequest.title,
149
+ pullRequest.body,
150
+ ]);
151
+ if (ownerOwnedArea) {
152
+ await updateBabysitMetadata(itemId, orgId, {
153
+ prBabysitState: "owner-managed",
154
+ prBabysitOwnerArea: ownerOwnedArea,
155
+ prBabysitLastCheckedAt: new Date().toISOString(),
156
+ });
157
+ return {
158
+ ok: true,
159
+ action: "skipped",
160
+ reason: `${ownerOwnedArea} is owner-managed.`,
161
+ };
162
+ }
163
+
164
+ const privateKey = await resolveConnectorSecret(
165
+ "BUILDER_PRIVATE_KEY",
166
+ userEmail,
167
+ { orgId },
168
+ );
169
+ if (!privateKey) {
170
+ throw new Error(
171
+ "BUILDER_PRIVATE_KEY is required to read PR feedback for babysitting.",
172
+ );
173
+ }
174
+ const snapshot = await createAiServicesGitReadClient({
175
+ baseUrl: requiredAiServicesEnv("BUILDER_AI_SERVICES_URL"),
176
+ authorization: `Bearer ${privateKey.startsWith("bpk-") ? privateKey : `bpk-${privateKey}`}`,
177
+ }).fetchPullRequest({
178
+ projectId: requiredAiServicesEnv("BUILDER_PROJECT_ID"),
179
+ repo: item.repository,
180
+ pullRequestNumber: item.pullRequestNumber,
181
+ });
182
+ if (snapshot.headSha !== pullRequest.headSha) {
183
+ throw new Error(
184
+ `PR evidence is stale: GitHub reports ${pullRequest.headSha}, ai-services reports ${snapshot.headSha}.`,
185
+ );
186
+ }
187
+
188
+ const proposal = reconcileBabysitState({
189
+ comments: snapshot.comments,
190
+ checks: snapshot.checks,
191
+ commentsTruncated: snapshot.commentsTruncated,
192
+ botAuthors: [...DEFAULT_BABYSIT_BOT_AUTHORS],
193
+ });
194
+ const unresolvedReviewState = snapshot.reviews.some(
195
+ (review) =>
196
+ review.state === "changes_requested" || review.state === "pending",
197
+ );
198
+ const signal = {
199
+ ...proposal,
200
+ isClean: proposal.isClean && !unresolvedReviewState,
201
+ };
202
+ const needsBabysit = shouldBabysitBuilderBotPullRequest({
203
+ author: pullRequest.userLogin,
204
+ mergeable: pullRequest.mergeable,
205
+ mergeableState: pullRequest.mergeableState,
206
+ snapshot: signal,
207
+ });
208
+ const now = new Date();
209
+ const nowIso = now.toISOString();
210
+ const metadata = parseTriageMetadata(item.metadataJson);
211
+ const fingerprint = babysitFingerprint({
212
+ headSha: snapshot.headSha,
213
+ mergeable: pullRequest.mergeable,
214
+ mergeableState: pullRequest.mergeableState,
215
+ snapshot: signal,
216
+ reviewStates: snapshot.reviews.map((review) => review.state),
217
+ });
218
+ const previousFingerprint = metadataString(
219
+ metadata,
220
+ "prBabysitFingerprint",
221
+ );
222
+ const previousState = metadataString(metadata, "prBabysitState");
223
+ if (!needsBabysit) {
224
+ await updateBabysitMetadata(itemId, orgId, {
225
+ prBabysitState: "clean",
226
+ prBabysitLastCheckedAt: nowIso,
227
+ prBabysitFingerprint: fingerprint,
228
+ });
229
+ return { ok: true, action: "clean" };
230
+ }
231
+
232
+ const quietSince =
233
+ previousFingerprint === fingerprint && previousState !== "clean"
234
+ ? (parseTimestamp(metadataString(metadata, "prBabysitQuietSinceAt")) ??
235
+ now.getTime())
236
+ : now.getTime();
237
+ const lastCommentAt = parseTimestamp(
238
+ metadataString(metadata, "prBabysitLastCommentAt"),
239
+ );
240
+ const quietForMs = now.getTime() - quietSince;
241
+ const shouldPost =
242
+ previousFingerprint !== fingerprint &&
243
+ (lastCommentAt === null ||
244
+ now.getTime() - lastCommentAt >= MIN_COMMENT_INTERVAL_MS);
245
+ if (!shouldPost || quietForMs >= QUIET_PERIOD_MS) {
246
+ await updateBabysitMetadata(itemId, orgId, {
247
+ prBabysitState: quietForMs >= QUIET_PERIOD_MS ? "quiet" : "waiting",
248
+ prBabysitFingerprint: fingerprint,
249
+ prBabysitQuietSinceAt: new Date(quietSince).toISOString(),
250
+ prBabysitLastCheckedAt: nowIso,
251
+ });
252
+ return {
253
+ ok: true,
254
+ action: quietForMs >= QUIET_PERIOD_MS ? "quiet" : "waiting",
255
+ quietForMinutes: Math.floor(Math.max(0, quietForMs) / 60_000),
256
+ };
257
+ }
258
+
259
+ const comment = await github.createIssueComment(
260
+ repository,
261
+ item.pullRequestNumber,
262
+ BUILDER_BOT_REQUEST,
263
+ );
264
+ await updateBabysitMetadata(itemId, orgId, {
265
+ prBabysitState: "active",
266
+ prBabysitFingerprint: fingerprint,
267
+ prBabysitQuietSinceAt: new Date(quietSince).toISOString(),
268
+ prBabysitLastCheckedAt: nowIso,
269
+ prBabysitLastCommentAt: nowIso,
270
+ prBabysitLastCommentUrl: comment.htmlUrl,
271
+ });
272
+ return {
273
+ ok: true,
274
+ action: "commented",
275
+ commentUrl: comment.htmlUrl,
276
+ quietForMinutes: Math.floor(Math.max(0, quietForMs) / 60_000),
277
+ };
278
+ },
279
+ });
@@ -19,10 +19,27 @@ export default defineAction({
19
19
  const { orgId } = await requireWorkspaceMember(
20
20
  workspaceMemberIdentityFromContext(context),
21
21
  );
22
- const health = await getAutomationSchedulerHealth({
23
- appId: "factory",
24
- orgId,
25
- });
22
+ const [organizationHealth, globalHealth] = await Promise.all([
23
+ getAutomationSchedulerHealth({
24
+ appId: "factory",
25
+ orgId,
26
+ }),
27
+ getAutomationSchedulerHealth({ appId: "factory", orgId: null }),
28
+ ]);
29
+ const health =
30
+ [organizationHealth, globalHealth]
31
+ .filter(
32
+ (candidate): candidate is NonNullable<typeof candidate> =>
33
+ candidate !== null && candidate.lastCheckedAt !== null,
34
+ )
35
+ .sort(
36
+ (left, right) =>
37
+ (right.lastCheckedAt ?? 0) - (left.lastCheckedAt ?? 0),
38
+ )[0] ??
39
+ organizationHealth ??
40
+ globalHealth;
41
+ const healthScope =
42
+ health?.orgId === orgId ? ("organization" as const) : ("global" as const);
26
43
  if (!health?.lastCheckedAt) {
27
44
  return {
28
45
  status: "no-data" as const,
@@ -30,6 +47,7 @@ export default defineAction({
30
47
  lastDispatchedAt: health?.lastDispatchedAt ?? null,
31
48
  lastError: health?.lastError ?? null,
32
49
  runtime: health?.runtime ?? null,
50
+ scope: healthScope,
33
51
  staleAfterMs: STALE_AFTER_MS,
34
52
  };
35
53
  }
@@ -44,6 +62,7 @@ export default defineAction({
44
62
  lastDispatchedAt: health.lastDispatchedAt,
45
63
  lastError: health.lastError,
46
64
  runtime: health.runtime,
65
+ scope: healthScope,
47
66
  staleAfterMs: STALE_AFTER_MS,
48
67
  };
49
68
  },
@@ -92,7 +92,7 @@ type DragState = {
92
92
  startPosition: { x: number; y: number };
93
93
  };
94
94
 
95
- const DRAG_THRESHOLD = 3;
95
+ const DRAG_THRESHOLD = 6;
96
96
 
97
97
  export function FactoryCanvas({
98
98
  graph,
@@ -258,7 +258,10 @@ export default function FactoryRoute() {
258
258
 
259
259
  function updateGraph(next: FactoryCanvasGraph) {
260
260
  setDraftGraph(next);
261
- setDirty(true);
261
+ setDirty(
262
+ !graphData?.graph ||
263
+ JSON.stringify(next) !== JSON.stringify(graphData.graph),
264
+ );
262
265
  }
263
266
 
264
267
  function addNode() {
@@ -645,14 +648,29 @@ function AutomationsView({
645
648
 
646
649
  useEffect(() => {
647
650
  if (!selected) {
648
- setDraft(null);
651
+ setDraft((current) => (current === null ? current : null));
649
652
  return;
650
653
  }
651
654
  if (selected.id !== selectedId) {
652
655
  selectAutomation(selected.id);
653
656
  return;
654
657
  }
655
- setDraft(draftForAutomation(selected));
658
+ const nextDraft = draftForAutomation(selected);
659
+ setDraft((current) => {
660
+ if (
661
+ current &&
662
+ current.id === nextDraft.id &&
663
+ current.name === nextDraft.name &&
664
+ current.prompt === nextDraft.prompt &&
665
+ current.body === nextDraft.body &&
666
+ current.model === nextDraft.model &&
667
+ current.schedule === nextDraft.schedule &&
668
+ current.enabled === nextDraft.enabled
669
+ ) {
670
+ return current;
671
+ }
672
+ return nextDraft;
673
+ });
656
674
  }, [selected, selectedId]);
657
675
 
658
676
  async function saveAutomation() {
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: added
3
+ date: 2026-08-07
4
+ ---
5
+
6
+ Factory can keep Builder bot pull requests moving by requesting fixes for review feedback, CI failures, and merge conflicts.
@@ -10,6 +10,7 @@ const FACTORY_AUTOMATION_NAMES = {
10
10
  "factory-github-issues",
11
11
  ]),
12
12
  governance: new Set(["factory-pr-governance"]),
13
+ prBabysit: new Set(["factory-pr-babysit"]),
13
14
  sourcePolling: new Set([
14
15
  "factory-slack-feedback",
15
16
  "factory-sentry-errors",
@@ -24,6 +24,7 @@ const INITIAL_TOOL_NAMES = [
24
24
  "start-builder-for-item",
25
25
  "govern-agent-native-pull-request",
26
26
  "babysit-pull-request",
27
+ "babysit-agent-native-pull-request",
27
28
  "approve-factory-item",
28
29
  "list-triage-rules",
29
30
  "get-triage-config",
@@ -70,7 +71,9 @@ BuilderIO author, a clear bug, passing CI, and handled review feedback. Auto-mer
70
71
  also requires a verified Factory Builder run. When a user says to do a review-gated
71
72
  item now, use the explicit approval action, which records the approver and applies
72
73
  the rule's configured executor policy. Keep Slack replies concise and link to the
73
- Factory item when a review is needed.`,
74
+ Factory item when a review is needed. The scheduled builder-io-bot PR babysitter
75
+ posts its exact feedback-fix request through GitHub, persists a 20-minute quiet
76
+ window, and never approves or merges.`,
74
77
  } satisfies AgentChatPluginOptions;
75
78
 
76
79
  export default createAgentChatPlugin(options);
@@ -5,6 +5,7 @@ import {
5
5
  organizationResourceOwner,
6
6
  resourceGetByPath,
7
7
  resourcePut,
8
+ resourcePutIfCurrent,
8
9
  WORKSPACE_OWNER,
9
10
  } from "@agent-native/core/resources";
10
11
  import {
@@ -264,6 +265,30 @@ fully owned by their product owners. Auto-merge is limited to PRs with a
264
265
  verified Factory Builder run; all other PRs can at most pass the approval
265
266
  policy. Do not call GitHub write actions directly or claim a merge unless the
266
267
  governance action confirms it.
268
+ `,
269
+ },
270
+ {
271
+ name: "factory-pr-babysit",
272
+ schedule: "*/2 * * * *",
273
+ body: `
274
+ # Factory builder-io-bot PR babysitting
275
+
276
+ Read the Factory configuration. When GitHub polling is enabled and a repository
277
+ is configured, call poll-github-sources with includeIssues false and
278
+ includePullRequests true. List a bounded page of open github pull-request items.
279
+
280
+ For each item, call babysit-agent-native-pull-request. That action fetches fresh
281
+ GitHub and ai-services evidence and is the only place allowed to decide whether
282
+ to post the bounded @builderio-bot feedback-fix request. It only acts on open
283
+ non-draft PRs authored by builder-io-bot (including GitHub's bot login variants),
284
+ and skips owner-managed Clips, Design, and Content work. It persists the latest
285
+ feedback fingerprint and quiet window, so repeated scheduler ticks do not spam
286
+ comments. A changed commit, new unresolved feedback, failing or pending CI, or
287
+ merge conflict starts a new bounded request; twenty minutes without new work to
288
+ address ends that babysitting window. The action never approves or merges.
289
+
290
+ Preserve action errors and never claim that Builder fixed a PR unless fresh
291
+ evidence confirms the resulting state.
267
292
  `,
268
293
  },
269
294
  ];
@@ -274,6 +299,19 @@ function workspaceOwnerEmail(): string | undefined {
274
299
  return email;
275
300
  }
276
301
 
302
+ function defaultRepository(): string | null {
303
+ const repository = process.env.FACTORY_DEFAULT_REPOSITORY?.trim(); // guard:allow-env-credential - repository configuration, not a credential
304
+ if (!repository || /[\r\n]/.test(repository)) return null;
305
+ return repository;
306
+ }
307
+
308
+ function defaultGithubPollingEnabled(): 0 | 1 {
309
+ return process.env.FACTORY_ENABLE_GITHUB_POLLING?.trim().toLowerCase() === // guard:allow-env-credential - deployment feature flag, not a credential
310
+ "true"
311
+ ? 1
312
+ : 0;
313
+ }
314
+
277
315
  function setFrontmatterField(
278
316
  content: string,
279
317
  key: string,
@@ -327,16 +365,47 @@ async function ensureOrganizationAutomations(
327
365
  orgId: string,
328
366
  ): Promise<void> {
329
367
  const owner = organizationResourceOwner(orgId);
330
- for (const seed of AUTOMATION_SEEDS) {
331
- const path = `jobs/${seed.name}.md`;
332
- if (await resourceGetByPath(owner, path)) continue;
333
- await resourcePut(
334
- owner,
335
- path,
336
- automationContent(ownerEmail, orgId, seed),
337
- "text/markdown",
338
- );
339
- }
368
+ await Promise.all(
369
+ AUTOMATION_SEEDS.map(async (seed) => {
370
+ const path = `jobs/${seed.name}.md`;
371
+ const existing = await resourceGetByPath(owner, path);
372
+ if (!existing) {
373
+ await resourcePut(
374
+ owner,
375
+ path,
376
+ automationContent(ownerEmail, orgId, seed),
377
+ "text/markdown",
378
+ );
379
+ return;
380
+ }
381
+
382
+ // Earlier Factory versions created these rows without the metadata the
383
+ // list and action guards use. Patch only identity metadata and keep the
384
+ // user's prompt, model, schedule, and enabled state intact.
385
+ let repaired = existing.content;
386
+ repaired = setFrontmatterField(repaired, "triggerType", "schedule");
387
+ repaired = setFrontmatterField(repaired, "domain", "factory");
388
+ repaired = setFrontmatterField(repaired, "orgId", orgId);
389
+ repaired = setFrontmatterField(repaired, "createdBy", ownerEmail);
390
+ repaired = setFrontmatterField(repaired, "runAs", "creator");
391
+ if (repaired === existing.content) return;
392
+
393
+ const updated = await resourcePutIfCurrent({
394
+ owner,
395
+ path,
396
+ content: repaired,
397
+ mimeType: "text/markdown",
398
+ expectedId: existing.id,
399
+ expectedUpdatedAt: existing.updatedAt,
400
+ expectedContent: existing.content,
401
+ });
402
+ if (!updated) {
403
+ console.warn(
404
+ `[factory-scheduler-job] skipped metadata repair for ${path}: the resource changed concurrently`,
405
+ );
406
+ }
407
+ }),
408
+ );
340
409
  }
341
410
 
342
411
  async function ensureDefaultTriageConfig(
@@ -359,11 +428,11 @@ async function ensureDefaultTriageConfig(
359
428
  slackChannelId: DEFAULT_SLACK_CHANNEL_ID,
360
429
  slackChannelName: DEFAULT_SLACK_CHANNEL_NAME,
361
430
  pollingEnabled: 1,
362
- githubPollingEnabled: 0,
431
+ githubPollingEnabled: defaultGithubPollingEnabled(),
363
432
  sentryPollingEnabled: 0,
364
433
  lastSlackTs: null,
365
434
  slackHistoryCursor: null,
366
- repository: null,
435
+ repository: defaultRepository(),
367
436
  sentryOrgSlug: null,
368
437
  sentryProjectSlug: null,
369
438
  sentryEnvironment: null,
@@ -73,6 +73,11 @@ export interface GitHubMergeResult {
73
73
  message: string;
74
74
  }
75
75
 
76
+ export interface GitHubComment {
77
+ id: number;
78
+ htmlUrl: string;
79
+ }
80
+
76
81
  interface JsonResponse {
77
82
  ok: boolean;
78
83
  status: number;
@@ -361,6 +366,32 @@ export function createGitHubClient(options: GitHubClientOptions) {
361
366
  };
362
367
  },
363
368
 
369
+ async createIssueComment(
370
+ repository: GitHubRepositoryRef,
371
+ issueNumber: number,
372
+ body: string,
373
+ ): Promise<GitHubComment> {
374
+ if (!Number.isInteger(issueNumber) || issueNumber < 1) {
375
+ throw new Error("GitHub issue number must be a positive integer");
376
+ }
377
+ const trimmedBody = body.trim();
378
+ if (!trimmedBody) throw new Error("GitHub comment body is required");
379
+ const item = record(
380
+ await request<unknown>(
381
+ `${repositoryPath(repository)}/issues/${issueNumber}/comments`,
382
+ {
383
+ method: "POST",
384
+ headers: { "Content-Type": "application/json" },
385
+ body: JSON.stringify({ body: trimmedBody.slice(0, 65_536) }),
386
+ },
387
+ ),
388
+ );
389
+ return {
390
+ id: requiredNumber(item.id, "comment id"),
391
+ htmlUrl: requiredString(item.html_url, "comment URL"),
392
+ };
393
+ },
394
+
364
395
  async mergePullRequest(
365
396
  repository: GitHubRepositoryRef,
366
397
  pullRequestNumber: number,
@@ -1,5 +1,24 @@
1
1
  import type { PullRequestCheckObservation } from "./pr-monitor.js";
2
2
 
3
+ export const BUILDER_BOT_LOGINS = new Set([
4
+ "builder-io-bot",
5
+ "builder-io-bot[bot]",
6
+ "builderio-bot",
7
+ "builderio-bot[bot]",
8
+ "builderio[bot]",
9
+ ]);
10
+
11
+ export const DEFAULT_BABYSIT_BOT_AUTHORS = [
12
+ "builder-io-bot",
13
+ "builder-io-bot[bot]",
14
+ "builderio-bot",
15
+ "builderio-bot[bot]",
16
+ "builderio[bot]",
17
+ "github-actions",
18
+ "github-actions[bot]",
19
+ "dependabot[bot]",
20
+ ] as const;
21
+
3
22
  export interface ReviewCommentObservation {
4
23
  id: string;
5
24
  author: string;
@@ -30,6 +49,61 @@ export interface BabysitProposal {
30
49
  isClean: boolean;
31
50
  }
32
51
 
52
+ export interface BuilderBotBabysitSignal {
53
+ author: string;
54
+ mergeable: boolean | null;
55
+ mergeableState: string | null;
56
+ snapshot: BabysitProposal;
57
+ }
58
+
59
+ export function isBuilderBotLogin(login: string): boolean {
60
+ return BUILDER_BOT_LOGINS.has(login.trim().toLowerCase());
61
+ }
62
+
63
+ export function hasMergeConflict(input: {
64
+ mergeable: boolean | null;
65
+ mergeableState: string | null;
66
+ }): boolean {
67
+ return (
68
+ input.mergeable === false ||
69
+ input.mergeableState === "dirty" ||
70
+ input.mergeableState === "conflicting"
71
+ );
72
+ }
73
+
74
+ export function shouldBabysitBuilderBotPullRequest(
75
+ input: BuilderBotBabysitSignal,
76
+ ): boolean {
77
+ return (
78
+ isBuilderBotLogin(input.author) &&
79
+ (hasMergeConflict(input) || !input.snapshot.isClean)
80
+ );
81
+ }
82
+
83
+ export function babysitFingerprint(input: {
84
+ headSha: string;
85
+ mergeable: boolean | null;
86
+ mergeableState: string | null;
87
+ snapshot: BabysitProposal;
88
+ reviewStates?: readonly string[];
89
+ }): string {
90
+ return JSON.stringify({
91
+ headSha: input.headSha,
92
+ mergeable: input.mergeable,
93
+ mergeableState: input.mergeableState,
94
+ unansweredComments: input.snapshot.unansweredComments.map((comment) => ({
95
+ id: comment.id,
96
+ body: comment.body,
97
+ isResolved: comment.isResolved ?? null,
98
+ })),
99
+ failingChecks: input.snapshot.failingChecks.map((check) => check.name),
100
+ pendingChecks: input.snapshot.pendingChecks.map((check) => check.name),
101
+ missingChangesetPackages: input.snapshot.missingChangesetPackages,
102
+ commentsTruncated: input.snapshot.commentsTruncated,
103
+ reviewStates: input.reviewStates ?? [],
104
+ });
105
+ }
106
+
33
107
  const MISSING_CHANGESET_LINE = /^MISSING_CHANGESET_PACKAGES:\s*(.*)$/m;
34
108
 
35
109
  function parseMissingChangesetPackages(log: string | undefined): string[] {
@@ -71,7 +145,7 @@ export function reconcileBabysitState(input: BabysitInput): BabysitProposal {
71
145
  !botAuthors.has(comment.author),
72
146
  );
73
147
  const failingChecks = input.checks.filter(
74
- (check) => check.state === "failed",
148
+ (check) => check.state === "failed" || check.state === "cancelled",
75
149
  );
76
150
  const pendingChecks = input.checks.filter(
77
151
  (check) => check.state === "queued" || check.state === "in_progress",