@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
@@ -50,6 +50,11 @@ const ARTIFACT_IDENTITY_WRITE_TOOLS = new Set([
50
50
  "create-deck",
51
51
  "duplicate-deck",
52
52
  "add-slide",
53
+ "update-slide",
54
+ "patch-deck",
55
+ "save-deck",
56
+ "import-pptx",
57
+ "restore-deck-version",
53
58
  "update-dashboard",
54
59
  "rename-dashboard",
55
60
  "save-analysis",
@@ -513,27 +518,43 @@ function addImageArtifact(
513
518
  });
514
519
  }
515
520
 
516
- function isReadyDeckArtifact(parsed: Record<string, unknown>): boolean {
517
- const slideCount = numberValue(parsed.slideCount);
518
- if (slideCount !== undefined) return slideCount > 0;
519
- if (Array.isArray(parsed.slides)) return parsed.slides.length > 0;
520
- return true;
521
- }
522
-
523
521
  function addDeckArtifact(
524
522
  decks: Map<string, CreatedDeckArtifact>,
525
523
  parsed: Record<string, unknown>,
526
- options: { requireReady: boolean },
527
524
  ): void {
528
525
  const id = deckIdValue(parsed);
529
526
  if (!id) return;
530
- if (options.requireReady && !isReadyDeckArtifact(parsed)) return;
531
527
  decks.set(id, {
532
528
  id,
533
529
  url: stringValue(parsed.url) ?? stringValue(parsed.urlPath),
534
530
  });
535
531
  }
536
532
 
533
+ // Deck writes are spread across a dozen actions (create-deck, add-slide,
534
+ // patch-deck, save-deck, update-slide, import-*, restore-deck-version), so a
535
+ // per-tool allow-list refuses a real deck URL every time an action is added.
536
+ // Trust any successful result that names a deck the way the deck routes do: an
537
+ // explicit deckId, or a canonical /deck/<id> URL the action itself returned.
538
+ function addDeckArtifactFromAnyResult(
539
+ decks: Map<string, CreatedDeckArtifact>,
540
+ parsed: Record<string, unknown>,
541
+ ): void {
542
+ const url = stringValue(parsed.url) ?? stringValue(parsed.urlPath);
543
+ const deckId = stringValue(parsed.deckId);
544
+ if (deckId) {
545
+ decks.set(deckId, {
546
+ id: deckId,
547
+ url:
548
+ url && artifactUrlReferencesId(url, "deck", deckId) ? url : undefined,
549
+ });
550
+ }
551
+
552
+ const reference = url ? parseArtifactReferenceUrl(url) : null;
553
+ if (reference?.kind === "deck") {
554
+ decks.set(reference.id, { id: reference.id, url });
555
+ }
556
+ }
557
+
537
558
  function addListedDeckArtifacts(
538
559
  decks: Map<string, CreatedDeckArtifact>,
539
560
  parsed: Record<string, unknown>,
@@ -543,7 +564,7 @@ function addListedDeckArtifacts(
543
564
  for (const item of items) {
544
565
  const deck = asRecord(item);
545
566
  if (!deck) continue;
546
- addDeckArtifact(decks, deck, { requireReady: false });
567
+ addDeckArtifact(decks, deck);
547
568
  }
548
569
  }
549
570
 
@@ -617,6 +638,8 @@ function collectArtifacts(results: A2AToolResultSummary[]): {
617
638
  const parsed = parseToolResultJson(toolResult.result);
618
639
  if (!parsed) continue;
619
640
 
641
+ addDeckArtifactFromAnyResult(decks, parsed);
642
+
620
643
  if (toolResult.tool === "save-monitor") {
621
644
  const id = stringValue(parsed.id);
622
645
  const url = stringValue(parsed.monitorAppUrl);
@@ -711,14 +734,10 @@ function collectArtifacts(results: A2AToolResultSummary[]): {
711
734
 
712
735
  if (
713
736
  toolResult.tool === "create-deck" ||
714
- toolResult.tool === "duplicate-deck"
737
+ toolResult.tool === "duplicate-deck" ||
738
+ toolResult.tool === "get-deck"
715
739
  ) {
716
- addDeckArtifact(decks, parsed, { requireReady: true });
717
- continue;
718
- }
719
-
720
- if (toolResult.tool === "get-deck") {
721
- addDeckArtifact(decks, parsed, { requireReady: false });
740
+ addDeckArtifact(decks, parsed);
722
741
  continue;
723
742
  }
724
743
 
@@ -727,18 +746,6 @@ function collectArtifacts(results: A2AToolResultSummary[]): {
727
746
  continue;
728
747
  }
729
748
 
730
- if (toolResult.tool === "add-slide") {
731
- const id = stringValue(parsed.deckId);
732
- const slideCount = numberValue(parsed.slideCount);
733
- if (id && slideCount !== undefined && slideCount > 0) {
734
- decks.set(id, {
735
- id,
736
- url: stringValue(parsed.url) ?? stringValue(parsed.urlPath),
737
- });
738
- }
739
- continue;
740
- }
741
-
742
749
  if (
743
750
  toolResult.tool === "update-dashboard" ||
744
751
  toolResult.tool === "rename-dashboard" ||
@@ -123,6 +123,19 @@ export interface ActionRunContext {
123
123
  turnId?: string;
124
124
  }
125
125
 
126
+ /**
127
+ * Pre-run authorization gate. Throw to deny with a specific message (the
128
+ * framework's `ForbiddenError` carries a 403), or return `false` for a generic
129
+ * denial. Returning `undefined` allows the call — a guard that forgets to
130
+ * return is therefore permissive, which is why `false` is honoured at all:
131
+ * `(args) => someCheck(args)` written against a boolean helper would otherwise
132
+ * pass silently on every denial.
133
+ */
134
+ export type ActionAuthorize<TArgs> = (
135
+ args: TArgs,
136
+ ctx?: ActionRunContext,
137
+ ) => void | boolean | Promise<void | boolean>;
138
+
126
139
  export interface AgentActionStopOptions {
127
140
  /** Optional stable code surfaced in run metadata and tests. */
128
141
  errorCode?: string;
@@ -466,6 +479,30 @@ interface DefineActionWithSchema<
466
479
  args: StandardSchemaV1.InferOutput<TSchema>,
467
480
  ctx?: ActionRunContext,
468
481
  ) => boolean | Promise<boolean>);
482
+ /**
483
+ * Authorization gate that runs before `run()` on **every** caller — agent
484
+ * tool, HTTP, frontend, MCP, A2A, and CLI. It wraps `run` itself rather than
485
+ * hanging off the action entry, because a flag consulted by the dispatcher
486
+ * only guards the dispatchers that remember to consult it.
487
+ *
488
+ * This is *authorization*, not approval: `needsApproval` asks a human to
489
+ * bless one call the caller is already allowed to make, while `authorize`
490
+ * decides whether they are allowed at all. It also does not replace
491
+ * `accessFilter` / `assertAccess` — those scope which rows a permitted caller
492
+ * may see; this decides whether the operation is open to them.
493
+ *
494
+ * ```ts
495
+ * import { coachAccess } from "../lib/access.js";
496
+ *
497
+ * export default defineAction({
498
+ * description: "Archive a training plan.",
499
+ * schema,
500
+ * authorize: coachAccess.requireAny("coach-admin"),
501
+ * run: async (args) => { ... },
502
+ * });
503
+ * ```
504
+ */
505
+ authorize?: ActionAuthorize<StandardSchemaV1.InferOutput<TSchema>>;
469
506
  /**
470
507
  * Audit-log configuration. **Default-on for mutating actions** — you only
471
508
  * need this to tune capture: declare the mutated `target` (so the change
@@ -556,6 +593,9 @@ interface DefineActionWithParams<
556
593
  args: InferParams<TParams>,
557
594
  ctx?: ActionRunContext,
558
595
  ) => boolean | Promise<boolean>);
596
+ /** Pre-run authorization gate applied to every caller. See the schema
597
+ * overload above for full semantics. */
598
+ authorize?: ActionAuthorize<InferParams<TParams>>;
559
599
  /** Audit-log configuration (default-on for mutations). See the schema
560
600
  * overload above and the `audit-log` skill. */
561
601
  audit?: ActionAuditConfig;
@@ -714,12 +754,21 @@ export function defineAction(options: any) {
714
754
  );
715
755
  }
716
756
 
757
+ // Authorization sits INSIDE input validation, so a gate that inspects `args`
758
+ // is handed the parsed, coerced value its type promises rather than whatever
759
+ // shape the caller sent. Putting it outside would have every guard reading
760
+ // attacker-shaped input while typed as though it were validated.
761
+ const guardedRun =
762
+ typeof options.authorize === "function"
763
+ ? wrapRunWithAuthorize(options.run, options.authorize)
764
+ : options.run;
765
+
717
766
  // Wrap run() with INPUT validation when schema is provided.
718
767
  // Pass toolParameters so the validation error can echo the expected signature
719
768
  // (required vs optional fields) and help the caller self-correct.
720
769
  const inputValidatedRun = hasSchema
721
- ? wrapWithValidation(options.schema, options.run, toolParameters)
722
- : options.run;
770
+ ? wrapWithValidation(options.schema, guardedRun, toolParameters)
771
+ : guardedRun;
723
772
 
724
773
  // Then wrap with OUTPUT validation when an outputSchema is provided. This
725
774
  // composes AROUND the input-validated run so the order is: validate input →
@@ -877,6 +926,38 @@ export function defineAction(options: any) {
877
926
  };
878
927
  }
879
928
 
929
+ /**
930
+ * Wrap an action's run with its `authorize` gate.
931
+ *
932
+ * The gate is applied here, around `run`, rather than exposed as a flag on the
933
+ * action entry: `run` is the one thing all six dispatch sites (agent loop, HTTP
934
+ * route, frontend, MCP, A2A, CLI) go through, so there is no caller that can
935
+ * reach the body without passing the check. `needsApproval` took the flag route
936
+ * and is consequently honoured only inside the agent loop.
937
+ *
938
+ * Composed so the full order is: validate input → authorize → run → validate
939
+ * output → audit. The audit wrapper is outermost, so a denial is still recorded
940
+ * as an attempt — which is precisely what an audit trail is for.
941
+ *
942
+ * A guard that throws denies with its own message. A guard that returns `false`
943
+ * denies generically. Anything else — including `undefined` — allows.
944
+ */
945
+ function wrapRunWithAuthorize(
946
+ run: (args: any, ctx?: ActionRunContext) => any,
947
+ authorize: ActionAuthorize<any>,
948
+ ): (args: any, ctx?: ActionRunContext) => Promise<any> {
949
+ return async function authorizedRun(args: any, ctx?: ActionRunContext) {
950
+ const verdict = await authorize(args, ctx);
951
+ if (verdict === false) {
952
+ const err = new Error("Not authorized") as Error & { statusCode: number };
953
+ err.name = "ForbiddenError";
954
+ err.statusCode = 403;
955
+ throw err;
956
+ }
957
+ return run(args, ctx);
958
+ };
959
+ }
960
+
880
961
  /**
881
962
  * Wrap an action's (already input/output-validated) run so each call records an
882
963
  * audit event after it resolves — on success and on error. Best-effort: the
@@ -159,9 +159,6 @@ async function ensureTable(): Promise<void> {
159
159
  "chat_thread_shares_resource_idx",
160
160
  CHAT_THREAD_SHARES_RESOURCE_INDEX_SQL,
161
161
  );
162
- // One-time backfill of message_count for legacy rows written before
163
- // the column was maintained.
164
- await backfillLegacyMessageCounts(client);
165
162
  return;
166
163
  }
167
164
 
@@ -221,15 +218,6 @@ async function ensureTable(): Promise<void> {
221
218
  // Index already exists or the dialect rejected a duplicate.
222
219
  }
223
220
  }
224
- // One-time backfill of message_count for legacy rows written before
225
- // the column was maintained. The list/summary path now reads
226
- // message_count directly (instead of re-parsing the thread_data blob)
227
- // and filters on `message_count > 0`, so any legacy row that has
228
- // messages but a stale `message_count = 0` would otherwise vanish from
229
- // the sidebar. Recompute the count from thread_data and persist it so
230
- // the hot path can stay blob-free. Idempotent: only touches rows where
231
- // the count is still 0 but the blob clearly contains a messages array.
232
- await backfillLegacyMessageCounts(client);
233
221
  })().catch((err) => {
234
222
  // Retry init on the next call after a failed startup.
235
223
  _initPromise = undefined;
@@ -240,28 +228,47 @@ async function ensureTable(): Promise<void> {
240
228
  }
241
229
 
242
230
  /**
243
- * Recompute `message_count` from `thread_data` for legacy rows that still
244
- * have a stale `message_count = 0` despite carrying a messages array in the
245
- * blob. Without this, dropping the `thread_data` payload (and the
246
- * `OR thread_data LIKE '%"messages"%'` filter) from the list path would make
247
- * those rows disappear from the sidebar. Runs once at table bootstrap and is
248
- * idempotent — after the first pass no row matches the WHERE clause again.
231
+ * Explicitly repair `message_count` for legacy rows written before the count
232
+ * was maintained. This must never run from table/bootstrap initialization:
233
+ * serverless isolates would each scan the full `thread_data` blob column on
234
+ * cold start. Operators may invoke it once when upgrading an old database.
249
235
  */
250
- async function backfillLegacyMessageCounts(
251
- client: ReturnType<typeof getDbExec>,
252
- ): Promise<void> {
253
- const { rows } = await client.execute({
254
- sql: `SELECT id, thread_data, message_count FROM chat_threads WHERE message_count = 0 AND thread_data LIKE '%"messages"%'`,
255
- args: [],
256
- });
257
- for (const r of rows) {
258
- const count = deriveMessageCount(r.thread_data, 0);
259
- if (count <= 0) continue;
260
- await client.execute({
261
- sql: `UPDATE chat_threads SET message_count = ? WHERE id = ? AND message_count = 0`,
262
- args: [count, r.id as string],
236
+ export async function repairLegacyChatThreadMessageCounts(
237
+ options: {
238
+ batchSize?: number;
239
+ } = {},
240
+ ): Promise<{ scanned: number; updated: number }> {
241
+ await ensureTable();
242
+ const client = getDbExec();
243
+ const batchSize = Math.max(1, Math.min(options.batchSize ?? 100, 1_000));
244
+ let afterId = "";
245
+ let scanned = 0;
246
+ let updated = 0;
247
+ while (true) {
248
+ const { rows } = await client.execute({
249
+ sql: `SELECT id, thread_data, message_count FROM chat_threads
250
+ WHERE message_count = 0
251
+ AND thread_data LIKE '%"messages"%'
252
+ AND id > ?
253
+ ORDER BY id
254
+ LIMIT ?`,
255
+ args: [afterId, batchSize],
263
256
  });
257
+ if (rows.length === 0) break;
258
+ for (const row of rows) {
259
+ afterId = String(row.id);
260
+ scanned++;
261
+ const count = deriveMessageCount(row.thread_data, 0);
262
+ if (count <= 0) continue;
263
+ const result = await client.execute({
264
+ sql: `UPDATE chat_threads SET message_count = ? WHERE id = ? AND message_count = 0`,
265
+ args: [count, afterId],
266
+ });
267
+ if (result.rowsAffected > 0) updated++;
268
+ }
269
+ if (rows.length < batchSize) break;
264
270
  }
271
+ return { scanned, updated };
265
272
  }
266
273
 
267
274
  function generateId(): string {
@@ -407,8 +414,8 @@ function rowToThread(r: Record<string, unknown>): ChatThread {
407
414
 
408
415
  function rowToSummary(r: Record<string, unknown>): ChatThreadSummary | null {
409
416
  // The summary path never loads `thread_data`; the count comes from the
410
- // dedicated `message_count` column (maintained on write, backfilled for
411
- // legacy rows at bootstrap). Empty threads are filtered out of the list.
417
+ // dedicated `message_count` column maintained on write. Empty threads are
418
+ // filtered out of the list.
412
419
  const messageCount = Number(r.message_count);
413
420
  if (!Number.isFinite(messageCount) || messageCount <= 0) return null;
414
421
  return {
@@ -475,9 +482,8 @@ const THREAD_COLUMNS = `id, owner_email, title, preview, thread_data, message_co
475
482
  // message-history JSON blob and selecting it for every row turns "open the
476
483
  // sidebar" into "download every conversation". The summary derives nothing
477
484
  // from the blob anymore — preview and message_count are dedicated columns
478
- // (message_count is maintained on write and backfilled for legacy rows at
479
- // bootstrap). The detail path (`THREAD_COLUMNS` / `getThread`) still returns
480
- // the full blob.
485
+ // (message_count is maintained on write). The detail path (`THREAD_COLUMNS` /
486
+ // `getThread`) still returns the full blob.
481
487
  const SUMMARY_COLUMNS = `id, title, preview, message_count, created_at, updated_at, scope_type, scope_id, scope_label, pinned_at, archived_at, org_id, visibility`;
482
488
 
483
489
  export function registerChatThreadsShareable(): void {
@@ -684,10 +690,9 @@ export async function listThreads(
684
690
  const limit = opts.limit ?? 50;
685
691
  const offset = opts.offset ?? 0;
686
692
  const client = getDbExec();
687
- // `message_count > 0` is the authoritative "has messages" signal: it is
688
- // maintained on every write and backfilled for legacy rows at bootstrap,
689
- // so the old `OR thread_data LIKE '%"messages"%'` substring scan over the
690
- // full blob is no longer needed here.
693
+ // `message_count > 0` is the authoritative "has messages" signal maintained
694
+ // on every write, so the old `OR thread_data LIKE '%"messages"%'` substring
695
+ // scan over the full blob is no longer needed here.
691
696
  const access = chatThreadAccessSql(
692
697
  ownerEmail,
693
698
  opts.orgId ?? getRequestOrgId(),
@@ -731,9 +736,9 @@ export async function searchThreads(
731
736
  await ensureTable();
732
737
  const client = getDbExec();
733
738
  const pattern = `%${escapeLike(query)}%`;
734
- // The count-guard uses the maintained/backfilled `message_count` column
735
- // (same as listThreads). The content match still scans `thread_data` —
736
- // search legitimately needs to look inside message history.
739
+ // The count-guard uses the maintained `message_count` column (same as
740
+ // listThreads). The content match still scans `thread_data` — search
741
+ // legitimately needs to look inside message history.
737
742
  const access = chatThreadAccessSql(
738
743
  ownerEmail,
739
744
  options.orgId ?? getRequestOrgId(),
@@ -25,6 +25,32 @@ hosted Design MCP connector together. The open Skills CLI path
25
25
  (\`npx skills@latest add BuilderIO/agent-native --skill visual-edit\`) installs
26
26
  exported instructions only, with no MCP connector registration.
27
27
 
28
+ ## Put Design Beside The Chat
29
+
30
+ After \`open-visual-edit\` returns \`openUrl\`, open that URL in the coding host's
31
+ inline browser when one is available. This is the preferred working surface:
32
+ the user can keep Design's canvas beside the conversation, inspect the same
33
+ screens as the agent, and iterate without switching apps.
34
+
35
+ - In Codex Desktop, use the in-app Browser tool to open \`openUrl\`. The built-in
36
+ browser is the right surface for localhost and public pages that should stay
37
+ inside the app.
38
+ - In Claude Code Desktop's Code tab, open or preview \`openUrl\` in the Browser
39
+ pane. Ask Claude to preview it rather than opening the system browser.
40
+ - In VS Code, use the Agent Native Design webview/deep link described below.
41
+ - Inline browser availability is host-dependent. CLI, remote, or restricted
42
+ sessions may not expose one. If the inline surface is unavailable or disabled,
43
+ return the normal **Open design** link instead of claiming it opened.
44
+
45
+ Prefer the host's browser/preview tool over telling the user to press a keyboard
46
+ shortcut. Keep the canvas pane beside chat when the host supports rearrangeable
47
+ panes.
48
+
49
+ Inside Design, use **Show/Hide UI** from the \`Cmd+K\` menu or press
50
+ \`Cmd+Shift+\\\` on Apple platforms / \`Ctrl+Shift+\\\` elsewhere to toggle all
51
+ editing chrome so only the canvas remains. The same action is available from
52
+ Design's empty-canvas context menu.
53
+
28
54
  ## Core Model
29
55
 
30
56
  - Each screen is a URL-backed iframe, not copied HTML.
@@ -54,6 +80,23 @@ exported instructions only, with no MCP connector registration.
54
80
  \`localhost:1234/onboarding/1\` means
55
81
  \`http://localhost:1234/onboarding/1\`.
56
82
 
83
+ ## Useful Canvas Sets
84
+
85
+ Translate the user's requested review into the smallest useful set of frames:
86
+
87
+ - **Multi-step flow:** one ordered frame per route or query state, such as cart,
88
+ shipping, payment, and confirmation.
89
+ - **Multiple pages:** one frame per meaningful route, such as home, pricing,
90
+ docs, and account settings.
91
+ - **Responsive comparison:** repeat the same route at the requested desktop,
92
+ tablet, and mobile viewports so they align in one row.
93
+ - **State review:** repeat a route for meaningful URL-addressable states such as
94
+ empty, loading, error, modal-open, or selected-item views.
95
+
96
+ Do not expand every discovered route or every viewport unless the user asks for
97
+ an exhaustive audit. Preserve the user's labels and sequence so the canvas reads
98
+ like the workflow they described.
99
+
57
100
  ## Select And Reprompt
58
101
 
59
102
  When a chat message begins with \`[Reprompt selection]\`, the selected subtree is
@@ -275,9 +318,9 @@ Fallback, only when \`open-visual-edit\` is unavailable:
275
318
  ## Open The Design Surface
276
319
 
277
320
  - Use the \`link\`, \`deepLink\`, or MCP App embed returned by Design actions so
278
- the user sees the canvas. In Codex Desktop or VS Code, prefer opening that
279
- Design URL in the available preview/webview panel; otherwise surface the
280
- "Open design" link.
321
+ the user sees the canvas. Follow **Put Design Beside The Chat**: prefer the
322
+ host's inline Browser, preview, or webview panel; otherwise surface the
323
+ **Open design** link.
281
324
  - Return or open the \`openUrl\` / action link, not a hand-built
282
325
  \`/design/:id?_session=...\` URL.
283
326
  - If the user is working in VS Code, the Agent Native extension can open the
@@ -198,7 +198,9 @@ type PanelMode = "chat" | "cli" | "resources" | "settings";
198
198
  export function normalizeAgentPanelModeForSurface(
199
199
  mode: PanelMode,
200
200
  allowSettingsMode: boolean,
201
+ chatOnly = false,
201
202
  ): PanelMode {
203
+ if (chatOnly) return "chat";
202
204
  return mode === "settings" && !allowSettingsMode ? "chat" : mode;
203
205
  }
204
206
  const AGENT_PANEL_FONT_FAMILY =
@@ -597,6 +599,8 @@ export interface AgentPanelProps extends Omit<
597
599
  showPageNewChatButton?: boolean;
598
600
  /** Allow the sidebar settings view to render inside this panel. Default: true. */
599
601
  allowSettingsMode?: boolean;
602
+ /** Keep this surface on chat even when mode controls are hidden. */
603
+ chatOnly?: boolean;
600
604
  /** Optional link shown in Resources and Settings modes for the full Agent page. */
601
605
  agentPageHref?: string;
602
606
  /** Capability gate for source edits and CLI access. */
@@ -754,6 +758,7 @@ function AgentPanelInner({
754
758
  showTabBar = true,
755
759
  showPageNewChatButton = false,
756
760
  allowSettingsMode = true,
761
+ chatOnly = false,
757
762
  agentPageHref,
758
763
  codeAccess,
759
764
  ...assistantChatProps
@@ -807,9 +812,17 @@ function AgentPanelInner({
807
812
  saved === "resources" ||
808
813
  saved === "settings"
809
814
  )
810
- return normalizeAgentPanelModeForSurface(saved, allowSettingsMode);
815
+ return normalizeAgentPanelModeForSurface(
816
+ saved,
817
+ allowSettingsMode,
818
+ chatOnly,
819
+ );
811
820
  } catch {}
812
- return normalizeAgentPanelModeForSurface(defaultMode, allowSettingsMode);
821
+ return normalizeAgentPanelModeForSurface(
822
+ defaultMode,
823
+ allowSettingsMode,
824
+ chatOnly,
825
+ );
813
826
  });
814
827
  useEffect(() => {
815
828
  try {
@@ -823,15 +836,21 @@ function AgentPanelInner({
823
836
  const switchMode = useCallback(
824
837
  (m: PanelMode) => {
825
838
  startTransition(() =>
826
- setMode(normalizeAgentPanelModeForSurface(m, allowSettingsMode)),
839
+ setMode(
840
+ normalizeAgentPanelModeForSurface(m, allowSettingsMode, chatOnly),
841
+ ),
827
842
  );
828
843
  },
829
- [allowSettingsMode],
844
+ [allowSettingsMode, chatOnly],
830
845
  );
831
846
  useEffect(() => {
832
- const nextMode = normalizeAgentPanelModeForSurface(mode, allowSettingsMode);
847
+ const nextMode = normalizeAgentPanelModeForSurface(
848
+ mode,
849
+ allowSettingsMode,
850
+ chatOnly,
851
+ );
833
852
  if (nextMode !== mode) switchMode(nextMode);
834
- }, [mode, allowSettingsMode, switchMode]);
853
+ }, [mode, allowSettingsMode, chatOnly, switchMode]);
835
854
  const openRunThread = useCallback(
836
855
  (threadId: string, run?: AgentRun) => {
837
856
  switchMode("chat");
@@ -3349,6 +3368,7 @@ export function AgentSidebar({
3349
3368
  threadUrlSync={threadUrlSync}
3350
3369
  agentPageHref={agentPageHref}
3351
3370
  allowSettingsMode={false}
3371
+ chatOnly
3352
3372
  />
3353
3373
  </div>
3354
3374
  </div>
@@ -333,8 +333,16 @@ function activeRunStuckThresholdMs(runInfo: ActiveRunLookup): number {
333
333
  }
334
334
 
335
335
  function activeRunLooksStale(runInfo: ActiveRunLookup): boolean {
336
+ // A run killed before it emitted anything has no `lastProgressAt`. Falling
337
+ // back to the heartbeat keeps that case from reading as perpetually fresh —
338
+ // "never reported progress" is the worst case, not an exemption from the
339
+ // staleness check.
336
340
  const lastProgressAt =
337
- typeof runInfo.lastProgressAt === "number" ? runInfo.lastProgressAt : null;
341
+ typeof runInfo.lastProgressAt === "number"
342
+ ? runInfo.lastProgressAt
343
+ : typeof runInfo.heartbeatAt === "number"
344
+ ? runInfo.heartbeatAt
345
+ : null;
338
346
  const nowMs =
339
347
  typeof runInfo.serverNow === "number" ? runInfo.serverNow : Date.now();
340
348
  const thresholdMs = activeRunStuckThresholdMs(runInfo);
@@ -345,6 +353,16 @@ function activeRunLooksStale(runInfo: ActiveRunLookup): boolean {
345
353
  );
346
354
  }
347
355
 
356
+ /**
357
+ * The stored active run is what keeps the "Thinking…" spinner up across a
358
+ * reload, and the `/runs/active` probe is the only path that clears it. A 5xx
359
+ * or a network drop there means "couldn't determine", NOT "still running" —
360
+ * collapsing the two is what strands the spinner forever when the server is
361
+ * briefly unreachable, because no caller reschedules the probe. Retry inside
362
+ * the call, then give up loudly.
363
+ */
364
+ const ACTIVE_RUN_PROBE_RETRY_DELAYS_MS = [400, 1200];
365
+
348
366
  /**
349
367
  * Decide whether a reconnect should give up with "no progress". The signal is
350
368
  * *time since the last streamed event*, NOT total reconnect duration: a healthy
@@ -3440,12 +3458,50 @@ const AssistantChatInner = forwardRef<
3440
3458
  if (isRuntimeRunningRef.current || isAutoResumingRef.current) {
3441
3459
  return false;
3442
3460
  }
3461
+ const storedActiveRun = getActiveRun();
3462
+ let runRes: Response | null = null;
3463
+ for (let attempt = 0; ; attempt += 1) {
3464
+ try {
3465
+ const res = await fetch(
3466
+ `${apiUrl}/runs/active?threadId=${encodeURIComponent(threadId)}`,
3467
+ );
3468
+ if (res.ok) {
3469
+ runRes = res;
3470
+ break;
3471
+ }
3472
+ } catch {
3473
+ // Fall through to the retry/give-up path below.
3474
+ }
3475
+ const retryDelayMs = ACTIVE_RUN_PROBE_RETRY_DELAYS_MS[attempt];
3476
+ if (retryDelayMs === undefined) break;
3477
+ await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
3478
+ }
3479
+
3480
+ if (!runRes) {
3481
+ // Still unreachable. Only a stored run for this thread is holding the
3482
+ // spinner up, so that is also the only case worth interrupting the user
3483
+ // for — drop it and say why, rather than leaving "Thinking…" forever.
3484
+ if (storedActiveRun?.threadId === threadId) {
3485
+ clearActiveRunIfMatches(threadId, storedActiveRun.runId);
3486
+ window.dispatchEvent(
3487
+ new CustomEvent("agent-chat:run-error", {
3488
+ detail: {
3489
+ message:
3490
+ "Couldn't reach the server to check whether the agent is still working. Send your message again to retry.",
3491
+ errorCode: "run_status_unavailable",
3492
+ recoverable: true,
3493
+ ...(storedActiveRun.runId
3494
+ ? { runId: storedActiveRun.runId }
3495
+ : {}),
3496
+ ...(tabId ? { tabId } : {}),
3497
+ },
3498
+ }),
3499
+ );
3500
+ }
3501
+ return false;
3502
+ }
3503
+
3443
3504
  try {
3444
- const storedActiveRun = getActiveRun();
3445
- const runRes = await fetch(
3446
- `${apiUrl}/runs/active?threadId=${encodeURIComponent(threadId)}`,
3447
- );
3448
- if (!runRes.ok) return false;
3449
3505
  const runInfo = (await runRes.json()) as ActiveRunLookup;
3450
3506
  if (
3451
3507
  !runInfo.active ||
@@ -3464,7 +3520,7 @@ const AssistantChatInner = forwardRef<
3464
3520
  } catch {
3465
3521
  return false;
3466
3522
  }
3467
- }, [apiUrl, refreshThreadFromServer, startReconnectToRun, threadId]);
3523
+ }, [apiUrl, refreshThreadFromServer, startReconnectToRun, tabId, threadId]);
3468
3524
 
3469
3525
  useEffect(() => {
3470
3526
  if (!threadId || !isNewThread) return;