@agent-native/core 0.101.12 → 0.101.14

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 (307) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +15 -0
  3. package/corpus/core/package.json +4 -2
  4. package/corpus/core/src/cli/create.ts +76 -17
  5. package/corpus/core/src/client/AgentPanel.tsx +61 -48
  6. package/corpus/core/src/client/assistant-ui-recovery.tsx +9 -3
  7. package/corpus/core/src/client/chat/message-components.tsx +26 -2
  8. package/corpus/core/src/client/chat/tool-call-display.tsx +18 -11
  9. package/corpus/core/src/mcp/server.ts +10 -1
  10. package/corpus/core/src/server/agent-chat/framework-prompts.ts +0 -3
  11. package/corpus/core/src/server/agent-chat-plugin.ts +2 -58
  12. package/corpus/core/src/server/prompts/framework-core-compact.ts +0 -1
  13. package/corpus/core/src/server/prompts/framework-core.ts +0 -30
  14. package/corpus/core/src/server/prompts/index.ts +1 -4
  15. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +0 -14
  16. package/corpus/templates/chat/changelog/2026-07-15-chat-navigation-focuses-on-chat-and-agent.md +6 -0
  17. package/corpus/templates/clips/app/components/player/share-dialog.tsx +1 -1
  18. package/corpus/templates/clips/app/i18n/ar-SA.ts +1 -0
  19. package/corpus/templates/clips/app/i18n/de-DE.ts +1 -0
  20. package/corpus/templates/clips/app/i18n/en-US.ts +1 -0
  21. package/corpus/templates/clips/app/i18n/es-ES.ts +1 -0
  22. package/corpus/templates/clips/app/i18n/fr-FR.ts +1 -0
  23. package/corpus/templates/clips/app/i18n/hi-IN.ts +1 -0
  24. package/corpus/templates/clips/app/i18n/ja-JP.ts +1 -0
  25. package/corpus/templates/clips/app/i18n/ko-KR.ts +1 -0
  26. package/corpus/templates/clips/app/i18n/pt-BR.ts +1 -0
  27. package/corpus/templates/clips/app/i18n/zh-CN.ts +1 -0
  28. package/corpus/templates/clips/app/i18n/zh-TW.ts +1 -0
  29. package/corpus/templates/clips/changelog/2026-07-15-public-clip-links-are-labeled-share-with-humans-for-clarity.md +6 -0
  30. package/corpus/templates/forms/actions/delete-form.ts +4 -0
  31. package/corpus/templates/forms/actions/patch-form-fields.ts +3 -0
  32. package/corpus/templates/forms/actions/restore-form.ts +3 -0
  33. package/corpus/templates/forms/actions/update-form.ts +3 -0
  34. package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +2 -2
  35. package/corpus/templates/forms/app/pages/ResponsesPage.tsx +2 -2
  36. package/corpus/templates/forms/changelog/2026-07-15-published-forms-now-reflect-field-updates-immediately-at-the.md +6 -0
  37. package/corpus/templates/forms/changelog/2026-07-15-response-rows-now-keep-every-column-aligned-to-the-top-for-c.md +6 -0
  38. package/corpus/templates/forms/server/handlers/forms.ts +1 -0
  39. package/corpus/templates/forms/server/lib/public-form-ssr.ts +47 -4
  40. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +189 -82
  41. package/corpus/templates/slides/app/pages/DeckEditor.tsx +1 -1
  42. package/dist/cli/create.d.ts +5 -2
  43. package/dist/cli/create.d.ts.map +1 -1
  44. package/dist/cli/create.js +52 -17
  45. package/dist/cli/create.js.map +1 -1
  46. package/dist/client/AgentPanel.d.ts +2 -0
  47. package/dist/client/AgentPanel.d.ts.map +1 -1
  48. package/dist/client/AgentPanel.js +24 -13
  49. package/dist/client/AgentPanel.js.map +1 -1
  50. package/dist/client/assistant-ui-recovery.d.ts +2 -0
  51. package/dist/client/assistant-ui-recovery.d.ts.map +1 -1
  52. package/dist/client/assistant-ui-recovery.js +5 -2
  53. package/dist/client/assistant-ui-recovery.js.map +1 -1
  54. package/dist/client/chat/message-components.d.ts +6 -0
  55. package/dist/client/chat/message-components.d.ts.map +1 -1
  56. package/dist/client/chat/message-components.js +15 -2
  57. package/dist/client/chat/message-components.js.map +1 -1
  58. package/dist/client/chat/tool-call-display.d.ts +4 -2
  59. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  60. package/dist/client/chat/tool-call-display.js +11 -13
  61. package/dist/client/chat/tool-call-display.js.map +1 -1
  62. package/dist/collab/awareness.d.ts +2 -2
  63. package/dist/collab/awareness.d.ts.map +1 -1
  64. package/dist/collab/struct-routes.d.ts +1 -1
  65. package/dist/mcp/server.d.ts.map +1 -1
  66. package/dist/mcp/server.js +10 -1
  67. package/dist/mcp/server.js.map +1 -1
  68. package/dist/notifications/routes.d.ts +2 -2
  69. package/dist/resources/handlers.d.ts +3 -3
  70. package/dist/server/agent-chat/framework-prompts.d.ts.map +1 -1
  71. package/dist/server/agent-chat/framework-prompts.js +0 -3
  72. package/dist/server/agent-chat/framework-prompts.js.map +1 -1
  73. package/dist/server/agent-chat-plugin.d.ts +0 -22
  74. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  75. package/dist/server/agent-chat-plugin.js +2 -51
  76. package/dist/server/agent-chat-plugin.js.map +1 -1
  77. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  78. package/dist/server/prompts/framework-core-compact.d.ts +0 -1
  79. package/dist/server/prompts/framework-core-compact.d.ts.map +1 -1
  80. package/dist/server/prompts/framework-core-compact.js +0 -1
  81. package/dist/server/prompts/framework-core-compact.js.map +1 -1
  82. package/dist/server/prompts/framework-core.d.ts +0 -9
  83. package/dist/server/prompts/framework-core.d.ts.map +1 -1
  84. package/dist/server/prompts/framework-core.js +0 -29
  85. package/dist/server/prompts/framework-core.js.map +1 -1
  86. package/dist/server/prompts/index.d.ts +1 -1
  87. package/dist/server/prompts/index.d.ts.map +1 -1
  88. package/dist/server/prompts/index.js +1 -1
  89. package/dist/server/prompts/index.js.map +1 -1
  90. package/dist/server/transcribe-voice.d.ts +1 -1
  91. package/dist/templates/chat/.agents/skills/actions/SKILL.md +492 -0
  92. package/dist/templates/chat/.agents/skills/adding-a-feature/SKILL.md +189 -0
  93. package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +76 -0
  94. package/dist/templates/chat/.agents/skills/capture-learnings/SKILL.md +89 -0
  95. package/dist/templates/chat/.agents/skills/create-skill/SKILL.md +221 -0
  96. package/dist/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +263 -0
  97. package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +112 -0
  98. package/dist/templates/chat/.agents/skills/real-time-sync/SKILL.md +232 -0
  99. package/dist/templates/chat/.agents/skills/security/SKILL.md +280 -0
  100. package/dist/templates/chat/.agents/skills/self-modifying-code/SKILL.md +106 -0
  101. package/dist/templates/chat/.agents/skills/shadcn-ui/SKILL.md +95 -0
  102. package/dist/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  103. package/dist/templates/chat/.env.example +5 -0
  104. package/dist/templates/chat/.ignore +0 -0
  105. package/dist/templates/chat/.oxfmtrc.json +8 -0
  106. package/dist/templates/chat/.react-router/types/+server-build.d.ts +18 -0
  107. package/dist/templates/chat/.react-router/types/app/+types/root.ts +68 -0
  108. package/dist/templates/chat/AGENTS.md +62 -0
  109. package/dist/templates/chat/CHANGELOG.md +10 -0
  110. package/dist/templates/chat/DEVELOPING.md +185 -0
  111. package/dist/templates/chat/README.md +32 -0
  112. package/dist/templates/chat/_gitignore +43 -0
  113. package/dist/templates/chat/actions/hello.ts +13 -0
  114. package/dist/templates/chat/actions/navigate.ts +41 -0
  115. package/dist/templates/chat/actions/run.ts +2 -0
  116. package/dist/templates/chat/actions/view-screen.ts +31 -0
  117. package/dist/templates/chat/app/components/layout/Header.tsx +59 -0
  118. package/dist/templates/chat/app/components/layout/Layout.tsx +184 -0
  119. package/dist/templates/chat/app/components/layout/Sidebar.tsx +580 -0
  120. package/dist/templates/chat/app/components/ui/button.tsx +1 -0
  121. package/dist/templates/chat/app/components/ui/card.tsx +1 -0
  122. package/dist/templates/chat/app/components/ui/dropdown-menu.tsx +1 -0
  123. package/dist/templates/chat/app/components/ui/input.tsx +1 -0
  124. package/dist/templates/chat/app/components/ui/label.tsx +1 -0
  125. package/dist/templates/chat/app/components/ui/sheet.tsx +1 -0
  126. package/dist/templates/chat/app/components/ui/toolkit-provider.tsx +12 -0
  127. package/dist/templates/chat/app/components/ui/tooltip.tsx +1 -0
  128. package/dist/templates/chat/app/entry.client.tsx +19 -0
  129. package/dist/templates/chat/app/entry.server.tsx +10 -0
  130. package/dist/templates/chat/app/global.css +93 -0
  131. package/dist/templates/chat/app/hooks/use-navigation-state.ts +111 -0
  132. package/dist/templates/chat/app/i18n/ar-SA.ts +68 -0
  133. package/dist/templates/chat/app/i18n/de-DE.ts +71 -0
  134. package/dist/templates/chat/app/i18n/en-US.ts +70 -0
  135. package/dist/templates/chat/app/i18n/es-ES.ts +71 -0
  136. package/dist/templates/chat/app/i18n/fr-FR.ts +71 -0
  137. package/dist/templates/chat/app/i18n/hi-IN.ts +69 -0
  138. package/dist/templates/chat/app/i18n/index.ts +34 -0
  139. package/dist/templates/chat/app/i18n/ja-JP.ts +70 -0
  140. package/dist/templates/chat/app/i18n/ko-KR.ts +70 -0
  141. package/dist/templates/chat/app/i18n/pt-BR.ts +71 -0
  142. package/dist/templates/chat/app/i18n/zh-CN.ts +67 -0
  143. package/dist/templates/chat/app/i18n/zh-TW.ts +67 -0
  144. package/dist/templates/chat/app/i18n-data.ts +556 -0
  145. package/dist/templates/chat/app/lib/agent-page.tsx +40 -0
  146. package/dist/templates/chat/app/lib/app-config.ts +11 -0
  147. package/dist/templates/chat/app/lib/tab-id.ts +1 -0
  148. package/dist/templates/chat/app/lib/utils.ts +1 -0
  149. package/dist/templates/chat/app/root.tsx +172 -0
  150. package/dist/templates/chat/app/routes/_index.tsx +91 -0
  151. package/dist/templates/chat/app/routes/agent.tsx +17 -0
  152. package/dist/templates/chat/app/routes/chat.$threadId.tsx +1 -0
  153. package/dist/templates/chat/app/routes/database.tsx +17 -0
  154. package/dist/templates/chat/app/routes/extensions.$id.$slug.tsx +2 -0
  155. package/dist/templates/chat/app/routes/extensions.$id.tsx +11 -0
  156. package/dist/templates/chat/app/routes/extensions._index.tsx +11 -0
  157. package/dist/templates/chat/app/routes/extensions.tsx +5 -0
  158. package/dist/templates/chat/app/routes/observability.tsx +18 -0
  159. package/dist/templates/chat/app/routes/settings.tsx +88 -0
  160. package/dist/templates/chat/app/routes/team.tsx +11 -0
  161. package/dist/templates/chat/app/routes.ts +4 -0
  162. package/dist/templates/chat/app/vite-env.d.ts +6 -0
  163. package/dist/templates/chat/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +6 -0
  164. package/dist/templates/chat/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  165. package/dist/templates/chat/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
  166. package/dist/templates/chat/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  167. package/dist/templates/chat/changelog/2026-06-29-chat-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
  168. package/dist/templates/chat/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  169. package/dist/templates/chat/changelog/2026-07-10-chat-now-makes-ai-connection-setup-clear-without-shifting-th.md +6 -0
  170. package/dist/templates/chat/changelog/2026-07-13-a-full-agent-page-now-brings-context-files-connections-jobs-.md +6 -0
  171. package/dist/templates/chat/changelog/2026-07-14-chat-opens-reliably-on-hosted-deployments-instead-of-failing.md +6 -0
  172. package/dist/templates/chat/changelog/2026-07-14-fixed-chat-template-startup-with-older-core-versions.md +6 -0
  173. package/dist/templates/chat/changelog/2026-07-15-chat-navigation-focuses-on-chat-and-agent.md +6 -0
  174. package/dist/templates/chat/components.json +20 -0
  175. package/dist/templates/chat/data/.gitkeep +0 -0
  176. package/dist/templates/chat/data/sync-config.json +1 -0
  177. package/dist/templates/chat/learnings.defaults.md +5 -0
  178. package/dist/templates/chat/netlify.toml +10 -0
  179. package/dist/templates/chat/package.json +92 -0
  180. package/dist/templates/chat/public/agent-native-icon-dark.svg +10 -0
  181. package/dist/templates/chat/public/agent-native-icon-light.svg +10 -0
  182. package/dist/templates/chat/public/agent-native-logo-dark.svg +21 -0
  183. package/dist/templates/chat/public/agent-native-logo-light.svg +21 -0
  184. package/dist/templates/chat/public/favicon.svg +1 -0
  185. package/dist/templates/chat/public/icon-180.svg +1 -0
  186. package/dist/templates/chat/public/icon-192.svg +1 -0
  187. package/dist/templates/chat/public/icon-512.svg +1 -0
  188. package/dist/templates/chat/public/manifest.json +21 -0
  189. package/dist/templates/chat/react-router.config.ts +7 -0
  190. package/dist/templates/chat/server/middleware/auth.ts +15 -0
  191. package/dist/templates/chat/server/plugins/agent-chat.ts +21 -0
  192. package/dist/templates/chat/server/plugins/auth.ts +17 -0
  193. package/dist/templates/chat/server/routes/[...page].get.ts +5 -0
  194. package/dist/templates/chat/ssr-entry.ts +15 -0
  195. package/dist/templates/chat/tsconfig.json +21 -0
  196. package/dist/templates/chat/vite.config.ts +19 -0
  197. package/package.json +2 -1
  198. package/src/templates/chat/.agents/skills/actions/SKILL.md +492 -0
  199. package/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +189 -0
  200. package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +76 -0
  201. package/src/templates/chat/.agents/skills/capture-learnings/SKILL.md +89 -0
  202. package/src/templates/chat/.agents/skills/create-skill/SKILL.md +221 -0
  203. package/src/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +263 -0
  204. package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +112 -0
  205. package/src/templates/chat/.agents/skills/real-time-sync/SKILL.md +232 -0
  206. package/src/templates/chat/.agents/skills/security/SKILL.md +280 -0
  207. package/src/templates/chat/.agents/skills/self-modifying-code/SKILL.md +106 -0
  208. package/src/templates/chat/.agents/skills/shadcn-ui/SKILL.md +95 -0
  209. package/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  210. package/src/templates/chat/.env.example +5 -0
  211. package/src/templates/chat/.ignore +0 -0
  212. package/src/templates/chat/.oxfmtrc.json +8 -0
  213. package/src/templates/chat/.react-router/types/+server-build.d.ts +18 -0
  214. package/src/templates/chat/.react-router/types/app/+types/root.ts +68 -0
  215. package/src/templates/chat/AGENTS.md +62 -0
  216. package/src/templates/chat/CHANGELOG.md +10 -0
  217. package/src/templates/chat/DEVELOPING.md +185 -0
  218. package/src/templates/chat/README.md +32 -0
  219. package/src/templates/chat/_gitignore +43 -0
  220. package/src/templates/chat/actions/hello.spec.ts +23 -0
  221. package/src/templates/chat/actions/hello.ts +13 -0
  222. package/src/templates/chat/actions/navigate.spec.ts +68 -0
  223. package/src/templates/chat/actions/navigate.ts +41 -0
  224. package/src/templates/chat/actions/run.ts +2 -0
  225. package/src/templates/chat/actions/view-screen.spec.ts +40 -0
  226. package/src/templates/chat/actions/view-screen.ts +31 -0
  227. package/src/templates/chat/app/components/layout/Header.tsx +59 -0
  228. package/src/templates/chat/app/components/layout/Layout.tsx +184 -0
  229. package/src/templates/chat/app/components/layout/Sidebar.tsx +580 -0
  230. package/src/templates/chat/app/components/ui/button.tsx +1 -0
  231. package/src/templates/chat/app/components/ui/card.tsx +1 -0
  232. package/src/templates/chat/app/components/ui/dropdown-menu.tsx +1 -0
  233. package/src/templates/chat/app/components/ui/input.tsx +1 -0
  234. package/src/templates/chat/app/components/ui/label.tsx +1 -0
  235. package/src/templates/chat/app/components/ui/sheet.tsx +1 -0
  236. package/src/templates/chat/app/components/ui/toolkit-provider.tsx +12 -0
  237. package/src/templates/chat/app/components/ui/tooltip.tsx +1 -0
  238. package/src/templates/chat/app/entry.client.tsx +19 -0
  239. package/src/templates/chat/app/entry.server.tsx +10 -0
  240. package/src/templates/chat/app/global.css +93 -0
  241. package/src/templates/chat/app/hooks/use-navigation-state.ts +111 -0
  242. package/src/templates/chat/app/i18n/ar-SA.ts +68 -0
  243. package/src/templates/chat/app/i18n/de-DE.ts +71 -0
  244. package/src/templates/chat/app/i18n/en-US.ts +70 -0
  245. package/src/templates/chat/app/i18n/es-ES.ts +71 -0
  246. package/src/templates/chat/app/i18n/fr-FR.ts +71 -0
  247. package/src/templates/chat/app/i18n/hi-IN.ts +69 -0
  248. package/src/templates/chat/app/i18n/index.ts +34 -0
  249. package/src/templates/chat/app/i18n/ja-JP.ts +70 -0
  250. package/src/templates/chat/app/i18n/ko-KR.ts +70 -0
  251. package/src/templates/chat/app/i18n/pt-BR.ts +71 -0
  252. package/src/templates/chat/app/i18n/zh-CN.ts +67 -0
  253. package/src/templates/chat/app/i18n/zh-TW.ts +67 -0
  254. package/src/templates/chat/app/i18n-data.ts +556 -0
  255. package/src/templates/chat/app/lib/agent-page.spec.tsx +52 -0
  256. package/src/templates/chat/app/lib/agent-page.tsx +40 -0
  257. package/src/templates/chat/app/lib/app-config.ts +11 -0
  258. package/src/templates/chat/app/lib/tab-id.ts +1 -0
  259. package/src/templates/chat/app/lib/utils.ts +1 -0
  260. package/src/templates/chat/app/root.tsx +172 -0
  261. package/src/templates/chat/app/routes/_index.tsx +91 -0
  262. package/src/templates/chat/app/routes/agent.tsx +17 -0
  263. package/src/templates/chat/app/routes/chat.$threadId.tsx +1 -0
  264. package/src/templates/chat/app/routes/database.tsx +17 -0
  265. package/src/templates/chat/app/routes/extensions.$id.$slug.tsx +2 -0
  266. package/src/templates/chat/app/routes/extensions.$id.tsx +11 -0
  267. package/src/templates/chat/app/routes/extensions._index.tsx +11 -0
  268. package/src/templates/chat/app/routes/extensions.tsx +5 -0
  269. package/src/templates/chat/app/routes/observability.tsx +18 -0
  270. package/src/templates/chat/app/routes/settings.tsx +88 -0
  271. package/src/templates/chat/app/routes/team.tsx +11 -0
  272. package/src/templates/chat/app/routes.ts +4 -0
  273. package/src/templates/chat/app/vite-env.d.ts +6 -0
  274. package/src/templates/chat/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +6 -0
  275. package/src/templates/chat/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  276. package/src/templates/chat/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
  277. package/src/templates/chat/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  278. package/src/templates/chat/changelog/2026-06-29-chat-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
  279. package/src/templates/chat/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  280. package/src/templates/chat/changelog/2026-07-10-chat-now-makes-ai-connection-setup-clear-without-shifting-th.md +6 -0
  281. package/src/templates/chat/changelog/2026-07-13-a-full-agent-page-now-brings-context-files-connections-jobs-.md +6 -0
  282. package/src/templates/chat/changelog/2026-07-14-chat-opens-reliably-on-hosted-deployments-instead-of-failing.md +6 -0
  283. package/src/templates/chat/changelog/2026-07-14-fixed-chat-template-startup-with-older-core-versions.md +6 -0
  284. package/src/templates/chat/changelog/2026-07-15-chat-navigation-focuses-on-chat-and-agent.md +6 -0
  285. package/src/templates/chat/components.json +20 -0
  286. package/src/templates/chat/data/.gitkeep +0 -0
  287. package/src/templates/chat/data/sync-config.json +1 -0
  288. package/src/templates/chat/learnings.defaults.md +5 -0
  289. package/src/templates/chat/netlify.toml +10 -0
  290. package/src/templates/chat/package.json +92 -0
  291. package/src/templates/chat/public/agent-native-icon-dark.svg +10 -0
  292. package/src/templates/chat/public/agent-native-icon-light.svg +10 -0
  293. package/src/templates/chat/public/agent-native-logo-dark.svg +21 -0
  294. package/src/templates/chat/public/agent-native-logo-light.svg +21 -0
  295. package/src/templates/chat/public/favicon.svg +1 -0
  296. package/src/templates/chat/public/icon-180.svg +1 -0
  297. package/src/templates/chat/public/icon-192.svg +1 -0
  298. package/src/templates/chat/public/icon-512.svg +1 -0
  299. package/src/templates/chat/public/manifest.json +21 -0
  300. package/src/templates/chat/react-router.config.ts +7 -0
  301. package/src/templates/chat/server/middleware/auth.ts +15 -0
  302. package/src/templates/chat/server/plugins/agent-chat.ts +21 -0
  303. package/src/templates/chat/server/plugins/auth.ts +17 -0
  304. package/src/templates/chat/server/routes/[...page].get.ts +5 -0
  305. package/src/templates/chat/ssr-entry.ts +15 -0
  306. package/src/templates/chat/tsconfig.json +21 -0
  307. package/src/templates/chat/vite.config.ts +19 -0
@@ -86,7 +86,6 @@ import type {
86
86
  MentionProvider,
87
87
  } from "../agent/types.js";
88
88
  import { readAppStateForCurrentTab } from "../application-state/script-helpers.js";
89
- import { appStateGet } from "../application-state/store.js";
90
89
  import {
91
90
  createThread,
92
91
  forkThread,
@@ -167,10 +166,7 @@ import {
167
166
  } from "./framework-request-handler.js";
168
167
  import { getOrigin } from "./google-oauth.js";
169
168
  import { readBody } from "./h3-helpers.js";
170
- import {
171
- FIRST_SESSION_PERSONALIZATION,
172
- getModelFamilyOverlay,
173
- } from "./prompts/index.js";
169
+ import { getModelFamilyOverlay } from "./prompts/index.js";
174
170
  import { mountRealtimeVoiceRoutes } from "./realtime-voice.js";
175
171
  import {
176
172
  runWithRequestContext,
@@ -283,41 +279,6 @@ export function buildLeanRunPolicyPrompt(
283
279
  return codeEditingSurfaceRestriction + prodCodeExecPromptNote;
284
280
  }
285
281
 
286
- /**
287
- * Returns whether `owner` has already finished (or explicitly skipped) the
288
- * First-Session Personalization flow, via the owner-scoped
289
- * `application_state` "personalization" flag the agent itself writes
290
- * (`writeAppState("personalization", { done: true })` — see
291
- * FIRST_SESSION_PERSONALIZATION in prompts/framework-core.ts).
292
- *
293
- * This used to be gated on "does this thread have prior messages", which
294
- * flips false the instant a second request comes in for the SAME thread —
295
- * making turn 2's system prompt diverge from turn 1's and invalidating the
296
- * prompt-cache prefix on every thread's second request. The flow itself
297
- * spans two turns (turn 1 asks the personalization questions and waits;
298
- * turn 2 answers them and only then writes the "done" flag), so this flag
299
- * is still false when BOTH turns' system prompts are assembled — turn 1
300
- * and turn 2 come out byte-identical. It only flips once the flow
301
- * completes, and it never flips back, so every later turn (and every
302
- * later thread the same owner creates) stays consistent from then on. As
303
- * a bonus, it also fixes a latent waste: the old gate re-included the
304
- * ~1.5KB block on turn 1 of every new thread a user ever created, even
305
- * long after they'd completed personalization once.
306
- */
307
- export async function hasCompletedFirstSessionPersonalization(
308
- owner: string,
309
- ): Promise<boolean> {
310
- try {
311
- const state = await appStateGet(owner, "personalization");
312
- return state?.done === true;
313
- } catch {
314
- // Fail open to "not done" — same default as a brand-new user (block
315
- // shown) rather than silently skipping personalization because of a
316
- // transient appstate read error.
317
- return false;
318
- }
319
- }
320
-
321
282
  /**
322
283
  * In-memory rate-limit tracker for `/generate-title`. Keyed by user email,
323
284
  * value is recent invocation timestamps within the rolling window. Stale
@@ -2650,14 +2611,6 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
2650
2611
  )
2651
2612
  ? APP_RENDERED_CHAT_NO_DIRECT_CODE_PROMPT
2652
2613
  : "";
2653
- // Personalization block: included until this owner has finished (or
2654
- // skipped) the flow — see hasCompletedFirstSessionPersonalization
2655
- // for why this is gated on the owner-scoped appstate flag rather
2656
- // than "is this a new thread" (keeps turn 1 and turn 2 identical).
2657
- const personalizationBlock =
2658
- (await hasCompletedFirstSessionPersonalization(owner))
2659
- ? ""
2660
- : FIRST_SESSION_PERSONALIZATION;
2661
2614
  // Per-model overlay: nudge GPT/Gemini engines toward our behavioral norms.
2662
2615
  const modelOverlay = resolveModelOverlay();
2663
2616
  // Stable-first ordering: base prompt / schema / extra come before
@@ -2712,13 +2665,10 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
2712
2665
  modelOverlay,
2713
2666
  runtimeContext,
2714
2667
  additionalFramework:
2715
- personalizationBlock +
2716
- codeEditingSurfaceRestriction +
2717
- prodCodeExecPromptNote,
2668
+ codeEditingSurfaceRestriction + prodCodeExecPromptNote,
2718
2669
  });
2719
2670
  return setSystemPromptOnContext(
2720
2671
  basePrompt +
2721
- personalizationBlock +
2722
2672
  resources +
2723
2673
  schemaBlock +
2724
2674
  codeEditingSurfaceRestriction +
@@ -2940,10 +2890,6 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
2940
2890
  systemPrompt: async (event: any) => {
2941
2891
  const { owner, extra } = await prepareRun(event);
2942
2892
  const runtimeContext = runtimeContextForEvent(event);
2943
- const personalizationBlock =
2944
- (await hasCompletedFirstSessionPersonalization(owner))
2945
- ? ""
2946
- : FIRST_SESSION_PERSONALIZATION;
2947
2893
  const modelOverlay = resolveModelOverlay();
2948
2894
  // Stable-first ordering: runtimeContext (day-granular) is
2949
2895
  // appended LAST so a day rollover invalidates as little of the
@@ -2989,11 +2935,9 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
2989
2935
  extra,
2990
2936
  modelOverlay,
2991
2937
  runtimeContext,
2992
- additionalFramework: personalizationBlock,
2993
2938
  });
2994
2939
  return setSystemPromptOnContext(
2995
2940
  devPrompt +
2996
- personalizationBlock +
2997
2941
  resources +
2998
2942
  schemaBlock +
2999
2943
  extra +
@@ -7,7 +7,6 @@
7
7
  * - Verbose "Extended Capabilities" section (agent uses get-framework-context)
8
8
  * - Detailed "Parallel Tool Calls" prose (replaced with one-liner)
9
9
  * - Detailed "Resources" section (agent uses resources tool)
10
- * - "First-Session Personalization" (gated externally — see buildSystemPrompt)
11
10
  */
12
11
 
13
12
  import {
@@ -141,33 +141,3 @@ Each of these has a one-line pointer here and a full doc you can pull on demand
141
141
  - **Structured memory** — persist knowledge across sessions with \`save-memory\` / \`delete-memory\`; save proactively when you learn preferences, corrections, or project context. Detailed instructions: call \`get-framework-context\` with key \`memory\`.
142
142
  `;
143
143
  }
144
-
145
- /**
146
- * Build the First-Session Personalization block.
147
- * Gated by caller: only include when the session has no prior messages
148
- * (cheapest reliable signal that personalization hasn't run yet).
149
- * Recording happens via writeAppState("personalization", { done: true })
150
- * so the block is omitted from all subsequent requests once the agent
151
- * completes the flow.
152
- */
153
- export const FIRST_SESSION_PERSONALIZATION = `
154
- ### First-Session Personalization
155
-
156
- On the user's very first interaction in this app, before answering their actual request, briefly personalize the workspace.
157
-
158
- Check the application_state key \`personalization\` via \`readAppState("personalization")\`:
159
- - If it returns null (or has no \`done: true\`), this is the first session — run the flow below.
160
- - If \`done: true\` is set, skip the flow and answer normally.
161
-
162
- **The flow (keep it to one short message, then wait for their answer before continuing):**
163
-
164
- 1. Greet briefly in one sentence.
165
- 2. Ask **two** yes/no questions inline, on separate lines:
166
- - A theme question: _"Want me to pick a color theme for your workspace? I have a few presets — say a name or just 'yes' for my pick."_ Available presets: \`warm\`, \`ocean\`, \`forest\`, \`rose\`, \`slate\` (call \`change-appearance\` with one of these; or \`default\` to clear). When the user says yes without a name, pick one preset that fits this template's tone.
167
- - A template-specific question that the template's AGENTS.md / CLAUDE.md documents (e.g. for calendar: _"Want me to color-code meetings by attendee or by category?"_; for mail: _"Want me to surface emails that look like they need a reply at the top?"_). If the template doesn't suggest a question, ask one generic preference question (e.g. _"Do you prefer a denser layout or roomy spacing?"_).
168
- 3. After they answer (or decline), call \`change-appearance\` if appropriate, do whatever the second answer implies (e.g. set a calendar visual preference), and then write \`application_state.personalization\` = \`{ "done": true }\` via \`writeAppState\` so this flow doesn't run again.
169
-
170
- If the user's first message is clearly already on-task (e.g. "what's on my calendar today?"), answer it first — but still surface ONE line at the end like _"By the way, want me to set a theme for your workspace? Try \`change-appearance warm\` or just ask."_ — then mark personalization done so the offer never repeats.
171
-
172
- Do NOT block on this flow. If the user ignores it, just proceed; never re-ask the personalization questions in later sessions.
173
- `;
@@ -3,10 +3,7 @@
3
3
  * agent-chat-plugin.ts has a single clean import.
4
4
  */
5
5
 
6
- export {
7
- buildFrameworkCore,
8
- FIRST_SESSION_PERSONALIZATION,
9
- } from "./framework-core.js";
6
+ export { buildFrameworkCore } from "./framework-core.js";
10
7
  export { buildFrameworkCoreCompact } from "./framework-core-compact.js";
11
8
  export {
12
9
  sharedRule8,
@@ -9,10 +9,8 @@ import {
9
9
  import { ExtensionsSidebarSection } from "@agent-native/core/client/extensions";
10
10
  import { OrgSwitcher } from "@agent-native/core/client/org";
11
11
  import {
12
- IconActivity,
13
12
  IconArchive,
14
13
  IconBrain,
15
- IconDatabase,
16
14
  IconDots,
17
15
  IconEdit,
18
16
  IconLayoutSidebarLeftCollapse,
@@ -48,18 +46,6 @@ const navItems = [
48
46
  href: "/",
49
47
  view: "chat",
50
48
  },
51
- {
52
- icon: IconActivity,
53
- labelKey: "navigation.observability",
54
- href: "/observability",
55
- view: "observability",
56
- },
57
- {
58
- icon: IconDatabase,
59
- labelKey: "navigation.database",
60
- href: "/database",
61
- view: "database",
62
- },
63
49
  {
64
50
  icon: IconBrain,
65
51
  labelKey: "settings.agentTitle",
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: removed
3
+ date: 2026-07-15
4
+ ---
5
+
6
+ The main navigation is now focused on Chat, Agent, and essential workspace settings.
@@ -380,7 +380,7 @@ function LinkTab({
380
380
  )}
381
381
 
382
382
  <CopyField
383
- label={t("shareDialog.shareLink")}
383
+ label={t("shareDialog.shareWithHumans")}
384
384
  value={shareUrl}
385
385
  disabled={
386
386
  visibilityPending || !sharesLoaded || (!isPublic && canManage)
@@ -444,6 +444,7 @@ const messages = {
444
444
  invite: "دعوة",
445
445
  embed: "تضمين",
446
446
  shareLink: "رابط المشاركة",
447
+ shareWithHumans: "مشاركة مع الأشخاص",
447
448
  shareWithAgents: "شارك مع الوكلاء",
448
449
  copyAgentPrompt: "نسخ مطالبة الوكيل",
449
450
  agentPrompt:
@@ -457,6 +457,7 @@ const messages = {
457
457
  invite: "Einladen",
458
458
  embed: "Einbetten",
459
459
  shareLink: "Teillink",
460
+ shareWithHumans: "Mit Menschen teilen",
460
461
  shareWithAgents: "Mit Agenten teilen",
461
462
  copyAgentPrompt: "Agent-Prompt kopieren",
462
463
  agentPrompt:
@@ -440,6 +440,7 @@ const messages = {
440
440
  invite: "Invite",
441
441
  embed: "Embed",
442
442
  shareLink: "Share link",
443
+ shareWithHumans: "Share with humans",
443
444
  shareWithAgents: "Share with agents",
444
445
  copyAgentPrompt: "Copy agent prompt",
445
446
  agentPrompt:
@@ -454,6 +454,7 @@ const messages = {
454
454
  invite: "Invitar",
455
455
  embed: "Insertar",
456
456
  shareLink: "Enlace para compartir",
457
+ shareWithHumans: "Compartir con personas",
457
458
  shareWithAgents: "Compartir con agentes",
458
459
  copyAgentPrompt: "Copiar indicación para agente",
459
460
  agentPrompt:
@@ -454,6 +454,7 @@ const messages = {
454
454
  invite: "Inviter",
455
455
  embed: "Intégrer",
456
456
  shareLink: "Lien de partage",
457
+ shareWithHumans: "Partager avec des personnes",
457
458
  shareWithAgents: "Partager avec les agents",
458
459
  copyAgentPrompt: "Copier le prompt pour agent",
459
460
  agentPrompt:
@@ -437,6 +437,7 @@ const messages = {
437
437
  invite: "आमंत्रित करें",
438
438
  embed: "एम्बेड",
439
439
  shareLink: "शेयर लिंक",
440
+ shareWithHumans: "लोगों के साथ साझा करें",
440
441
  shareWithAgents: "एजेंटों के साथ साझा करें",
441
442
  copyAgentPrompt: "एजेंट प्रॉम्प्ट कॉपी करें",
442
443
  agentPrompt:
@@ -449,6 +449,7 @@ const messages = {
449
449
  invite: "招待",
450
450
  embed: "埋め込み",
451
451
  shareLink: "共有リンク",
452
+ shareWithHumans: "人と共有する",
452
453
  shareWithAgents: "エージェントと共有する",
453
454
  copyAgentPrompt: "エージェント用プロンプトをコピー",
454
455
  agentPrompt:
@@ -442,6 +442,7 @@ const messages = {
442
442
  invite: "초대",
443
443
  embed: "임베드",
444
444
  shareLink: "공유 링크",
445
+ shareWithHumans: "사람과 공유",
445
446
  shareWithAgents: "상담원과 공유",
446
447
  copyAgentPrompt: "에이전트 프롬프트 복사",
447
448
  agentPrompt:
@@ -451,6 +451,7 @@ const messages = {
451
451
  invite: "Convidar",
452
452
  embed: "Incorporar",
453
453
  shareLink: "Link de compartilhamento",
454
+ shareWithHumans: "Compartilhe com pessoas",
454
455
  shareWithAgents: "Compartilhe com agentes",
455
456
  copyAgentPrompt: "Copiar prompt para agente",
456
457
  agentPrompt:
@@ -424,6 +424,7 @@ const messages = {
424
424
  invite: "邀请",
425
425
  embed: "嵌入",
426
426
  shareLink: "分享链接",
427
+ shareWithHumans: "与人分享",
427
428
  shareWithAgents: "与代理商分享",
428
429
  copyAgentPrompt: "复制代理提示",
429
430
  agentPrompt:
@@ -424,6 +424,7 @@ const messages = {
424
424
  invite: "邀請",
425
425
  embed: "嵌入",
426
426
  shareLink: "分享連結",
427
+ shareWithHumans: "與人分享",
427
428
  shareWithAgents: "與 Agent 分享",
428
429
  copyAgentPrompt: "複製 Agent 提示",
429
430
  agentPrompt:
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-15
4
+ ---
5
+
6
+ Public clip links are labeled Share with humans for clarity.
@@ -4,6 +4,7 @@ import { eq } from "drizzle-orm";
4
4
  import { z } from "zod";
5
5
 
6
6
  import { getDb, schema } from "../server/db/index.js";
7
+ import { invalidatePublicFormCache } from "../server/lib/public-form-ssr.js";
7
8
 
8
9
  export default defineAction({
9
10
  description:
@@ -37,6 +38,7 @@ export default defineAction({
37
38
  .delete(schema.responses)
38
39
  .where(eq(schema.responses.formId, args.id));
39
40
  await db.delete(schema.forms).where(eq(schema.forms.id, args.id));
41
+ invalidatePublicFormCache(existing);
40
42
  return { success: true, purged: true };
41
43
  }
42
44
 
@@ -46,6 +48,8 @@ export default defineAction({
46
48
  .set({ deletedAt: now, updatedAt: now })
47
49
  .where(eq(schema.forms.id, args.id));
48
50
 
51
+ invalidatePublicFormCache(existing);
52
+
49
53
  return { success: true, purged: false, deletedAt: now };
50
54
  },
51
55
  });
@@ -23,6 +23,7 @@ import { z } from "zod";
23
23
 
24
24
  import { getDb, schema } from "../server/db/index.js";
25
25
  import { applyFieldOps } from "../server/lib/merge-fields.js";
26
+ import { invalidatePublicFormCache } from "../server/lib/public-form-ssr.js";
26
27
  import { assertValidFields } from "../server/lib/validate-fields.js";
27
28
  import type { FormField } from "../shared/types.js";
28
29
  import { assertPublishableForm } from "./lib/assert-publishable-form.js";
@@ -139,6 +140,8 @@ export default defineAction({
139
140
  .set({ fields: JSON.stringify(nextFields), updatedAt: now })
140
141
  .where(eq(schema.forms.id, args.id));
141
142
 
143
+ invalidatePublicFormCache(existing);
144
+
142
145
  return { id: args.id, fields: nextFields, updatedAt: now };
143
146
  });
144
147
  },
@@ -4,6 +4,7 @@ import { eq } from "drizzle-orm";
4
4
  import { z } from "zod";
5
5
 
6
6
  import { getDb, schema } from "../server/db/index.js";
7
+ import { invalidatePublicFormCache } from "../server/lib/public-form-ssr.js";
7
8
 
8
9
  export default defineAction({
9
10
  description:
@@ -31,6 +32,8 @@ export default defineAction({
31
32
  .set({ deletedAt: null, updatedAt: now })
32
33
  .where(eq(schema.forms.id, args.id));
33
34
 
35
+ invalidatePublicFormCache(existing);
36
+
34
37
  return { success: true };
35
38
  },
36
39
  });
@@ -5,6 +5,7 @@ import { z } from "zod";
5
5
 
6
6
  import { getDb, schema } from "../server/db/index.js";
7
7
  import { assertIntegrationUrlsAllowed } from "../server/lib/integrations.js";
8
+ import { invalidatePublicFormCache } from "../server/lib/public-form-ssr.js";
8
9
  import { assertValidFields } from "../server/lib/validate-fields.js";
9
10
  import type { FormField, FormSettings } from "../shared/types.js";
10
11
  import { assertPublishableForm } from "./lib/assert-publishable-form.js";
@@ -136,6 +137,8 @@ export default defineAction({
136
137
  .where(eq(schema.forms.id, args.id))
137
138
  .limit(1);
138
139
 
140
+ invalidatePublicFormCache(existing, row);
141
+
139
142
  return {
140
143
  id: row!.id,
141
144
  title: row!.title,
@@ -1468,10 +1468,10 @@ function ResultsContent({ formId, form }: { formId: string; form: any }) {
1468
1468
  key={response.id}
1469
1469
  className="border-b border-border hover:bg-muted/20"
1470
1470
  >
1471
- <td className="px-4 py-2.5 text-xs text-muted-foreground">
1471
+ <td className="px-4 py-2.5 align-top text-xs text-muted-foreground">
1472
1472
  {responses.length - idx}
1473
1473
  </td>
1474
- <td className="min-w-36 px-4 py-2.5 text-xs text-muted-foreground whitespace-nowrap">
1474
+ <td className="min-w-36 px-4 py-2.5 align-top text-xs text-muted-foreground whitespace-nowrap">
1475
1475
  {format(new Date(response.submittedAt), "MMM d, h:mm a")}
1476
1476
  </td>
1477
1477
  {hasSubmitterEmail && (
@@ -428,10 +428,10 @@ export function ResponsesPage() {
428
428
  key={response.id}
429
429
  className="border-b border-border transition-[background-color] duration-150 hover:bg-muted/20 motion-reduce:transition-none"
430
430
  >
431
- <td className="px-4 py-2.5 text-xs text-muted-foreground">
431
+ <td className="px-4 py-2.5 align-top text-xs text-muted-foreground">
432
432
  {filteredSorted.length - idx}
433
433
  </td>
434
- <td className="min-w-36 px-4 py-2.5 text-xs text-muted-foreground whitespace-nowrap">
434
+ <td className="min-w-36 px-4 py-2.5 align-top text-xs text-muted-foreground whitespace-nowrap">
435
435
  {formatDate(response.submittedAt, {
436
436
  month: "short",
437
437
  day: "numeric",
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-15
4
+ ---
5
+
6
+ Published forms now reflect field updates immediately at their shared links
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-15
4
+ ---
5
+
6
+ Response rows now keep every column aligned to the top for consistent scanning
@@ -53,6 +53,7 @@ export const getPublicForm = defineEventHandler(async (event: H3Event) => {
53
53
  const settings = JSON.parse(row.settings) as FormSettings;
54
54
  const result = {
55
55
  id: row.id,
56
+ updatedAt: row.updatedAt,
56
57
  title: row.title,
57
58
  description: row.description,
58
59
  fields: JSON.parse(row.fields),
@@ -22,14 +22,38 @@ import { getDb, schema } from "../db/index.js";
22
22
  const cache = new Map<string, { data: any; ts: number }>();
23
23
  const TTL = 60_000;
24
24
 
25
+ type PublicFormCacheKeys = {
26
+ id?: string | null;
27
+ slug?: string | null;
28
+ };
29
+
30
+ export function invalidatePublicFormCache(
31
+ ...forms: Array<PublicFormCacheKeys | null | undefined>
32
+ ) {
33
+ for (const form of forms) {
34
+ for (const key of [form?.id, form?.slug]) {
35
+ if (!key) continue;
36
+ cache.delete(key);
37
+ const versionPrefix = `${key}?v=`;
38
+ for (const cachedKey of cache.keys()) {
39
+ if (cachedKey.startsWith(versionPrefix)) cache.delete(cachedKey);
40
+ }
41
+ }
42
+ }
43
+ }
44
+
25
45
  function getCached(key: string) {
26
46
  const entry = cache.get(key);
27
47
  if (entry && Date.now() - entry.ts < TTL) return entry.data;
28
48
  return null;
29
49
  }
30
50
 
31
- export async function getPublicFormBySlugOrId(slugOrId: string) {
32
- const cached = getCached(slugOrId);
51
+ export async function getPublicFormBySlugOrId(
52
+ slugOrId: string,
53
+ version?: string,
54
+ ) {
55
+ const cacheKey = version ? `${slugOrId}?v=${version}` : slugOrId;
56
+ const cached = getCached(cacheKey);
33
57
  if (cached) return cached;
34
58
 
35
59
  const db = getDb();
@@ -66,7 +90,7 @@ export async function getPublicFormBySlugOrId(slugOrId: string) {
66
90
  settings: toPublicFormSettings(settings),
67
91
  };
68
92
 
69
- cache.set(slugOrId, { data: result, ts: Date.now() });
93
+ cache.set(cacheKey, { data: result, ts: Date.now() });
70
94
  return result;
71
95
  }
72
96
 
@@ -103,6 +127,7 @@ const FALLBACK_PUBLIC_FORM_ORIGIN = "http://agent-native.local";
103
127
  function parsePublicFormUrl(url: string): {
104
128
  pathname: string;
105
129
  origin?: string;
130
+ version?: string;
106
131
  } {
107
132
  try {
108
133
  const parsed = new URL(url, FALLBACK_PUBLIC_FORM_ORIGIN);
@@ -110,6 +135,7 @@ function parsePublicFormUrl(url: string): {
110
135
  return {
111
136
  pathname: parsed.pathname,
112
137
  origin: isAbsolute ? parsed.origin : undefined,
138
+ version: parsed.searchParams.get("v") || undefined,
113
139
  };
114
140
  } catch {
115
141
  return { pathname: url.split("?")[0] || "/" };
@@ -261,7 +287,9 @@ export async function renderPublicFormHtml(
261
287
  ? pathname.slice(basePath.length)
262
288
  : pathname;
263
289
  const slugOrId = decodeURIComponent(pathWithoutBase.replace(/^\/f\//, ""));
264
- const form = slugOrId ? await getPublicFormBySlugOrId(slugOrId) : null;
290
+ const form = slugOrId
291
+ ? await getPublicFormBySlugOrId(slugOrId, parsedUrl.version)
292
+ : null;
265
293
 
266
294
  if (!form) {
267
295
  return { html: notFoundPage(parsedUrl.origin), status: 404 };
@@ -402,10 +430,25 @@ function renderFormPage(
402
430
  <script>
403
431
  (function(){
404
432
  var FORM_ID = ${JSON.stringify(form.id)};
433
+ var FORM_VERSION = ${JSON.stringify(form.updatedAt || "")};
434
+ var PUBLIC_FORM_API = ${JSON.stringify(`${appBasePath}/api/forms/public/${encodeURIComponent(form.slug || form.id)}`)};
405
435
  var REDIRECT = ${JSON.stringify(safeRedirectUrl(settings.redirectUrl))};
406
436
  var TURNSTILE_KEY = ${JSON.stringify(turnstileSiteKey)};
407
437
  var FIELDS = ${JSON.stringify(fields.map((f) => ({ id: f.id, type: f.type, required: f.required, validation: f.validation, label: f.label, conditional: f.conditional })))};
408
438
 
439
+ function revalidateFormVersion() {
440
+ fetch(PUBLIC_FORM_API, { cache: "no-store" })
441
+ .then(function(response) { return response.ok ? response.json() : null; })
442
+ .then(function(latest) {
443
+ if (!latest || typeof latest.updatedAt !== "string" || !latest.updatedAt || latest.updatedAt === FORM_VERSION) return;
444
+ var currentUrl = new URL(window.location.href);
445
+ currentUrl.searchParams.set("v", latest.updatedAt);
446
+ window.location.replace(currentUrl.toString());
447
+ })
448
+ .catch(function() {});
449
+ }
450
+ revalidateFormVersion();
451
+
409
452
  // Theme toggle
410
453
  var html = document.documentElement;
411
454
  var saved = localStorage.getItem("theme");