@agent-native/core 0.75.4 → 0.76.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 (459) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +47 -0
  3. package/corpus/core/docs/AGENTS.md +1 -0
  4. package/corpus/core/docs/content/client.md +15 -0
  5. package/corpus/core/docs/content/internationalization.md +145 -0
  6. package/corpus/core/docs/content/locales/ar-SA/internationalization.md +102 -0
  7. package/corpus/core/docs/content/locales/de-DE/internationalization.md +102 -0
  8. package/corpus/core/docs/content/locales/es-ES/internationalization.md +102 -0
  9. package/corpus/core/docs/content/locales/fr-FR/internationalization.md +102 -0
  10. package/corpus/core/docs/content/locales/hi-IN/internationalization.md +102 -0
  11. package/corpus/core/docs/content/locales/ja-JP/internationalization.md +114 -0
  12. package/corpus/core/docs/content/locales/ko-KR/internationalization.md +102 -0
  13. package/corpus/core/docs/content/locales/pt-BR/internationalization.md +102 -0
  14. package/corpus/core/docs/content/locales/zh-CN/internationalization.md +102 -0
  15. package/corpus/core/docs/content/skills-guide.md +19 -18
  16. package/corpus/core/package.json +7 -1
  17. package/corpus/core/src/agent/durable-background.ts +62 -28
  18. package/corpus/core/src/agent/production-agent.ts +16 -12
  19. package/corpus/core/src/cli/skills.ts +22 -4
  20. package/corpus/core/src/client/CommandMenu.tsx +16 -0
  21. package/corpus/core/src/client/app-providers.tsx +26 -1
  22. package/corpus/core/src/client/i18n.tsx +605 -0
  23. package/corpus/core/src/client/index.ts +28 -0
  24. package/corpus/core/src/deploy/build.ts +47 -113
  25. package/corpus/core/src/deploy/workspace-deploy.ts +62 -30
  26. package/corpus/core/src/index.browser.ts +25 -0
  27. package/corpus/core/src/localization/actions/get-localization-preference.ts +23 -0
  28. package/corpus/core/src/localization/actions/set-localization-preference.ts +30 -0
  29. package/corpus/core/src/localization/index.ts +2 -0
  30. package/corpus/core/src/localization/server.ts +131 -0
  31. package/corpus/core/src/localization/shared.ts +163 -0
  32. package/corpus/core/src/server/action-discovery.ts +8 -0
  33. package/corpus/core/src/server/index.ts +8 -0
  34. package/corpus/core/src/server/self-dispatch.ts +29 -2
  35. package/corpus/core/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +5 -0
  36. package/corpus/core/src/templates/default/.agents/skills/internationalization/SKILL.md +77 -0
  37. package/corpus/core/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +6 -0
  38. package/corpus/core/src/templates/default/AGENTS.md +16 -15
  39. package/corpus/core/src/templates/default/app/i18n/en-US.ts +29 -0
  40. package/corpus/core/src/templates/default/app/i18n/index.ts +13 -0
  41. package/corpus/core/src/templates/default/app/root.tsx +20 -1
  42. package/corpus/core/src/templates/default/app/routes/_index.tsx +24 -9
  43. package/corpus/core/src/templates/default/app/routes/settings.tsx +67 -0
  44. package/corpus/core/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +5 -0
  45. package/corpus/core/src/templates/workspace-core/.agents/skills/internationalization/SKILL.md +77 -0
  46. package/corpus/core/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +6 -0
  47. package/corpus/core/src/vite/action-types-plugin.ts +10 -0
  48. package/corpus/templates/analytics/.agents/skills/self-modifying-code/SKILL.md +6 -0
  49. package/corpus/templates/analytics/app/components/layout/Header.tsx +18 -15
  50. package/corpus/templates/analytics/app/components/layout/Layout.tsx +7 -5
  51. package/corpus/templates/analytics/app/components/layout/MobileNav.tsx +9 -3
  52. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +5 -3
  53. package/corpus/templates/analytics/app/i18n/ar-SA.ts +3 -0
  54. package/corpus/templates/analytics/app/i18n/de-DE.ts +3 -0
  55. package/corpus/templates/analytics/app/i18n/en-US.ts +3 -0
  56. package/corpus/templates/analytics/app/i18n/es-ES.ts +3 -0
  57. package/corpus/templates/analytics/app/i18n/fr-FR.ts +3 -0
  58. package/corpus/templates/analytics/app/i18n/hi-IN.ts +3 -0
  59. package/corpus/templates/analytics/app/i18n/index.ts +31 -0
  60. package/corpus/templates/analytics/app/i18n/ja-JP.ts +3 -0
  61. package/corpus/templates/analytics/app/i18n/ko-KR.ts +3 -0
  62. package/corpus/templates/analytics/app/i18n/pt-BR.ts +3 -0
  63. package/corpus/templates/analytics/app/i18n/zh-CN.ts +3 -0
  64. package/corpus/templates/analytics/app/i18n-data.ts +433 -0
  65. package/corpus/templates/analytics/app/pages/Settings.tsx +50 -16
  66. package/corpus/templates/analytics/app/root.tsx +14 -1
  67. package/corpus/templates/analytics/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  68. package/corpus/templates/analytics/changelog/2026-06-24-settings-now-link-directly-to-agent-settings-for-model-api-k.md +6 -0
  69. package/corpus/templates/assets/.agents/skills/self-modifying-code/SKILL.md +6 -0
  70. package/corpus/templates/assets/app/components/layout/Header.tsx +17 -8
  71. package/corpus/templates/assets/app/components/layout/Layout.tsx +10 -6
  72. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +40 -23
  73. package/corpus/templates/assets/app/i18n/ar-SA.ts +3 -0
  74. package/corpus/templates/assets/app/i18n/de-DE.ts +3 -0
  75. package/corpus/templates/assets/app/i18n/en-US.ts +3 -0
  76. package/corpus/templates/assets/app/i18n/es-ES.ts +3 -0
  77. package/corpus/templates/assets/app/i18n/fr-FR.ts +3 -0
  78. package/corpus/templates/assets/app/i18n/hi-IN.ts +3 -0
  79. package/corpus/templates/assets/app/i18n/index.ts +31 -0
  80. package/corpus/templates/assets/app/i18n/ja-JP.ts +3 -0
  81. package/corpus/templates/assets/app/i18n/ko-KR.ts +3 -0
  82. package/corpus/templates/assets/app/i18n/pt-BR.ts +3 -0
  83. package/corpus/templates/assets/app/i18n/zh-CN.ts +3 -0
  84. package/corpus/templates/assets/app/i18n-data.ts +668 -0
  85. package/corpus/templates/assets/app/root.tsx +40 -15
  86. package/corpus/templates/assets/app/routes/_index.tsx +9 -10
  87. package/corpus/templates/assets/app/routes/settings.tsx +37 -6
  88. package/corpus/templates/assets/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  89. package/corpus/templates/assets/changelog/2026-06-24-settings-now-link-directly-to-agent-settings-for-model-api-k.md +6 -0
  90. package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +5 -0
  91. package/corpus/templates/brain/.agents/skills/self-modifying-code/SKILL.md +6 -0
  92. package/corpus/templates/brain/app/components/layout/Layout.tsx +12 -8
  93. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +23 -12
  94. package/corpus/templates/brain/app/i18n/ar-SA.ts +3 -0
  95. package/corpus/templates/brain/app/i18n/de-DE.ts +3 -0
  96. package/corpus/templates/brain/app/i18n/en-US.ts +3 -0
  97. package/corpus/templates/brain/app/i18n/es-ES.ts +3 -0
  98. package/corpus/templates/brain/app/i18n/fr-FR.ts +3 -0
  99. package/corpus/templates/brain/app/i18n/hi-IN.ts +3 -0
  100. package/corpus/templates/brain/app/i18n/index.ts +31 -0
  101. package/corpus/templates/brain/app/i18n/ja-JP.ts +3 -0
  102. package/corpus/templates/brain/app/i18n/ko-KR.ts +3 -0
  103. package/corpus/templates/brain/app/i18n/pt-BR.ts +3 -0
  104. package/corpus/templates/brain/app/i18n/zh-CN.ts +3 -0
  105. package/corpus/templates/brain/app/i18n-data.ts +624 -0
  106. package/corpus/templates/brain/app/root.tsx +27 -12
  107. package/corpus/templates/brain/app/routes/settings.tsx +45 -8
  108. package/corpus/templates/brain/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  109. package/corpus/templates/brain/changelog/2026-06-24-settings-now-link-directly-to-agent-settings-for-model-api-k.md +6 -0
  110. package/corpus/templates/calendar/.agents/skills/self-modifying-code/SKILL.md +6 -0
  111. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +2 -0
  112. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +16 -9
  113. package/corpus/templates/calendar/app/i18n/ar-SA.ts +57 -0
  114. package/corpus/templates/calendar/app/i18n/de-DE.ts +58 -0
  115. package/corpus/templates/calendar/app/i18n/en-US.ts +57 -0
  116. package/corpus/templates/calendar/app/i18n/es-ES.ts +58 -0
  117. package/corpus/templates/calendar/app/i18n/fr-FR.ts +58 -0
  118. package/corpus/templates/calendar/app/i18n/hi-IN.ts +57 -0
  119. package/corpus/templates/calendar/app/i18n/index.ts +31 -0
  120. package/corpus/templates/calendar/app/i18n/ja-JP.ts +58 -0
  121. package/corpus/templates/calendar/app/i18n/ko-KR.ts +57 -0
  122. package/corpus/templates/calendar/app/i18n/pt-BR.ts +57 -0
  123. package/corpus/templates/calendar/app/i18n/zh-CN.ts +57 -0
  124. package/corpus/templates/calendar/app/i18n-data.ts +516 -0
  125. package/corpus/templates/calendar/app/pages/CalendarView.tsx +2 -0
  126. package/corpus/templates/calendar/app/pages/Settings.tsx +63 -28
  127. package/corpus/templates/calendar/app/root.tsx +78 -7
  128. package/corpus/templates/calendar/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  129. package/corpus/templates/calendar/changelog/2026-06-24-settings-now-link-directly-to-agent-settings-for-model-api-k.md +6 -0
  130. package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +5 -0
  131. package/corpus/templates/chat/.agents/skills/self-modifying-code/SKILL.md +6 -0
  132. package/corpus/templates/chat/app/components/layout/Header.tsx +17 -11
  133. package/corpus/templates/chat/app/components/layout/Layout.tsx +12 -8
  134. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +47 -18
  135. package/corpus/templates/chat/app/i18n/ar-SA.ts +62 -0
  136. package/corpus/templates/chat/app/i18n/de-DE.ts +63 -0
  137. package/corpus/templates/chat/app/i18n/en-US.ts +63 -0
  138. package/corpus/templates/chat/app/i18n/es-ES.ts +63 -0
  139. package/corpus/templates/chat/app/i18n/fr-FR.ts +63 -0
  140. package/corpus/templates/chat/app/i18n/hi-IN.ts +63 -0
  141. package/corpus/templates/chat/app/i18n/index.ts +31 -0
  142. package/corpus/templates/chat/app/i18n/ja-JP.ts +63 -0
  143. package/corpus/templates/chat/app/i18n/ko-KR.ts +63 -0
  144. package/corpus/templates/chat/app/i18n/pt-BR.ts +63 -0
  145. package/corpus/templates/chat/app/i18n/zh-CN.ts +61 -0
  146. package/corpus/templates/chat/app/i18n-data.ts +475 -0
  147. package/corpus/templates/chat/app/root.tsx +18 -5
  148. package/corpus/templates/chat/app/routes/_index.tsx +9 -8
  149. package/corpus/templates/chat/app/routes/settings.tsx +86 -0
  150. package/corpus/templates/chat/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +6 -0
  151. package/corpus/templates/chat/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  152. package/corpus/templates/clips/.agents/skills/self-modifying-code/SKILL.md +6 -0
  153. package/corpus/templates/clips/app/components/layout/Header.tsx +23 -17
  154. package/corpus/templates/clips/app/components/library/empty-state.tsx +10 -34
  155. package/corpus/templates/clips/app/components/library/library-layout.tsx +45 -34
  156. package/corpus/templates/clips/app/i18n/ar-SA.ts +182 -0
  157. package/corpus/templates/clips/app/i18n/de-DE.ts +184 -0
  158. package/corpus/templates/clips/app/i18n/en-US.ts +179 -0
  159. package/corpus/templates/clips/app/i18n/es-ES.ts +183 -0
  160. package/corpus/templates/clips/app/i18n/fr-FR.ts +184 -0
  161. package/corpus/templates/clips/app/i18n/hi-IN.ts +180 -0
  162. package/corpus/templates/clips/app/i18n/index.ts +41 -0
  163. package/corpus/templates/clips/app/i18n/ja-JP.ts +180 -0
  164. package/corpus/templates/clips/app/i18n/ko-KR.ts +178 -0
  165. package/corpus/templates/clips/app/i18n/pt-BR.ts +183 -0
  166. package/corpus/templates/clips/app/i18n/zh-CN.ts +173 -0
  167. package/corpus/templates/clips/app/root.tsx +104 -10
  168. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +154 -95
  169. package/corpus/templates/clips/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  170. package/corpus/templates/clips/changelog/2026-06-24-chrome-extension-setup-now-shows-a-clear-all-done-confirmati.md +6 -0
  171. package/corpus/templates/clips/changelog/2026-06-24-clips-now-includes-a-language-picker-and-simplified-chinese-ui.md +6 -0
  172. package/corpus/templates/clips/changelog/2026-06-24-settings-now-link-directly-to-agent-settings-for-model-api-k.md +6 -0
  173. package/corpus/templates/clips/chrome-extension/src/permission.html +60 -0
  174. package/corpus/templates/clips/chrome-extension/src/permission.ts +28 -15
  175. package/corpus/templates/content/.agents/skills/self-modifying-code/SKILL.md +6 -0
  176. package/corpus/templates/content/app/components/EmptyState.tsx +7 -5
  177. package/corpus/templates/content/app/components/ThemeToggle.tsx +4 -2
  178. package/corpus/templates/content/app/components/layout/Header.tsx +2 -0
  179. package/corpus/templates/content/app/components/layout/Layout.tsx +8 -7
  180. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +41 -1
  181. package/corpus/templates/content/app/i18n/ar-SA.ts +3 -0
  182. package/corpus/templates/content/app/i18n/de-DE.ts +3 -0
  183. package/corpus/templates/content/app/i18n/en-US.ts +3 -0
  184. package/corpus/templates/content/app/i18n/es-ES.ts +3 -0
  185. package/corpus/templates/content/app/i18n/fr-FR.ts +3 -0
  186. package/corpus/templates/content/app/i18n/hi-IN.ts +3 -0
  187. package/corpus/templates/content/app/i18n/index.ts +31 -0
  188. package/corpus/templates/content/app/i18n/ja-JP.ts +3 -0
  189. package/corpus/templates/content/app/i18n/ko-KR.ts +3 -0
  190. package/corpus/templates/content/app/i18n/pt-BR.ts +3 -0
  191. package/corpus/templates/content/app/i18n/zh-CN.ts +3 -0
  192. package/corpus/templates/content/app/i18n-data.ts +490 -0
  193. package/corpus/templates/content/app/root.tsx +110 -23
  194. package/corpus/templates/content/app/routes/_app.settings.tsx +84 -0
  195. package/corpus/templates/content/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +6 -0
  196. package/corpus/templates/content/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  197. package/corpus/templates/design/.agents/skills/self-modifying-code/SKILL.md +6 -0
  198. package/corpus/templates/design/app/components/layout/Header.tsx +16 -8
  199. package/corpus/templates/design/app/components/layout/Layout.tsx +8 -6
  200. package/corpus/templates/design/app/components/layout/Sidebar.tsx +25 -9
  201. package/corpus/templates/design/app/i18n/ar-SA.ts +3 -0
  202. package/corpus/templates/design/app/i18n/de-DE.ts +3 -0
  203. package/corpus/templates/design/app/i18n/en-US.ts +3 -0
  204. package/corpus/templates/design/app/i18n/es-ES.ts +3 -0
  205. package/corpus/templates/design/app/i18n/fr-FR.ts +3 -0
  206. package/corpus/templates/design/app/i18n/hi-IN.ts +3 -0
  207. package/corpus/templates/design/app/i18n/index.ts +31 -0
  208. package/corpus/templates/design/app/i18n/ja-JP.ts +3 -0
  209. package/corpus/templates/design/app/i18n/ko-KR.ts +3 -0
  210. package/corpus/templates/design/app/i18n/pt-BR.ts +3 -0
  211. package/corpus/templates/design/app/i18n/zh-CN.ts +3 -0
  212. package/corpus/templates/design/app/i18n-data.ts +350 -0
  213. package/corpus/templates/design/app/root.tsx +40 -15
  214. package/corpus/templates/design/app/routes/settings.tsx +43 -0
  215. package/corpus/templates/design/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  216. package/corpus/templates/design/changelog/2026-06-24-settings-now-link-directly-to-agent-settings-for-model-api-k.md +6 -0
  217. package/corpus/templates/dispatch/.agents/skills/self-modifying-code/SKILL.md +6 -0
  218. package/corpus/templates/dispatch/app/i18n/ar-SA.ts +3 -0
  219. package/corpus/templates/dispatch/app/i18n/de-DE.ts +3 -0
  220. package/corpus/templates/dispatch/app/i18n/en-US.ts +3 -0
  221. package/corpus/templates/dispatch/app/i18n/es-ES.ts +3 -0
  222. package/corpus/templates/dispatch/app/i18n/fr-FR.ts +3 -0
  223. package/corpus/templates/dispatch/app/i18n/hi-IN.ts +3 -0
  224. package/corpus/templates/dispatch/app/i18n/index.ts +31 -0
  225. package/corpus/templates/dispatch/app/i18n/ja-JP.ts +3 -0
  226. package/corpus/templates/dispatch/app/i18n/ko-KR.ts +3 -0
  227. package/corpus/templates/dispatch/app/i18n/pt-BR.ts +3 -0
  228. package/corpus/templates/dispatch/app/i18n/zh-CN.ts +3 -0
  229. package/corpus/templates/dispatch/app/i18n-data.ts +267 -0
  230. package/corpus/templates/dispatch/app/root.tsx +18 -4
  231. package/corpus/templates/dispatch/app/routes/settings.tsx +86 -0
  232. package/corpus/templates/dispatch/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +6 -0
  233. package/corpus/templates/dispatch/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  234. package/corpus/templates/forms/.agents/skills/self-modifying-code/SKILL.md +6 -0
  235. package/corpus/templates/forms/app/components/layout/Header.tsx +16 -9
  236. package/corpus/templates/forms/app/components/layout/Layout.tsx +6 -4
  237. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +34 -17
  238. package/corpus/templates/forms/app/i18n/ar-SA.ts +58 -0
  239. package/corpus/templates/forms/app/i18n/de-DE.ts +59 -0
  240. package/corpus/templates/forms/app/i18n/en-US.ts +59 -0
  241. package/corpus/templates/forms/app/i18n/es-ES.ts +59 -0
  242. package/corpus/templates/forms/app/i18n/fr-FR.ts +59 -0
  243. package/corpus/templates/forms/app/i18n/hi-IN.ts +59 -0
  244. package/corpus/templates/forms/app/i18n/index.ts +31 -0
  245. package/corpus/templates/forms/app/i18n/ja-JP.ts +59 -0
  246. package/corpus/templates/forms/app/i18n/ko-KR.ts +59 -0
  247. package/corpus/templates/forms/app/i18n/pt-BR.ts +59 -0
  248. package/corpus/templates/forms/app/i18n/zh-CN.ts +56 -0
  249. package/corpus/templates/forms/app/root.tsx +65 -16
  250. package/corpus/templates/forms/app/routes/_app.settings.tsx +85 -0
  251. package/corpus/templates/forms/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +6 -0
  252. package/corpus/templates/forms/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  253. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +29 -17
  254. package/corpus/templates/macros/app/components/layout/Header.tsx +16 -10
  255. package/corpus/templates/macros/app/i18n/ar-SA.ts +54 -0
  256. package/corpus/templates/macros/app/i18n/de-DE.ts +55 -0
  257. package/corpus/templates/macros/app/i18n/en-US.ts +55 -0
  258. package/corpus/templates/macros/app/i18n/es-ES.ts +55 -0
  259. package/corpus/templates/macros/app/i18n/fr-FR.ts +55 -0
  260. package/corpus/templates/macros/app/i18n/hi-IN.ts +55 -0
  261. package/corpus/templates/macros/app/i18n/index.ts +31 -0
  262. package/corpus/templates/macros/app/i18n/ja-JP.ts +55 -0
  263. package/corpus/templates/macros/app/i18n/ko-KR.ts +55 -0
  264. package/corpus/templates/macros/app/i18n/pt-BR.ts +55 -0
  265. package/corpus/templates/macros/app/i18n/zh-CN.ts +53 -0
  266. package/corpus/templates/macros/app/root.tsx +65 -15
  267. package/corpus/templates/macros/app/routes/settings.tsx +85 -0
  268. package/corpus/templates/macros/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +6 -0
  269. package/corpus/templates/macros/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  270. package/corpus/templates/mail/.agents/skills/self-modifying-code/SKILL.md +6 -0
  271. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +9 -4
  272. package/corpus/templates/mail/app/i18n/ar-SA.ts +33 -0
  273. package/corpus/templates/mail/app/i18n/de-DE.ts +33 -0
  274. package/corpus/templates/mail/app/i18n/en-US.ts +32 -0
  275. package/corpus/templates/mail/app/i18n/es-ES.ts +33 -0
  276. package/corpus/templates/mail/app/i18n/fr-FR.ts +33 -0
  277. package/corpus/templates/mail/app/i18n/hi-IN.ts +32 -0
  278. package/corpus/templates/mail/app/i18n/index.ts +31 -0
  279. package/corpus/templates/mail/app/i18n/ja-JP.ts +32 -0
  280. package/corpus/templates/mail/app/i18n/ko-KR.ts +33 -0
  281. package/corpus/templates/mail/app/i18n/pt-BR.ts +34 -0
  282. package/corpus/templates/mail/app/i18n/zh-CN.ts +32 -0
  283. package/corpus/templates/mail/app/pages/SettingsPage.tsx +67 -13
  284. package/corpus/templates/mail/app/root.tsx +20 -0
  285. package/corpus/templates/mail/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  286. package/corpus/templates/mail/changelog/2026-06-24-settings-now-link-directly-to-agent-settings-for-model-api-k.md +6 -0
  287. package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +5 -0
  288. package/corpus/templates/plan/.agents/skills/self-modifying-code/SKILL.md +6 -0
  289. package/corpus/templates/plan/.agents/skills/visual-plan/references/wireframe.md +22 -4
  290. package/corpus/templates/plan/.agents/skills/visual-recap/references/wireframe.md +22 -4
  291. package/corpus/templates/plan/app/components/layout/Header.tsx +19 -12
  292. package/corpus/templates/plan/app/components/layout/Layout.tsx +11 -7
  293. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +41 -28
  294. package/corpus/templates/plan/app/i18n/ar-SA.ts +77 -0
  295. package/corpus/templates/plan/app/i18n/de-DE.ts +78 -0
  296. package/corpus/templates/plan/app/i18n/en-US.ts +78 -0
  297. package/corpus/templates/plan/app/i18n/es-ES.ts +78 -0
  298. package/corpus/templates/plan/app/i18n/fr-FR.ts +78 -0
  299. package/corpus/templates/plan/app/i18n/hi-IN.ts +78 -0
  300. package/corpus/templates/plan/app/i18n/index.ts +31 -0
  301. package/corpus/templates/plan/app/i18n/ja-JP.ts +79 -0
  302. package/corpus/templates/plan/app/i18n/ko-KR.ts +77 -0
  303. package/corpus/templates/plan/app/i18n/pt-BR.ts +78 -0
  304. package/corpus/templates/plan/app/i18n/zh-CN.ts +74 -0
  305. package/corpus/templates/plan/app/root.tsx +45 -8
  306. package/corpus/templates/plan/app/routes/settings.tsx +86 -0
  307. package/corpus/templates/plan/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +6 -0
  308. package/corpus/templates/plan/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  309. package/corpus/templates/slides/.agents/skills/self-modifying-code/SKILL.md +6 -0
  310. package/corpus/templates/slides/app/components/layout/Header.tsx +23 -11
  311. package/corpus/templates/slides/app/components/layout/Layout.tsx +7 -6
  312. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +23 -11
  313. package/corpus/templates/slides/app/i18n/ar-SA.ts +54 -0
  314. package/corpus/templates/slides/app/i18n/de-DE.ts +56 -0
  315. package/corpus/templates/slides/app/i18n/en-US.ts +55 -0
  316. package/corpus/templates/slides/app/i18n/es-ES.ts +55 -0
  317. package/corpus/templates/slides/app/i18n/fr-FR.ts +55 -0
  318. package/corpus/templates/slides/app/i18n/hi-IN.ts +55 -0
  319. package/corpus/templates/slides/app/i18n/index.ts +31 -0
  320. package/corpus/templates/slides/app/i18n/ja-JP.ts +55 -0
  321. package/corpus/templates/slides/app/i18n/ko-KR.ts +55 -0
  322. package/corpus/templates/slides/app/i18n/pt-BR.ts +55 -0
  323. package/corpus/templates/slides/app/i18n/zh-CN.ts +53 -0
  324. package/corpus/templates/slides/app/root.tsx +50 -8
  325. package/corpus/templates/slides/app/routes/settings.tsx +85 -0
  326. package/corpus/templates/slides/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +6 -0
  327. package/corpus/templates/slides/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  328. package/corpus/templates/videos/.agents/skills/self-modifying-code/SKILL.md +6 -0
  329. package/corpus/templates/videos/app/components/NewCompositionPopover.tsx +14 -9
  330. package/corpus/templates/videos/app/components/Sidebar.tsx +16 -9
  331. package/corpus/templates/videos/app/components/StudioHeader.tsx +12 -8
  332. package/corpus/templates/videos/app/components/layout/Header.tsx +21 -15
  333. package/corpus/templates/videos/app/components/layout/Layout.tsx +10 -7
  334. package/corpus/templates/videos/app/components/layout/NavSidebar.tsx +21 -6
  335. package/corpus/templates/videos/app/i18n/ar-SA.ts +73 -0
  336. package/corpus/templates/videos/app/i18n/de-DE.ts +75 -0
  337. package/corpus/templates/videos/app/i18n/en-US.ts +74 -0
  338. package/corpus/templates/videos/app/i18n/es-ES.ts +75 -0
  339. package/corpus/templates/videos/app/i18n/fr-FR.ts +75 -0
  340. package/corpus/templates/videos/app/i18n/hi-IN.ts +74 -0
  341. package/corpus/templates/videos/app/i18n/index.ts +31 -0
  342. package/corpus/templates/videos/app/i18n/ja-JP.ts +74 -0
  343. package/corpus/templates/videos/app/i18n/ko-KR.ts +74 -0
  344. package/corpus/templates/videos/app/i18n/pt-BR.ts +75 -0
  345. package/corpus/templates/videos/app/i18n/zh-CN.ts +72 -0
  346. package/corpus/templates/videos/app/pages/Index.tsx +11 -9
  347. package/corpus/templates/videos/app/root.tsx +45 -7
  348. package/corpus/templates/videos/app/routes/settings.tsx +85 -0
  349. package/corpus/templates/videos/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +6 -0
  350. package/corpus/templates/videos/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  351. package/dist/agent/durable-background.d.ts +32 -28
  352. package/dist/agent/durable-background.d.ts.map +1 -1
  353. package/dist/agent/durable-background.js +59 -28
  354. package/dist/agent/durable-background.js.map +1 -1
  355. package/dist/agent/production-agent.d.ts.map +1 -1
  356. package/dist/agent/production-agent.js +16 -12
  357. package/dist/agent/production-agent.js.map +1 -1
  358. package/dist/cli/skills.d.ts +1 -1
  359. package/dist/cli/skills.d.ts.map +1 -1
  360. package/dist/cli/skills.js +22 -4
  361. package/dist/cli/skills.js.map +1 -1
  362. package/dist/client/CommandMenu.d.ts +3 -0
  363. package/dist/client/CommandMenu.d.ts.map +1 -1
  364. package/dist/client/CommandMenu.js +9 -0
  365. package/dist/client/CommandMenu.js.map +1 -1
  366. package/dist/client/app-providers.d.ts +8 -1
  367. package/dist/client/app-providers.d.ts.map +1 -1
  368. package/dist/client/app-providers.js +7 -5
  369. package/dist/client/app-providers.js.map +1 -1
  370. package/dist/client/i18n.d.ts +54 -0
  371. package/dist/client/i18n.d.ts.map +1 -0
  372. package/dist/client/i18n.js +354 -0
  373. package/dist/client/i18n.js.map +1 -0
  374. package/dist/client/index.d.ts +2 -1
  375. package/dist/client/index.d.ts.map +1 -1
  376. package/dist/client/index.js +2 -1
  377. package/dist/client/index.js.map +1 -1
  378. package/dist/deploy/build.d.ts +32 -36
  379. package/dist/deploy/build.d.ts.map +1 -1
  380. package/dist/deploy/build.js +47 -104
  381. package/dist/deploy/build.js.map +1 -1
  382. package/dist/deploy/workspace-deploy.js +62 -30
  383. package/dist/deploy/workspace-deploy.js.map +1 -1
  384. package/dist/index.browser.d.ts +1 -1
  385. package/dist/index.browser.d.ts.map +1 -1
  386. package/dist/index.browser.js +1 -1
  387. package/dist/index.browser.js.map +1 -1
  388. package/dist/localization/actions/get-localization-preference.d.ts +4 -0
  389. package/dist/localization/actions/get-localization-preference.d.ts.map +1 -0
  390. package/dist/localization/actions/get-localization-preference.js +16 -0
  391. package/dist/localization/actions/get-localization-preference.js.map +1 -0
  392. package/dist/localization/actions/set-localization-preference.d.ts +6 -0
  393. package/dist/localization/actions/set-localization-preference.d.ts.map +1 -0
  394. package/dist/localization/actions/set-localization-preference.js +24 -0
  395. package/dist/localization/actions/set-localization-preference.js.map +1 -0
  396. package/dist/localization/index.d.ts +3 -0
  397. package/dist/localization/index.d.ts.map +1 -0
  398. package/dist/localization/index.js +3 -0
  399. package/dist/localization/index.js.map +1 -0
  400. package/dist/localization/server.d.ts +25 -0
  401. package/dist/localization/server.d.ts.map +1 -0
  402. package/dist/localization/server.js +69 -0
  403. package/dist/localization/server.js.map +1 -0
  404. package/dist/localization/shared.d.ts +25 -0
  405. package/dist/localization/shared.d.ts.map +1 -0
  406. package/dist/localization/shared.js +134 -0
  407. package/dist/localization/shared.js.map +1 -0
  408. package/dist/server/action-discovery.d.ts.map +1 -1
  409. package/dist/server/action-discovery.js +8 -0
  410. package/dist/server/action-discovery.js.map +1 -1
  411. package/dist/server/index.d.ts +1 -0
  412. package/dist/server/index.d.ts.map +1 -1
  413. package/dist/server/index.js +1 -0
  414. package/dist/server/index.js.map +1 -1
  415. package/dist/server/self-dispatch.d.ts +0 -10
  416. package/dist/server/self-dispatch.d.ts.map +1 -1
  417. package/dist/server/self-dispatch.js +27 -2
  418. package/dist/server/self-dispatch.js.map +1 -1
  419. package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +5 -0
  420. package/dist/templates/default/.agents/skills/internationalization/SKILL.md +77 -0
  421. package/dist/templates/default/.agents/skills/self-modifying-code/SKILL.md +6 -0
  422. package/dist/templates/default/AGENTS.md +16 -15
  423. package/dist/templates/default/app/i18n/en-US.ts +29 -0
  424. package/dist/templates/default/app/i18n/index.ts +13 -0
  425. package/dist/templates/default/app/root.tsx +20 -1
  426. package/dist/templates/default/app/routes/_index.tsx +24 -9
  427. package/dist/templates/default/app/routes/settings.tsx +67 -0
  428. package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +5 -0
  429. package/dist/templates/workspace-core/.agents/skills/internationalization/SKILL.md +77 -0
  430. package/dist/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +6 -0
  431. package/dist/vite/action-types-plugin.d.ts.map +1 -1
  432. package/dist/vite/action-types-plugin.js +8 -0
  433. package/dist/vite/action-types-plugin.js.map +1 -1
  434. package/docs/AGENTS.md +1 -0
  435. package/docs/content/client.md +15 -0
  436. package/docs/content/internationalization.md +145 -0
  437. package/docs/content/locales/ar-SA/internationalization.md +102 -0
  438. package/docs/content/locales/de-DE/internationalization.md +102 -0
  439. package/docs/content/locales/es-ES/internationalization.md +102 -0
  440. package/docs/content/locales/fr-FR/internationalization.md +102 -0
  441. package/docs/content/locales/hi-IN/internationalization.md +102 -0
  442. package/docs/content/locales/ja-JP/internationalization.md +114 -0
  443. package/docs/content/locales/ko-KR/internationalization.md +102 -0
  444. package/docs/content/locales/pt-BR/internationalization.md +102 -0
  445. package/docs/content/locales/zh-CN/internationalization.md +102 -0
  446. package/docs/content/skills-guide.md +19 -18
  447. package/package.json +7 -1
  448. package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +5 -0
  449. package/src/templates/default/.agents/skills/internationalization/SKILL.md +77 -0
  450. package/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +6 -0
  451. package/src/templates/default/AGENTS.md +16 -15
  452. package/src/templates/default/app/i18n/en-US.ts +29 -0
  453. package/src/templates/default/app/i18n/index.ts +13 -0
  454. package/src/templates/default/app/root.tsx +20 -1
  455. package/src/templates/default/app/routes/_index.tsx +24 -9
  456. package/src/templates/default/app/routes/settings.tsx +67 -0
  457. package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +5 -0
  458. package/src/templates/workspace-core/.agents/skills/internationalization/SKILL.md +77 -0
  459. package/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +6 -0
@@ -1510,61 +1510,57 @@ export function isDurableBackgroundDeployEnabled(): boolean {
1510
1510
  * 15-min async function instead of the synchronous `/*` catch-all.
1511
1511
  * Additive + flag-gated (see `isDurableBackgroundDeployEnabled`).
1512
1512
  *
1513
- * GROUNDED IN THE REAL NETLIFY BUILD OUTPUT (verified from a local Nitro build):
1513
+ * GROUNDED IN THE REAL NETLIFY BUILD OUTPUT (verified from a local Nitro build)
1514
+ * AND THE NETLIFY DOCS DEFAULT-URL RULE:
1514
1515
  * - Nitro's `netlify` preset emits exactly ONE function source at
1515
1516
  * `.netlify/functions-internal/server/`. `server.mjs` re-exports `main.mjs`
1516
1517
  * and declares `export const config = { path: "/*", excludedPath:
1517
- * ["/.netlify/*"], preferStatic: true, ... }`. Nitro writes NO `netlify.toml`
1518
- * and NO `[[redirects]]`; the `/*` catch-all is an IN-CODE Functions-API-v2
1519
- * `config.path`.
1518
+ * ["/.netlify/*"], preferStatic: true, ... }`. The `/*` catch-all is an
1519
+ * IN-CODE Functions-API-v2 `config.path` and it ALREADY EXCLUDES
1520
+ * `/.netlify/*`.
1520
1521
  * - The generated `.netlify/netlify.toml` sets
1521
1522
  * `functionsDirectory = ".netlify/functions-internal"`. Netlify scans EXACTLY
1522
1523
  * that dir; functions placed anywhere else (e.g. `.netlify/functions/`, which
1523
1524
  * is the BUILD OUTPUT dir where `@netlify/build` later writes the zipped
1524
1525
  * functions + `manifest.json`) are NEVER deployed.
1525
- * - On Netlify CI, `@netlify/build` reads each scanned function's
1526
- * `export const config`, zips it, and materializes
1527
- * `.netlify/functions/manifest.json` with `routes` derived from each
1528
- * `config.path`. So per-file `export const config` (including `background` and
1529
- * `path`) IS honored — the `server` manifest entry's `routes: [{ pattern:
1530
- * "/*" }]` came straight from `server.mjs`'s `config.path`.
1526
+ * - Every scanned function is reachable at its DEFAULT url
1527
+ * `/.netlify/functions/<name>` BY DEFAULT. A custom `config.path` REMOVES
1528
+ * that default url; declaring NO custom `config.path` KEEPS it.
1531
1529
  *
1532
1530
  * THEREFORE we:
1533
1531
  * 1. Emit the background function INTO the scanned dir
1534
1532
  * (`.netlify/functions-internal/server-agent-background/`), sharing the same
1535
1533
  * built `main.mjs` bundle, so Netlify discovers it and honors its config.
1536
- * 2. Give its `export const config` BOTH `background: true` (→ async invoke,
1537
- * immediate 202, 15-min budget) AND `path: AGENT_CHAT_PROCESS_RUN_PATH` (so
1538
- * it claims that exact path at function-matching time, which Netlify
1539
- * evaluates BEFORE redirects — step 10 vs 11 in the request chain).
1540
- * 3. PATCH the Nitro `server` function's own `server.mjs` so its catch-all
1541
- * `config.path: "/*"` EXCLUDES `AGENT_CHAT_PROCESS_RUN_PATH` (append it to
1542
- * `excludedPath`). Netlify does NOT define a winner when two serverless
1543
- * functions both match a path; rather than rely on that undocumented order,
1544
- * we make the match UNAMBIGUOUS — only the background function matches
1545
- * `_process-run`, and `server` matches everything else exactly as before.
1534
+ * 2. Give its `export const config` `background: true` (→ async invoke,
1535
+ * immediate 202, 15-min budget) and NO custom `config.path`. With no custom
1536
+ * path the function keeps its DEFAULT url
1537
+ * `/.netlify/functions/server-agent-background`, and because the Nitro
1538
+ * `server` function's `/*` catch-all already excludes `/.netlify/*`, that
1539
+ * default-url namespace is NEVER shadowed by the synchronous function — no
1540
+ * catch-all patch is needed.
1541
+ * 3. The entry NORMALIZES/rewrites the incoming request pathname to
1542
+ * `AGENT_CHAT_PROCESS_RUN_PATH` before delegating to `./main.mjs`. The
1543
+ * function is reached at its default url
1544
+ * (`/.netlify/functions/server-agent-background`), so the Nitro router needs
1545
+ * the path rewritten to the framework `_process-run` route, preserving the
1546
+ * method, ALL headers (the HMAC `Authorization: Bearer` MUST survive), and
1547
+ * the body.
1546
1548
  * 4. Set `globalThis.__AGENT_NATIVE_BACKGROUND_RUNTIME__ = true` at cold start
1547
1549
  * (read back by `isInBackgroundFunctionRuntime()` so the worker takes the
1548
1550
  * ~13-min soft-timeout). A `globalThis` flag — NOT `process.env` — keeps the
1549
1551
  * no-env-mutation guard satisfied and carries no cross-request state.
1550
1552
  *
1551
- * With a real `config.path` the function is reachable at that path directly, so
1552
- * the foreground POSTs to `AGENT_CHAT_PROCESS_RUN_PATH`
1553
- * (`resolveAgentChatProcessRunDispatchPath`) and the request entry no longer
1554
- * needs to rewrite the path — it already arrives at the framework route. We keep
1555
- * a defensive normalize-to-PROCESS_RUN_PATH in the entry anyway (cheap, and it
1556
- * makes the function correct even if reached via its default function url).
1553
+ * The foreground dispatches to this DEFAULT url on hosted Netlify
1554
+ * (`resolveAgentChatProcessRunDispatchPath` `AGENT_BACKGROUND_FUNCTION_URL_PATH`).
1557
1555
  *
1558
- * WHY THIS BEATS ALL THREE PRIOR FAILURES:
1559
- * - Attempts 1 & 2 emitted into `functions-internal` (correct dir) with a
1560
- * `config.path` but did NOT exclude that path from the `server` `/*`
1561
- * catch-all. Two functions matched `_process-run`; the order is undocumented
1562
- * and the catch-all `server` (priority 0, synchronous) won SYNC 401, not a
1563
- * 202. We now exclude the path from `server`, so only the async function
1564
- * matches.
1565
- * - Attempt 3 emitted a standalone function into `.netlify/functions/` — the
1566
- * OUTPUT dir, which Netlify does not scan — so it never entered the manifest
1567
- * → 404. We now emit into the SCANNED `functions-internal` dir.
1556
+ * WHY THIS IS THE DOC-CORRECT FIX: a prior attempt gave the function a custom
1557
+ * `config.path` (= the framework route) plus a catch-all `excludedPath` patch.
1558
+ * The custom `config.path` was NOT honored as a route in prod — a probe of
1559
+ * `POST /_agent-native/agent-chat/_process-run` returned 404. The doc-correct
1560
+ * approach (confirmed against the Netlify docs) is to use the DEFAULT function
1561
+ * url with no custom path: the function stays reachable at
1562
+ * `/.netlify/functions/<name>` and is never shadowed because `/.netlify/*` is
1563
+ * already excluded from the `server` catch-all.
1568
1564
  *
1569
1565
  * Safety net regardless of Netlify routing nuance: if the dispatch fast-fails
1570
1566
  * (e.g. the function was not emitted), the foreground handler degrades to an
@@ -1596,11 +1592,6 @@ export function emitSingleTemplateNetlifyBackgroundFunction(
1596
1592
  // copied bundle does NOT re-register the catch-all `config.path`.
1597
1593
  fs.rmSync(path.join(dest, "server.mjs"), { force: true });
1598
1594
 
1599
- // Make the `server` `/*` catch-all NOT match the process-run path, so only the
1600
- // async background function matches it (function-vs-function path order is
1601
- // undocumented on Netlify — don't rely on it).
1602
- excludeProcessRunPathFromServerCatchAll(serverDir);
1603
-
1604
1595
  const processRunPath = JSON.stringify(AGENT_CHAT_PROCESS_RUN_PATH);
1605
1596
  const entry = `// Mark this isolate as the durable background runtime BEFORE the handler
1606
1597
  // bundle is imported, so isInBackgroundFunctionRuntime() reliably returns true
@@ -1618,11 +1609,10 @@ let cachedHandler;
1618
1609
 
1619
1610
  // Netlify v2 invokes this as (request, context). The Nitro netlify handler is a
1620
1611
  // Web-standard \`async (Request) => Response\` (see nitro/presets/netlify/runtime).
1621
- // Because this function declares \`config.path = PROCESS_RUN_PATH\`, Netlify routes
1622
- // that exact path here and the request already arrives as PROCESS_RUN_PATH — no
1623
- // rewrite is needed. We still NORMALIZE the pathname to PROCESS_RUN_PATH so the
1624
- // function stays correct even if it is ever reached via its default function url
1625
- // (/.netlify/functions/${backgroundName}). Method, ALL headers (the HMAC
1612
+ // This function declares NO custom \`config.path\`, so it is reached at its
1613
+ // DEFAULT url (/.netlify/functions/${backgroundName}). The Nitro router only
1614
+ // knows the framework route, so we REWRITE the incoming pathname to
1615
+ // PROCESS_RUN_PATH before delegating. Method, ALL headers (the HMAC
1626
1616
  // Authorization: Bearer MUST survive — the plugin verifies it) and the body are
1627
1617
  // preserved by cloning the incoming Request with only its URL pathname set.
1628
1618
  export default async function handler(request) {
@@ -1646,13 +1636,12 @@ export const config = {
1646
1636
  generator: "agent-native build",
1647
1637
  // background: true makes Netlify invoke this ASYNCHRONOUSLY (immediate HTTP
1648
1638
  // 202 ack) with the 15-minute budget (Netlify docs:
1649
- // build/functions/background-functions + build/functions/api). path claims the
1650
- // process-run route directly; Netlify evaluates serverless functions BEFORE
1651
- // redirects (request-chain step 10 vs 11), and we exclude this path from the
1652
- // \`server\` /* catch-all so only THIS function matches it no ambiguous
1653
- // function-vs-function order.
1639
+ // build/functions/background-functions + build/functions/api). We declare NO
1640
+ // custom path, so the function keeps its DEFAULT url
1641
+ // /.netlify/functions/${backgroundName}; the Nitro \`server\` /* catch-all
1642
+ // already excludes /.netlify/* so that default url is never shadowed by the
1643
+ // synchronous function. The foreground dispatches to that default url.
1654
1644
  background: true,
1655
- path: PROCESS_RUN_PATH,
1656
1645
  nodeBundler: "none",
1657
1646
  includedFiles: ["**"],
1658
1647
  preferStatic: false,
@@ -1661,67 +1650,12 @@ export const config = {
1661
1650
  fs.writeFileSync(path.join(dest, `${backgroundName}.mjs`), entry);
1662
1651
  console.log(
1663
1652
  `[build] Emitted durable-background function "${backgroundName}" into the ` +
1664
- `scanned dir .netlify/functions-internal with config { background:true, ` +
1665
- `path:"${AGENT_CHAT_PROCESS_RUN_PATH}" } and excluded that path from the ` +
1666
- `server /* catch-all. REQUIRES real-deploy verification of Netlify async ` +
1667
- `(202) invocation see docs/design/durable-agent-runs.md.`,
1668
- );
1669
- }
1670
-
1671
- /**
1672
- * Append `AGENT_CHAT_PROCESS_RUN_PATH` to the Nitro `server` function's
1673
- * `config.excludedPath` so its `/*` catch-all does NOT match the process-run
1674
- * path. That guarantees the async background function (which declares
1675
- * `config.path = AGENT_CHAT_PROCESS_RUN_PATH`) is the ONLY function that matches
1676
- * that path — Netlify does not define a winner when two serverless functions
1677
- * both match, so we make the match unambiguous instead of relying on order.
1678
- *
1679
- * The Nitro-generated `server/server.mjs` is small and deterministic:
1680
- * export { default } from "./main.mjs";
1681
- * export const config = { ... excludedPath: ["/.netlify/*"], ... };
1682
- * We parse the `excludedPath: [...]` array literal and add our path if absent.
1683
- * If the shape ever changes and we can't find/parse it, we log and leave the
1684
- * file untouched (the inline-40s fallback still keeps chat working).
1685
- */
1686
- function excludeProcessRunPathFromServerCatchAll(serverDir: string): void {
1687
- const serverEntry = path.join(serverDir, "server.mjs");
1688
- if (!fs.existsSync(serverEntry)) {
1689
- console.warn(
1690
- "[build] Durable-background: server/server.mjs not found; cannot exclude " +
1691
- `${AGENT_CHAT_PROCESS_RUN_PATH} from the /* catch-all.`,
1692
- );
1693
- return;
1694
- }
1695
- const original = fs.readFileSync(serverEntry, "utf8");
1696
- if (original.includes(AGENT_CHAT_PROCESS_RUN_PATH)) {
1697
- // Already excluded (idempotent — emit may run on a re-used output tree).
1698
- return;
1699
- }
1700
- const excludedPathRe = /excludedPath:\s*\[([^\]]*)\]/;
1701
- const match = original.match(excludedPathRe);
1702
- const quotedPath = JSON.stringify(AGENT_CHAT_PROCESS_RUN_PATH);
1703
- if (match) {
1704
- const existing = match[1].trim();
1705
- const next = existing
1706
- ? `excludedPath: [${existing.replace(/,\s*$/, "")}, ${quotedPath}]`
1707
- : `excludedPath: [${quotedPath}]`;
1708
- fs.writeFileSync(serverEntry, original.replace(excludedPathRe, next));
1709
- return;
1710
- }
1711
- // No existing `excludedPath` — inject one into the config object. Match the
1712
- // `path: "/*"` line and add `excludedPath` right after it.
1713
- const pathLineRe = /(path:\s*("\/\*"|'\/\*'),?)/;
1714
- if (pathLineRe.test(original)) {
1715
- fs.writeFileSync(
1716
- serverEntry,
1717
- original.replace(pathLineRe, `$1\n excludedPath: [${quotedPath}],`),
1718
- );
1719
- return;
1720
- }
1721
- console.warn(
1722
- "[build] Durable-background: could not locate excludedPath/path in " +
1723
- "server/server.mjs; leaving the /* catch-all unchanged (the background " +
1724
- "function may be shadowed — the inline-40s fallback still applies).",
1653
+ `scanned dir .netlify/functions-internal with config { background:true } ` +
1654
+ `and NO custom path reachable at its default url ` +
1655
+ `/.netlify/functions/${backgroundName} (never shadowed; the server /* ` +
1656
+ `catch-all already excludes /.netlify/*). REQUIRES real-deploy ` +
1657
+ `verification of Netlify async (202) invocation — see ` +
1658
+ `docs/design/durable-agent-runs.md.`,
1725
1659
  );
1726
1660
  }
1727
1661
 
@@ -696,24 +696,30 @@ function isDurableBackgroundDeployEnabled(): boolean {
696
696
  /**
697
697
  * Emit a SECOND Netlify function for `app` whose name ends in `-background`,
698
698
  * re-exporting the SAME `main.mjs` handler bundle. Netlify invokes any function
699
- * whose deployed name ends in `-background` asynchronously (202 immediately, up
700
- * to 15-min budget), which is exactly what the durable-background chat
701
- * dispatch (`fireInternalDispatch` → AGENT_CHAT_PROCESS_RUN_PATH) needs.
699
+ * with `config.background: true` asynchronously (202 immediately, up to 15-min
700
+ * budget), which is exactly what the durable-background chat dispatch
701
+ * (`fireInternalDispatch` → the function's default url) needs.
702
702
  *
703
- * The function is given a `config.path` of the chat process-run route so
704
- * Netlify routes that POST to this async function instead of the synchronous
705
- * `<app>-server` function. It shares the same bundle (`includedFiles: ["**"]`)
706
- * so `A2A_SECRET`, the DB URL, and the rest of the env/bundle are present.
703
+ * DOC-CORRECT DEFAULT-URL APPROACH (mirrors the single-template emit in
704
+ * deploy/build.ts): the function declares NO custom `config.path`, so it keeps
705
+ * its DEFAULT url `/.netlify/functions/<app>-agent-background`. The `<app>-server`
706
+ * function's catch-all already excludes `/.netlify/*`, so that default-url
707
+ * namespace is NEVER shadowed by the synchronous function — no overlapping
708
+ * `config.path` and no catch-all patch are needed. The foreground dispatches to
709
+ * that default url (`resolveAgentChatProcessRunDispatchPath` resolves the per-app
710
+ * name from `AGENT_NATIVE_WORKSPACE_APP_ID`); `fireInternalDispatch` strips the
711
+ * app base path for `/.netlify/*` targets so the request reaches the host-root
712
+ * function url. The entry then REWRITES the incoming pathname to the
713
+ * base-path-prefixed `_process-run` route before delegating to the Nitro router.
707
714
  *
708
- * ⚠️ REAL-DEPLOY VERIFICATION REQUIRED. The exact Netlify routing/precedence
709
- * between this `-background` function's `config.path` and the synchronous
710
- * `<app>-server` function's broader `config.path` (which also matches
711
- * `/_agent-native/*` for the dispatch app, or `/<app>/*` otherwise) cannot be
712
- * verified in this environment. It is emitted additively and only under the
713
- * flag; if Netlify resolves the overlap to the wrong function, the dispatch
714
- * would land on the synchronous function (no 15-min budget) the run would
715
- * still work via the existing 40s soft-timeout path, just without the durable
716
- * win. See packages/core/docs/design/durable-agent-runs.md.
715
+ * It shares the same bundle (`includedFiles: ["**"]`) so `A2A_SECRET`, the DB
716
+ * URL, and the rest of the env/bundle are present. A prior attempt gave the
717
+ * function a custom `config.path` (the framework route) that overlapped the
718
+ * synchronous `<app>-server` catch-all; that path was not honored as a route in
719
+ * prod (probe 404). The default url is the doc-correct fix.
720
+ *
721
+ * Safety net: if the dispatch fast-fails the foreground degrades to an inline
722
+ * 40s synchronous run (see production-agent.ts).
717
723
  */
718
724
  function emitNetlifyBackgroundFunction(
719
725
  workspaceRoot: string,
@@ -721,7 +727,9 @@ function emitNetlifyBackgroundFunction(
721
727
  srcServerDir: string,
722
728
  workspaceApps: WorkspaceAppManifestEntry[],
723
729
  ): void {
724
- // Name MUST end in `-background` for Netlify async invocation.
730
+ // Name MUST end in `-background` (Netlify async convention + the runtime guard
731
+ // reads the -background Lambda-name suffix as a fallback). It is reached at its
732
+ // DEFAULT url /.netlify/functions/<app>-agent-background.
725
733
  const backgroundName = `${app}-agent-background`;
726
734
  const dest = path.join(netlifyFunctionsDir(workspaceRoot), backgroundName);
727
735
  fs.rmSync(dest, { recursive: true, force: true });
@@ -733,14 +741,20 @@ function emitNetlifyBackgroundFunction(
733
741
  workspaceApps,
734
742
  app,
735
743
  );
736
- // Only the chat process-run route needs the async function. Keeping the path
737
- // narrow avoids stealing any other traffic from the synchronous function.
738
- // The dispatch URL is app-base-path-prefixed (same as the agent-teams
739
- // processor dispatch), so the route Netlify must map to this async function
740
- // is `/<app>/_agent-native/agent-chat/_process-run`.
744
+ // The Nitro router for this app expects the base-path-prefixed framework route.
745
+ // The function is reached at its default url, so the entry rewrites the
746
+ // incoming pathname to `/<app>/_agent-native/agent-chat/_process-run`.
741
747
  const processRunPath = `${basePath}${AGENT_CHAT_PROCESS_RUN_PATH}`;
742
- const pathConfig = [processRunPath];
743
- const server = `const basePath = ${JSON.stringify(basePath)};
748
+ const server = `// Mark this isolate as the durable background runtime BEFORE the handler bundle
749
+ // is imported, so isInBackgroundFunctionRuntime() reliably returns true in this
750
+ // function (the deployed Lambda name is not guaranteed to end in -background). A
751
+ // globalThis flag (NOT process.env) avoids the no-env-mutation guard and carries
752
+ // no cross-request state.
753
+ globalThis.__AGENT_NATIVE_BACKGROUND_RUNTIME__ = true;
754
+
755
+ const basePath = ${JSON.stringify(basePath)};
756
+ // The base-path-prefixed framework route the Nitro router dispatches to.
757
+ const PROCESS_RUN_PATH = ${JSON.stringify(processRunPath)};
744
758
 
745
759
  function setBasePathEnv() {
746
760
  const processRef = globalThis.process ??= { env: {} };
@@ -767,16 +781,33 @@ setBasePathEnv();
767
781
 
768
782
  let cachedHandler;
769
783
 
770
- export default async function handler(...args) {
784
+ // Reached at the DEFAULT url /.netlify/functions/${backgroundName}; REWRITE the
785
+ // incoming pathname to the base-path-prefixed _process-run route so the Nitro
786
+ // router runs the plugin. Method, ALL headers (the HMAC Authorization: Bearer
787
+ // MUST survive) and the body are preserved.
788
+ export default async function handler(request) {
771
789
  setBasePathEnv();
772
790
  cachedHandler ??= (await import("./main.mjs")).default;
773
- return cachedHandler(...args);
791
+ const url = new URL(request.url);
792
+ url.pathname = PROCESS_RUN_PATH;
793
+ const method = request.method || "POST";
794
+ const hasBody = method !== "GET" && method !== "HEAD";
795
+ const body = hasBody ? await request.text() : undefined;
796
+ const rewritten = new Request(url.toString(), {
797
+ method,
798
+ headers: request.headers,
799
+ body,
800
+ });
801
+ return cachedHandler(rewritten);
774
802
  }
775
803
 
776
804
  export const config = {
777
805
  name: ${JSON.stringify(`${app} agent background handler`)},
778
806
  generator: "agent-native workspace deploy",
779
- path: ${JSON.stringify(pathConfig)},
807
+ // background: true → async invoke (202, 15-min budget). NO custom path: the
808
+ // function keeps its default url /.netlify/functions/${backgroundName}, which
809
+ // the <app>-server catch-all never shadows (it excludes /.netlify/*).
810
+ background: true,
780
811
  nodeBundler: "none",
781
812
  includedFiles: ["**"],
782
813
  preferStatic: false,
@@ -788,9 +819,10 @@ export const config = {
788
819
  fs.writeFileSync(path.join(dest, `${backgroundName}.mjs`), server);
789
820
  console.log(
790
821
  `[workspace-deploy] Emitted durable-background function "${backgroundName}" ` +
791
- `for app "${app}" (path ${processRunPath}). ` +
792
- `REQUIRES real-deploy verification of Netlify async routing — see ` +
793
- `docs/design/durable-agent-runs.md.`,
822
+ `for app "${app}" with config { background:true } and NO custom path — ` +
823
+ `reachable at its default url /.netlify/functions/${backgroundName} ` +
824
+ `(rewrites to ${processRunPath}). REQUIRES real-deploy verification of ` +
825
+ `Netlify async (202) invocation — see docs/design/durable-agent-runs.md.`,
794
826
  );
795
827
  }
796
828
 
@@ -25,6 +25,23 @@ export {
25
25
  updateMcpAppModelContext,
26
26
  useMcpAppHostContext,
27
27
  CodeRequiredDialog,
28
+ AgentNativeI18nProvider,
29
+ LanguagePicker,
30
+ getLocaleInitScript,
31
+ localeDirection,
32
+ normalizeLocaleCode,
33
+ normalizeLocalePreference,
34
+ normalizeLocalizationPreference,
35
+ resolveLocaleFromCandidates,
36
+ resolveLocaleFromPreference,
37
+ useFormatters,
38
+ useLocale,
39
+ useT,
40
+ DEFAULT_LOCALE,
41
+ LOCALE_HYDRATION_GLOBAL,
42
+ LOCALE_METADATA,
43
+ LOCALE_STORAGE_KEY,
44
+ SUPPORTED_LOCALES,
28
45
  useDbSync,
29
46
  useFileWatcher,
30
47
  useSession,
@@ -48,6 +65,14 @@ export {
48
65
  type CodeRequiredDialogProps,
49
66
  type AuthSession,
50
67
  type UseAgentChatContextResult,
68
+ type AgentNativeI18nCatalog,
69
+ type AgentNativeI18nProviderProps,
70
+ type LocaleCode,
71
+ type LocaleHydrationPayload,
72
+ type LocaleMessages,
73
+ type LocaleMetadata,
74
+ type LocalePreference,
75
+ type LocalizationPreference,
51
76
  } from "./client/index.js";
52
77
 
53
78
  // Shared (isomorphic)
@@ -0,0 +1,23 @@
1
+ import { z } from "zod";
2
+ import { defineAction } from "../../action.js";
3
+ import { getUserSetting } from "../../settings/user-settings.js";
4
+ import {
5
+ LOCALIZATION_SETTING_KEY,
6
+ normalizeLocalizationPreference,
7
+ type LocalizationPreference,
8
+ } from "../shared.js";
9
+
10
+ export default defineAction({
11
+ description:
12
+ "Get the current user's interface language preference. Returns { locale }, where locale is 'system' or a supported BCP-47 locale.",
13
+ schema: z.object({}),
14
+ http: { method: "GET" },
15
+ run: async (_args, ctx): Promise<LocalizationPreference> => {
16
+ if (!ctx?.userEmail) throw new Error("Not authenticated.");
17
+ const stored = await getUserSetting(
18
+ ctx.userEmail,
19
+ LOCALIZATION_SETTING_KEY,
20
+ );
21
+ return normalizeLocalizationPreference(stored);
22
+ },
23
+ });
@@ -0,0 +1,30 @@
1
+ import { z } from "zod";
2
+ import { defineAction } from "../../action.js";
3
+ import { putUserSetting } from "../../settings/user-settings.js";
4
+ import {
5
+ LOCALIZATION_SETTING_KEY,
6
+ normalizeLocalePreference,
7
+ type LocalizationPreference,
8
+ } from "../shared.js";
9
+
10
+ export default defineAction({
11
+ description:
12
+ "Set the current user's interface language preference to 'system' or a supported BCP-47 locale.",
13
+ schema: z.object({
14
+ locale: z
15
+ .string()
16
+ .describe("Language preference: 'system' or a supported BCP-47 locale."),
17
+ }),
18
+ run: async (args, ctx): Promise<LocalizationPreference> => {
19
+ if (!ctx?.userEmail) throw new Error("Not authenticated.");
20
+ const locale = normalizeLocalePreference(args.locale);
21
+ if (!locale) {
22
+ throw new Error(
23
+ "Unsupported locale. Use system, en-US, zh-CN, es-ES, fr-FR, de-DE, ja-JP, ko-KR, pt-BR, hi-IN, or ar-SA.",
24
+ );
25
+ }
26
+ const value: LocalizationPreference & Record<string, unknown> = { locale };
27
+ await putUserSetting(ctx.userEmail, LOCALIZATION_SETTING_KEY, value);
28
+ return value;
29
+ },
30
+ });
@@ -0,0 +1,2 @@
1
+ export * from "./shared.js";
2
+ export * from "./server.js";
@@ -0,0 +1,131 @@
1
+ import {
2
+ DEFAULT_LOCALE,
3
+ LOCALE_HYDRATION_GLOBAL,
4
+ LOCALE_STORAGE_KEY,
5
+ SUPPORTED_LOCALES,
6
+ localeDirection,
7
+ normalizeLocaleCode,
8
+ normalizeLocalizationPreference,
9
+ resolveLocaleFromPreference,
10
+ type LocaleCode,
11
+ type LocalePreference,
12
+ type LocalizationPreference,
13
+ } from "./shared.js";
14
+
15
+ interface RequestLike {
16
+ headers?: Headers | Record<string, string | string[] | undefined> | null;
17
+ }
18
+
19
+ type HeaderMap = Headers | Record<string, string | string[] | undefined>;
20
+
21
+ export interface ResolvedRequestLocale {
22
+ locale: LocaleCode;
23
+ preference: LocalizationPreference;
24
+ dir: "ltr" | "rtl";
25
+ }
26
+
27
+ export interface ResolveLocaleFromRequestOptions {
28
+ request?: Request | RequestLike | null;
29
+ acceptLanguage?: string | null;
30
+ preference?: LocalizationPreference | LocalePreference | null;
31
+ fallback?: LocaleCode;
32
+ }
33
+
34
+ export interface LocaleInitScriptOptions {
35
+ locale?: LocaleCode;
36
+ preference?: LocalizationPreference | LocalePreference;
37
+ messages?: Record<string, unknown> | null;
38
+ }
39
+
40
+ function readHeader(
41
+ headers: HeaderMap | undefined | null,
42
+ key: string,
43
+ ): string | null {
44
+ if (!headers) return null;
45
+ if (typeof (headers as Headers).get === "function") {
46
+ return (headers as Headers).get(key);
47
+ }
48
+ const lowerKey = key.toLowerCase();
49
+ for (const [name, value] of Object.entries(headers)) {
50
+ if (name.toLowerCase() !== lowerKey) continue;
51
+ if (Array.isArray(value)) return value.join(",");
52
+ return value ?? null;
53
+ }
54
+ return null;
55
+ }
56
+
57
+ export function parseAcceptLanguage(header: string | null | undefined) {
58
+ if (!header) return [];
59
+ return header
60
+ .split(",")
61
+ .map((part) => {
62
+ const [tag, ...params] = part.trim().split(";");
63
+ const q = params
64
+ .map((param) => param.trim())
65
+ .find((param) => param.startsWith("q="));
66
+ const weight = q ? Number.parseFloat(q.slice(2)) : 1;
67
+ return {
68
+ tag,
69
+ weight: Number.isFinite(weight) ? weight : 0,
70
+ };
71
+ })
72
+ .filter((entry) => entry.tag && entry.weight > 0)
73
+ .sort((a, b) => b.weight - a.weight)
74
+ .map((entry) => entry.tag);
75
+ }
76
+
77
+ export function resolveLocaleFromRequest(
78
+ options: ResolveLocaleFromRequestOptions = {},
79
+ ): ResolvedRequestLocale {
80
+ const header =
81
+ options.acceptLanguage ??
82
+ readHeader(options.request?.headers, "accept-language");
83
+ const candidates = parseAcceptLanguage(header);
84
+ const preference = normalizeLocalizationPreference(
85
+ options.preference ?? { locale: "system" },
86
+ );
87
+ const locale =
88
+ preference.locale === "system"
89
+ ? resolveLocaleFromPreference(preference, [
90
+ ...candidates,
91
+ options.fallback ?? DEFAULT_LOCALE,
92
+ ])
93
+ : (normalizeLocaleCode(preference.locale) ??
94
+ options.fallback ??
95
+ DEFAULT_LOCALE);
96
+ return {
97
+ locale,
98
+ preference,
99
+ dir: localeDirection(locale),
100
+ };
101
+ }
102
+
103
+ export function getLocaleInitScript(options: LocaleInitScriptOptions = {}) {
104
+ const safeLocale = normalizeLocaleCode(options.locale) ?? DEFAULT_LOCALE;
105
+ const shouldStorePreference = options.preference !== undefined;
106
+ const safePreference = normalizeLocalizationPreference(
107
+ options.preference ?? { locale: "system" },
108
+ );
109
+ const payload = {
110
+ locale: safeLocale,
111
+ preference: safePreference,
112
+ dir: localeDirection(safeLocale),
113
+ messages: options.messages ?? undefined,
114
+ };
115
+
116
+ return `(function(){try{var supported=${JSON.stringify(
117
+ SUPPORTED_LOCALES,
118
+ )};var payload=${JSON.stringify(
119
+ payload,
120
+ )};var shouldStorePreference=${JSON.stringify(
121
+ shouldStorePreference,
122
+ )};function valid(x){return supported.indexOf(x)>=0}function canon(x){if(typeof x!=='string'||!x)return null;try{var c=Intl.getCanonicalLocales(x)[0];if(valid(c))return c;var lang=c&&c.split('-')[0].toLowerCase();for(var i=0;i<supported.length;i++){if(supported[i].split('-')[0].toLowerCase()===lang)return supported[i]}}catch(e){}return null}function storageGet(k){try{return window.localStorage.getItem(k)}catch(e){return null}}function storageSet(k,v){try{window.localStorage.setItem(k,v)}catch(e){}}var stored=storageGet(${JSON.stringify(
123
+ LOCALE_STORAGE_KEY,
124
+ )});var pref=payload.preference&&payload.preference.locale;var locale=payload.locale;if(!valid(locale)){locale=null}if(!locale&&stored&&stored!=='system'){locale=canon(stored)}if(!locale&&pref&&pref!=='system'){locale=canon(pref)}if(!locale){var langs=navigator.languages&&navigator.languages.length?navigator.languages:[navigator.language];for(var j=0;j<langs.length&&!locale;j++){locale=canon(langs[j])}}if(!locale)locale=${JSON.stringify(
125
+ DEFAULT_LOCALE,
126
+ )};var root=document.documentElement;root.setAttribute('lang',locale);root.setAttribute('dir',locale==='ar-SA'?'rtl':'ltr');root.setAttribute('data-locale',locale);payload.locale=locale;payload.dir=locale==='ar-SA'?'rtl':'ltr';window[${JSON.stringify(
127
+ LOCALE_HYDRATION_GLOBAL,
128
+ )}]=payload;if(shouldStorePreference&&pref){storageSet(${JSON.stringify(
129
+ LOCALE_STORAGE_KEY,
130
+ )},pref)}}catch(e){}})();`;
131
+ }