@agent-native/core 0.146.8 → 0.148.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 (317) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +115 -68
  3. package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +18 -6
  4. package/corpus/templates/analytics/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  5. package/corpus/templates/analytics/DEVELOPING.md +50 -3
  6. package/corpus/templates/analytics/actions/purge-first-party-analytics-postgres.ts +190 -0
  7. package/corpus/templates/analytics/app/i18n/index.ts +14 -29
  8. package/corpus/templates/analytics/app/i18n-data.ts +10 -10
  9. package/corpus/templates/analytics/app/pages/Settings.tsx +5 -21
  10. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +1 -3
  11. package/corpus/templates/analytics/app/routes/status.$slug.tsx +4 -2
  12. package/corpus/templates/analytics/scripts/first-party-analytics-bigquery-backfill.ts +253 -24
  13. package/corpus/templates/analytics/server/db/schema.ts +23 -0
  14. package/corpus/templates/analytics/server/handlers/first-party-analytics.ts +3 -1
  15. package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +1 -1
  16. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +113 -13
  17. package/corpus/templates/analytics/server/lib/first-party-analytics-purge.ts +140 -0
  18. package/corpus/templates/analytics/server/lib/first-party-analytics-volume.ts +207 -0
  19. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +40 -9
  20. package/corpus/templates/analytics/server/lib/gcloud.ts +148 -20
  21. package/corpus/templates/analytics/server/plugins/db.ts +42 -0
  22. package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +115 -68
  23. package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +18 -6
  24. package/corpus/templates/assets/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  25. package/corpus/templates/assets/app/i18n/index.ts +14 -29
  26. package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +9 -0
  27. package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +115 -68
  28. package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +18 -6
  29. package/corpus/templates/brain/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  30. package/corpus/templates/brain/app/i18n/index.ts +14 -29
  31. package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +115 -68
  32. package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +18 -6
  33. package/corpus/templates/calendar/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  34. package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +9 -0
  35. package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +115 -68
  36. package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -6
  37. package/corpus/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  38. package/corpus/templates/chat/app/i18n/index.ts +14 -29
  39. package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +115 -68
  40. package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +18 -6
  41. package/corpus/templates/clips/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  42. package/corpus/templates/clips/app/components/player/transcript-panel.tsx +2 -7
  43. package/corpus/templates/clips/app/components/recorder/storage-setup-card.tsx +18 -13
  44. package/corpus/templates/clips/app/components/settings/ai-setup-section.tsx +87 -370
  45. package/corpus/templates/clips/app/components/settings/slack-section.tsx +59 -101
  46. package/corpus/templates/clips/app/components/settings/video-storage-section.tsx +136 -213
  47. package/corpus/templates/clips/app/i18n/en-US.ts +11 -8
  48. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +16 -4
  49. package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +14 -5
  50. package/corpus/templates/clips/desktop/src/app.tsx +1 -1
  51. package/corpus/templates/clips/package.json +1 -0
  52. package/corpus/templates/clips/react-router.config.ts +7 -0
  53. package/corpus/templates/clips/server/plugins/auth.ts +6 -1
  54. package/corpus/templates/clips/shared/prerendered-public-paths.ts +21 -0
  55. package/corpus/templates/clips/shared/share-meta.ts +8 -3
  56. package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +115 -68
  57. package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +18 -6
  58. package/corpus/templates/content/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  59. package/corpus/templates/content/app/i18n/index.ts +14 -29
  60. package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +18 -6
  61. package/corpus/templates/crm/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  62. package/corpus/templates/crm/app/i18n/index.ts +14 -29
  63. package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +115 -68
  64. package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +18 -6
  65. package/corpus/templates/design/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  66. package/corpus/templates/design/actions/analyze-brand-assets.ts +15 -15
  67. package/corpus/templates/design/actions/import-code.ts +2 -43
  68. package/corpus/templates/design/app/i18n/index.ts +14 -29
  69. package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +115 -68
  70. package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +18 -6
  71. package/corpus/templates/dispatch/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  72. package/corpus/templates/dispatch/app/chat-first-pages.ts +747 -0
  73. package/corpus/templates/dispatch/app/i18n-data.ts +182 -1
  74. package/corpus/templates/dispatch/app/routes/settings.tsx +62 -1
  75. package/corpus/templates/dispatch/changelog/2026-08-08-chat-first-navigation-keeps-conversations-central-while-open.md +6 -0
  76. package/corpus/templates/factory/.agents/skills/adding-a-feature/SKILL.md +9 -0
  77. package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +115 -68
  78. package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +18 -6
  79. package/corpus/templates/factory/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  80. package/corpus/templates/factory/AGENTS.md +40 -49
  81. package/corpus/templates/factory/actions/babysit-agent-native-pull-request.ts +66 -0
  82. package/corpus/templates/factory/actions/evaluate-triage-item.ts +37 -0
  83. package/corpus/templates/factory/actions/get-slack-feedback-context.ts +20 -0
  84. package/corpus/templates/factory/actions/get-triage-item.ts +25 -4
  85. package/corpus/templates/factory/actions/govern-agent-native-pull-request.ts +55 -0
  86. package/corpus/templates/factory/actions/ingest-github-observation.ts +21 -0
  87. package/corpus/templates/factory/actions/list-factory-audit.ts +118 -0
  88. package/corpus/templates/factory/actions/list-factory-automations.ts +2 -1
  89. package/corpus/templates/factory/actions/list-triage-items.ts +24 -2
  90. package/corpus/templates/factory/actions/poll-github-sources.ts +60 -0
  91. package/corpus/templates/factory/actions/poll-sentry-errors.ts +39 -0
  92. package/corpus/templates/factory/actions/poll-slack-channel.ts +45 -1
  93. package/corpus/templates/factory/actions/run-factory-automation.ts +1 -1
  94. package/corpus/templates/factory/actions/save-factory-automation.ts +2 -2
  95. package/corpus/templates/factory/actions/start-builder-for-item.ts +51 -0
  96. package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +685 -0
  97. package/corpus/templates/factory/app/hooks/use-navigation-state.ts +6 -0
  98. package/corpus/templates/factory/app/i18n/en-US.ts +25 -0
  99. package/corpus/templates/factory/app/routes/factory.tsx +203 -118
  100. package/corpus/templates/factory/changelog/2026-08-08-scheduler-health-moves-to-settings.md +6 -0
  101. package/corpus/templates/factory/server/db/schema.ts +37 -0
  102. package/corpus/templates/factory/server/lib/require-factory-automation.ts +5 -1
  103. package/corpus/templates/factory/server/plugins/factory-migrations.ts +29 -0
  104. package/corpus/templates/factory/server/triage/audit.ts +79 -0
  105. package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +115 -68
  106. package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +18 -6
  107. package/corpus/templates/forms/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  108. package/corpus/templates/forms/app/i18n/index.ts +14 -29
  109. package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +115 -68
  110. package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +18 -6
  111. package/corpus/templates/macros/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  112. package/corpus/templates/macros/app/i18n/index.ts +14 -29
  113. package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +115 -68
  114. package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +18 -6
  115. package/corpus/templates/mail/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  116. package/corpus/templates/mail/app/i18n/index.ts +14 -29
  117. package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +9 -0
  118. package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +115 -68
  119. package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +18 -6
  120. package/corpus/templates/plan/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  121. package/corpus/templates/plan/app/components/plan/wireframe/Wireframe.tsx +7 -7
  122. package/corpus/templates/plan/app/i18n/index.ts +14 -29
  123. package/corpus/templates/plan/app/lib/plan-document-title.ts +3 -1
  124. package/corpus/templates/plan/app/root.tsx +1 -0
  125. package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +115 -68
  126. package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +18 -6
  127. package/corpus/templates/slides/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  128. package/corpus/templates/slides/actions/analyze-brand-assets.ts +15 -15
  129. package/corpus/templates/slides/actions/import-code.ts +2 -43
  130. package/corpus/templates/slides/app/i18n/index.ts +14 -29
  131. package/corpus/templates/slides/server/routes/api/preview-images.get.ts +4 -1
  132. package/corpus/templates/tasks/.agents/skills/adding-a-feature/SKILL.md +9 -0
  133. package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +115 -68
  134. package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +18 -6
  135. package/corpus/templates/tasks/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  136. package/corpus/templates/tasks/app/components/layout/HeaderActions.tsx +1 -84
  137. package/corpus/templates/tasks/app/hooks/use-mobile.tsx +1 -21
  138. package/corpus/templates/tasks/app/i18n/index.ts +14 -29
  139. package/dist/agent/engine/ai-sdk-engine.js +2 -1
  140. package/dist/agent/engine/builder-engine.d.ts +11 -1
  141. package/dist/agent/engine/builder-engine.js +11 -4
  142. package/dist/agent/engine/openai-compatible-endpoint.d.ts +2 -0
  143. package/dist/agent/engine/openai-compatible-endpoint.js +5 -1
  144. package/dist/agent/engine/provider-endpoint-validation.d.ts +9 -0
  145. package/dist/agent/engine/provider-endpoint-validation.js +26 -0
  146. package/dist/agent/engine/provider-env-vars.d.ts +1 -1
  147. package/dist/agent/engine/provider-env-vars.js +1 -1
  148. package/dist/agent/engine/registry.d.ts +8 -6
  149. package/dist/agent/engine/registry.js +37 -24
  150. package/dist/agent/tool-search.d.ts +1 -0
  151. package/dist/agent/tool-search.js +17 -1
  152. package/dist/automations/service.js +4 -10
  153. package/dist/brand-kit/brand-signals.d.ts +13 -0
  154. package/dist/brand-kit/brand-signals.js +15 -0
  155. package/dist/brand-kit/index.d.ts +2 -2
  156. package/dist/brand-kit/index.js +1 -1
  157. package/dist/chat-threads/store.d.ts +2 -0
  158. package/dist/chat-threads/store.js +1 -1
  159. package/dist/cli/agent-plugin.d.ts +5 -2
  160. package/dist/cli/agent-plugin.js +17 -9
  161. package/dist/cli/code-agent-executor.js +25 -5
  162. package/dist/cli/code-agent-mcp-config.d.ts +21 -0
  163. package/dist/cli/code-agent-mcp-config.js +103 -0
  164. package/dist/cli/plan-blocks.d.ts +3 -18
  165. package/dist/cli/plan-blocks.js +2 -95
  166. package/dist/cli/plan-publish-store.d.ts +2 -61
  167. package/dist/cli/plan-publish-store.js +2 -127
  168. package/dist/cli/skills-content/connection.d.ts +1 -1
  169. package/dist/cli/skills-content/connection.js +1 -52
  170. package/dist/cli/skills-content/visual-recap-skill.d.ts +1 -1
  171. package/dist/cli/skills-content/visual-recap-skill.js +1 -553
  172. package/dist/client/NewWorkspaceAppFlow.js +4 -1
  173. package/dist/client/agent-chat/index.d.ts +4 -1
  174. package/dist/client/agent-chat/index.js +4 -1
  175. package/dist/client/agent-engine-key.d.ts +14 -4
  176. package/dist/client/agent-engine-key.js +51 -5
  177. package/dist/client/agent-page/AgentTabsPage.d.ts +1 -0
  178. package/dist/client/agent-page/AgentTabsPage.js +4 -3
  179. package/dist/client/agent-provider-catalog.d.ts +20 -0
  180. package/dist/client/agent-provider-catalog.js +100 -0
  181. package/dist/client/app-providers.d.ts +3 -1
  182. package/dist/client/app-providers.js +50 -5
  183. package/dist/client/blocks/index.d.ts +1 -0
  184. package/dist/client/blocks/index.js +1 -0
  185. package/dist/client/chat/run-recovery.js +4 -48
  186. package/dist/client/chat/runtime.js +63 -0
  187. package/dist/client/chat-first/agents-pane.d.ts +2 -0
  188. package/dist/client/chat-first/agents-pane.js +6 -0
  189. package/dist/client/chat-first/app-pane.d.ts +2 -0
  190. package/dist/client/chat-first/app-pane.js +6 -0
  191. package/dist/client/chat-first/apps-rail.d.ts +2 -0
  192. package/dist/client/chat-first/apps-rail.js +103 -0
  193. package/dist/client/chat-first/browser-pane.d.ts +2 -0
  194. package/dist/client/chat-first/browser-pane.js +64 -0
  195. package/dist/client/chat-first/chat-history.d.ts +12 -0
  196. package/dist/client/chat-first/chat-history.js +10 -0
  197. package/dist/client/chat-first/copy.d.ts +2 -0
  198. package/dist/client/chat-first/copy.js +117 -0
  199. package/dist/client/chat-first/index.d.ts +13 -0
  200. package/dist/client/chat-first/index.js +12 -0
  201. package/dist/client/chat-first/primary-nav.d.ts +8 -0
  202. package/dist/client/chat-first/primary-nav.js +6 -0
  203. package/dist/client/chat-first/session-watch-pane.d.ts +2 -0
  204. package/dist/client/chat-first/session-watch-pane.js +9 -0
  205. package/dist/client/chat-first/surface-panel.d.ts +9 -0
  206. package/dist/client/chat-first/surface-panel.js +9 -0
  207. package/dist/client/chat-first/surface-tabs.d.ts +9 -0
  208. package/dist/client/chat-first/surface-tabs.js +74 -0
  209. package/dist/client/chat-first/types.d.ts +74 -0
  210. package/dist/client/chat-first/types.js +1 -0
  211. package/dist/client/chat-first-agent-activity.d.ts +11 -0
  212. package/dist/client/chat-first-agent-activity.js +51 -0
  213. package/dist/client/chat-first-surface-panel-toggle.d.ts +5 -0
  214. package/dist/client/chat-first-surface-panel-toggle.js +6 -0
  215. package/dist/client/chat-first.d.ts +208 -0
  216. package/dist/client/chat-first.js +817 -0
  217. package/dist/client/extensions/ExtensionViewer.js +8 -1
  218. package/dist/client/i18n.d.ts +14 -0
  219. package/dist/client/i18n.js +18 -0
  220. package/dist/client/resources/McpIntegrationDialog.js +3 -2
  221. package/dist/client/resources/McpServerDetail.js +6 -11
  222. package/dist/client/resources/index.d.ts +1 -0
  223. package/dist/client/resources/index.js +1 -0
  224. package/dist/client/resources/use-mcp-servers.d.ts +20 -0
  225. package/dist/client/resources/use-mcp-servers.js +82 -46
  226. package/dist/client/settings/ProviderSetupForm.d.ts +21 -0
  227. package/dist/client/settings/ProviderSetupForm.js +145 -0
  228. package/dist/client/settings/SettingsPanel.js +52 -49
  229. package/dist/client/settings/index.d.ts +3 -0
  230. package/dist/client/settings/index.js +3 -0
  231. package/dist/coding-tools/run-code.d.ts +5 -0
  232. package/dist/coding-tools/run-code.js +196 -36
  233. package/dist/coding-tools/tool-orchestration.d.ts +10 -0
  234. package/dist/coding-tools/tool-orchestration.js +107 -0
  235. package/dist/collab/routes.d.ts +1 -1
  236. package/dist/collab/struct-routes.d.ts +1 -1
  237. package/dist/jobs/background-automation-runner.js +19 -2
  238. package/dist/jobs/frontmatter.d.ts +9 -0
  239. package/dist/jobs/frontmatter.js +16 -0
  240. package/dist/jobs/scheduler-health.d.ts +20 -0
  241. package/dist/jobs/scheduler-health.js +86 -1
  242. package/dist/jobs/scheduler.js +46 -9
  243. package/dist/jobs/tools.d.ts +1 -1
  244. package/dist/jobs/tools.js +2 -7
  245. package/dist/localization/default-messages.d.ts +20 -0
  246. package/dist/localization/default-messages.js +25 -5
  247. package/dist/mcp-client/routes.d.ts +3 -0
  248. package/dist/mcp-client/routes.js +14 -0
  249. package/dist/notifications/routes.d.ts +1 -1
  250. package/dist/observability/routes.d.ts +3 -3
  251. package/dist/onboarding/app-profile.js +1 -1
  252. package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
  253. package/dist/provider-api/actions/provider-api.d.ts +11 -11
  254. package/dist/scripts/agent-engines/test-agent-engine.js +34 -10
  255. package/dist/secrets/routes.d.ts +6 -6
  256. package/dist/server/agent-chat/run-code-tools.d.ts +1 -1
  257. package/dist/server/agent-chat/run-code-tools.js +3 -1
  258. package/dist/server/agent-chat-plugin.js +6 -6
  259. package/dist/server/agent-engine-api-key-route.js +43 -12
  260. package/dist/server/agents-bundle.d.ts +2 -0
  261. package/dist/server/agents-bundle.js +32 -2
  262. package/dist/server/auth.js +21 -5
  263. package/dist/server/credential-provider.d.ts +8 -2
  264. package/dist/server/credential-provider.js +14 -9
  265. package/dist/server/design-token-utils.d.ts +18 -0
  266. package/dist/server/design-token-utils.js +31 -0
  267. package/dist/server/onboarding-html.js +22 -2
  268. package/dist/server/transcribe-voice.d.ts +1 -1
  269. package/dist/shared/chat-first-app-creation.d.ts +19 -0
  270. package/dist/shared/chat-first-app-creation.js +75 -0
  271. package/dist/shared/document-title.d.ts +7 -0
  272. package/dist/shared/document-title.js +29 -0
  273. package/dist/shared/index.d.ts +2 -0
  274. package/dist/shared/index.js +2 -0
  275. package/dist/styles/chat-history-list.css +16 -0
  276. package/dist/templates/chat/.agents/skills/adding-a-feature/SKILL.md +9 -0
  277. package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +115 -68
  278. package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -6
  279. package/dist/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  280. package/dist/templates/chat/app/i18n/index.ts +14 -29
  281. package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +9 -0
  282. package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +115 -68
  283. package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +18 -6
  284. package/dist/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  285. package/dist/templates/default/app/i18n/index.ts +14 -29
  286. package/dist/templates/default/react-router.config.ts +18 -0
  287. package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +18 -6
  288. package/dist/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  289. package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +9 -0
  290. package/dist/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +22 -9
  291. package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +115 -68
  292. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +18 -6
  293. package/dist/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  294. package/dist/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +7 -0
  295. package/dist/triggers/dispatcher.js +1 -8
  296. package/docs/content/environment-variables.mdx +39 -38
  297. package/package.json +5 -4
  298. package/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +9 -0
  299. package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +115 -68
  300. package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -6
  301. package/src/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  302. package/src/templates/chat/app/i18n/index.ts +14 -29
  303. package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +9 -0
  304. package/src/templates/default/.agents/skills/frontend-design/SKILL.md +115 -68
  305. package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +18 -6
  306. package/src/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  307. package/src/templates/default/app/i18n/index.ts +14 -29
  308. package/src/templates/default/react-router.config.ts +18 -0
  309. package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +18 -6
  310. package/src/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  311. package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +9 -0
  312. package/src/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +22 -9
  313. package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +115 -68
  314. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +18 -6
  315. package/src/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  316. package/src/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +7 -0
  317. package/corpus/templates/plan/app/components/plan/wireframe/sanitize-html.ts +0 -343
@@ -0,0 +1,107 @@
1
+ import { executeSandboxCode, } from "./run-code.js";
2
+ const DEFAULT_TIMEOUT_MS = 60_000;
3
+ const MAX_TIMEOUT_MS = 120_000;
4
+ const DEFAULT_MAX_OUTPUT_CHARS = 50_000;
5
+ const MAX_OUTPUT_CHARS = 100_000;
6
+ const DEFAULT_MAX_TOOL_CALLS = 32;
7
+ const MAX_TOOL_CALLS = 128;
8
+ /**
9
+ * Create the bounded read-only orchestration tool.
10
+ *
11
+ * This deliberately has a separate registry entry from run-code. The latter
12
+ * retains its existing workspace staging and background-execution contract;
13
+ * this entry is for short fan-out, reduction, and aggregation over tools that
14
+ * the host can prove are read-only for the supplied arguments.
15
+ */
16
+ export function createToolOrchestrationEntry(getActions) {
17
+ return {
18
+ readOnly: true,
19
+ allowInPlanMode: false,
20
+ timeoutMs: MAX_TIMEOUT_MS,
21
+ maxResultChars: MAX_OUTPUT_CHARS,
22
+ tool: {
23
+ description: [
24
+ "Run a bounded JavaScript orchestration script in the existing sandbox.",
25
+ "Use toolSearch(query) to discover read-only or conditionally read-only tools, then toolCall(name, args) to fan out, join, filter, and aggregate their results without putting every intermediate payload into chat. The host rechecks conditional policies against each argument object.",
26
+ "The host rechecks every child call: mutating actions, hidden actions, provider writes, non-GET/HEAD web requests, staging, file saves, and workspace writes are rejected. Call mutations directly as native tools.",
27
+ "The orchestration sandbox has no background mode, a strict child-tool-call budget, and a 20-page cap on each provider fetchAllPages call. It is a bounded orchestration path, not a general-purpose replacement for run-code.",
28
+ "Available globals: toolSearch(query?, options?), toolCall(name, args?), providerFetch(provider, path, init?), providerFetchAll(...), providerSearchAll(...), webFetch(url, init?), webRead(url, init?), workspaceRead(path, opts?), workspaceReadMeta(path, opts?), workspaceList(prefix?), and appAction(name, args?) for eligible read-only actions.",
29
+ "Print only the compact result needed by the conversation with console.log().",
30
+ ].join(" "),
31
+ parameters: {
32
+ type: "object",
33
+ properties: {
34
+ code: {
35
+ type: "string",
36
+ description: "JavaScript source to execute. ESM syntax and top-level await are supported.",
37
+ },
38
+ timeoutMs: {
39
+ type: "number",
40
+ description: `Execution timeout in milliseconds. Default: ${DEFAULT_TIMEOUT_MS}; max: ${MAX_TIMEOUT_MS}.`,
41
+ },
42
+ maxOutputChars: {
43
+ type: "number",
44
+ description: `Maximum combined stdout+stderr characters. Default: ${DEFAULT_MAX_OUTPUT_CHARS}; max: ${MAX_OUTPUT_CHARS}.`,
45
+ },
46
+ maxToolCalls: {
47
+ type: "number",
48
+ description: `Maximum bridged child-tool calls. Default: ${DEFAULT_MAX_TOOL_CALLS}; max: ${MAX_TOOL_CALLS}.`,
49
+ },
50
+ },
51
+ required: ["code"],
52
+ },
53
+ },
54
+ run: async (args, context) => {
55
+ if (args.background || args.executionId) {
56
+ return "Error: tool-orchestration is foreground-only and does not support background or polling arguments. Use run-code for durable long-running execution.";
57
+ }
58
+ const code = typeof args.code === "string" ? args.code : "";
59
+ if (!code.trim())
60
+ return "Error: code is required.";
61
+ const requestedTimeout = Number(args.timeoutMs);
62
+ const timeoutMs = Number.isFinite(requestedTimeout) && requestedTimeout > 0
63
+ ? Math.min(requestedTimeout, MAX_TIMEOUT_MS)
64
+ : DEFAULT_TIMEOUT_MS;
65
+ const requestedOutput = Number(args.maxOutputChars);
66
+ const maxOutputChars = Number.isFinite(requestedOutput) && requestedOutput > 0
67
+ ? Math.min(requestedOutput, MAX_OUTPUT_CHARS)
68
+ : DEFAULT_MAX_OUTPUT_CHARS;
69
+ const requestedCalls = Number(args.maxToolCalls);
70
+ const maxToolCalls = Number.isFinite(requestedCalls) && requestedCalls > 0
71
+ ? Math.min(Math.floor(requestedCalls), MAX_TOOL_CALLS)
72
+ : DEFAULT_MAX_TOOL_CALLS;
73
+ const result = await executeSandboxCode({
74
+ code,
75
+ timeoutMs,
76
+ getActions,
77
+ mode: "tool-orchestration",
78
+ maxToolCalls,
79
+ context,
80
+ });
81
+ return formatResult(result, timeoutMs, maxOutputChars);
82
+ },
83
+ };
84
+ }
85
+ function formatResult(result, timeoutMs, maxOutputChars) {
86
+ const combined = [
87
+ result.stdout ? `stdout:\n${result.stdout}` : "",
88
+ result.stderr ? `stderr:\n${result.stderr}` : "",
89
+ ]
90
+ .filter(Boolean)
91
+ .join("\n\n") || "(no output)";
92
+ const lines = [];
93
+ if (result.timedOut)
94
+ lines.push(`timedOut: true (${timeoutMs}ms)`);
95
+ if (result.exitCode !== 0 && result.exitCode !== null) {
96
+ lines.push(`exitCode: ${result.exitCode}`);
97
+ }
98
+ if (result.bridgeToolsUsed.length) {
99
+ lines.push(`bridgeToolsUsed: ${result.bridgeToolsUsed.join(", ")}`);
100
+ }
101
+ lines.push(combined);
102
+ const full = lines.join("\n\n");
103
+ if (full.length <= maxOutputChars)
104
+ return full;
105
+ const truncated = full.slice(0, maxOutputChars);
106
+ return `${truncated}\n\n...[truncated ${(full.length - maxOutputChars).toLocaleString()} chars]`;
107
+ }
@@ -26,8 +26,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
26
26
  * Body: { update: string (base64), requestSource?: string }
27
27
  */
28
28
  export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
29
- error: string;
30
29
  ok?: undefined;
30
+ error: string;
31
31
  } | {
32
32
  error?: undefined;
33
33
  ok: boolean;
@@ -13,8 +13,8 @@
13
13
  * Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
14
14
  */
15
15
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
16
- error: string;
17
16
  ok?: undefined;
17
+ error: string;
18
18
  } | {
19
19
  error?: undefined;
20
20
  ok: boolean;
@@ -1,4 +1,5 @@
1
1
  import { collectFinalResponseTextFromAgentEvents } from "../a2a/response-text.js";
2
+ import { createBuilderEngine } from "../agent/engine/builder-engine.js";
2
3
  import { getStoredModelForEngine, normalizeModelForEngine, resolveEngine, } from "../agent/engine/index.js";
3
4
  import { actionsToEngineTools, filterInitialEngineTools, getOwnerActiveApiKey, } from "../agent/production-agent.js";
4
5
  import { runAgentLoopDirectWithSoftTimeout } from "../agent/run-loop-with-resume.js";
@@ -9,6 +10,7 @@ import { resolveAutomationExecutionIdentity, } from "../automations/service.js";
9
10
  import { createThread } from "../chat-threads/store.js";
10
11
  import { queryOrgMembers } from "../org/context.js";
11
12
  import { organizationIdFromResourceOwner, organizationResourceOwner, } from "../resources/store.js";
13
+ import { resolveBuilderCredentialsDetailed } from "../server/credential-provider.js";
12
14
  import { runWithRequestContext, } from "../server/request-context.js";
13
15
  import { attachAutomationRunThread, finishAutomationRun, startAutomationRun, } from "./run-history.js";
14
16
  const BACKGROUND_RUN_STUCK_MS = 10 * 60_000;
@@ -236,18 +238,33 @@ async function executeBackgroundAutomation(options, deps, historyId) {
236
238
  const availableTools = actionsToEngineTools(actions);
237
239
  const tools = filterInitialEngineTools(availableTools, initialToolNames);
238
240
  const userApiKey = await getOwnerActiveApiKey(ownerEmail);
239
- const engine = deps.engine ??
241
+ const resolvedEngine = deps.engine ??
240
242
  (await resolveEngine({
241
243
  apiKey: userApiKey ?? deps.apiKey,
242
244
  appId: deps.appId,
243
245
  }));
246
+ // The run manager invokes its detached callback after the scheduler's
247
+ // setup stack has yielded. Capture the verified Builder pair while the
248
+ // owner/org identity is explicit, then keep it on the engine so a
249
+ // concurrent serverless run cannot make this call look unauthenticated.
250
+ const engine = !deps.engine && resolvedEngine.name === "builder"
251
+ ? createBuilderEngine({
252
+ credentials: await resolveBuilderCredentialsDetailed({
253
+ userEmail: ownerEmail,
254
+ orgId,
255
+ }),
256
+ })
257
+ : resolvedEngine;
244
258
  const modelCandidate = automation.meta.model ??
245
259
  deps.model ??
246
260
  (await getStoredModelForEngine(engine, { appId: deps.appId })) ??
247
261
  engine.defaultModel;
248
262
  const model = normalizeModelForEngine(engine, modelCandidate);
249
263
  const systemPrompt = await deps.getSystemPrompt(ownerEmail);
250
- const thread = await createThread(ownerEmail, { title: threadTitle });
264
+ const thread = await createThread(ownerEmail, {
265
+ title: threadTitle,
266
+ orgId: orgId ?? null,
267
+ });
251
268
  const runId = createRunId(options.runIdPrefix);
252
269
  await recordRunThread(historyId, thread.id, runId);
253
270
  // Scheduled work is background work: it has no synchronous serverless
@@ -54,6 +54,15 @@ export interface JobFrontmatter {
54
54
  */
55
55
  delegatedPolicyId?: string;
56
56
  }
57
+ /**
58
+ * Return whether a scheduler or trigger dispatcher may claim this resource.
59
+ *
60
+ * Personal legacy jobs have no app owner and remain compatible with the
61
+ * shared scheduler. An organization-owned resource without an explicit app
62
+ * owner is ambiguous, though: letting every installed app claim it can run
63
+ * the same job multiple times and with the wrong deployment credentials.
64
+ */
65
+ export declare function jobBelongsToApp(meta: Pick<JobFrontmatter, "appId" | "orgId">, appId: string | null | undefined): boolean;
57
66
  export interface JobResourceClassification {
58
67
  kind: "job" | "automation";
59
68
  hasExplicitTriggerType: boolean;
@@ -1,3 +1,19 @@
1
+ /**
2
+ * Return whether a scheduler or trigger dispatcher may claim this resource.
3
+ *
4
+ * Personal legacy jobs have no app owner and remain compatible with the
5
+ * shared scheduler. An organization-owned resource without an explicit app
6
+ * owner is ambiguous, though: letting every installed app claim it can run
7
+ * the same job multiple times and with the wrong deployment credentials.
8
+ */
9
+ export function jobBelongsToApp(meta, appId) {
10
+ const ownerAppId = meta.appId?.trim();
11
+ if (ownerAppId) {
12
+ const schedulerAppId = appId?.trim();
13
+ return Boolean(schedulerAppId && ownerAppId === schedulerAppId);
14
+ }
15
+ return !meta.orgId?.trim();
16
+ }
1
17
  const MAX_JOB_MCP_TOOLS = 64;
2
18
  const JOB_MCP_TOOL_NAME_RE = /^mcp__[^\s]+__[^\s]+$/;
3
19
  const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n)?([\s\S]*)$/;
@@ -1,4 +1,6 @@
1
1
  import { type MigrationEntry } from "../db/migrations.js";
2
+ export declare const AUTOMATION_SCHEDULER_LEASE_MS: number;
3
+ export declare const AUTOMATION_SCHEDULER_LEASE_RENEWAL_MS = 60000;
2
4
  /** Authoritative release-time schema for recurring scheduler health. */
3
5
  export declare const AUTOMATION_SCHEDULER_HEALTH_MIGRATIONS: MigrationEntry[];
4
6
  export declare function runAutomationSchedulerHealthMigrations(nitroApp: unknown): Promise<void>;
@@ -11,6 +13,24 @@ export interface AutomationSchedulerHealth {
11
13
  runtime: string | null;
12
14
  updatedAt: number | null;
13
15
  }
16
+ /** Claim one recurring scheduler across all deployments of an app. */
17
+ export declare function acquireAutomationSchedulerLease(input?: {
18
+ appId?: string;
19
+ now?: number;
20
+ leaseMs?: number;
21
+ }): Promise<string | null>;
22
+ /** Renew a lease while a slow sweep is still executing. */
23
+ export declare function renewAutomationSchedulerLease(input: {
24
+ appId?: string;
25
+ owner: string;
26
+ now?: number;
27
+ leaseMs?: number;
28
+ }): Promise<boolean>;
29
+ /** Release only the lease owned by this invocation. */
30
+ export declare function releaseAutomationSchedulerLease(input: {
31
+ appId?: string;
32
+ owner: string;
33
+ }): Promise<void>;
14
34
  /** Record the last scheduler tick without making health bookkeeping fatal. */
15
35
  export declare function recordAutomationSchedulerHealth(input: {
16
36
  appId?: string;
@@ -1,9 +1,12 @@
1
+ import { randomUUID } from "node:crypto";
1
2
  import { getDbExec, intType, isPostgres } from "../db/client.js";
2
3
  import { ensureColumnExists, ensureIndexExists, ensureTableExists, } from "../db/ddl-guard.js";
3
4
  import { runMigrations } from "../db/migrations.js";
4
5
  const TABLE = "automation_scheduler_health";
5
6
  const DEFAULT_APP_ID = "default";
6
7
  const MAX_ERROR_LENGTH = 500;
8
+ export const AUTOMATION_SCHEDULER_LEASE_MS = 10 * 60_000;
9
+ export const AUTOMATION_SCHEDULER_LEASE_RENEWAL_MS = 60_000;
7
10
  /** Authoritative release-time schema for recurring scheduler health. */
8
11
  export const AUTOMATION_SCHEDULER_HEALTH_MIGRATIONS = [
9
12
  {
@@ -30,6 +33,14 @@ export const AUTOMATION_SCHEDULER_HEALTH_MIGRATIONS = [
30
33
  CREATE INDEX IF NOT EXISTS idx_${TABLE}_updated ON ${TABLE} (updated_at)
31
34
  `,
32
35
  },
36
+ {
37
+ version: 2,
38
+ name: "automation-scheduler-health-lease",
39
+ sql: `
40
+ ALTER TABLE ${TABLE} ADD COLUMN IF NOT EXISTS lease_owner TEXT;
41
+ ALTER TABLE ${TABLE} ADD COLUMN IF NOT EXISTS lease_expires_at INTEGER;
42
+ `,
43
+ },
33
44
  ];
34
45
  export async function runAutomationSchedulerHealthMigrations(nitroApp) {
35
46
  await runMigrations(AUTOMATION_SCHEDULER_HEALTH_MIGRATIONS, {
@@ -56,7 +67,9 @@ async function ensureHealthTable() {
56
67
  last_dispatched_at ${intType()},
57
68
  last_error TEXT,
58
69
  runtime TEXT,
59
- updated_at ${intType()} NOT NULL
70
+ updated_at ${intType()} NOT NULL,
71
+ lease_owner TEXT,
72
+ lease_expires_at ${intType()}
60
73
  )
61
74
  `;
62
75
  const indexSql = `CREATE INDEX IF NOT EXISTS idx_${TABLE}_updated ON ${TABLE} (updated_at)`;
@@ -69,6 +82,8 @@ async function ensureHealthTable() {
69
82
  await ensureColumnExists(TABLE, "last_error", `ALTER TABLE ${TABLE} ADD COLUMN IF NOT EXISTS last_error TEXT`);
70
83
  await ensureColumnExists(TABLE, "runtime", `ALTER TABLE ${TABLE} ADD COLUMN IF NOT EXISTS runtime TEXT`);
71
84
  await ensureColumnExists(TABLE, "updated_at", `ALTER TABLE ${TABLE} ADD COLUMN IF NOT EXISTS updated_at ${intType()}`);
85
+ await ensureColumnExists(TABLE, "lease_owner", `ALTER TABLE ${TABLE} ADD COLUMN IF NOT EXISTS lease_owner TEXT`);
86
+ await ensureColumnExists(TABLE, "lease_expires_at", `ALTER TABLE ${TABLE} ADD COLUMN IF NOT EXISTS lease_expires_at ${intType()}`);
72
87
  await ensureIndexExists(`idx_${TABLE}_updated`, indexSql);
73
88
  return;
74
89
  }
@@ -84,6 +99,8 @@ async function ensureHealthTable() {
84
99
  ["last_error", "TEXT"],
85
100
  ["runtime", "TEXT"],
86
101
  ["updated_at", `${intType()} NOT NULL DEFAULT 0`],
102
+ ["lease_owner", "TEXT"],
103
+ ["lease_expires_at", `${intType()}`],
87
104
  ]) {
88
105
  if (columns.has(name))
89
106
  continue;
@@ -106,6 +123,74 @@ async function ensureHealthTable() {
106
123
  }
107
124
  return initPromise;
108
125
  }
126
+ function isUniqueViolation(error) {
127
+ const candidate = error;
128
+ return (candidate?.code === "23505" ||
129
+ /unique|duplicate|already exists/i.test(String(candidate?.message ?? error)));
130
+ }
131
+ function leaseRowId(appId) {
132
+ return rowIdForScope(appId, null);
133
+ }
134
+ /** Claim one recurring scheduler across all deployments of an app. */
135
+ export async function acquireAutomationSchedulerLease(input = {}) {
136
+ await ensureHealthTable();
137
+ const appId = normalizeAppId(input.appId);
138
+ const id = leaseRowId(appId);
139
+ const now = input.now ?? Date.now();
140
+ const leaseMs = Math.max(input.leaseMs ?? AUTOMATION_SCHEDULER_LEASE_MS, AUTOMATION_SCHEDULER_LEASE_RENEWAL_MS * 2);
141
+ const owner = randomUUID();
142
+ const expiresAt = now + leaseMs;
143
+ const client = getDbExec();
144
+ try {
145
+ await client.execute({
146
+ sql: `INSERT INTO ${TABLE}
147
+ (id, app_id, org_id, last_checked_at, last_dispatched_at, last_error, runtime, updated_at, lease_owner, lease_expires_at)
148
+ VALUES (?, ?, NULL, NULL, NULL, NULL, 'recurring-jobs', ?, ?, ?)`,
149
+ args: [id, appId, now, owner, expiresAt],
150
+ });
151
+ return owner;
152
+ }
153
+ catch (error) {
154
+ if (!isUniqueViolation(error))
155
+ throw error;
156
+ }
157
+ const result = await client.execute({
158
+ sql: `UPDATE ${TABLE}
159
+ SET lease_owner = ?, lease_expires_at = ?, updated_at = ?
160
+ WHERE id = ?
161
+ AND (lease_owner IS NULL OR lease_expires_at IS NULL OR lease_expires_at <= ?)`,
162
+ args: [owner, expiresAt, now, id, now],
163
+ });
164
+ return Number(result.rowsAffected ?? 0) > 0 ? owner : null;
165
+ }
166
+ /** Renew a lease while a slow sweep is still executing. */
167
+ export async function renewAutomationSchedulerLease(input) {
168
+ await ensureHealthTable();
169
+ const now = input.now ?? Date.now();
170
+ const expiresAt = now + Math.max(input.leaseMs ?? AUTOMATION_SCHEDULER_LEASE_MS, 0);
171
+ const result = await getDbExec().execute({
172
+ sql: `UPDATE ${TABLE}
173
+ SET lease_expires_at = ?, updated_at = ?
174
+ WHERE id = ? AND lease_owner = ?`,
175
+ args: [
176
+ expiresAt,
177
+ now,
178
+ leaseRowId(normalizeAppId(input.appId)),
179
+ input.owner,
180
+ ],
181
+ });
182
+ return Number(result.rowsAffected ?? 0) > 0;
183
+ }
184
+ /** Release only the lease owned by this invocation. */
185
+ export async function releaseAutomationSchedulerLease(input) {
186
+ await ensureHealthTable();
187
+ await getDbExec().execute({
188
+ sql: `UPDATE ${TABLE}
189
+ SET lease_owner = NULL, lease_expires_at = NULL, updated_at = ?
190
+ WHERE id = ? AND lease_owner = ?`,
191
+ args: [Date.now(), leaseRowId(normalizeAppId(input.appId)), input.owner],
192
+ });
193
+ }
109
194
  function fromRow(row) {
110
195
  return {
111
196
  appId: String(row.app_id ?? DEFAULT_APP_ID),
@@ -1,9 +1,9 @@
1
1
  import { resourceGetByPath, resourceListAllOwners, resourcePutIfCurrent, } from "../resources/store.js";
2
2
  import { backgroundRunCutOffReason, isBackgroundAutomationRunActive, resolveBackgroundAutomationIdentity, runBackgroundAutomation, } from "./background-automation-runner.js";
3
3
  import { nextOccurrence, isValidCron, describeCron, effectiveTimezone, } from "./cron.js";
4
- import { buildJobResourceContent, parseJobResource, } from "./frontmatter.js";
4
+ import { buildJobResourceContent, jobBelongsToApp, parseJobResource, } from "./frontmatter.js";
5
5
  import { claimAutomationRun, finishAutomationRun, getAutomationRun, listAutomationRuns, } from "./run-history.js";
6
- import { recordAutomationSchedulerHealth } from "./scheduler-health.js";
6
+ import { acquireAutomationSchedulerLease, recordAutomationSchedulerHealth, releaseAutomationSchedulerLease, renewAutomationSchedulerLease, AUTOMATION_SCHEDULER_LEASE_RENEWAL_MS, } from "./scheduler-health.js";
7
7
  // ─── Frontmatter parsing ────────────────────────────────────────────────────
8
8
  export { classifyJobFrontmatter, classifyJobResource, normalizeJobMcpTools, parseJobResource, } from "./frontmatter.js";
9
9
  export function parseJobFrontmatter(content) {
@@ -18,13 +18,6 @@ const MAX_IDENTITY_PREFLIGHTS_PER_TICK = MAX_CONCURRENT_SCHEDULED_JOBS * 4;
18
18
  const IDENTITY_FAILURE_RETRY_MS = 5 * 60_000;
19
19
  const _activeScheduledJobs = new Set();
20
20
  const _preflightingScheduledJobs = new Set();
21
- function jobBelongsToApp(meta, appId) {
22
- const ownerAppId = meta.appId?.trim();
23
- if (!ownerAppId)
24
- return true;
25
- const schedulerAppId = appId?.trim();
26
- return Boolean(schedulerAppId && ownerAppId === schedulerAppId);
27
- }
28
21
  // Skip the DB query on every tick if we recently confirmed no jobs exist.
29
22
  // `_hasJobsCache` is invalidated whenever a `jobs/*` resource is written or
30
23
  // deleted (subscribed below), and refreshed at most every 5 minutes.
@@ -74,6 +67,43 @@ function subscribeToJobsResourceEvents() {
74
67
  * one job cannot run twice while leaving other due jobs waiting behind it.
75
68
  */
76
69
  export async function processRecurringJobs(deps) {
70
+ const leaseOwner = await acquireAutomationSchedulerLease({
71
+ appId: deps.appId,
72
+ });
73
+ if (!leaseOwner)
74
+ return;
75
+ const leaseRenewal = setInterval(() => {
76
+ void renewAutomationSchedulerLease({
77
+ appId: deps.appId,
78
+ owner: leaseOwner,
79
+ }).catch((error) => {
80
+ console.warn("[recurring-jobs] Scheduler lease renewal failed:", error instanceof Error ? error.message : error);
81
+ });
82
+ }, AUTOMATION_SCHEDULER_LEASE_RENEWAL_MS);
83
+ let primaryFailed = false;
84
+ try {
85
+ await processRecurringJobsWithLease(deps);
86
+ }
87
+ catch (error) {
88
+ primaryFailed = true;
89
+ throw error;
90
+ }
91
+ finally {
92
+ clearInterval(leaseRenewal);
93
+ try {
94
+ await releaseAutomationSchedulerLease({
95
+ appId: deps.appId,
96
+ owner: leaseOwner,
97
+ });
98
+ }
99
+ catch (releaseError) {
100
+ console.warn("[recurring-jobs] Scheduler lease release failed:", releaseError instanceof Error ? releaseError.message : releaseError);
101
+ if (!primaryFailed)
102
+ throw releaseError;
103
+ }
104
+ }
105
+ }
106
+ async function processRecurringJobsWithLease(deps) {
77
107
  subscribeToJobsResourceEvents();
78
108
  // Skip if we recently confirmed there are no job resources to run.
79
109
  const nowMs = Date.now();
@@ -392,6 +422,13 @@ async function executeJob(resource, meta, body, deps, now, options = {}) {
392
422
  requestContext,
393
423
  ...(options.historyId ? { historyId: options.historyId } : {}),
394
424
  actionCaller: "automation",
425
+ actionAutomation: {
426
+ triggerId: resource.id,
427
+ triggerName: jobName,
428
+ ...(meta.delegatedPolicyId
429
+ ? { policyId: meta.delegatedPolicyId }
430
+ : {}),
431
+ },
395
432
  }, deps);
396
433
  await recordExecutionOutcome(resource, {
397
434
  lastRun: meta.lastRun,
@@ -1,6 +1,6 @@
1
1
  import type { ActionEntry } from "../agent/production-agent.js";
2
2
  import { type JobFrontmatter } from "./scheduler.js";
3
- export declare function jobBelongsToApp(meta: JobFrontmatter, appId?: string): boolean;
3
+ export { jobBelongsToApp } from "./frontmatter.js";
4
4
  /**
5
5
  * Authorise a mutation (update / delete) against a job resource. When the
6
6
  * job is in the SHARED scope the caller must either be the original
@@ -3,8 +3,9 @@ import { resolveUserSchedulingTimezone } from "../localization/user-timezone.js"
3
3
  import { resourcePut, resourceGetByPath, resourceList, resourceDelete, organizationIdFromResourceOwner, sharedResourceOwner, SHARED_OWNER, } from "../resources/store.js";
4
4
  import { getRequestUserEmail, getRequestOrgId, getIntegrationRequestContext, } from "../server/request-context.js";
5
5
  import { isValidCron, nextOccurrence, describeCron, effectiveTimezone, isValidTimezone, } from "./cron.js";
6
- import { classifyJobResource } from "./frontmatter.js";
6
+ import { classifyJobResource, jobBelongsToApp } from "./frontmatter.js";
7
7
  import { parseJobFrontmatter, buildJobContent, normalizeJobMcpTools, } from "./scheduler.js";
8
+ export { jobBelongsToApp } from "./frontmatter.js";
8
9
  function getOwner() {
9
10
  const email = getRequestUserEmail();
10
11
  if (!email)
@@ -14,12 +15,6 @@ function getOwner() {
14
15
  function getSharedOwner() {
15
16
  return sharedResourceOwner(getRequestOrgId());
16
17
  }
17
- export function jobBelongsToApp(meta, appId) {
18
- const ownerAppId = meta.appId?.trim();
19
- if (!ownerAppId)
20
- return true;
21
- return ownerAppId === appId?.trim();
22
- }
23
18
  /**
24
19
  * Determine if the current request's user is an org owner/admin in the
25
20
  * given org. Used to allow privileged users to update or delete shared
@@ -455,6 +455,26 @@ declare const messages: {
455
455
  builderModelCredits: string;
456
456
  addOwnKeys: string;
457
457
  configureProviderKeys: string;
458
+ chooseProvider: string;
459
+ searchProviders: string;
460
+ noProvidersFound: string;
461
+ availableProviders: string;
462
+ configured: string;
463
+ apiKey: string;
464
+ localRuntime: string;
465
+ enterApiKey: string;
466
+ providerSetupFailed: string;
467
+ noApiKeyNeeded: string;
468
+ modelId: string;
469
+ endpointUrl: string;
470
+ optional: string;
471
+ ollamaEndpointHint: string;
472
+ compatibleEndpointHint: string;
473
+ savingProvider: string;
474
+ providerSaved: string;
475
+ useProvider: string;
476
+ saveAndUseProvider: string;
477
+ getApiKey: string;
458
478
  checkingAiConnection: string;
459
479
  delegatedAgent: {
460
480
  asking: string;
@@ -389,7 +389,7 @@ const messages = {
389
389
  threadDebugRefreshFailures: "Refresh failed runs",
390
390
  threadDebugNoFailures: "No failed runs found.",
391
391
  threadDebugCurrentDatabase: "Current Dispatch DB",
392
- threadDebugSearchPlaceholder: "Search title, preview, messages, tools",
392
+ threadDebugSearchPlaceholder: "Search threads or email",
393
393
  threadDebugSearch: "Search",
394
394
  threadDebugLookupPlaceholder: "Paste thread or request/run ID",
395
395
  threadDebugInspect: "Inspect",
@@ -455,12 +455,32 @@ const messages = {
455
455
  askAgentTitle: "Ask the agent",
456
456
  askAgentPlaceholder: "Tell the agent what you want to do…",
457
457
  connectAi: "Connect AI",
458
- builderOrOwnKeys: "Use Builder.io free credits, or add your own provider keys.",
458
+ builderOrOwnKeys: "Choose Builder.io or custom keys.",
459
459
  connectBuilderIo: "Connect Builder.io",
460
460
  connectingBuilder: "Connecting Builder.io…",
461
461
  builderModelCredits: "Free credits for Claude, OpenAI & Gemini",
462
- addOwnKeys: "Add your own keys",
463
- configureProviderKeys: "Configure Anthropic, OpenAI, or another provider",
462
+ addOwnKeys: "Custom keys",
463
+ configureProviderKeys: "Choose a provider.",
464
+ chooseProvider: "Choose a provider",
465
+ searchProviders: "Search providers...",
466
+ noProvidersFound: "No providers found.",
467
+ availableProviders: "Available providers",
468
+ configured: "Configured",
469
+ apiKey: "API key",
470
+ localRuntime: "Local",
471
+ enterApiKey: "Enter your {{provider}} API key.",
472
+ providerSetupFailed: "Could not configure this provider.",
473
+ noApiKeyNeeded: "No API key required.",
474
+ modelId: "Model ID",
475
+ endpointUrl: "Endpoint URL",
476
+ optional: "Optional",
477
+ ollamaEndpointHint: "Defaults to Ollama at http://localhost:11434.",
478
+ compatibleEndpointHint: "Use this for LiteLLM or another OpenAI-compatible gateway.",
479
+ savingProvider: "Saving...",
480
+ providerSaved: "Connected",
481
+ useProvider: "Use {{provider}}",
482
+ saveAndUseProvider: "Save and use {{provider}}",
483
+ getApiKey: "Get an API key",
464
484
  checkingAiConnection: "Checking AI connection...",
465
485
  delegatedAgent: {
466
486
  asking: "Asking {{name}}...",
@@ -475,7 +495,7 @@ const messages = {
475
495
  setupTitle: "Set up voice mode",
476
496
  setupDescription: "Connect Builder.io to use managed voice with free credits, or add your own keys.",
477
497
  connectBuilder: "Connect Builder.io",
478
- useOpenAiKey: "Add your own keys",
498
+ useOpenAiKey: "Custom keys",
479
499
  startWithOpenAiKey: "Start with OpenAI key",
480
500
  start: "Real-time voice",
481
501
  keepDictating: "Dictate",
@@ -6,6 +6,9 @@
6
6
  * hot-reload the configured server set.
7
7
  *
8
8
  * GET /_agent-native/mcp/servers list user + org servers
9
+ * GET /_agent-native/mcp/servers/runtime-config
10
+ * reserved; returns 410 until a
11
+ * desktop capability broker exists
9
12
  * POST /_agent-native/mcp/servers add a server
10
13
  * DELETE /_agent-native/mcp/servers/:id remove a server (scope via ?scope=)
11
14
  * POST /_agent-native/mcp/servers/:id/test dry-run connect (no persist)
@@ -6,6 +6,9 @@
6
6
  * hot-reload the configured server set.
7
7
  *
8
8
  * GET /_agent-native/mcp/servers list user + org servers
9
+ * GET /_agent-native/mcp/servers/runtime-config
10
+ * reserved; returns 410 until a
11
+ * desktop capability broker exists
9
12
  * POST /_agent-native/mcp/servers add a server
10
13
  * DELETE /_agent-native/mcp/servers/:id remove a server (scope via ?scope=)
11
14
  * POST /_agent-native/mcp/servers/:id/test dry-run connect (no persist)
@@ -344,6 +347,11 @@ export function mountMcpServersRoutes(nitroApp, manager, options = {}) {
344
347
  .replace(/\/+$/, "");
345
348
  const parts = pathname ? pathname.split("/") : [];
346
349
  setResponseHeader(event, "Content-Type", "application/json");
350
+ if (method === "GET" &&
351
+ parts.length === 1 &&
352
+ parts[0] === "runtime-config") {
353
+ return handleRuntimeConfig(event);
354
+ }
347
355
  // POST /servers/test — dry-run a URL+headers before persisting
348
356
  if (method === "POST" && parts.length === 1 && parts[0] === "test") {
349
357
  return handleTestUrl(event);
@@ -700,6 +708,12 @@ async function handleList(event, manager) {
700
708
  role,
701
709
  };
702
710
  }
711
+ function handleRuntimeConfig(event) {
712
+ setResponseStatus(event, 410);
713
+ return {
714
+ error: "Cleartext MCP runtime config requires a desktop capability broker and is not available over session-authenticated HTTP.",
715
+ };
716
+ }
703
717
  async function handleAdd(event, manager) {
704
718
  const body = (await readBody(event).catch(() => ({})));
705
719
  const scope = body.scope === "org" ? "org" : body.scope === "user" ? "user" : null;
@@ -28,6 +28,6 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
28
28
  } | {
29
29
  count?: undefined;
30
30
  updated?: undefined;
31
- ok: boolean;
32
31
  error?: undefined;
32
+ ok: boolean;
33
33
  }>>;
@@ -41,16 +41,16 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
41
41
  thumbsUpRate: number;
42
42
  avgEvalScore: number;
43
43
  } | {
44
+ error?: undefined;
44
45
  summary: import("./types.js").TraceSummary;
45
46
  spans: import("./types.js").TraceSpan[];
46
47
  id?: undefined;
47
- error?: undefined;
48
48
  ok?: undefined;
49
49
  } | {
50
+ error?: undefined;
50
51
  summary?: undefined;
51
52
  spans?: undefined;
52
53
  id: string;
53
- error?: undefined;
54
54
  ok?: undefined;
55
55
  } | {
56
56
  summary?: undefined;
@@ -59,9 +59,9 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
59
59
  error: any;
60
60
  ok?: undefined;
61
61
  } | {
62
+ error?: undefined;
62
63
  summary?: undefined;
63
64
  spans?: undefined;
64
65
  id?: undefined;
65
66
  ok: boolean;
66
- error?: undefined;
67
67
  }>>;