@agent-native/core 0.127.3 → 0.128.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 (410) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +80 -0
  3. package/corpus/core/README.md +5 -26
  4. package/corpus/core/docs/content/actions.mdx +47 -4
  5. package/corpus/core/docs/content/native-chat-ui.mdx +7 -0
  6. package/corpus/core/docs/content/organizations-teams-permissions.mdx +109 -3
  7. package/corpus/core/docs/content/template-design-collaboration-and-full-apps.mdx +15 -0
  8. package/corpus/core/docs/content/toolkit-org-team.mdx +72 -12
  9. package/corpus/core/package.json +1 -1
  10. package/corpus/core/src/a2a/artifact-response.ts +36 -29
  11. package/corpus/core/src/action.ts +83 -2
  12. package/corpus/core/src/chat-threads/store.ts +48 -43
  13. package/corpus/core/src/cli/skills-content/design-visual-edit-skill.ts +46 -3
  14. package/corpus/core/src/client/AgentPanel.tsx +26 -6
  15. package/corpus/core/src/client/AssistantChat.tsx +63 -7
  16. package/corpus/core/src/client/DefaultSpinner.tsx +29 -0
  17. package/corpus/core/src/client/org/TeamPage.tsx +161 -6
  18. package/corpus/core/src/client/org/hooks.ts +67 -0
  19. package/corpus/core/src/client/org/index.ts +9 -0
  20. package/corpus/core/src/client/transcription/use-live-transcription.ts +62 -10
  21. package/corpus/core/src/db/client.ts +42 -3
  22. package/corpus/core/src/db/ensure-additive-columns.ts +60 -33
  23. package/corpus/core/src/deploy/build.ts +31 -2
  24. package/corpus/core/src/mcp-client/routes.ts +10 -1
  25. package/corpus/core/src/org/app-roles-handlers.ts +152 -0
  26. package/corpus/core/src/org/app-roles.ts +355 -0
  27. package/corpus/core/src/org/index.ts +27 -1
  28. package/corpus/core/src/org/migrations.ts +22 -0
  29. package/corpus/core/src/org/plugin.ts +27 -0
  30. package/corpus/core/src/org/schema.ts +15 -0
  31. package/corpus/core/src/scripts/docs/search.ts +17 -0
  32. package/corpus/core/src/scripts/docs/source-search.ts +10 -0
  33. package/corpus/core/src/server/agent-chat/script-entries.ts +3 -0
  34. package/corpus/core/src/server/agent-chat-plugin.ts +53 -52
  35. package/corpus/core/src/server/core-routes-plugin.ts +6 -1
  36. package/corpus/core/src/server/framework-request-handler.ts +44 -6
  37. package/corpus/core/src/templates/default/.agents/skills/actions/SKILL.md +32 -0
  38. package/corpus/core/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +7 -0
  39. package/corpus/core/src/templates/default/.agents/skills/security/SKILL.md +31 -0
  40. package/corpus/core/src/templates/headless/.agents/skills/actions/SKILL.md +32 -0
  41. package/corpus/core/src/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -0
  42. package/corpus/core/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +7 -0
  43. package/corpus/core/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +40 -0
  44. package/corpus/core/src/templates/workspace-core/.agents/skills/security/SKILL.md +31 -0
  45. package/corpus/core/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +4 -0
  46. package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +32 -0
  47. package/corpus/templates/analytics/.agents/skills/security/SKILL.md +31 -0
  48. package/corpus/templates/analytics/.agents/skills/sharing/SKILL.md +4 -0
  49. package/corpus/templates/analytics/actions/data-source-status.ts +21 -12
  50. package/corpus/templates/analytics/app/global.css +7 -7
  51. package/corpus/templates/analytics/app/i18n-data.ts +30 -0
  52. package/corpus/templates/analytics/app/lib/data-source-status.ts +2 -1
  53. package/corpus/templates/analytics/app/pages/DataSources.tsx +54 -10
  54. package/corpus/templates/analytics/changelog/2026-07-28-analytics-pages-load-reliably-with-large-dashboard-workspaces.md +6 -0
  55. package/corpus/templates/analytics/changelog/2026-07-28-dashboard-loading-shimmer-now-flows-smoothly-in-one-directi.md +6 -0
  56. package/corpus/templates/analytics/server/lib/first-party-dashboard-repair.ts +5 -4
  57. package/corpus/templates/analytics/server/plugins/agent-chat.ts +54 -42
  58. package/corpus/templates/analytics/server/plugins/db.ts +1 -18
  59. package/corpus/templates/assets/.agents/skills/actions/SKILL.md +32 -0
  60. package/corpus/templates/assets/.agents/skills/security/SKILL.md +31 -0
  61. package/corpus/templates/assets/.agents/skills/sharing/SKILL.md +4 -0
  62. package/corpus/templates/brain/.agents/skills/actions/SKILL.md +32 -0
  63. package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +7 -0
  64. package/corpus/templates/brain/.agents/skills/security/SKILL.md +31 -0
  65. package/corpus/templates/brain/.agents/skills/sharing/SKILL.md +4 -0
  66. package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +32 -0
  67. package/corpus/templates/calendar/.agents/skills/security/SKILL.md +31 -0
  68. package/corpus/templates/calendar/.agents/skills/sharing/SKILL.md +4 -0
  69. package/corpus/templates/chat/.agents/skills/actions/SKILL.md +32 -0
  70. package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +7 -0
  71. package/corpus/templates/chat/.agents/skills/security/SKILL.md +31 -0
  72. package/corpus/templates/chat/.agents/skills/sharing/SKILL.md +4 -0
  73. package/corpus/templates/clips/.agents/skills/actions/SKILL.md +32 -0
  74. package/corpus/templates/clips/.agents/skills/security/SKILL.md +31 -0
  75. package/corpus/templates/clips/actions/request-transcript.ts +77 -11
  76. package/corpus/templates/clips/actions/save-browser-transcript.ts +28 -7
  77. package/corpus/templates/clips/app/routes/record.tsx +11 -3
  78. package/corpus/templates/clips/changelog/2026-07-28-browser-recordings-no-longer-save-a-truncated-transcript-as-.md +6 -0
  79. package/corpus/templates/clips/changelog/2026-07-28-browser-recordings-no-longer-stop-transcribing-partway-throu.md +6 -0
  80. package/corpus/templates/clips/changelog/2026-07-28-desktop-full-screen-clips-now-get-an-instant-local-transcrip.md +6 -0
  81. package/corpus/templates/clips/changelog/2026-07-28-long-transcriptions-no-longer-show-a-false-transcription-sto.md +6 -0
  82. package/corpus/templates/clips/changelog/2026-07-28-restarting-for-an-update-now-installs-the-newest-release-ins.md +6 -0
  83. package/corpus/templates/clips/changelog/2026-07-28-the-meeting-recording-pill-now-anchors-to-the-right-edge-of-.md +6 -0
  84. package/corpus/templates/clips/desktop/src/lib/audio-meter.ts +31 -2
  85. package/corpus/templates/clips/desktop/src/lib/recorder.ts +114 -13
  86. package/corpus/templates/clips/desktop/src/lib/updater.ts +12 -4
  87. package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +40 -15
  88. package/corpus/templates/clips/desktop/src/styles.css +10 -7
  89. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +21 -14
  90. package/corpus/templates/clips/shared/transcript-status.ts +10 -0
  91. package/corpus/templates/content/.agents/skills/actions/SKILL.md +32 -0
  92. package/corpus/templates/content/.agents/skills/security/SKILL.md +31 -0
  93. package/corpus/templates/content/.agents/skills/sharing/SKILL.md +4 -0
  94. package/corpus/templates/crm/.agents/skills/sharing/SKILL.md +4 -0
  95. package/corpus/templates/design/.agents/skills/actions/SKILL.md +32 -0
  96. package/corpus/templates/design/.agents/skills/security/SKILL.md +31 -0
  97. package/corpus/templates/design/.agents/skills/sharing/SKILL.md +4 -0
  98. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +46 -3
  99. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +7 -5
  100. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +2 -2
  101. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +7 -4
  102. package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +1 -1
  103. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +10 -4
  104. package/corpus/templates/design/app/lib/design-ui-events.ts +5 -0
  105. package/corpus/templates/design/app/root.tsx +18 -1
  106. package/corpus/templates/design/changelog/2026-07-28-show-or-hide-design-editing-chrome-with-cmd-on-apple-devices.md +6 -0
  107. package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +32 -0
  108. package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +31 -0
  109. package/corpus/templates/dispatch/.agents/skills/sharing/SKILL.md +4 -0
  110. package/corpus/templates/forms/.agents/skills/actions/SKILL.md +32 -0
  111. package/corpus/templates/forms/.agents/skills/security/SKILL.md +31 -0
  112. package/corpus/templates/forms/.agents/skills/sharing/SKILL.md +4 -0
  113. package/corpus/templates/macros/.agents/skills/security/SKILL.md +31 -0
  114. package/corpus/templates/macros/.agents/skills/sharing/SKILL.md +4 -0
  115. package/corpus/templates/mail/.agents/skills/actions/SKILL.md +32 -0
  116. package/corpus/templates/mail/.agents/skills/security/SKILL.md +31 -0
  117. package/corpus/templates/mail/.agents/skills/sharing/SKILL.md +4 -0
  118. package/corpus/templates/plan/.agents/skills/actions/SKILL.md +32 -0
  119. package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +7 -0
  120. package/corpus/templates/plan/.agents/skills/security/SKILL.md +31 -0
  121. package/corpus/templates/plan/.agents/skills/sharing/SKILL.md +4 -0
  122. package/corpus/templates/slides/.agents/skills/actions/SKILL.md +32 -0
  123. package/corpus/templates/slides/.agents/skills/security/SKILL.md +31 -0
  124. package/corpus/templates/slides/.agents/skills/sharing/SKILL.md +4 -0
  125. package/corpus/templates/tasks/.agents/skills/actions/SKILL.md +32 -0
  126. package/corpus/templates/tasks/.agents/skills/adding-a-feature/SKILL.md +7 -0
  127. package/corpus/templates/tasks/.agents/skills/security/SKILL.md +31 -0
  128. package/corpus/templates/tasks/.agents/skills/sharing/SKILL.md +4 -0
  129. package/dist/a2a/artifact-response.d.ts.map +1 -1
  130. package/dist/a2a/artifact-response.js +30 -29
  131. package/dist/a2a/artifact-response.js.map +1 -1
  132. package/dist/action.d.ts +36 -0
  133. package/dist/action.d.ts.map +1 -1
  134. package/dist/action.js +37 -2
  135. package/dist/action.js.map +1 -1
  136. package/dist/chat-threads/store.d.ts +12 -0
  137. package/dist/chat-threads/store.d.ts.map +1 -1
  138. package/dist/chat-threads/store.js +48 -42
  139. package/dist/chat-threads/store.js.map +1 -1
  140. package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
  141. package/dist/cli/skills-content/design-visual-edit-skill.d.ts.map +1 -1
  142. package/dist/cli/skills-content/design-visual-edit-skill.js +46 -3
  143. package/dist/cli/skills-content/design-visual-edit-skill.js.map +1 -1
  144. package/dist/client/AgentPanel.d.ts +3 -1
  145. package/dist/client/AgentPanel.d.ts.map +1 -1
  146. package/dist/client/AgentPanel.js +11 -9
  147. package/dist/client/AgentPanel.js.map +1 -1
  148. package/dist/client/AssistantChat.d.ts.map +1 -1
  149. package/dist/client/AssistantChat.js +57 -6
  150. package/dist/client/AssistantChat.js.map +1 -1
  151. package/dist/client/DefaultSpinner.d.ts +7 -0
  152. package/dist/client/DefaultSpinner.d.ts.map +1 -1
  153. package/dist/client/DefaultSpinner.js +25 -1
  154. package/dist/client/DefaultSpinner.js.map +1 -1
  155. package/dist/client/org/TeamPage.d.ts +13 -1
  156. package/dist/client/org/TeamPage.d.ts.map +1 -1
  157. package/dist/client/org/TeamPage.js +41 -11
  158. package/dist/client/org/TeamPage.js.map +1 -1
  159. package/dist/client/org/hooks.d.ts +37 -0
  160. package/dist/client/org/hooks.d.ts.map +1 -1
  161. package/dist/client/org/hooks.js +37 -0
  162. package/dist/client/org/hooks.js.map +1 -1
  163. package/dist/client/org/index.d.ts +3 -2
  164. package/dist/client/org/index.d.ts.map +1 -1
  165. package/dist/client/org/index.js +1 -1
  166. package/dist/client/org/index.js.map +1 -1
  167. package/dist/client/transcription/use-live-transcription.d.ts +8 -0
  168. package/dist/client/transcription/use-live-transcription.d.ts.map +1 -1
  169. package/dist/client/transcription/use-live-transcription.js +38 -11
  170. package/dist/client/transcription/use-live-transcription.js.map +1 -1
  171. package/dist/collab/routes.d.ts +2 -2
  172. package/dist/db/client.d.ts +12 -0
  173. package/dist/db/client.d.ts.map +1 -1
  174. package/dist/db/client.js +40 -3
  175. package/dist/db/client.js.map +1 -1
  176. package/dist/db/ensure-additive-columns.d.ts.map +1 -1
  177. package/dist/db/ensure-additive-columns.js +54 -32
  178. package/dist/db/ensure-additive-columns.js.map +1 -1
  179. package/dist/deploy/build.d.ts +1 -0
  180. package/dist/deploy/build.d.ts.map +1 -1
  181. package/dist/deploy/build.js +23 -2
  182. package/dist/deploy/build.js.map +1 -1
  183. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  184. package/dist/mcp-client/routes.d.ts +3 -1
  185. package/dist/mcp-client/routes.d.ts.map +1 -1
  186. package/dist/mcp-client/routes.js +8 -2
  187. package/dist/mcp-client/routes.js.map +1 -1
  188. package/dist/notifications/routes.d.ts +1 -1
  189. package/dist/org/app-roles-handlers.d.ts +27 -0
  190. package/dist/org/app-roles-handlers.d.ts.map +1 -0
  191. package/dist/org/app-roles-handlers.js +125 -0
  192. package/dist/org/app-roles-handlers.js.map +1 -0
  193. package/dist/org/app-roles.d.ts +136 -0
  194. package/dist/org/app-roles.d.ts.map +1 -0
  195. package/dist/org/app-roles.js +216 -0
  196. package/dist/org/app-roles.js.map +1 -0
  197. package/dist/org/index.d.ts +4 -1
  198. package/dist/org/index.d.ts.map +1 -1
  199. package/dist/org/index.js +3 -1
  200. package/dist/org/index.js.map +1 -1
  201. package/dist/org/migrations.d.ts.map +1 -1
  202. package/dist/org/migrations.js +22 -0
  203. package/dist/org/migrations.js.map +1 -1
  204. package/dist/org/plugin.d.ts +2 -0
  205. package/dist/org/plugin.d.ts.map +1 -1
  206. package/dist/org/plugin.js +20 -0
  207. package/dist/org/plugin.js.map +1 -1
  208. package/dist/org/schema.d.ts +143 -0
  209. package/dist/org/schema.d.ts.map +1 -1
  210. package/dist/org/schema.js +14 -0
  211. package/dist/org/schema.js.map +1 -1
  212. package/dist/progress/routes.d.ts +1 -1
  213. package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
  214. package/dist/provider-api/actions/provider-api.d.ts +12 -12
  215. package/dist/scripts/docs/search.d.ts.map +1 -1
  216. package/dist/scripts/docs/search.js +15 -0
  217. package/dist/scripts/docs/search.js.map +1 -1
  218. package/dist/scripts/docs/source-search.d.ts +7 -0
  219. package/dist/scripts/docs/source-search.d.ts.map +1 -1
  220. package/dist/scripts/docs/source-search.js +9 -0
  221. package/dist/scripts/docs/source-search.js.map +1 -1
  222. package/dist/secrets/routes.d.ts +9 -9
  223. package/dist/server/agent-chat/script-entries.d.ts.map +1 -1
  224. package/dist/server/agent-chat/script-entries.js +3 -0
  225. package/dist/server/agent-chat/script-entries.js.map +1 -1
  226. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  227. package/dist/server/agent-chat-plugin.js +46 -48
  228. package/dist/server/agent-chat-plugin.js.map +1 -1
  229. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  230. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  231. package/dist/server/core-routes-plugin.js +6 -1
  232. package/dist/server/core-routes-plugin.js.map +1 -1
  233. package/dist/server/framework-request-handler.d.ts.map +1 -1
  234. package/dist/server/framework-request-handler.js +42 -6
  235. package/dist/server/framework-request-handler.js.map +1 -1
  236. package/dist/server/realtime-token.d.ts +1 -1
  237. package/dist/templates/chat/.agents/skills/actions/SKILL.md +32 -0
  238. package/dist/templates/chat/.agents/skills/adding-a-feature/SKILL.md +7 -0
  239. package/dist/templates/chat/.agents/skills/security/SKILL.md +31 -0
  240. package/dist/templates/chat/.agents/skills/sharing/SKILL.md +4 -0
  241. package/dist/templates/default/.agents/skills/actions/SKILL.md +32 -0
  242. package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +7 -0
  243. package/dist/templates/default/.agents/skills/security/SKILL.md +31 -0
  244. package/dist/templates/headless/.agents/skills/actions/SKILL.md +32 -0
  245. package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -0
  246. package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +7 -0
  247. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +40 -0
  248. package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +31 -0
  249. package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +4 -0
  250. package/docs/content/actions.mdx +47 -4
  251. package/docs/content/native-chat-ui.mdx +7 -0
  252. package/docs/content/organizations-teams-permissions.mdx +109 -3
  253. package/docs/content/template-design-collaboration-and-full-apps.mdx +15 -0
  254. package/docs/content/toolkit-org-team.mdx +72 -12
  255. package/package.json +1 -1
  256. package/src/a2a/artifact-response.ts +36 -29
  257. package/src/action.ts +83 -2
  258. package/src/chat-threads/store.ts +48 -43
  259. package/src/cli/skills-content/design-visual-edit-skill.ts +46 -3
  260. package/src/client/AgentPanel.tsx +26 -6
  261. package/src/client/AssistantChat.tsx +63 -7
  262. package/src/client/DefaultSpinner.tsx +29 -0
  263. package/src/client/org/TeamPage.tsx +161 -6
  264. package/src/client/org/hooks.ts +67 -0
  265. package/src/client/org/index.ts +9 -0
  266. package/src/client/transcription/use-live-transcription.ts +62 -10
  267. package/src/db/client.ts +42 -3
  268. package/src/db/ensure-additive-columns.ts +60 -33
  269. package/src/deploy/build.ts +31 -2
  270. package/src/mcp-client/routes.ts +10 -1
  271. package/src/org/app-roles-handlers.ts +152 -0
  272. package/src/org/app-roles.ts +355 -0
  273. package/src/org/index.ts +27 -1
  274. package/src/org/migrations.ts +22 -0
  275. package/src/org/plugin.ts +27 -0
  276. package/src/org/schema.ts +15 -0
  277. package/src/scripts/docs/search.ts +17 -0
  278. package/src/scripts/docs/source-search.ts +10 -0
  279. package/src/server/agent-chat/script-entries.ts +3 -0
  280. package/src/server/agent-chat-plugin.ts +53 -52
  281. package/src/server/core-routes-plugin.ts +6 -1
  282. package/src/server/framework-request-handler.ts +44 -6
  283. package/src/templates/chat/.agents/skills/actions/SKILL.md +32 -0
  284. package/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +7 -0
  285. package/src/templates/chat/.agents/skills/security/SKILL.md +31 -0
  286. package/src/templates/chat/.agents/skills/sharing/SKILL.md +4 -0
  287. package/src/templates/default/.agents/skills/actions/SKILL.md +32 -0
  288. package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +7 -0
  289. package/src/templates/default/.agents/skills/security/SKILL.md +31 -0
  290. package/src/templates/headless/.agents/skills/actions/SKILL.md +32 -0
  291. package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -0
  292. package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +7 -0
  293. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +40 -0
  294. package/src/templates/workspace-core/.agents/skills/security/SKILL.md +31 -0
  295. package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +4 -0
  296. package/corpus/core/src/templates/chat/.agents/skills/actions/SKILL.md +0 -530
  297. package/corpus/core/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +0 -191
  298. package/corpus/core/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +0 -115
  299. package/corpus/core/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +0 -177
  300. package/corpus/core/src/templates/chat/.agents/skills/capture-learnings/SKILL.md +0 -89
  301. package/corpus/core/src/templates/chat/.agents/skills/create-skill/SKILL.md +0 -221
  302. package/corpus/core/src/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +0 -220
  303. package/corpus/core/src/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +0 -263
  304. package/corpus/core/src/templates/chat/.agents/skills/feature-flags/SKILL.md +0 -169
  305. package/corpus/core/src/templates/chat/.agents/skills/frontend-design/SKILL.md +0 -174
  306. package/corpus/core/src/templates/chat/.agents/skills/real-time-sync/SKILL.md +0 -232
  307. package/corpus/core/src/templates/chat/.agents/skills/security/SKILL.md +0 -282
  308. package/corpus/core/src/templates/chat/.agents/skills/self-modifying-code/SKILL.md +0 -119
  309. package/corpus/core/src/templates/chat/.agents/skills/shadcn-ui/SKILL.md +0 -123
  310. package/corpus/core/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +0 -122
  311. package/corpus/core/src/templates/chat/.env.example +0 -5
  312. package/corpus/core/src/templates/chat/.ignore +0 -0
  313. package/corpus/core/src/templates/chat/.oxfmtrc.json +0 -8
  314. package/corpus/core/src/templates/chat/AGENTS.md +0 -77
  315. package/corpus/core/src/templates/chat/CHANGELOG.md +0 -10
  316. package/corpus/core/src/templates/chat/DEVELOPING.md +0 -185
  317. package/corpus/core/src/templates/chat/README.md +0 -32
  318. package/corpus/core/src/templates/chat/_gitignore +0 -46
  319. package/corpus/core/src/templates/chat/actions/hello.ts +0 -13
  320. package/corpus/core/src/templates/chat/actions/navigate.ts +0 -41
  321. package/corpus/core/src/templates/chat/actions/run.ts +0 -2
  322. package/corpus/core/src/templates/chat/actions/view-screen.ts +0 -31
  323. package/corpus/core/src/templates/chat/app/components/layout/Header.tsx +0 -60
  324. package/corpus/core/src/templates/chat/app/components/layout/Layout.tsx +0 -188
  325. package/corpus/core/src/templates/chat/app/components/layout/Sidebar.tsx +0 -505
  326. package/corpus/core/src/templates/chat/app/components/ui/button.tsx +0 -1
  327. package/corpus/core/src/templates/chat/app/components/ui/card.tsx +0 -1
  328. package/corpus/core/src/templates/chat/app/components/ui/dropdown-menu.tsx +0 -1
  329. package/corpus/core/src/templates/chat/app/components/ui/input.tsx +0 -1
  330. package/corpus/core/src/templates/chat/app/components/ui/label.tsx +0 -1
  331. package/corpus/core/src/templates/chat/app/components/ui/sheet.tsx +0 -1
  332. package/corpus/core/src/templates/chat/app/components/ui/toolkit-provider.tsx +0 -17
  333. package/corpus/core/src/templates/chat/app/components/ui/tooltip.tsx +0 -1
  334. package/corpus/core/src/templates/chat/app/design-system.ts +0 -3
  335. package/corpus/core/src/templates/chat/app/entry.client.tsx +0 -22
  336. package/corpus/core/src/templates/chat/app/entry.server.tsx +0 -10
  337. package/corpus/core/src/templates/chat/app/global.css +0 -93
  338. package/corpus/core/src/templates/chat/app/hooks/use-navigation-state.ts +0 -93
  339. package/corpus/core/src/templates/chat/app/i18n/ar-SA.ts +0 -68
  340. package/corpus/core/src/templates/chat/app/i18n/de-DE.ts +0 -71
  341. package/corpus/core/src/templates/chat/app/i18n/en-US.ts +0 -70
  342. package/corpus/core/src/templates/chat/app/i18n/es-ES.ts +0 -71
  343. package/corpus/core/src/templates/chat/app/i18n/fr-FR.ts +0 -71
  344. package/corpus/core/src/templates/chat/app/i18n/hi-IN.ts +0 -69
  345. package/corpus/core/src/templates/chat/app/i18n/index.ts +0 -34
  346. package/corpus/core/src/templates/chat/app/i18n/ja-JP.ts +0 -70
  347. package/corpus/core/src/templates/chat/app/i18n/ko-KR.ts +0 -70
  348. package/corpus/core/src/templates/chat/app/i18n/pt-BR.ts +0 -71
  349. package/corpus/core/src/templates/chat/app/i18n/zh-CN.ts +0 -66
  350. package/corpus/core/src/templates/chat/app/i18n/zh-TW.ts +0 -66
  351. package/corpus/core/src/templates/chat/app/i18n-data.ts +0 -556
  352. package/corpus/core/src/templates/chat/app/lib/agent-page.tsx +0 -49
  353. package/corpus/core/src/templates/chat/app/lib/app-config.ts +0 -11
  354. package/corpus/core/src/templates/chat/app/lib/tab-id.ts +0 -1
  355. package/corpus/core/src/templates/chat/app/lib/utils.ts +0 -1
  356. package/corpus/core/src/templates/chat/app/root.tsx +0 -173
  357. package/corpus/core/src/templates/chat/app/routes/_index.tsx +0 -94
  358. package/corpus/core/src/templates/chat/app/routes/agent.tsx +0 -24
  359. package/corpus/core/src/templates/chat/app/routes/chat.$threadId.tsx +0 -1
  360. package/corpus/core/src/templates/chat/app/routes/database.tsx +0 -17
  361. package/corpus/core/src/templates/chat/app/routes/extensions.$id.$slug.tsx +0 -2
  362. package/corpus/core/src/templates/chat/app/routes/extensions.$id.tsx +0 -11
  363. package/corpus/core/src/templates/chat/app/routes/extensions._index.tsx +0 -11
  364. package/corpus/core/src/templates/chat/app/routes/extensions.tsx +0 -5
  365. package/corpus/core/src/templates/chat/app/routes/observability.tsx +0 -19
  366. package/corpus/core/src/templates/chat/app/routes/settings.tsx +0 -89
  367. package/corpus/core/src/templates/chat/app/routes/team.tsx +0 -11
  368. package/corpus/core/src/templates/chat/app/routes.ts +0 -4
  369. package/corpus/core/src/templates/chat/app/vite-env.d.ts +0 -6
  370. package/corpus/core/src/templates/chat/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +0 -6
  371. package/corpus/core/src/templates/chat/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +0 -6
  372. package/corpus/core/src/templates/chat/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +0 -6
  373. package/corpus/core/src/templates/chat/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +0 -6
  374. package/corpus/core/src/templates/chat/changelog/2026-06-29-chat-layouts-adapt-when-the-agent-sidebar-is-open.md +0 -6
  375. package/corpus/core/src/templates/chat/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +0 -5
  376. package/corpus/core/src/templates/chat/changelog/2026-07-10-chat-now-makes-ai-connection-setup-clear-without-shifting-th.md +0 -6
  377. package/corpus/core/src/templates/chat/changelog/2026-07-13-a-full-agent-page-now-brings-context-files-connections-jobs-.md +0 -6
  378. package/corpus/core/src/templates/chat/changelog/2026-07-14-chat-opens-reliably-on-hosted-deployments-instead-of-failing.md +0 -6
  379. package/corpus/core/src/templates/chat/changelog/2026-07-14-fixed-chat-template-startup-with-older-core-versions.md +0 -6
  380. package/corpus/core/src/templates/chat/changelog/2026-07-15-chat-navigation-focuses-on-chat-and-agent.md +0 -6
  381. package/corpus/core/src/templates/chat/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +0 -6
  382. package/corpus/core/src/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +0 -6
  383. package/corpus/core/src/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +0 -6
  384. package/corpus/core/src/templates/chat/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +0 -6
  385. package/corpus/core/src/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +0 -6
  386. package/corpus/core/src/templates/chat/changelog/2026-07-23-full-page-chat-is-better-centered-with-quieter-chat-history-.md +0 -6
  387. package/corpus/core/src/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +0 -6
  388. package/corpus/core/src/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +0 -6
  389. package/corpus/core/src/templates/chat/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +0 -6
  390. package/corpus/core/src/templates/chat/components.json +0 -20
  391. package/corpus/core/src/templates/chat/learnings.defaults.md +0 -5
  392. package/corpus/core/src/templates/chat/netlify.toml +0 -11
  393. package/corpus/core/src/templates/chat/package.json +0 -92
  394. package/corpus/core/src/templates/chat/public/agent-native-icon-dark.svg +0 -10
  395. package/corpus/core/src/templates/chat/public/agent-native-icon-light.svg +0 -10
  396. package/corpus/core/src/templates/chat/public/agent-native-logo-dark.svg +0 -21
  397. package/corpus/core/src/templates/chat/public/agent-native-logo-light.svg +0 -21
  398. package/corpus/core/src/templates/chat/public/favicon.svg +0 -1
  399. package/corpus/core/src/templates/chat/public/icon-180.svg +0 -1
  400. package/corpus/core/src/templates/chat/public/icon-192.svg +0 -1
  401. package/corpus/core/src/templates/chat/public/icon-512.svg +0 -1
  402. package/corpus/core/src/templates/chat/public/manifest.json +0 -21
  403. package/corpus/core/src/templates/chat/react-router.config.ts +0 -7
  404. package/corpus/core/src/templates/chat/server/middleware/auth.ts +0 -15
  405. package/corpus/core/src/templates/chat/server/plugins/agent-chat.ts +0 -21
  406. package/corpus/core/src/templates/chat/server/plugins/auth.ts +0 -17
  407. package/corpus/core/src/templates/chat/server/routes/[...page].get.ts +0 -5
  408. package/corpus/core/src/templates/chat/ssr-entry.ts +0 -15
  409. package/corpus/core/src/templates/chat/tsconfig.json +0 -21
  410. package/corpus/core/src/templates/chat/vite.config.ts +0 -19
@@ -132,38 +132,56 @@ async function loadGetTableConfig(): Promise<
132
132
  }
133
133
 
134
134
  /**
135
- * Live columns already present on `table`, keyed by column name.
136
- * Postgres: `information_schema.columns` scoped to the table's schema
137
- * (default `public`). SQLite: `PRAGMA table_info(table)`.
138
- *
139
- * Returns `null` when the table itself does not exist (caller no-ops —
140
- * table creation owns that path) or when introspection fails outright.
135
+ * Load every requested Postgres table's live columns in one round trip.
136
+ * Calling information_schema separately for each table adds dozens of
137
+ * serialized network requests to every serverless cold start.
141
138
  */
142
- async function introspectLiveColumns(
139
+ async function introspectPostgresColumns(
143
140
  db: DbExec,
144
- table: string,
145
- schema: string | undefined,
146
- ): Promise<Set<string> | null> {
147
- if (isPostgres()) {
148
- try {
149
- const tableSchema = schema || "public";
150
- const { rows: existsRows } = await db.execute({
151
- sql: `SELECT 1 FROM information_schema.tables
152
- WHERE table_schema = ? AND table_name = ? LIMIT 1`,
153
- args: [tableSchema, table],
154
- });
155
- if (existsRows.length === 0) return null;
156
- const { rows } = await db.execute({
157
- sql: `SELECT column_name FROM information_schema.columns
158
- WHERE table_schema = ? AND table_name = ?`,
159
- args: [tableSchema, table],
160
- });
161
- return new Set(rows.map((r) => String(r.column_name)));
162
- } catch {
163
- return null;
141
+ tables: DeclaredTableLike[],
142
+ ): Promise<Map<string, Set<string>> | null> {
143
+ if (tables.length === 0) return new Map();
144
+ const pairs = [
145
+ ...new Map(
146
+ tables.map((table) => {
147
+ const schema = table.schema || "public";
148
+ return [`${schema}.${table.name}`, { schema, table: table.name }];
149
+ }),
150
+ ).values(),
151
+ ];
152
+ const args: unknown[] = [];
153
+ const predicates = pairs.map(({ schema, table }) => {
154
+ args.push(schema, table);
155
+ return `(table_schema = ? AND table_name = ?)`;
156
+ });
157
+ try {
158
+ const { rows } = await db.execute({
159
+ sql: `SELECT table_schema, table_name, column_name
160
+ FROM information_schema.columns
161
+ WHERE ${predicates.join(" OR ")}`,
162
+ args,
163
+ });
164
+ const columns = new Map<string, Set<string>>();
165
+ for (const row of rows) {
166
+ const key = `${String(row.table_schema)}.${String(row.table_name)}`;
167
+ const tableColumns = columns.get(key) ?? new Set<string>();
168
+ tableColumns.add(String(row.column_name));
169
+ columns.set(key, tableColumns);
164
170
  }
171
+ return columns;
172
+ } catch {
173
+ return null;
165
174
  }
175
+ }
166
176
 
177
+ /**
178
+ * Live SQLite columns already present on `table`, keyed by column name.
179
+ * Returns `null` when the table does not exist or introspection fails.
180
+ */
181
+ async function introspectSqliteLiveColumns(
182
+ db: DbExec,
183
+ table: string,
184
+ ): Promise<Set<string> | null> {
167
185
  // SQLite: PRAGMA table_info returns zero rows for a non-existent table
168
186
  // (no error), so we can't distinguish "missing table" from "no columns"
169
187
  // that way — probe sqlite_master first.
@@ -308,10 +326,13 @@ export async function ensureAdditiveColumns(
308
326
  return result;
309
327
  }
310
328
 
329
+ const declaredTables: DeclaredTableLike[] = [];
311
330
  for (const tableObj of tables) {
312
- let config: DeclaredTableLike;
313
331
  try {
314
- config = getTableConfig(tableObj);
332
+ const config = getTableConfig(tableObj);
333
+ if (config.name && PLAIN_IDENTIFIER.test(config.name)) {
334
+ declaredTables.push(config);
335
+ }
315
336
  } catch (err) {
316
337
  // Not a table this dialect's getTableConfig understands (e.g. a stray
317
338
  // export that isn't a Drizzle table) — skip quietly rather than
@@ -319,15 +340,21 @@ export async function ensureAdditiveColumns(
319
340
  logger.warn(
320
341
  `[ensure-additive-columns] skipping non-table export: ${err instanceof Error ? err.message : String(err)}`,
321
342
  );
322
- continue;
323
343
  }
344
+ }
324
345
 
325
- const tableName = config.name;
326
- if (!tableName || !PLAIN_IDENTIFIER.test(tableName)) continue;
346
+ const postgresColumns = isPostgres()
347
+ ? await introspectPostgresColumns(db, declaredTables)
348
+ : null;
327
349
 
350
+ for (const config of declaredTables) {
351
+ const tableName = config.name;
328
352
  let liveColumns: Set<string> | null;
329
353
  try {
330
- liveColumns = await introspectLiveColumns(db, tableName, config.schema);
354
+ liveColumns = isPostgres()
355
+ ? (postgresColumns?.get(`${config.schema || "public"}.${tableName}`) ??
356
+ null)
357
+ : await introspectSqliteLiveColumns(db, tableName);
331
358
  } catch (err) {
332
359
  result.errors.push({
333
360
  column: `${tableName}.*`,
@@ -1688,7 +1688,7 @@ export function generateCloudflarePagesStaticShellFromManifest(
1688
1688
  ? DEFAULT_ROOT_LOADER_REACT_ROUTER_TURBO_STREAM
1689
1689
  : EMPTY_REACT_ROUTER_TURBO_STREAM;
1690
1690
 
1691
- return `<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/><link rel="manifest" href="/manifest.json"/><link rel="icon" type="image/svg+xml" href="/favicon.svg"/>${modulePreloads}${stylesheets}</head><body><div style="display:flex;align-items:center;justify-content:center;height:100vh;width:100%"><svg role="status" aria-label="Loading" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="animation:an-spin 1s linear infinite;opacity:0.7"><path d="M21 12a9 9 0 1 1-6.219-8.56"></path></svg><style>@keyframes an-spin { to { transform: rotate(360deg) } } @media (prefers-color-scheme: dark) { html { background: #09090b; color: #fafafa } }</style></div><script>window.__reactRouterContext = ${JSON.stringify(context)};window.__reactRouterContext.stream = new ReadableStream({start(controller){window.__reactRouterContext.streamController = controller;}}).pipeThrough(new TextEncoderStream());</script><script type="module" async="">${routeModuleScript}</script><!--$--><script>window.__reactRouterContext.streamController.enqueue(${JSON.stringify(encodedInitialState)});</script><!--$--><script>window.__reactRouterContext.streamController.close();</script><!--/$--><!--/$--></body></html>`;
1691
+ return `<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/><link rel="manifest" href="/manifest.json"/><link rel="icon" type="image/svg+xml" href="/favicon.svg"/>${modulePreloads}${stylesheets}</head><body><div style="display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;height:100vh;width:100%"><svg role="status" aria-label="Loading" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="animation:an-spin 1s linear infinite;opacity:0.7"><path d="M21 12a9 9 0 1 1-6.219-8.56"></path></svg><p class="an-stall-hint">Still loading. If this does not finish, reload the page — the browser console may show what failed.</p><style>@keyframes an-spin { to { transform: rotate(360deg) } } @keyframes an-stall-in { to { opacity: 0.6 } } .an-stall-hint { opacity: 0; margin: 0; max-width: 32rem; padding: 0 1.5rem; text-align: center; font-size: 0.875rem; line-height: 1.5; font-family: ui-sans-serif, system-ui, sans-serif; animation: an-stall-in 0.4s ease-out 10s forwards } @media (prefers-reduced-motion: reduce) { .an-stall-hint { animation-duration: 0s } } @media (prefers-color-scheme: dark) { html { background: #09090b; color: #fafafa } }</style></div><script>window.__reactRouterContext = ${JSON.stringify(context)};window.__reactRouterContext.stream = new ReadableStream({start(controller){window.__reactRouterContext.streamController = controller;}}).pipeThrough(new TextEncoderStream());</script><script type="module" async="">${routeModuleScript}</script><!--$--><script>window.__reactRouterContext.streamController.enqueue(${JSON.stringify(encodedInitialState)});</script><!--$--><script>window.__reactRouterContext.streamController.close();</script><!--/$--><!--/$--></body></html>`;
1692
1692
  }
1693
1693
 
1694
1694
  function writeCloudflarePagesStaticShell({
@@ -2343,6 +2343,28 @@ const LIBSQL_NATIVE_PACKAGE_NAMES = [
2343
2343
  const FFMPEG_STATIC_PACKAGE_NAME = "ffmpeg-static";
2344
2344
  const RESVG_SCOPE = "@resvg";
2345
2345
  const RESVG_PACKAGE_PREFIX = "resvg-js";
2346
+
2347
+ // Serverless functions only ever run on 64-bit Linux. The darwin/win32/android
2348
+ // and 32-bit-arm prebuilds of these native packages are ~100MB that can never
2349
+ // execute there, and Netlify copies the whole server dir again for every extra
2350
+ // emitted function — so the dead weight is paid once per function. Cold start
2351
+ // scales with bundle size, and a page that opens several requests at once
2352
+ // scales out to that many cold containers, which is how this surfaces: 502/504
2353
+ // on the first burst rather than as an obviously slow deploy.
2354
+ const SERVERLESS_NATIVE_PACKAGE_SUFFIXES = [
2355
+ "linux-x64-gnu",
2356
+ "linux-x64-musl",
2357
+ "linux-arm64-gnu",
2358
+ "linux-arm64-musl",
2359
+ ];
2360
+
2361
+ export function isServerlessNativePlatformPackage(
2362
+ packageName: string,
2363
+ ): boolean {
2364
+ return SERVERLESS_NATIVE_PACKAGE_SUFFIXES.some((suffix) =>
2365
+ packageName.endsWith(suffix),
2366
+ );
2367
+ }
2346
2368
  const FFMPEG_STATIC_BINARY_NAMES =
2347
2369
  process.platform === "win32" ? ["ffmpeg.exe", "ffmpeg"] : ["ffmpeg"];
2348
2370
  const SERVERLESS_FFMPEG_STATIC_PLATFORM = "linux";
@@ -3441,6 +3463,7 @@ function copyInstalledLibsqlNativePackages(serverDir: string | undefined) {
3441
3463
  let copied = 0;
3442
3464
 
3443
3465
  for (const packageName of LIBSQL_NATIVE_PACKAGE_NAMES) {
3466
+ if (!isServerlessNativePlatformPackage(packageName)) continue;
3444
3467
  const src = findInstalledLibsqlNativePackage(nodeModulesRoots, packageName);
3445
3468
  if (!src) continue;
3446
3469
 
@@ -3457,7 +3480,13 @@ function copyInstalledLibsqlNativePackages(serverDir: string | undefined) {
3457
3480
 
3458
3481
  function copyInstalledResvgPackages(serverDir: string | undefined) {
3459
3482
  if (!serverDir || !fs.existsSync(serverDir)) return;
3460
- const packages = findInstalledResvgPackages(nodeModulesAncestors(cwd));
3483
+ // `resvg-js` itself is the JS wrapper that gets imported; everything else in
3484
+ // the scope is a per-platform prebuild.
3485
+ const packages = findInstalledResvgPackages(nodeModulesAncestors(cwd)).filter(
3486
+ ({ packageName }) =>
3487
+ packageName === RESVG_PACKAGE_PREFIX ||
3488
+ isServerlessNativePlatformPackage(packageName),
3489
+ );
3461
3490
  if (packages.length === 0) return;
3462
3491
 
3463
3492
  const destScopeDir = path.join(serverDir, "node_modules", RESVG_SCOPE);
@@ -367,6 +367,9 @@ async function reconfigureManager(manager: McpClientManager): Promise<void> {
367
367
  export function mountMcpServersRoutes(
368
368
  nitroApp: any,
369
369
  manager: McpClientManager,
370
+ options: {
371
+ waitUntilReady?: () => Promise<void>;
372
+ } = {},
370
373
  ): void {
371
374
  const mountedApps: WeakSet<object> = ((
372
375
  globalThis as any
@@ -375,13 +378,17 @@ export function mountMcpServersRoutes(
375
378
  mountedApps.add(nitroApp);
376
379
 
377
380
  mountMcpOAuthRoutes(nitroApp, {
378
- reconfigure: () => reconfigureManager(manager),
381
+ reconfigure: async () => {
382
+ await options.waitUntilReady?.();
383
+ await reconfigureManager(manager);
384
+ },
379
385
  });
380
386
 
381
387
  try {
382
388
  getH3App(nitroApp).use(
383
389
  "/_agent-native/mcp/servers",
384
390
  defineEventHandler(async (event: H3Event) => {
391
+ await options.waitUntilReady?.();
385
392
  const method = getMethod(event);
386
393
  const pathname = (event.url?.pathname || "")
387
394
  .replace(/^\/+/, "")
@@ -421,6 +428,7 @@ export function mountMcpServersRoutes(
421
428
  getH3App(nitroApp).use(
422
429
  "/_agent-native/mcp/builtin",
423
430
  defineEventHandler(async (event: H3Event) => {
431
+ await options.waitUntilReady?.();
424
432
  const method = getMethod(event);
425
433
  const pathname = (event.url?.pathname || "")
426
434
  .replace(/^\/+/, "")
@@ -442,6 +450,7 @@ export function mountMcpServersRoutes(
442
450
  getH3App(nitroApp).use(
443
451
  "/_agent-native/mcp/apps",
444
452
  defineEventHandler(async (event: H3Event) => {
453
+ await options.waitUntilReady?.();
445
454
  const method = getMethod(event);
446
455
  const pathname = (event.url?.pathname || "")
447
456
  .replace(/^\/+/, "")
@@ -0,0 +1,152 @@
1
+ import {
2
+ defineEventHandler,
3
+ getRequestURL,
4
+ createError,
5
+ type H3Event,
6
+ } from "h3";
7
+
8
+ import { getDbExec } from "../db/client.js";
9
+ import { readBody } from "../server/h3-helpers.js";
10
+ import {
11
+ getRegisteredAppRoles,
12
+ listAppMemberRoles,
13
+ setAppMemberRole,
14
+ type AppRolesDescriptor,
15
+ } from "./app-roles.js";
16
+ import { getOrgContext } from "./context.js";
17
+ import { canManageOrg } from "./permissions.js";
18
+
19
+ /**
20
+ * Resolve the descriptor a request is talking about.
21
+ *
22
+ * The `appId` arrives from the client but can only ever select among
23
+ * descriptors the server already declared through `defineAppRoles`; an
24
+ * unregistered id is a 404, never an implicit new app. That keeps the trusted
25
+ * vocabulary in app source while still letting one workspace host several apps.
26
+ */
27
+ function requireDescriptor(appId: string | null): AppRolesDescriptor<string> {
28
+ if (!appId?.trim()) {
29
+ throw createError({ statusCode: 400, message: "appId is required" });
30
+ }
31
+ const descriptor = getRegisteredAppRoles(appId.trim());
32
+ if (!descriptor) {
33
+ throw createError({
34
+ statusCode: 404,
35
+ message: `No app roles registered for "${appId}"`,
36
+ });
37
+ }
38
+ return descriptor;
39
+ }
40
+
41
+ /** Extract the :email tail. The mount prefix is stripped before we see it. */
42
+ function extractMemberEmail(event: H3Event): string | undefined {
43
+ const path = getRequestURL(event).pathname;
44
+ const match =
45
+ path.match(/^\/([^/]+)\/?$/) ?? path.match(/\/app-roles\/([^/]+)\/?$/);
46
+ return match?.[1] ? decodeURIComponent(match[1]) : undefined;
47
+ }
48
+
49
+ async function isOrgMember(orgId: string, email: string): Promise<boolean> {
50
+ const { rows } = await getDbExec().execute({
51
+ sql: `SELECT 1 FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1`,
52
+ args: [orgId, email.trim().toLowerCase()],
53
+ });
54
+ return rows.length > 0;
55
+ }
56
+
57
+ /**
58
+ * GET /_agent-native/org/app-roles?appId=X — the app's vocabulary plus every
59
+ * assignment in the active org, and the caller's own resolved role.
60
+ */
61
+ export const listAppRolesHandler = defineEventHandler(
62
+ async (event: H3Event) => {
63
+ const url = getRequestURL(event);
64
+ const descriptor = requireDescriptor(url.searchParams.get("appId"));
65
+ const ctx = await getOrgContext(event);
66
+
67
+ const base = {
68
+ appId: descriptor.appId,
69
+ roles: descriptor.roles,
70
+ defaultRole: descriptor.defaultRole ?? null,
71
+ roleLabels: descriptor.roleLabels ?? {},
72
+ canManage: canManageOrg(ctx.role),
73
+ };
74
+ if (!ctx.orgId) return { ...base, assignments: [], myRole: null };
75
+
76
+ const assignments = await listAppMemberRoles(descriptor.appId, ctx.orgId);
77
+ const mine = assignments.find(
78
+ (a) => a.email.toLowerCase() === ctx.email.toLowerCase(),
79
+ );
80
+ return {
81
+ ...base,
82
+ assignments,
83
+ // The caller's own role, for progressive disclosure only. Every guarded
84
+ // operation re-resolves this server-side; a client that lies about it gains
85
+ // nothing but a differently-shaped UI.
86
+ myRole: mine && descriptor.roles.includes(mine.role) ? mine.role : null,
87
+ };
88
+ },
89
+ );
90
+
91
+ /**
92
+ * PUT /_agent-native/org/app-roles/:email — assign or clear an app role.
93
+ * Body: `{ appId, role }`, where `role: null` clears the assignment.
94
+ *
95
+ * Org owner/admin only. App roles never confer the right to manage app roles:
96
+ * that would let an app admin escalate inside a team they cannot otherwise
97
+ * administer, and it is the org roster this overlay hangs off.
98
+ */
99
+ export const setAppRoleHandler = defineEventHandler(async (event: H3Event) => {
100
+ const ctx = await getOrgContext(event);
101
+ if (!ctx.email) {
102
+ throw createError({ statusCode: 401, message: "Authentication required" });
103
+ }
104
+ if (!ctx.orgId) {
105
+ throw createError({ statusCode: 400, message: "No active organization" });
106
+ }
107
+ if (!canManageOrg(ctx.role)) {
108
+ throw createError({
109
+ statusCode: 403,
110
+ message: "Organization admin role required",
111
+ });
112
+ }
113
+
114
+ const body = await readBody(event);
115
+ const descriptor = requireDescriptor(body?.appId ?? null);
116
+
117
+ const email = extractMemberEmail(event);
118
+ if (!email) {
119
+ throw createError({ statusCode: 400, message: "Member email is required" });
120
+ }
121
+
122
+ const role = body?.role ?? null;
123
+ if (role !== null && !descriptor.roles.includes(String(role))) {
124
+ throw createError({
125
+ statusCode: 400,
126
+ message: `Unknown ${descriptor.appId} role "${role}"`,
127
+ });
128
+ }
129
+
130
+ // Assignments hang off membership. Writing one for a non-member would leave a
131
+ // row that resolves to nothing and reappears if that person is ever invited.
132
+ if (!(await isOrgMember(ctx.orgId, email))) {
133
+ throw createError({
134
+ statusCode: 404,
135
+ message: "Not a member of this organization",
136
+ });
137
+ }
138
+
139
+ await setAppMemberRole({
140
+ appId: descriptor.appId,
141
+ orgId: ctx.orgId,
142
+ email,
143
+ role: role === null ? null : String(role),
144
+ updatedBy: ctx.email,
145
+ });
146
+
147
+ return {
148
+ appId: descriptor.appId,
149
+ email,
150
+ role: role === null ? null : String(role),
151
+ };
152
+ });