@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
@@ -8,8 +8,9 @@
8
8
  * LLM settings panel does — UI code should call this instead of hand-writing
9
9
  * a fetch to framework routes.
10
10
  */
11
+ import { type AgentProviderId } from "./agent-provider-catalog.js";
11
12
  /** Providers that can be configured with a single pasted API key. */
12
- export type AgentEngineProvider = "anthropic" | "openai";
13
+ export type AgentEngineProvider = AgentProviderId;
13
14
  export interface SaveAgentEngineApiKeyOptions {
14
15
  provider?: AgentEngineProvider;
15
16
  key?: string;
@@ -32,8 +33,17 @@ export interface SaveAgentEngineProviderSettingsOptions {
32
33
  */
33
34
  export declare function saveAgentEngineApiKey({ provider, key, apiKey, scope, }: SaveAgentEngineApiKeyOptions): Promise<void>;
34
35
  /**
35
- * Persist provider-specific settings for the current owner. This intentionally
36
- * stays narrow: API keys for built-in BYOK providers, plus OpenAI's optional
37
- * compatible endpoint URL. Values are stored server-side in scoped secrets.
36
+ * Persist provider-specific settings for the current owner. This covers
37
+ * built-in BYOK provider keys plus optional OpenAI-compatible and Ollama
38
+ * endpoint URLs. Values are stored server-side in scoped secrets.
38
39
  */
39
40
  export declare function saveAgentEngineProviderSettings({ provider, key, apiKey, baseUrl, clearBaseUrl, scope, }: SaveAgentEngineProviderSettingsOptions): Promise<void>;
41
+ /**
42
+ * Select the provider and model for the next conversation. This is separate
43
+ * from saving credentials so keyless local providers such as Ollama can use
44
+ * the same setup surface as API-key providers.
45
+ */
46
+ export declare function setAgentEngineProvider({ provider, model, }: {
47
+ provider: AgentEngineProvider;
48
+ model?: string;
49
+ }): Promise<void>;
@@ -8,10 +8,15 @@
8
8
  * LLM settings panel does — UI code should call this instead of hand-writing
9
9
  * a fetch to framework routes.
10
10
  */
11
+ import { OLLAMA_BASE_URL_ENV_VAR, PROVIDER_ENV_META, } from "../agent/engine/provider-env-vars.js";
12
+ import { getAgentProviderOption, } from "./agent-provider-catalog.js";
11
13
  import { agentNativePath } from "./api-path.js";
12
14
  const PROVIDER_ENV_VAR = {
13
- anthropic: "ANTHROPIC_API_KEY",
14
- openai: "OPENAI_API_KEY",
15
+ ...Object.fromEntries(Object.entries(PROVIDER_ENV_META).map(([provider, meta]) => [
16
+ provider,
17
+ meta.envVar,
18
+ ])),
19
+ ollama: OLLAMA_BASE_URL_ENV_VAR,
15
20
  };
16
21
  /** Event other parts of the agent UI listen for to re-check the LLM gate. */
17
22
  const CONFIGURED_CHANGED_EVENT = "agent-engine:configured-changed";
@@ -40,9 +45,9 @@ export async function saveAgentEngineApiKey({ provider, key, apiKey, scope, }) {
40
45
  await saveAgentEngineProviderSettings({ provider, key, apiKey, scope });
41
46
  }
42
47
  /**
43
- * Persist provider-specific settings for the current owner. This intentionally
44
- * stays narrow: API keys for built-in BYOK providers, plus OpenAI's optional
45
- * compatible endpoint URL. Values are stored server-side in scoped secrets.
48
+ * Persist provider-specific settings for the current owner. This covers
49
+ * built-in BYOK provider keys plus optional OpenAI-compatible and Ollama
50
+ * endpoint URLs. Values are stored server-side in scoped secrets.
46
51
  */
47
52
  export async function saveAgentEngineProviderSettings({ provider, key, apiKey, baseUrl, clearBaseUrl, scope, }) {
48
53
  const trimmed = apiKey?.trim() ?? "";
@@ -74,3 +79,44 @@ export async function saveAgentEngineProviderSettings({ provider, key, apiKey, b
74
79
  }
75
80
  dispatchConfiguredChanged();
76
81
  }
82
+ /**
83
+ * Select the provider and model for the next conversation. This is separate
84
+ * from saving credentials so keyless local providers such as Ollama can use
85
+ * the same setup surface as API-key providers.
86
+ */
87
+ export async function setAgentEngineProvider({ provider, model, }) {
88
+ const option = getAgentProviderOption(provider);
89
+ const res = await fetch(agentNativePath("/_agent-native/actions/manage-agent-engine"), {
90
+ method: "POST",
91
+ headers: { "Content-Type": "application/json" },
92
+ body: JSON.stringify({
93
+ action: "set",
94
+ engine: option.engine,
95
+ ...(model?.trim() ? { model: model.trim() } : {}),
96
+ }),
97
+ });
98
+ if (!res.ok) {
99
+ const message = await res
100
+ .json()
101
+ .then((body) => typeof body?.error === "string"
102
+ ? body.error
103
+ : typeof body?.result === "string"
104
+ ? body.result
105
+ : undefined)
106
+ .catch(() => undefined);
107
+ throw new Error(message ?? `Could not select ${option.label}.`);
108
+ }
109
+ const body = await res
110
+ .json()
111
+ .catch(() => null);
112
+ const actionResult = body?.result;
113
+ if (typeof body?.error === "string" ||
114
+ (typeof actionResult === "string" &&
115
+ /^(Error|Warning):/i.test(actionResult))) {
116
+ throw new Error(body.error ??
117
+ (typeof actionResult === "string"
118
+ ? actionResult
119
+ : `Could not select ${option.label}.`));
120
+ }
121
+ dispatchConfiguredChanged();
122
+ }
@@ -3,6 +3,7 @@ import type { ResourceView } from "../resources/ResourcesPanel.js";
3
3
  import type { SettingsTabItem } from "../settings/SettingsTabsPage.js";
4
4
  import type { AgentPageTabProps } from "./types.js";
5
5
  export declare const AGENT_RESOURCE_DOCS_HREF: Record<ResourceView, string>;
6
+ export declare function ConnectionsTab({ canManageOrg, }?: Partial<AgentPageTabProps>): import("react").JSX.Element;
6
7
  export declare const AGENT_ACCESS_DOCS_HREF: {
7
8
  readonly mcp: "https://agent-native.com/docs/mcp-protocol";
8
9
  readonly a2a: "https://agent-native.com/docs/a2a-protocol";
@@ -113,7 +113,7 @@ function ServerStatus({ server }) {
113
113
  }
114
114
  return (_jsx("span", { className: "text-[11px] text-muted-foreground", children: "Status unknown" }));
115
115
  }
116
- function ConnectionsTab({ canManageOrg = false }) {
116
+ export function ConnectionsTab({ canManageOrg, } = {}) {
117
117
  const t = useT();
118
118
  const serversQuery = useMcpServers();
119
119
  const createServer = useCreateMcpServer();
@@ -123,8 +123,9 @@ function ConnectionsTab({ canManageOrg = false }) {
123
123
  const [deleteTarget, setDeleteTarget] = useState(null);
124
124
  const [error, setError] = useState(null);
125
125
  const data = serversQuery.data;
126
+ const resolvedCanManageOrg = canManageOrg ?? (data?.role === "owner" || data?.role === "admin");
126
127
  const hasOrg = Boolean(data?.orgId);
127
- const canCreateOrgMcp = hasOrg && canManageOrg;
128
+ const canCreateOrgMcp = hasOrg && resolvedCanManageOrg;
128
129
  const onCreateMcpServer = useCallback(async (args) => {
129
130
  if (args.scope === "org" && !canCreateOrgMcp) {
130
131
  throw new Error("Only organization admins can add organization agent integrations.");
@@ -152,7 +153,7 @@ function ConnectionsTab({ canManageOrg = false }) {
152
153
  };
153
154
  const renderServer = (server) => {
154
155
  const key = `${server.scope}:${server.id}`;
155
- const canDelete = server.scope === "user" || canManageOrg;
156
+ const canDelete = server.scope === "user" || resolvedCanManageOrg;
156
157
  const selected = selectedServer?.id === server.id && selectedServer.scope === server.scope;
157
158
  return (_jsxs("div", { className: cn("group/connection-row py-4 transition-colors first:pt-5 last:pb-5", selected && "bg-accent/20"), children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsxs("button", { type: "button", onClick: () => setSelectedServer(selected ? null : server), className: "min-w-0 flex-1 cursor-pointer text-start", children: [_jsx("div", { className: "flex flex-wrap items-center gap-2", children: _jsx("span", { className: "truncate text-sm font-medium text-foreground", children: server.name }) }), _jsx("code", { className: "mt-1 block truncate text-[11px] text-muted-foreground", children: server.url }), _jsxs("div", { className: "mt-2 flex items-center gap-2", children: [_jsx(ServerStatus, { server: server }), server.description && (_jsx("span", { className: "truncate text-[11px] text-muted-foreground/70", children: server.description }))] })] }), canDelete && (_jsx("button", { type: "button", onClick: () => void removeServer(server), disabled: deleteServer.isPending, className: cn("cursor-pointer rounded-md px-2 py-1 text-[11px] font-medium text-muted-foreground hover:bg-destructive/10 hover:text-destructive", deleteTarget === key && "bg-destructive/10 text-destructive"), children: deleteTarget === key ? "Confirm" : "Delete" }))] }), selected && (_jsx("div", { className: "mt-3 border-t border-border/70 pt-3", children: _jsx(McpServerDetail, { server: server }) }))] }, key));
158
159
  };
@@ -0,0 +1,20 @@
1
+ export type AgentProviderId = "anthropic" | "openai" | "openrouter" | "google" | "groq" | "mistral" | "cohere" | "ollama";
2
+ export interface AgentProviderOption {
3
+ id: AgentProviderId;
4
+ engine: string;
5
+ label: string;
6
+ description: string;
7
+ key?: string;
8
+ endpointKey?: string;
9
+ placeholder?: string;
10
+ defaultModel: string;
11
+ supportedModels: readonly string[];
12
+ docsUrl?: string;
13
+ supportsCustomModel?: boolean;
14
+ supportsEndpoint?: boolean;
15
+ endpointPlaceholder?: string;
16
+ kind: "cloud" | "gateway" | "local";
17
+ }
18
+ export declare const AGENT_PROVIDER_CATALOG: readonly AgentProviderOption[];
19
+ export declare function getAgentProviderOption(provider: AgentProviderId): AgentProviderOption;
20
+ export declare function providerIdForEngine(engine: string): AgentProviderId | null;
@@ -0,0 +1,100 @@
1
+ import { OLLAMA_BASE_URL_ENV_VAR, OPENAI_BASE_URL_ENV_VAR, PROVIDER_ENV_META, } from "../agent/engine/provider-env-vars.js";
2
+ import { AI_SDK_MODEL_CONFIG, ANTHROPIC_MODEL_CONFIG, } from "../agent/model-config.js";
3
+ const PROVIDER_LABELS = {
4
+ anthropic: "Anthropic",
5
+ openai: "OpenAI",
6
+ openrouter: "OpenRouter",
7
+ google: "Google Gemini",
8
+ groq: "Groq",
9
+ mistral: "Mistral",
10
+ cohere: "Cohere",
11
+ ollama: "Ollama",
12
+ };
13
+ const PROVIDER_DESCRIPTIONS = {
14
+ anthropic: "Claude models with your own API key.",
15
+ openai: "GPT models and OpenAI-compatible gateways.",
16
+ openrouter: "One key for hundreds of hosted models.",
17
+ google: "Gemini models with a Google AI key.",
18
+ groq: "Fast inference for open models.",
19
+ mistral: "Mistral models through the Mistral API.",
20
+ cohere: "Command models through the Cohere API.",
21
+ ollama: "Run local models from Ollama on your machine.",
22
+ };
23
+ const PROVIDER_DOCS = {
24
+ anthropic: "https://console.anthropic.com/settings/keys",
25
+ openai: "https://platform.openai.com/api-keys",
26
+ openrouter: "https://openrouter.ai/keys",
27
+ google: "https://aistudio.google.com/apikey",
28
+ groq: "https://console.groq.com/keys",
29
+ mistral: "https://console.mistral.ai/api-keys/",
30
+ cohere: "https://dashboard.cohere.com/api-keys",
31
+ };
32
+ const PROVIDER_ORDER = [
33
+ "openrouter",
34
+ "ollama",
35
+ "anthropic",
36
+ "openai",
37
+ "google",
38
+ "groq",
39
+ "mistral",
40
+ "cohere",
41
+ ];
42
+ function modelConfig(provider) {
43
+ if (provider === "anthropic")
44
+ return ANTHROPIC_MODEL_CONFIG;
45
+ return AI_SDK_MODEL_CONFIG[provider];
46
+ }
47
+ export const AGENT_PROVIDER_CATALOG = PROVIDER_ORDER.map((id) => {
48
+ const config = modelConfig(id);
49
+ const envMeta = PROVIDER_ENV_META[id];
50
+ const isOllama = id === "ollama";
51
+ return {
52
+ id,
53
+ engine: id === "anthropic" ? "anthropic" : `ai-sdk:${id}`,
54
+ label: PROVIDER_LABELS[id],
55
+ description: PROVIDER_DESCRIPTIONS[id],
56
+ ...(envMeta
57
+ ? { key: envMeta.envVar, placeholder: envMeta.placeholder }
58
+ : {}),
59
+ ...(id === "openai"
60
+ ? { endpointKey: OPENAI_BASE_URL_ENV_VAR }
61
+ : isOllama
62
+ ? { endpointKey: OLLAMA_BASE_URL_ENV_VAR }
63
+ : {}),
64
+ defaultModel: config.defaultModel,
65
+ supportedModels: config.supportedModels,
66
+ ...(PROVIDER_DOCS[id] ? { docsUrl: PROVIDER_DOCS[id] } : {}),
67
+ ...(id === "openrouter" || isOllama ? { supportsCustomModel: true } : {}),
68
+ ...(id === "openai" || isOllama
69
+ ? {
70
+ supportsEndpoint: true,
71
+ endpointPlaceholder: isOllama
72
+ ? "http://localhost:11434"
73
+ : "https://gateway.example/v1",
74
+ }
75
+ : {}),
76
+ kind: isOllama
77
+ ? "local"
78
+ : id === "openrouter"
79
+ ? "gateway"
80
+ : "cloud",
81
+ };
82
+ });
83
+ export function getAgentProviderOption(provider) {
84
+ const option = AGENT_PROVIDER_CATALOG.find((item) => item.id === provider);
85
+ if (!option)
86
+ throw new Error(`Unknown AI provider: ${provider}`);
87
+ return option;
88
+ }
89
+ export function providerIdForEngine(engine) {
90
+ if (engine === "anthropic" || engine === "ai-sdk:anthropic") {
91
+ return "anthropic";
92
+ }
93
+ if (engine.startsWith("ai-sdk:")) {
94
+ const provider = engine.slice("ai-sdk:".length);
95
+ if (AGENT_PROVIDER_CATALOG.some((option) => option.id === provider)) {
96
+ return provider;
97
+ }
98
+ }
99
+ return null;
100
+ }
@@ -108,6 +108,8 @@ export interface AppProvidersProps {
108
108
  * its own scoped token. Public/SEO routes should use `isPublicPath` instead.
109
109
  */
110
110
  sessionBypass?: boolean;
111
+ /** Fallback used if route metadata leaves the browser title empty or structured. */
112
+ documentTitleFallback?: string;
111
113
  children: React.ReactNode;
112
114
  }
113
- export declare function AppProviders({ queryClient, isPublicPath, clientOnlyFallback, sessionBypass, defaultTheme, themeAttribute, tooltipDelayDuration, toaster, disableThemeTransitions, i18n, children, }: AppProvidersProps): React.JSX.Element;
115
+ export declare function AppProviders({ queryClient, isPublicPath, clientOnlyFallback, sessionBypass, defaultTheme, themeAttribute, tooltipDelayDuration, toaster, disableThemeTransitions, i18n, documentTitleFallback, children, }: AppProvidersProps): React.JSX.Element;
@@ -52,7 +52,9 @@ import { Toaster } from "@agent-native/toolkit/ui/sonner";
52
52
  import { TooltipProvider } from "@radix-ui/react-tooltip";
53
53
  import { QueryClientProvider } from "@tanstack/react-query";
54
54
  import { ThemeProvider } from "next-themes";
55
+ import { useEffect, useRef } from "react";
55
56
  import { useInRouterContext } from "react-router";
57
+ import { isHumanReadableDocumentTitle, normalizeDocumentTitle, } from "../shared/document-title.js";
56
58
  import { ClientOnly } from "./ClientOnly.js";
57
59
  import { DefaultSpinner } from "./DefaultSpinner.js";
58
60
  import { AgentNativeI18nProvider, } from "./i18n.js";
@@ -67,14 +69,57 @@ function RoutedAppEnhancements() {
67
69
  return null;
68
70
  return (_jsxs(_Fragment, { children: [_jsx(AgentNativeRouteWarmup, {}), _jsx(RouteTransitionIndicator, {})] }));
69
71
  }
70
- function ProvidersInner({ queryClient, defaultTheme = "system", themeAttribute = "class", tooltipDelayDuration, toaster = DEFAULT_TOASTER, disableThemeTransitions = true, i18n, children, }) {
72
+ function readDocumentTitleFallback() {
73
+ const selectors = [
74
+ 'meta[name="application-name"]',
75
+ 'meta[name="apple-mobile-web-app-title"]',
76
+ 'meta[property="og:site_name"]',
77
+ ];
78
+ const metadataTitle = selectors
79
+ .map((selector) => document.querySelector(selector)?.content ?? "")
80
+ .find((title) => isHumanReadableDocumentTitle(title));
81
+ return normalizeDocumentTitle(metadataTitle, "Agent Native");
82
+ }
83
+ /** Repairs route metadata that would otherwise expose a structured payload in the tab. */
84
+ function DocumentTitleGuard({ fallbackTitle }) {
85
+ const initialTitleRef = useRef(null);
86
+ if (initialTitleRef.current === null && typeof document !== "undefined") {
87
+ const initialTitle = document.title.trim();
88
+ if (isHumanReadableDocumentTitle(initialTitle)) {
89
+ initialTitleRef.current = initialTitle;
90
+ }
91
+ }
92
+ useEffect(() => {
93
+ let lastKnownTitle = normalizeDocumentTitle(initialTitleRef.current ?? fallbackTitle ?? readDocumentTitleFallback(), fallbackTitle ?? "Agent Native");
94
+ const repairTitle = () => {
95
+ const currentTitle = document.title.trim();
96
+ if (isHumanReadableDocumentTitle(currentTitle)) {
97
+ lastKnownTitle = currentTitle;
98
+ return;
99
+ }
100
+ const nextTitle = normalizeDocumentTitle(lastKnownTitle, "Agent Native");
101
+ if (currentTitle !== nextTitle)
102
+ document.title = nextTitle;
103
+ };
104
+ repairTitle();
105
+ const observer = new MutationObserver(repairTitle);
106
+ observer.observe(document.head, {
107
+ characterData: true,
108
+ childList: true,
109
+ subtree: true,
110
+ });
111
+ return () => observer.disconnect();
112
+ }, [fallbackTitle]);
113
+ return null;
114
+ }
115
+ function ProvidersInner({ queryClient, defaultTheme = "system", themeAttribute = "class", tooltipDelayDuration, toaster = DEFAULT_TOASTER, disableThemeTransitions = true, i18n, documentTitleFallback, children, }) {
71
116
  const localizedChildren = i18n === false ? (children) : (_jsx(AgentNativeI18nProvider, { ...(i18n ?? {}), children: children }));
72
- return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(ThemeProvider, { attribute: themeAttribute, defaultTheme: defaultTheme, enableSystem: true, disableTransitionOnChange: disableThemeTransitions, children: _jsxs(TooltipProvider, { delayDuration: tooltipDelayDuration, children: [localizedChildren, _jsx(RuntimeConfigNotice, {}), _jsx(RoutedAppEnhancements, {}), toaster] }) }) }));
117
+ return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(ThemeProvider, { attribute: themeAttribute, defaultTheme: defaultTheme, enableSystem: true, disableTransitionOnChange: disableThemeTransitions, children: _jsxs(TooltipProvider, { delayDuration: tooltipDelayDuration, children: [localizedChildren, _jsx(DocumentTitleGuard, { fallbackTitle: documentTitleFallback }), _jsx(RuntimeConfigNotice, {}), _jsx(RoutedAppEnhancements, {}), toaster] }) }) }));
73
118
  }
74
- export function AppProviders({ queryClient, isPublicPath = false, clientOnlyFallback, sessionBypass = false, defaultTheme, themeAttribute, tooltipDelayDuration, toaster, disableThemeTransitions, i18n, children, }) {
119
+ export function AppProviders({ queryClient, isPublicPath = false, clientOnlyFallback, sessionBypass = false, defaultTheme, themeAttribute, tooltipDelayDuration, toaster, disableThemeTransitions, i18n, documentTitleFallback, children, }) {
75
120
  const fallback = clientOnlyFallback ?? _jsx(DefaultSpinner, {});
76
121
  if (isPublicPath) {
77
- return (_jsx(ProvidersInner, { queryClient: queryClient, defaultTheme: defaultTheme, themeAttribute: themeAttribute, tooltipDelayDuration: tooltipDelayDuration, toaster: toaster, disableThemeTransitions: disableThemeTransitions, i18n: i18n, children: children }));
122
+ return (_jsx(ProvidersInner, { queryClient: queryClient, defaultTheme: defaultTheme, themeAttribute: themeAttribute, tooltipDelayDuration: tooltipDelayDuration, toaster: toaster, disableThemeTransitions: disableThemeTransitions, i18n: i18n, documentTitleFallback: documentTitleFallback, children: children }));
78
123
  }
79
- return (_jsx(ClientOnly, { fallback: fallback, children: _jsx(ProvidersInner, { queryClient: queryClient, defaultTheme: defaultTheme, themeAttribute: themeAttribute, tooltipDelayDuration: tooltipDelayDuration, toaster: toaster, disableThemeTransitions: disableThemeTransitions, i18n: i18n, children: _jsx(RequireSession, { bypass: sessionBypass, fallback: fallback, children: children }) }) }));
124
+ return (_jsx(ClientOnly, { fallback: fallback, children: _jsx(ProvidersInner, { queryClient: queryClient, defaultTheme: defaultTheme, themeAttribute: themeAttribute, tooltipDelayDuration: tooltipDelayDuration, toaster: toaster, disableThemeTransitions: disableThemeTransitions, i18n: i18n, documentTitleFallback: documentTitleFallback, children: _jsx(RequireSession, { bypass: sessionBypass, fallback: fallback, children: children }) }) }));
80
125
  }
@@ -45,6 +45,7 @@ export { questionFormSchema, questionFormMdx, visualQuestionsSchema, visualQuest
45
45
  export { diagramBlock, DiagramRead, DiagramEdit } from "./library/diagram.js";
46
46
  export { diagramSchema, diagramMdx, type DiagramData, type DiagramNode, type DiagramEdge, type DiagramNote, } from "./library/diagram.config.js";
47
47
  export { wireframeBlock, WireframeBlock, WireframeEditor, } from "./library/wireframe.js";
48
+ export { sanitizeDiagramHtml, sanitizeWireframeCss, sanitizeWireframeHtml, scopeDesignCss, } from "./library/sanitize-html.js";
48
49
  export { wireframeSchema, wireframeMdx, createStableWireframeNodeId, WIREFRAME_SURFACES, WIREFRAME_EL_NAMES, type WireframeData, type WireframeNode, type WireframeElName, type WireframeTone, type WireframeSurface, type WireframeRenderMode, } from "./library/wireframe.config.js";
49
50
  export { Screen, renderNode, renderNodes, hasRenderer, NODE_REGISTRY, KitConfigContext, RoughOverlay, HTML_ROUGH_SELECTOR, useWireframeStyle, setWireframeStyle, toggleWireframeStyle, useIsDark, type WireframeStyle, } from "./library/wireframe-kit.js";
50
51
  export { renderWireframeIconHtml } from "./library/wireframe-icons.js";
@@ -56,6 +56,7 @@ export { questionFormSchema, questionFormMdx, visualQuestionsSchema, visualQuest
56
56
  export { diagramBlock, DiagramRead, DiagramEdit } from "./library/diagram.js";
57
57
  export { diagramSchema, diagramMdx, } from "./library/diagram.config.js";
58
58
  export { wireframeBlock, WireframeBlock, WireframeEditor, } from "./library/wireframe.js";
59
+ export { sanitizeDiagramHtml, sanitizeWireframeCss, sanitizeWireframeHtml, scopeDesignCss, } from "./library/sanitize-html.js";
59
60
  export { wireframeSchema, wireframeMdx, createStableWireframeNodeId, WIREFRAME_SURFACES, WIREFRAME_EL_NAMES, } from "./library/wireframe.config.js";
60
61
  export { Screen, renderNode, renderNodes, hasRenderer, NODE_REGISTRY, KitConfigContext, RoughOverlay, HTML_ROUGH_SELECTOR, useWireframeStyle, setWireframeStyle, toggleWireframeStyle, useIsDark, } from "./library/wireframe-kit.js";
61
62
  export { renderWireframeIconHtml } from "./library/wireframe-icons.js";
@@ -5,11 +5,11 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
5
5
  // by AssistantChatInner.
6
6
  import { IconLoader2, IconCheck, IconCopy, IconX, IconChevronDown, IconGitFork, IconGauge, IconSettings, IconArrowRight, IconAlertTriangle, IconPlayerPlay, IconRefresh, IconPlus, IconClipboardList, } from "@tabler/icons-react";
7
7
  import { useState, useEffect, useCallback, useRef } from "react";
8
- import { saveAgentEngineApiKey, } from "../agent-engine-key.js";
9
8
  import { agentNativePath } from "../api-path.js";
10
9
  import { writeClipboardText } from "../clipboard.js";
11
10
  import { isProviderAuthenticationError } from "../error-format.js";
12
11
  import { useT } from "../i18n.js";
12
+ import { AgentProviderSetupForm } from "../settings/ProviderSetupForm.js";
13
13
  import { useBuilderConnectFlow } from "../settings/useBuilderStatus.js";
14
14
  import { cn } from "../utils.js";
15
15
  // ─── Metadata extractors ──────────────────────────────────────────────────────
@@ -132,65 +132,21 @@ export function BuilderConnectCta({ variant = "primary", onConnected, }) {
132
132
  return (_jsxs("div", { className: containerClass, children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "text-xs font-medium text-foreground", children: "Connect Builder.io" }), _jsx("p", { className: "text-[11px] text-muted-foreground mt-0.5 max-w-[220px]", children: "Free credits for LLM, hosting, and more \u2014 no API key needed" }), error && _jsx("p", { className: "mt-1 text-[10px] text-destructive", children: error })] }), _jsx("button", { type: "button", onClick: () => start(), disabled: connecting, className: "ml-auto inline-flex items-center gap-1 shrink-0 rounded-md bg-foreground px-3 py-1.5 text-[11px] font-medium no-underline text-background hover:opacity-90 disabled:opacity-60 disabled:cursor-wait", "aria-busy": connecting, children: connecting ? (_jsxs(_Fragment, { children: [_jsx(IconLoader2, { size: 10, className: "animate-spin" }), "Waiting\u2026"] })) : ("Connect") })] }));
133
133
  }
134
134
  // ─── ApiKeyConnect ────────────────────────────────────────────────────────────
135
- const API_KEY_PROVIDERS = [
136
- { value: "anthropic", label: "Anthropic", placeholder: "sk-ant-…" },
137
- { value: "openai", label: "OpenAI", placeholder: "sk-…" },
138
- ];
139
135
  export function ApiKeyConnect({ onConnected }) {
140
- const t = useT();
141
- const [provider, setProvider] = useState("anthropic");
142
- const [apiKey, setApiKey] = useState("");
143
- const [saving, setSaving] = useState(false);
144
- const [error, setError] = useState(null);
145
- const active = API_KEY_PROVIDERS.find((p) => p.value === provider);
146
- const handleSave = useCallback(async () => {
147
- if (!apiKey.trim() || saving)
148
- return;
149
- setSaving(true);
150
- setError(null);
151
- try {
152
- await saveAgentEngineApiKey({ provider, apiKey });
153
- setApiKey("");
154
- onConnected?.();
155
- }
156
- catch (err) {
157
- setError(err instanceof Error ? err.message : "Could not save the key.");
158
- }
159
- finally {
160
- setSaving(false);
161
- }
162
- }, [apiKey, onConnected, provider, saving]);
163
- return (_jsxs("div", { className: "rounded-md border border-border bg-background/60 p-3", children: [_jsx("div", { className: "mb-2 text-[11px] font-medium text-foreground", children: t("agentPanel.addOwnKeys", { defaultValue: "Add your own keys" }) }), _jsx("p", { className: "mb-2.5 text-[11px] leading-relaxed text-muted-foreground", children: "Stored securely for this app only." }), _jsx("div", { role: "tablist", "aria-label": "API key provider", className: "mb-2 inline-flex rounded-md border border-border bg-muted/40 p-0.5", children: API_KEY_PROVIDERS.map((option) => {
164
- const selected = option.value === provider;
165
- return (_jsx("button", { type: "button", role: "tab", "aria-selected": selected, onClick: () => {
166
- setProvider(option.value);
167
- setError(null);
168
- }, className: cn("rounded px-2.5 py-1 text-[11px] font-medium transition-colors", selected
169
- ? "bg-background text-foreground shadow-sm"
170
- : "text-muted-foreground hover:text-foreground"), children: option.label }, option.value));
171
- }) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "password", value: apiKey, autoComplete: "off", spellCheck: false, placeholder: active.placeholder, onChange: (e) => {
172
- setApiKey(e.target.value);
173
- if (error)
174
- setError(null);
175
- }, onKeyDown: (e) => {
176
- if (e.key === "Enter") {
177
- e.preventDefault();
178
- void handleSave();
179
- }
180
- }, className: "h-8 min-w-0 flex-1 rounded-md border border-input bg-background px-2.5 text-[12px] text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-1 focus:ring-offset-background" }), _jsx("button", { type: "button", onClick: handleSave, disabled: !apiKey.trim() || saving, className: "inline-flex h-8 shrink-0 items-center gap-1 rounded-md bg-foreground px-3 text-[11px] font-medium text-background hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-60", children: saving ? (_jsxs(_Fragment, { children: [_jsx(IconLoader2, { size: 11, className: "animate-spin" }), "Saving\u2026"] })) : ("Save") })] }), error ? (_jsx("p", { className: "mt-2 text-[11px] text-destructive", children: error })) : null] }));
136
+ return (_jsx(AgentProviderSetupForm, { onConnected: () => onConnected?.(), layout: "compact", showTitle: false }));
181
137
  }
182
138
  export function BuilderSetupContent({ onConnected, layout = "default", }) {
183
139
  const t = useT();
184
140
  const [keyOpen, setKeyOpen] = useState(false);
185
141
  const sidebarLayout = layout === "sidebar";
186
142
  return (_jsxs("div", { className: cn("agent-builder-setup-content", sidebarLayout && "agent-builder-setup-card--sidebar"), children: [_jsxs("div", { className: cn("agent-builder-setup-card__content flex flex-col sm:flex-row sm:items-center sm:justify-between", sidebarLayout ? "gap-2" : "gap-3"), children: [_jsxs("div", { className: "agent-builder-setup-card__copy min-w-0", children: [_jsx("h3", { className: "text-[13px] font-medium text-foreground", children: t("agentPanel.connectAi", { defaultValue: "Connect AI" }) }), _jsx("p", { className: "mt-0.5 text-[11px] leading-relaxed text-muted-foreground", children: t("agentPanel.builderOrOwnKeys", {
187
- defaultValue: "Use Builder.io (free credits), or add your own provider keys.",
143
+ defaultValue: "Choose Builder.io or custom keys.",
188
144
  }) })] }), _jsxs("div", { className: cn("agent-builder-setup-card__actions flex shrink-0", sidebarLayout
189
145
  ? "flex-col items-start gap-1 sm:items-center"
190
146
  : "flex-nowrap items-center gap-2"), children: [_jsx(BuilderConnectCta, { variant: "compact", onConnected: onConnected }), _jsx("button", { type: "button", onClick: () => setKeyOpen((open) => !open), className: cn("agent-builder-setup-card__key-button inline-flex shrink-0 items-center whitespace-nowrap rounded-md text-[11px] font-medium", sidebarLayout
191
147
  ? "h-7 border-0 bg-transparent px-0 text-muted-foreground hover:bg-transparent hover:text-foreground"
192
148
  : "h-8 border border-border bg-background px-3 text-foreground hover:bg-accent"), "aria-expanded": keyOpen, children: t("agentPanel.addOwnKeys", {
193
- defaultValue: "Add your own keys",
149
+ defaultValue: "Custom keys",
194
150
  }) })] })] }), keyOpen ? (_jsx("div", { className: "mt-3", children: _jsx(ApiKeyConnect, { onConnected: onConnected }) })) : null] }));
195
151
  }
196
152
  export function BuilderSetupCard({ onConnected, bouncePulse, fullWidth, layout = "default", }) {
@@ -1,4 +1,5 @@
1
1
  import { agentNativePath } from "../api-path.js";
2
+ import { emitChatFirstOpenApp, emitChatFirstOpenBrowser, } from "../chat-first.js";
2
3
  import { formatChatErrorText, normalizeChatError } from "../error-format.js";
3
4
  import { settleInterruptedToolCalls, } from "../sse-event-processor.js";
4
5
  const DEFAULT_RUNTIME_CAPABILITIES = {
@@ -977,6 +978,7 @@ export function createAgentChatRuntimeAdapter(runtime, options = {}) {
977
978
  };
978
979
  try {
979
980
  for await (const event of turn.events) {
981
+ emitChatFirstOpenAppFromRuntimeEvent(event);
980
982
  const result = applyRuntimeEventToContent(event, projection);
981
983
  if (result) {
982
984
  const metadata = (result.metadata ?? {});
@@ -1007,3 +1009,64 @@ export function createAgentChatRuntimeAdapter(runtime, options = {}) {
1007
1009
  },
1008
1010
  };
1009
1011
  }
1012
+ function emitChatFirstOpenAppFromRuntimeEvent(event) {
1013
+ if (event.type !== "tool-done")
1014
+ return;
1015
+ const toolEvent = event;
1016
+ if (toolEvent.status !== "completed" ||
1017
+ (!isOpenAppTool(toolEvent.toolName) &&
1018
+ !isOpenBrowserTool(toolEvent.toolName))) {
1019
+ return;
1020
+ }
1021
+ const result = asRecord(toolEvent.result) ?? parseResultRecord(toolEvent.resultText);
1022
+ if (!result) {
1023
+ console.warn(`[chat-first] ${toolEvent.toolName} completed without a readable result`);
1024
+ return;
1025
+ }
1026
+ if (isOpenBrowserTool(toolEvent.toolName)) {
1027
+ const delivery = emitChatFirstOpenBrowser({
1028
+ url: readString(result.url ?? result.href),
1029
+ title: readString(result.title ?? result.name),
1030
+ });
1031
+ warnWhenChatFirstDeliveryIsNotObserved(toolEvent.toolName, delivery);
1032
+ return;
1033
+ }
1034
+ const detail = {
1035
+ app: readString(result.app ?? result.appId ?? result.application),
1036
+ path: readString(result.path ?? result.targetPath),
1037
+ url: readString(result.url ?? result.href),
1038
+ view: readString(result.view),
1039
+ };
1040
+ const delivery = emitChatFirstOpenApp(detail);
1041
+ warnWhenChatFirstDeliveryIsNotObserved(toolEvent.toolName, delivery);
1042
+ }
1043
+ function warnWhenChatFirstDeliveryIsNotObserved(toolName, delivery) {
1044
+ if (delivery.delivered)
1045
+ return;
1046
+ console.warn(`[chat-first] ${toolName} was completed but not delivered (${delivery.reason ?? "unknown"})`);
1047
+ }
1048
+ function isOpenAppTool(toolName) {
1049
+ return toolName === "open_app";
1050
+ }
1051
+ function isOpenBrowserTool(toolName) {
1052
+ return toolName === "open_browser";
1053
+ }
1054
+ function asRecord(value) {
1055
+ return value && typeof value === "object" && !Array.isArray(value)
1056
+ ? value
1057
+ : null;
1058
+ }
1059
+ function readString(value) {
1060
+ return typeof value === "string" && value.trim() ? value : undefined;
1061
+ }
1062
+ function parseResultRecord(value) {
1063
+ if (!value?.trim())
1064
+ return null;
1065
+ try {
1066
+ return asRecord(JSON.parse(value));
1067
+ }
1068
+ catch {
1069
+ // coercion-ok: malformed tool output is an unreadable absence; the caller logs it.
1070
+ return null;
1071
+ }
1072
+ }
@@ -0,0 +1,2 @@
1
+ import type { ChatFirstAgentsPaneProps } from "./types.js";
2
+ export declare function ChatFirstAgentsPane({ activities, loading, error, onRefresh, onWatch, copy, }: ChatFirstAgentsPaneProps): import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { ChatFirstAgentActivityPanel } from "../chat-first-agent-activity.js";
3
+ import { defaultChatFirstCopy } from "./copy.js";
4
+ export function ChatFirstAgentsPane({ activities, loading = false, error, onRefresh, onWatch, copy = defaultChatFirstCopy, }) {
5
+ return (_jsx("section", { "data-chat-first-agents-pane": true, className: "flex h-full min-h-0 flex-col overflow-y-auto bg-background", "aria-label": copy("agentsTitle"), children: _jsx(ChatFirstAgentActivityPanel, { activities: activities, loading: loading, error: error ?? null, onRefresh: onRefresh, onWatch: onWatch, copy: copy }) }));
6
+ }
@@ -0,0 +1,2 @@
1
+ import type { ChatFirstAppPaneProps } from "./types.js";
2
+ export declare function ChatFirstAppPane({ app, status, embedUrl, errorMessage, onRetry, renderEmbed, copy, }: ChatFirstAppPaneProps): import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Skeleton } from "@agent-native/toolkit/ui";
3
+ import { defaultChatFirstCopy } from "./copy.js";
4
+ export function ChatFirstAppPane({ app, status, embedUrl, errorMessage, onRetry, renderEmbed, copy = defaultChatFirstCopy, }) {
5
+ return (_jsx("section", { "data-chat-first-app-pane": true, className: "flex h-full min-h-0 w-full flex-col overflow-hidden bg-background", "aria-label": app ? `${app.name} app` : copy("appUnavailable"), children: status === "loading" ? (_jsxs("div", { className: "space-y-3 p-4", children: [_jsx(Skeleton, { className: "h-5 w-40" }), _jsx(Skeleton, { className: "h-4 w-full" }), _jsx(Skeleton, { className: "h-4 w-2/3" })] })) : status === "ready" && app && embedUrl ? (_jsx("div", { className: "relative min-h-0 flex-1 overflow-hidden", children: renderEmbed({ url: embedUrl, title: app.name }) })) : status === "error" ? (_jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-3 p-6 text-center", children: [_jsx("p", { className: "text-sm text-muted-foreground", children: errorMessage || copy("appUnavailable") }), onRetry ? (_jsx("button", { type: "button", className: "rounded-md border border-border px-3 py-1.5 text-xs text-foreground hover:bg-accent", onClick: onRetry, children: copy("retry") })) : null] })) : (_jsx("div", { className: "flex h-full items-center justify-center p-6 text-center text-sm text-muted-foreground", children: copy("appUnavailable") })) }));
6
+ }
@@ -0,0 +1,2 @@
1
+ import type { ChatFirstAppRailProps } from "./types.js";
2
+ export declare function ChatFirstAppsRail({ apps, activeAppId, loading, error, collapsed, layout: controlledLayout, onLayoutChange, onLayoutError, onRetry, onOpenApp, onCreateApp, createAppTrigger, renderIcon, copy, }: ChatFirstAppRailProps): import("react").JSX.Element;