@agent-native/core 0.128.4 → 0.129.1

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 (351) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +90 -0
  3. package/corpus/core/docs/content/template-design-collaboration-and-full-apps.mdx +3 -1
  4. package/corpus/core/package.json +6 -3
  5. package/corpus/core/src/a2a/client.ts +18 -4
  6. package/corpus/core/src/a2a/server.ts +19 -3
  7. package/corpus/core/src/a2a/types.ts +7 -0
  8. package/corpus/core/src/action.ts +43 -16
  9. package/corpus/core/src/agent/engine/ai-sdk-engine.ts +14 -10
  10. package/corpus/core/src/agent/production-agent.ts +41 -3
  11. package/corpus/core/src/agent/thread-data-builder.ts +5 -0
  12. package/corpus/core/src/chat-threads/migrations.ts +53 -0
  13. package/corpus/core/src/cli/create.ts +4 -0
  14. package/corpus/core/src/cli/skills-content/design-visual-edit-skill.ts +36 -16
  15. package/corpus/core/src/cli/skills.ts +16 -0
  16. package/corpus/core/src/client/AgentPanel.tsx +9 -5
  17. package/corpus/core/src/client/AssistantChat.tsx +138 -46
  18. package/corpus/core/src/client/MultiTabAssistantChat.tsx +16 -10
  19. package/corpus/core/src/client/agent-chat-adapter.ts +21 -3
  20. package/corpus/core/src/client/analytics.ts +159 -102
  21. package/corpus/core/src/client/chat/message-components.tsx +12 -5
  22. package/corpus/core/src/client/chat/runtime.ts +2 -1
  23. package/corpus/core/src/client/chat/tool-call-display.tsx +25 -2
  24. package/corpus/core/src/client/chat-model-groups.ts +3 -0
  25. package/corpus/core/src/client/client-status-requests.ts +161 -0
  26. package/corpus/core/src/client/org/OrgSwitcher.tsx +4 -4
  27. package/corpus/core/src/client/settings/VoiceTranscriptionSection.tsx +2 -2
  28. package/corpus/core/src/client/sse-event-processor.ts +15 -3
  29. package/corpus/core/src/client/use-agent-engine-configured.ts +54 -50
  30. package/corpus/core/src/client/use-chat-models.ts +16 -11
  31. package/corpus/core/src/client/use-chat-threads.ts +32 -9
  32. package/corpus/core/src/client/use-session.ts +4 -5
  33. package/corpus/core/src/db/client.ts +83 -8
  34. package/corpus/core/src/db/ensure-additive-columns.ts +31 -20
  35. package/corpus/core/src/db/migrations.ts +22 -2
  36. package/corpus/core/src/mcp/approval-store.ts +99 -0
  37. package/corpus/core/src/mcp/build-server.ts +579 -303
  38. package/corpus/core/src/mcp/embed-app.ts +1 -1
  39. package/corpus/core/src/mcp/oauth-client-metadata.ts +380 -0
  40. package/corpus/core/src/mcp/oauth-route.ts +57 -52
  41. package/corpus/core/src/mcp/screen-memory-stdio.ts +400 -378
  42. package/corpus/core/src/mcp/server.ts +29 -145
  43. package/corpus/core/src/mcp/stdio.ts +72 -80
  44. package/corpus/core/src/mcp-client/manager.ts +6 -10
  45. package/corpus/core/src/mcp-client/oauth-client.ts +127 -36
  46. package/corpus/core/src/mcp-client/oauth-routes.ts +16 -6
  47. package/corpus/core/src/mcp-client/routes.ts +6 -5
  48. package/corpus/core/src/server/agent-capabilities.ts +20 -0
  49. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +27 -0
  50. package/corpus/core/src/server/agent-chat-plugin.ts +18 -0
  51. package/corpus/core/src/server/transcribe-voice.ts +14 -5
  52. package/corpus/core/src/templates/default/.agents/skills/security/SKILL.md +13 -2
  53. package/corpus/core/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +5 -2
  54. package/corpus/core/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +18 -0
  55. package/corpus/core/src/templates/workspace-core/.agents/skills/security/SKILL.md +13 -2
  56. package/corpus/templates/analytics/.agents/skills/security/SKILL.md +13 -2
  57. package/corpus/templates/analytics/app/components/dashboard/DashboardPanelSkeleton.tsx +1 -10
  58. package/corpus/templates/analytics/app/global.css +0 -31
  59. package/corpus/templates/analytics/app/lib/sql-query.ts +46 -20
  60. package/corpus/templates/analytics/changelog/2026-07-28-analytics-dashboard-loading-states-now-use-a-simpler-standar.md +6 -0
  61. package/corpus/templates/analytics/changelog/2026-07-28-analytics-dashboards-now-load-first-party-charts-reliably-in.md +6 -0
  62. package/corpus/templates/analytics/server/lib/first-party-analytics-cache.ts +42 -16
  63. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +4 -2
  64. package/corpus/templates/analytics/shared/sql-query-limits.ts +1 -0
  65. package/corpus/templates/assets/.agents/skills/security/SKILL.md +13 -2
  66. package/corpus/templates/brain/.agents/skills/security/SKILL.md +13 -2
  67. package/corpus/templates/calendar/.agents/skills/security/SKILL.md +13 -2
  68. package/corpus/templates/chat/.agents/skills/security/SKILL.md +13 -2
  69. package/corpus/templates/chat/README.md +0 -2
  70. package/corpus/templates/clips/.agents/skills/security/SKILL.md +13 -2
  71. package/corpus/templates/clips/app/components/player/player-controls.tsx +3 -6
  72. package/corpus/templates/clips/app/components/player/recording-views-badge.tsx +6 -2
  73. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +25 -10
  74. package/corpus/templates/clips/app/components/sharing/viewed-by-popover.tsx +28 -6
  75. package/corpus/templates/clips/app/lib/use-visible-avatar-url.ts +34 -0
  76. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +6 -2
  77. package/corpus/templates/clips/app/routes/share.$shareId.tsx +3 -1
  78. package/corpus/templates/clips/changelog/2026-07-28-copied-share-links-no-longer-leave-an-unnecessary-confirmati.md +6 -0
  79. package/corpus/templates/clips/changelog/2026-07-28-playback-skip-controls-no-longer-show-overlapping-numbers.md +6 -0
  80. package/corpus/templates/clips/changelog/2026-07-28-profile-avatars-now-appear-in-viewer-and-share-access-lists.md +6 -0
  81. package/corpus/templates/clips/changelog/2026-07-28-public-clips-share-buttons-now-use-a-clean-text-only-label.md +6 -0
  82. package/corpus/templates/clips/desktop/src/app.tsx +14 -17
  83. package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +3 -1
  84. package/corpus/templates/clips/desktop/src/styles.css +13 -10
  85. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +2 -2
  86. package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +36 -0
  87. package/corpus/templates/content/.agents/skills/security/SKILL.md +13 -2
  88. package/corpus/templates/content/actions/_builder-cms-read-client.ts +155 -34
  89. package/corpus/templates/content/actions/_builder-docs-client.ts +151 -30
  90. package/corpus/templates/content/actions/stage-builder-source-bulk-update.ts +5 -2
  91. package/corpus/templates/content/app/root.tsx +35 -14
  92. package/corpus/templates/content/changelog/2026-07-28-builder-backed-files-media-fields-now-accept-direct-file-url.md +6 -0
  93. package/corpus/templates/content/changelog/2026-07-28-builder-content-reads-now-negotiate-the-newest-mcp-protocol-.md +6 -0
  94. package/corpus/templates/content/changelog/2026-07-28-public-content-pages-load-faster-before-the-optional-ask-sid.md +6 -0
  95. package/corpus/templates/design/.agents/skills/security/SKILL.md +13 -2
  96. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +36 -16
  97. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +42 -3
  98. package/corpus/templates/design/actions/open-visual-edit.ts +2 -1
  99. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +2 -2
  100. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +14 -15
  101. package/corpus/templates/design/app/components/design/ResponsiveInteractBar.tsx +314 -0
  102. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +88 -3
  103. package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +1 -1
  104. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +7 -6
  105. package/corpus/templates/design/app/i18n-data.ts +56 -11
  106. package/corpus/templates/design/app/i18n-responsive-interact.ts +183 -0
  107. package/corpus/templates/design/app/lib/agent-chat.ts +60 -0
  108. package/corpus/templates/design/app/pages/design-editor/responsive-interact.ts +89 -0
  109. package/corpus/templates/design/changelog/2026-07-28-design-edits-can-be-applied-through-the-host-coding-agent-fr.md +6 -0
  110. package/corpus/templates/design/changelog/2026-07-28-interact-mode-can-preview-designs-in-responsive-device-sizes.md +6 -0
  111. package/corpus/templates/design/changelog/2026-07-28-interact-mode-now-opens-a-full-screen-responsive-preview-wit.md +6 -0
  112. package/corpus/templates/design/changelog/2026-07-28-show-or-hide-design-editing-chrome-with-cmd-on-apple-devices.md +2 -2
  113. package/corpus/templates/design/changelog/2026-07-28-visual-edit-now-always-shows-the-live-running-app-in-the-can.md +6 -0
  114. package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +13 -2
  115. package/corpus/templates/forms/.agents/skills/security/SKILL.md +13 -2
  116. package/corpus/templates/macros/.agents/skills/security/SKILL.md +13 -2
  117. package/corpus/templates/mail/.agents/skills/security/SKILL.md +13 -2
  118. package/corpus/templates/plan/.agents/skills/security/SKILL.md +13 -2
  119. package/corpus/templates/slides/.agents/skills/security/SKILL.md +13 -2
  120. package/corpus/templates/tasks/.agents/skills/security/SKILL.md +13 -2
  121. package/corpus/toolkit/CHANGELOG.md +13 -0
  122. package/corpus/toolkit/package.json +1 -1
  123. package/corpus/toolkit/src/chat-history.css +1 -2
  124. package/corpus/toolkit/src/composer/TiptapComposer.tsx +45 -0
  125. package/dist/a2a/client.d.ts +7 -0
  126. package/dist/a2a/client.d.ts.map +1 -1
  127. package/dist/a2a/client.js +8 -3
  128. package/dist/a2a/client.js.map +1 -1
  129. package/dist/a2a/server.d.ts.map +1 -1
  130. package/dist/a2a/server.js +18 -3
  131. package/dist/a2a/server.js.map +1 -1
  132. package/dist/a2a/types.d.ts +7 -0
  133. package/dist/a2a/types.d.ts.map +1 -1
  134. package/dist/a2a/types.js.map +1 -1
  135. package/dist/action.d.ts +15 -1
  136. package/dist/action.d.ts.map +1 -1
  137. package/dist/action.js +39 -16
  138. package/dist/action.js.map +1 -1
  139. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  140. package/dist/agent/engine/ai-sdk-engine.js +14 -10
  141. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  142. package/dist/agent/production-agent.d.ts.map +1 -1
  143. package/dist/agent/production-agent.js +35 -7
  144. package/dist/agent/production-agent.js.map +1 -1
  145. package/dist/agent/thread-data-builder.d.ts +2 -0
  146. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  147. package/dist/agent/thread-data-builder.js +3 -0
  148. package/dist/agent/thread-data-builder.js.map +1 -1
  149. package/dist/chat-threads/migrations.d.ts +21 -0
  150. package/dist/chat-threads/migrations.d.ts.map +1 -0
  151. package/dist/chat-threads/migrations.js +45 -0
  152. package/dist/chat-threads/migrations.js.map +1 -0
  153. package/dist/cli/create.d.ts.map +1 -1
  154. package/dist/cli/create.js +4 -0
  155. package/dist/cli/create.js.map +1 -1
  156. package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
  157. package/dist/cli/skills-content/design-visual-edit-skill.d.ts.map +1 -1
  158. package/dist/cli/skills-content/design-visual-edit-skill.js +36 -16
  159. package/dist/cli/skills-content/design-visual-edit-skill.js.map +1 -1
  160. package/dist/cli/skills.d.ts.map +1 -1
  161. package/dist/cli/skills.js +15 -0
  162. package/dist/cli/skills.js.map +1 -1
  163. package/dist/client/AgentPanel.d.ts.map +1 -1
  164. package/dist/client/AgentPanel.js +6 -5
  165. package/dist/client/AgentPanel.js.map +1 -1
  166. package/dist/client/AssistantChat.d.ts +37 -0
  167. package/dist/client/AssistantChat.d.ts.map +1 -1
  168. package/dist/client/AssistantChat.js +41 -8
  169. package/dist/client/AssistantChat.js.map +1 -1
  170. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  171. package/dist/client/MultiTabAssistantChat.js +11 -10
  172. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  173. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  174. package/dist/client/agent-chat-adapter.js +19 -3
  175. package/dist/client/agent-chat-adapter.js.map +1 -1
  176. package/dist/client/analytics.d.ts.map +1 -1
  177. package/dist/client/analytics.js +150 -101
  178. package/dist/client/analytics.js.map +1 -1
  179. package/dist/client/chat/message-components.d.ts +2 -1
  180. package/dist/client/chat/message-components.d.ts.map +1 -1
  181. package/dist/client/chat/message-components.js +11 -4
  182. package/dist/client/chat/message-components.js.map +1 -1
  183. package/dist/client/chat/runtime.d.ts.map +1 -1
  184. package/dist/client/chat/runtime.js +2 -1
  185. package/dist/client/chat/runtime.js.map +1 -1
  186. package/dist/client/chat/tool-call-display.d.ts +4 -1
  187. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  188. package/dist/client/chat/tool-call-display.js +14 -8
  189. package/dist/client/chat/tool-call-display.js.map +1 -1
  190. package/dist/client/chat-model-groups.d.ts.map +1 -1
  191. package/dist/client/chat-model-groups.js +3 -0
  192. package/dist/client/chat-model-groups.js.map +1 -1
  193. package/dist/client/client-status-requests.d.ts +14 -0
  194. package/dist/client/client-status-requests.d.ts.map +1 -0
  195. package/dist/client/client-status-requests.js +126 -0
  196. package/dist/client/client-status-requests.js.map +1 -0
  197. package/dist/client/org/OrgSwitcher.js +2 -2
  198. package/dist/client/org/OrgSwitcher.js.map +1 -1
  199. package/dist/client/settings/VoiceTranscriptionSection.js +1 -1
  200. package/dist/client/settings/VoiceTranscriptionSection.js.map +1 -1
  201. package/dist/client/sse-event-processor.d.ts +7 -0
  202. package/dist/client/sse-event-processor.d.ts.map +1 -1
  203. package/dist/client/sse-event-processor.js +8 -3
  204. package/dist/client/sse-event-processor.js.map +1 -1
  205. package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
  206. package/dist/client/use-agent-engine-configured.js +29 -43
  207. package/dist/client/use-agent-engine-configured.js.map +1 -1
  208. package/dist/client/use-chat-models.d.ts.map +1 -1
  209. package/dist/client/use-chat-models.js +11 -11
  210. package/dist/client/use-chat-models.js.map +1 -1
  211. package/dist/client/use-chat-threads.d.ts.map +1 -1
  212. package/dist/client/use-chat-threads.js +23 -7
  213. package/dist/client/use-chat-threads.js.map +1 -1
  214. package/dist/client/use-session.d.ts.map +1 -1
  215. package/dist/client/use-session.js +4 -4
  216. package/dist/client/use-session.js.map +1 -1
  217. package/dist/collab/awareness.d.ts +2 -2
  218. package/dist/collab/awareness.d.ts.map +1 -1
  219. package/dist/db/client.d.ts.map +1 -1
  220. package/dist/db/client.js +48 -4
  221. package/dist/db/client.js.map +1 -1
  222. package/dist/db/ensure-additive-columns.d.ts.map +1 -1
  223. package/dist/db/ensure-additive-columns.js +32 -21
  224. package/dist/db/ensure-additive-columns.js.map +1 -1
  225. package/dist/db/migrations.d.ts +9 -0
  226. package/dist/db/migrations.d.ts.map +1 -1
  227. package/dist/db/migrations.js +14 -3
  228. package/dist/db/migrations.js.map +1 -1
  229. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  230. package/dist/mcp/approval-store.d.ts +16 -0
  231. package/dist/mcp/approval-store.d.ts.map +1 -0
  232. package/dist/mcp/approval-store.js +85 -0
  233. package/dist/mcp/approval-store.js.map +1 -0
  234. package/dist/mcp/build-server.d.ts +1 -34
  235. package/dist/mcp/build-server.d.ts.map +1 -1
  236. package/dist/mcp/build-server.js +220 -23
  237. package/dist/mcp/build-server.js.map +1 -1
  238. package/dist/mcp/embed-app.js +1 -1
  239. package/dist/mcp/embed-app.js.map +1 -1
  240. package/dist/mcp/oauth-client-metadata.d.ts +15 -0
  241. package/dist/mcp/oauth-client-metadata.d.ts.map +1 -0
  242. package/dist/mcp/oauth-client-metadata.js +297 -0
  243. package/dist/mcp/oauth-client-metadata.js.map +1 -0
  244. package/dist/mcp/oauth-route.d.ts.map +1 -1
  245. package/dist/mcp/oauth-route.js +39 -53
  246. package/dist/mcp/oauth-route.js.map +1 -1
  247. package/dist/mcp/screen-memory-stdio.d.ts.map +1 -1
  248. package/dist/mcp/screen-memory-stdio.js +304 -296
  249. package/dist/mcp/screen-memory-stdio.js.map +1 -1
  250. package/dist/mcp/server.d.ts +12 -25
  251. package/dist/mcp/server.d.ts.map +1 -1
  252. package/dist/mcp/server.js +24 -133
  253. package/dist/mcp/server.js.map +1 -1
  254. package/dist/mcp/stdio.d.ts.map +1 -1
  255. package/dist/mcp/stdio.js +36 -35
  256. package/dist/mcp/stdio.js.map +1 -1
  257. package/dist/mcp-client/manager.d.ts.map +1 -1
  258. package/dist/mcp-client/manager.js +6 -6
  259. package/dist/mcp-client/manager.js.map +1 -1
  260. package/dist/mcp-client/oauth-client.d.ts +13 -17
  261. package/dist/mcp-client/oauth-client.d.ts.map +1 -1
  262. package/dist/mcp-client/oauth-client.js +74 -16
  263. package/dist/mcp-client/oauth-client.js.map +1 -1
  264. package/dist/mcp-client/oauth-routes.d.ts +2 -2
  265. package/dist/mcp-client/oauth-routes.d.ts.map +1 -1
  266. package/dist/mcp-client/oauth-routes.js +16 -6
  267. package/dist/mcp-client/oauth-routes.js.map +1 -1
  268. package/dist/mcp-client/routes.js +5 -5
  269. package/dist/mcp-client/routes.js.map +1 -1
  270. package/dist/observability/routes.d.ts +3 -3
  271. package/dist/progress/routes.d.ts +1 -1
  272. package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
  273. package/dist/provider-api/actions/provider-api.d.ts +8 -8
  274. package/dist/resources/handlers.d.ts +1 -1
  275. package/dist/secrets/routes.d.ts +9 -9
  276. package/dist/server/agent-capabilities.d.ts.map +1 -1
  277. package/dist/server/agent-capabilities.js +21 -0
  278. package/dist/server/agent-capabilities.js.map +1 -1
  279. package/dist/server/agent-chat/action-filters-a2a.d.ts +14 -0
  280. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
  281. package/dist/server/agent-chat/action-filters-a2a.js +16 -0
  282. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
  283. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  284. package/dist/server/agent-chat-plugin.js +11 -1
  285. package/dist/server/agent-chat-plugin.js.map +1 -1
  286. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  287. package/dist/server/realtime-token.d.ts +1 -1
  288. package/dist/server/transcribe-voice.d.ts +1 -1
  289. package/dist/server/transcribe-voice.js +12 -6
  290. package/dist/server/transcribe-voice.js.map +1 -1
  291. package/dist/templates/chat/.agents/skills/security/SKILL.md +13 -2
  292. package/dist/templates/chat/README.md +0 -2
  293. package/dist/templates/default/.agents/skills/security/SKILL.md +13 -2
  294. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +5 -2
  295. package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +18 -0
  296. package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +13 -2
  297. package/docs/content/template-design-collaboration-and-full-apps.mdx +3 -1
  298. package/package.json +7 -4
  299. package/src/a2a/client.ts +18 -4
  300. package/src/a2a/server.ts +19 -3
  301. package/src/a2a/types.ts +7 -0
  302. package/src/action.ts +43 -16
  303. package/src/agent/engine/ai-sdk-engine.ts +14 -10
  304. package/src/agent/production-agent.ts +41 -3
  305. package/src/agent/thread-data-builder.ts +5 -0
  306. package/src/chat-threads/migrations.ts +53 -0
  307. package/src/cli/create.ts +4 -0
  308. package/src/cli/skills-content/design-visual-edit-skill.ts +36 -16
  309. package/src/cli/skills.ts +16 -0
  310. package/src/client/AgentPanel.tsx +9 -5
  311. package/src/client/AssistantChat.tsx +138 -46
  312. package/src/client/MultiTabAssistantChat.tsx +16 -10
  313. package/src/client/agent-chat-adapter.ts +21 -3
  314. package/src/client/analytics.ts +159 -102
  315. package/src/client/chat/message-components.tsx +12 -5
  316. package/src/client/chat/runtime.ts +2 -1
  317. package/src/client/chat/tool-call-display.tsx +25 -2
  318. package/src/client/chat-model-groups.ts +3 -0
  319. package/src/client/client-status-requests.ts +161 -0
  320. package/src/client/org/OrgSwitcher.tsx +4 -4
  321. package/src/client/settings/VoiceTranscriptionSection.tsx +2 -2
  322. package/src/client/sse-event-processor.ts +15 -3
  323. package/src/client/use-agent-engine-configured.ts +54 -50
  324. package/src/client/use-chat-models.ts +16 -11
  325. package/src/client/use-chat-threads.ts +32 -9
  326. package/src/client/use-session.ts +4 -5
  327. package/src/db/client.ts +83 -8
  328. package/src/db/ensure-additive-columns.ts +31 -20
  329. package/src/db/migrations.ts +22 -2
  330. package/src/mcp/approval-store.ts +99 -0
  331. package/src/mcp/build-server.ts +579 -303
  332. package/src/mcp/embed-app.ts +1 -1
  333. package/src/mcp/oauth-client-metadata.ts +380 -0
  334. package/src/mcp/oauth-route.ts +57 -52
  335. package/src/mcp/screen-memory-stdio.ts +400 -378
  336. package/src/mcp/server.ts +29 -145
  337. package/src/mcp/stdio.ts +72 -80
  338. package/src/mcp-client/manager.ts +6 -10
  339. package/src/mcp-client/oauth-client.ts +127 -36
  340. package/src/mcp-client/oauth-routes.ts +16 -6
  341. package/src/mcp-client/routes.ts +6 -5
  342. package/src/server/agent-capabilities.ts +20 -0
  343. package/src/server/agent-chat/action-filters-a2a.ts +27 -0
  344. package/src/server/agent-chat-plugin.ts +18 -0
  345. package/src/server/transcribe-voice.ts +14 -5
  346. package/src/templates/chat/.agents/skills/security/SKILL.md +13 -2
  347. package/src/templates/chat/README.md +0 -2
  348. package/src/templates/default/.agents/skills/security/SKILL.md +13 -2
  349. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +5 -2
  350. package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +18 -0
  351. package/src/templates/workspace-core/.agents/skills/security/SKILL.md +13 -2
package/corpus/README.md CHANGED
@@ -28,6 +28,6 @@ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
28
28
 
29
29
  ## Generated Counts
30
30
 
31
- - core files: 1625
31
+ - core files: 1629
32
32
  - toolkit files: 160
33
- - template files: 6853
33
+ - template files: 6870
@@ -1,5 +1,95 @@
1
1
  # @agent-native/core
2
2
 
3
+ ## 0.129.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 8c4b44e: Keep the create organization and invite member popovers compact instead of allowing long helper text to expand their width.
8
+
9
+ ## 0.129.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 0aada94: Serve the stateless MCP 2026-07-28 protocol natively while preserving stateless
14
+ legacy clients, automatically negotiate the newest supported protocol from
15
+ outbound clients and stdio bridges, and harden MCP OAuth issuer, client type,
16
+ scope, credential binding, and Client ID Metadata Document behavior. Require
17
+ durable, single-use MCP 2026 approval elicitation before running actions marked
18
+ `needsApproval`.
19
+
20
+ Update the Pinpoint MCP server example to use the stable split MCP v2 packages.
21
+
22
+ ### Patch Changes
23
+
24
+ - 0aada94: Stop telling sibling agents that an app has no callable actions when it does.
25
+ The public agent card could only advertise actions with `requiresAuth !== true`,
26
+ while `actions/invoke` only ever executes actions with `requiresAuth === true` —
27
+ two disjoint sets. Every app whose A2A actions were authenticated therefore
28
+ published an empty skills list, and `describe-workspace-apps` reported
29
+ "exposes no directly callable actions" about an app the caller could in fact
30
+ call directly. Callers took that at face value and fell back to open-ended
31
+ `call-agent` delegation, which hands schema discovery to a second model; in
32
+ practice that model shelled out through `bash`, failed to find the data, and
33
+ looped until the repetition guard stopped the run.
34
+
35
+ The card now serves the invocable set to a caller with a verified A2A identity,
36
+ and sibling capability discovery signs its probe so it sees that set. Anonymous
37
+ card fetches are unchanged and still expose only the publicly-safe list, so no
38
+ capability is disclosed to an unauthenticated reader that was not disclosed
39
+ before.
40
+
41
+ - 0aada94: Let Design MCP App canvases hand pending visual source edits back to the host coding conversation while preserving the local Design-agent and copy-prompt fallbacks for ordinary browser panes.
42
+
43
+ Teach visual-edit users to minimize Design chrome with Figma's `Shift+\` shortcut or the command menu without claiming the host-reserved `Cmd+\` chord.
44
+
45
+ - 0aada94: Keep client status timeouts isolated to their own endpoint and preserve the last known model readiness when a status probe is temporarily unavailable.
46
+ - 0aada94: Visual edit: never render a source snapshot in place of the running app. A localhost screen now always loads a live document — the proxied `/live-edit` frame for viewers holding the connection's `previewToken`, and the plain dev-server URL for everyone else. Previously a viewer without a token (signed-out session, public link, inline browser with no cookies) got the `/snapshot` HTML as `srcdoc`: a frozen copy that looked exactly like the app but had no live DOM behind it, so selection, the layers panel, and edits all silently addressed stale markup.
47
+ - 0aada94: Show relative cost per model in the composer's model picker. Each row now
48
+ carries a quiet `$`/`$$`/`$$$` suffix so a user can tell an entry model from a
49
+ flagship one before selecting it, rather than discovering the difference in
50
+ their bill. The tier reuses the token list the picker already sorts by
51
+ (`MODEL_COST_ORDER`) and reflects each provider's own entry/mid/flagship ladder
52
+ — it is not a cross-provider price claim. Models outside that list render with
53
+ no label at all; a guessed tier would read as fact.
54
+ - 0aada94: Send `reasoning_effort: "none"` instead of omitting it when a custom OpenAI base
55
+ URL forces Chat Completions with tools present. Omitting the field let OpenAI
56
+ apply the model's own default effort, so GPT-5.6 runs kept failing with
57
+ "Function tools with reasoning_effort are not supported for <model> in
58
+ /v1/chat/completions" even after the field was dropped.
59
+ - 0aada94: Use OpenAI's current `gpt-transcribe` model for direct OpenAI voice dictation uploads.
60
+ - 0aada94: Refuse to replace symlinked project skill folders during built-in skill installs.
61
+ - 0aada94: Queued chat messages now run under the model, engine, and reasoning effort they
62
+ were composed with instead of whatever the picker happens to be set to when the
63
+ queue flushes. Queued bubbles also gain a "Send now" control that interrupts the
64
+ active run, and the pending group is labelled with its count.
65
+ - 0aada94: Restore a reachable path for the legacy chat-thread `message_count` repair. Databases predating the column left rows at 0, and both `listThreads` and `searchThreads` filter `message_count > 0` in SQL, so those threads never appeared in the sidebar and nothing called the repair anymore.
66
+
67
+ `repairLegacyChatThreadMessageCounts` now runs as a name-tracked migration (`_chat_threads_migrations`) in long-lived app processes, so the `thread_data` scan happens once per database and is skipped entirely on every later boot. Serverless isolates do not launch the repair during cold start; operators can run a long-lived maintenance process against an older hosted database without making concurrent functions race the same full-data scan. `MigrationEntry` gained an optional `run` hook for backfills SQL cannot express; it executes before the bookkeeping row is written, so a failed repair stays unrecorded and retries instead of being marked applied against work that never happened.
68
+
69
+ - 0aada94: Tell the model the expected parameter signature when a raw-JSON-schema action
70
+ rejects its arguments. Previously only Zod-backed actions echoed the expected
71
+ shape, so a model that guessed a wrong enum or type on a raw-schema action got
72
+ no new information, re-sent the same arguments, and tripped the identical-error
73
+ breaker with the write never executed. The repeated-error stop message is now
74
+ written for the user instead of instructing them to fix the tool arguments.
75
+ - 0aada94: Report failed batched schema introspection as an error instead of silently treating the database as up to date.
76
+ - 0aada94: Reduce agent-chat startup request fan-out by sharing concurrent status, session, model-discovery, and thread-list reads.
77
+ - 0aada94: Stop timed-out Neon database statements on the server instead of only abandoning the client request.
78
+ - 0aada94: Stop the chat from claiming a tool is running when nothing is running, and stop
79
+ recording interrupted actions as failures. A tool card only spins while a chat is
80
+ actually running — an activity placeholder alone no longer resurrects a spinner
81
+ on rehydrated history, which is how an email that WAS delivered showed as
82
+ perpetually "sending". When a stream ends with a tool still in flight the card is
83
+ now marked with a distinct unknown outcome ("it may or may not have completed")
84
+ instead of a red failure, both live and in the persisted transcript, because
85
+ "absent" and "unreadable" are not the same answer. The alternate runtime path now
86
+ settles its pending tool calls on `done` and on error like the main SSE path does,
87
+ and a turn whose tool never resolved keeps its "Worked for Xm Ys" summary instead
88
+ of rendering a permanent "Thinking" indicator with nothing behind it.
89
+ - Updated dependencies [0aada94]
90
+ - Updated dependencies [0aada94]
91
+ - @agent-native/toolkit@0.10.11
92
+
3
93
  ## 0.128.4
4
94
 
5
95
  ### Patch Changes
@@ -15,7 +15,9 @@ Design isn't only for prototypes generated from a prompt — a coding agent can
15
15
 
16
16
  When your coding app has an inline browser, ask `/visual-edit` to open the returned Design URL there. In Codex Desktop, that means the built-in Browser; in Claude Code Desktop's Code tab, it means the Browser pane. Both can keep the canvas inside the coding app beside the conversation. In VS Code, the Agent Native extension opens the same Design URL in its side-panel webview. Browser panes can be disabled or unavailable in CLI, remote, or restricted sessions, so `/visual-edit` falls back to an **Open design** link instead of claiming the canvas opened.
17
17
 
18
- Once Design is open, choose **Show/Hide UI** from the `Cmd+K` menu or press `Cmd+Shift+\` on Apple devices / `Ctrl+Shift+\` elsewhere to toggle all editing chrome so only the canvas remains. The same action is available by right-clicking empty canvas space.
18
+ Once Design is open, choose **Show/Hide UI** from the `Cmd+K` menu or press Figma's `Shift+\` shortcut to toggle all editing chrome so only the canvas remains. The same action is available by right-clicking empty canvas space.
19
+
20
+ When Design is rendered as an MCP App by a connected coding host, **Apply design updates** sends the pending source-edit handoff back to that host conversation after its normal confirmation. An ordinary inline Browser pane is still useful for the side-by-side canvas, but webpages cannot post into the active Codex or Claude Code task; there, Apply uses Design's local agent and **Copy prompt to your agent** is the coding-agent fallback.
19
21
 
20
22
  These are especially useful canvas sets:
21
23
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.128.4",
3
+ "version": "0.129.1",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -344,8 +344,11 @@
344
344
  "@codemirror/lang-sql": "^6.10.0",
345
345
  "@codemirror/theme-one-dark": "^6.1.3",
346
346
  "@libsql/client": "^0.15.0",
347
- "@modelcontextprotocol/ext-apps": "1.7.2",
348
- "@modelcontextprotocol/sdk": "^1.29.0",
347
+ "@modelcontextprotocol/client": "2.0.0",
348
+ "@modelcontextprotocol/core": "2.0.0",
349
+ "@modelcontextprotocol/ext-apps": "1.7.5",
350
+ "@modelcontextprotocol/sdk": "1.30.0",
351
+ "@modelcontextprotocol/server": "2.0.0",
349
352
  "@mozilla/readability": "0.6.0",
350
353
  "@neondatabase/serverless": "^1.1.0",
351
354
  "@radix-ui/react-popover": "catalog:",
@@ -277,12 +277,26 @@ export class A2AClient {
277
277
  throw lastError ?? new Error("No A2A endpoint candidates available");
278
278
  }
279
279
 
280
- async getAgentCard(options?: { timeoutMs?: number }): Promise<AgentCard> {
280
+ async getAgentCard(options?: {
281
+ timeoutMs?: number;
282
+ /**
283
+ * Identity token for the card fetch. The anonymous card can only advertise
284
+ * publicly-safe actions, which is a disjoint set from what `actions/invoke`
285
+ * runs — so a sibling that discovers anonymously is told there is nothing
286
+ * callable. Pass a token to see the invocable set.
287
+ */
288
+ token?: string;
289
+ }): Promise<AgentCard> {
281
290
  const res = await ssrfSafeFetch(
282
291
  `${this.baseUrl}/.well-known/agent-card.json`,
283
- options?.timeoutMs
284
- ? { signal: AbortSignal.timeout(options.timeoutMs) }
285
- : {},
292
+ {
293
+ ...(options?.timeoutMs
294
+ ? { signal: AbortSignal.timeout(options.timeoutMs) }
295
+ : {}),
296
+ ...(options?.token
297
+ ? { headers: { Authorization: `Bearer ${options.token}` } }
298
+ : {}),
299
+ },
286
300
  { maxRedirects: 3, allowedPrivateOrigins: workspacePrivateOrigins() },
287
301
  );
288
302
  if (!res.ok) {
@@ -222,7 +222,7 @@ export function mountA2A(
222
222
  // /tmp/security-audit/12-mcp-a2a-agent.md.
223
223
  getH3App(nitroApp).use(
224
224
  "/.well-known/agent-card.json",
225
- defineEventHandler((event) => {
225
+ defineEventHandler(async (event) => {
226
226
  if (getMethod(event) !== "GET") {
227
227
  setResponseStatus(event, 405);
228
228
  return { error: "Method not allowed" };
@@ -233,10 +233,26 @@ export function mountA2A(
233
233
  const host = getRequestHeader(event, "host") ?? "localhost";
234
234
  const baseUrl = `${protocol}://${host}`;
235
235
 
236
- const filteredSkills = filterPublicAgentCardSkills(config);
236
+ // The anonymous card may only advertise actions safe to disclose
237
+ // publicly (`requiresAuth !== true`), but `actions/invoke` only ever
238
+ // runs the opposite set (`requiresAuth === true`). Those are disjoint,
239
+ // so an unauthenticated card said "no directly callable actions" about
240
+ // an app whose actions a verified sibling can call — and callers fell
241
+ // back to open-ended delegation. Show a verified caller what it can
242
+ // actually invoke; anonymous fetches keep the public list unchanged.
243
+ let skills = filterPublicAgentCardSkills(config);
244
+ if (config.authenticatedSkills?.length) {
245
+ const bearer = extractBearerToken(
246
+ getRequestHeader(event, "authorization"),
247
+ );
248
+ if (bearer) {
249
+ const payload = await verifyA2AToken(bearer, event);
250
+ if (payload.email) skills = config.authenticatedSkills;
251
+ }
252
+ }
237
253
 
238
254
  return generateAgentCard(
239
- { ...config, skills: filteredSkills },
255
+ { ...config, skills },
240
256
  baseUrl,
241
257
  `${routePrefix}/a2a`,
242
258
  );
@@ -225,6 +225,13 @@ export interface A2AConfig {
225
225
  description: string;
226
226
  version?: string;
227
227
  skills: AgentSkill[];
228
+ /**
229
+ * Skills advertised only to a caller with a verified A2A identity — the set
230
+ * `actions/invoke` will actually run. Anonymous card fetches never see these.
231
+ * Without it the card advertises the public set, which is disjoint from the
232
+ * invocable set, so siblings are told nothing is directly callable.
233
+ */
234
+ authenticatedSkills?: AgentSkill[];
228
235
  /** If true, public agent-card discovery includes only explicit public-safe skills. */
229
236
  publicSkillsOnly?: boolean;
230
237
  handler?: A2AHandler;
@@ -1370,6 +1370,45 @@ function coerceGatewayStringifiedArgs(
1370
1370
  return out ?? args;
1371
1371
  }
1372
1372
 
1373
+ /**
1374
+ * Compact signature of an action's parameters, e.g.
1375
+ * `{ deckId*: string, operation*: "edit"|"replace", slideId?: string }` where
1376
+ * `*` = required and `?` = optional.
1377
+ *
1378
+ * Enum values are spelled out because a rejected call is usually a wrong enum:
1379
+ * gateways that pre-fill optional fields reach for the first allowed value, and
1380
+ * a model that only learns "must be equal to one of the allowed values" re-sends
1381
+ * the same guess until the identical-error breaker kills the turn.
1382
+ *
1383
+ * Shared so the raw-JSON-schema tool path in the agent loop describes a
1384
+ * rejection the same way `wrapWithValidation` does for Zod actions.
1385
+ */
1386
+ export function describeToolParameterSignature(
1387
+ parameters: ActionTool["parameters"] | undefined,
1388
+ only?: readonly string[],
1389
+ ): string | null {
1390
+ const properties = parameters?.properties;
1391
+ if (!properties) return null;
1392
+ const required = new Set(parameters?.required ?? []);
1393
+ const keys = Object.keys(properties).filter(
1394
+ (key) => !only?.length || only.includes(key),
1395
+ );
1396
+ const sig = (keys.length ? keys : Object.keys(properties))
1397
+ .map((key) => {
1398
+ const spec = properties[key];
1399
+ const mark = required.has(key) ? "*" : "?";
1400
+ const type = Array.isArray(spec.enum)
1401
+ ? spec.enum.map((value) => JSON.stringify(value)).join("|")
1402
+ : Array.isArray(spec.type)
1403
+ ? spec.type.join("|")
1404
+ : (spec.type ?? "any");
1405
+ return `${key}${mark}: ${type}`;
1406
+ })
1407
+ .join(", ");
1408
+ if (!sig) return null;
1409
+ return `{ ${sig.length > 600 ? `${sig.slice(0, 600)}…` : sig} }`;
1410
+ }
1411
+
1373
1412
  /**
1374
1413
  * Wrap an action's run function with schema validation.
1375
1414
  * Invalid inputs get a clear error message (including what was actually passed)
@@ -1427,22 +1466,10 @@ function wrapWithValidation(
1427
1466
  received = String(args);
1428
1467
  }
1429
1468
 
1430
- // Also show the EXPECTED signature so the agent doesn't have to guess.
1431
- // Format: `{ deckId*: string, content*: string, slideId?: string, ... }`
1432
- // where `*` = required, `?` = optional.
1433
- let expected = "";
1434
- if (toolParameters?.properties) {
1435
- const required = new Set(toolParameters.required ?? []);
1436
- const sig = Object.entries(toolParameters.properties)
1437
- .map(([k, v]) => {
1438
- const mark = required.has(k) ? "*" : "?";
1439
- const type = (v as { type?: string }).type ?? "any";
1440
- return `${k}${mark}: ${type}`;
1441
- })
1442
- .join(", ");
1443
- if (sig)
1444
- expected = ` Expected: { ${sig} } (where * = required, ? = optional).`;
1445
- }
1469
+ const signature = describeToolParameterSignature(toolParameters);
1470
+ const expected = signature
1471
+ ? ` Expected: ${signature} (where * = required, ? = optional).`
1472
+ : "";
1446
1473
 
1447
1474
  throw new Error(
1448
1475
  `Invalid action parameters — ${parts.join(". ")}. Received: ${received}.${expected}`,
@@ -360,18 +360,22 @@ class AISDKEngine implements AgentEngine {
360
360
  // `createProviderModel` forces Chat Completions specifically when
361
361
  // `this.baseUrl` is set (many OpenAI-compatible gateways/proxies
362
362
  // don't implement Responses — see that comment). In that exact
363
- // combination — forced Chat Completions AND tools present — drop
364
- // the explicit override and let the model use its default reasoning
365
- // behavior instead of hard-failing the whole request; Responses-API
366
- // calls (no baseUrl) are unaffected and keep full effort control.
363
+ // combination — forced Chat Completions AND tools present — send
364
+ // `"none"` rather than our resolved effort; Responses-API calls (no
365
+ // baseUrl) are unaffected and keep full effort control.
366
+ //
367
+ // Omitting the field does NOT work: OpenAI then applies the model's
368
+ // own default effort, which is not "none", and rejects the request
369
+ // exactly the same way. Only the explicit "none" clears it — the
370
+ // error text spells this out ("or set reasoning_effort to 'none'").
367
371
  const forcedChatCompletionsWithTools =
368
372
  Boolean(this.baseUrl) && aiSdkTools !== undefined;
369
- if (!forcedChatCompletionsWithTools) {
370
- providerOpts.openai = {
371
- ...((providerOpts.openai as object) ?? {}),
372
- reasoningEffort,
373
- };
374
- }
373
+ providerOpts.openai = {
374
+ ...((providerOpts.openai as object) ?? {}),
375
+ reasoningEffort: forcedChatCompletionsWithTools
376
+ ? "none"
377
+ : reasoningEffort,
378
+ };
375
379
  } else if (this.provider === "openrouter") {
376
380
  providerOpts.openrouter = {
377
381
  ...((providerOpts.openrouter as object) ?? {}),
@@ -13,6 +13,7 @@ import type { EventHandler as H3EventHandler } from "h3";
13
13
  import { parseA2AAgentActivityPart } from "../a2a/activity.js";
14
14
  import type { Task } from "../a2a/types.js";
15
15
  import {
16
+ describeToolParameterSignature,
16
17
  isAgentActionStopError,
17
18
  type ActionAutomationContext,
18
19
  type ActionCaller,
@@ -3405,14 +3406,46 @@ function dedupeAssistantToolCallsById(
3405
3406
  return deduped;
3406
3407
  }
3407
3408
 
3409
+ /**
3410
+ * Property names an Ajv `errorsText` line blames, e.g.
3411
+ * `input/operations must be array; input must have required property 'id'`.
3412
+ */
3413
+ function schemaErrorPropertyNames(error: string): string[] {
3414
+ const names = new Set<string>();
3415
+ for (const match of error.matchAll(/\binput\/([A-Za-z0-9_$-]+)/g)) {
3416
+ names.add(match[1]);
3417
+ }
3418
+ for (const match of error.matchAll(
3419
+ /must have required property '([^']+)'/g,
3420
+ )) {
3421
+ names.add(match[1]);
3422
+ }
3423
+ return [...names];
3424
+ }
3425
+
3426
+ /**
3427
+ * Raw-JSON-schema actions used to be told only that their arguments were wrong,
3428
+ * never what shape was expected — so a model re-sent the same guess until the
3429
+ * identical-error breaker ended the turn with the write never executed. Zod
3430
+ * actions have echoed the expected signature since `wrapWithValidation`; this
3431
+ * gives the raw path the same answer from the same helper.
3432
+ */
3408
3433
  function toolInputSchemaErrorResult(
3409
3434
  toolName: string,
3410
3435
  input: unknown,
3411
3436
  error: string,
3437
+ parameters?: ActionTool["parameters"],
3412
3438
  ): string {
3439
+ const signature = describeToolParameterSignature(
3440
+ parameters,
3441
+ schemaErrorPropertyNames(error),
3442
+ );
3413
3443
  return (
3414
3444
  `Invalid action parameters for ${toolName}: ${sanitizeToolErrorText(error)}. ` +
3415
3445
  `Received: ${stringifyToolInput(input)}. ` +
3446
+ (signature
3447
+ ? `Expected: ${signature} (where * = required, ? = optional). `
3448
+ : "") +
3416
3449
  "The tool was not executed; retry with arguments that match the tool schema."
3417
3450
  );
3418
3451
  }
@@ -4723,11 +4756,14 @@ export async function runAgentLoop(opts: {
4723
4756
  const result =
4724
4757
  `Stopped after ${count} identical errors from ${toolCall.name} with the same arguments. ` +
4725
4758
  `Last error: ${sanitizedResult}`;
4759
+ // This message is streamed to the USER, not back to the model — the
4760
+ // model's copy is `result` above. Describe the failure and what they
4761
+ // can do; never instruct them to "fix the arguments".
4726
4762
  requestedActionStop ??= {
4727
4763
  message:
4728
- `Stopped because ${toolCall.name} failed ${count} times with the same arguments and error. ` +
4729
- `Last error: ${sanitizedResult} ` +
4730
- "Fix the underlying issue or change the arguments before retrying.",
4764
+ `I stopped because the ${toolCall.name} action failed ${count} times in a row the same way, ` +
4765
+ "so retrying it again would not have worked. Anything completed before this is saved. " +
4766
+ `Error: ${sanitizedResult}`,
4731
4767
  errorCode: "repeated_identical_tool_error",
4732
4768
  };
4733
4769
  return result;
@@ -5114,6 +5150,7 @@ export async function runAgentLoop(opts: {
5114
5150
  toolCall.name,
5115
5151
  toolCallSchemaError.input,
5116
5152
  toolCallSchemaError.error,
5153
+ actionEntry?.tool.parameters,
5117
5154
  ),
5118
5155
  );
5119
5156
  send({
@@ -5146,6 +5183,7 @@ export async function runAgentLoop(opts: {
5146
5183
  toolCall.name,
5147
5184
  toolCall.input,
5148
5185
  rawToolInputError,
5186
+ actionEntry.tool.parameters,
5149
5187
  ),
5150
5188
  );
5151
5189
  send({
@@ -21,6 +21,8 @@ interface ContentPart {
21
21
  args?: Record<string, string>;
22
22
  result?: string;
23
23
  isError?: boolean;
24
+ /** Mirrors the client ContentPart marker in client/sse-event-processor.ts. */
25
+ outcome?: "unknown";
24
26
  completedSideEffect?: boolean;
25
27
  mcpApp?: AgentMcpAppPayload;
26
28
  chatUI?: ActionChatUIConfig;
@@ -385,6 +387,9 @@ function settleInterruptedToolCalls(content: ContentPart[]): void {
385
387
  for (const part of content) {
386
388
  if (part.type === "tool-call" && part.result === undefined) {
387
389
  part.result = INTERRUPTED_TOOL_RESULT;
390
+ // Interrupted is not failed — never set `isError` here. The persisted
391
+ // turn must agree with the live client (client/sse-event-processor.ts).
392
+ part.outcome = "unknown";
388
393
  }
389
394
  }
390
395
  }
@@ -0,0 +1,53 @@
1
+ import { isServerlessRuntime } from "../db/client.js";
2
+ import type { MigrationEntry } from "../db/migrations.js";
3
+ import { runMigrations } from "../db/migrations.js";
4
+ import { repairLegacyChatThreadMessageCounts } from "./store.js";
5
+
6
+ export const CHAT_THREADS_MIGRATIONS_TABLE = "_chat_threads_migrations";
7
+
8
+ export const CHAT_THREADS_REPAIR_MESSAGE_COUNTS_MIGRATION =
9
+ "chat-threads-repair-legacy-message-counts";
10
+
11
+ /**
12
+ * Rows written before `message_count` was maintained still carry 0, and both
13
+ * `listThreads` and `searchThreads` filter `message_count > 0` in SQL — so on a
14
+ * database that predates the column, threads that do have messages never appear
15
+ * in the sidebar. This entry is the only reachable caller of the repair; being
16
+ * name-tracked, the `thread_data` scan it performs runs once per database and
17
+ * is skipped entirely on every later boot.
18
+ */
19
+ export const CHAT_THREADS_MIGRATIONS: MigrationEntry[] = [
20
+ {
21
+ version: 1,
22
+ name: CHAT_THREADS_REPAIR_MESSAGE_COUNTS_MIGRATION,
23
+ // Run-only: the count comes from `normalizeThreadRepository`, which dedupes
24
+ // and re-parents message entries. No portable SQL equivalent.
25
+ sql: {},
26
+ run: async () => {
27
+ const { scanned, updated } = await repairLegacyChatThreadMessageCounts();
28
+ if (scanned > 0) {
29
+ console.log(
30
+ `[chat-threads] repaired legacy message_count on ${updated} of ${scanned} scanned row(s)`,
31
+ );
32
+ }
33
+ },
34
+ },
35
+ ];
36
+
37
+ /**
38
+ * Apply data migrations only in a long-lived process. A serverless cold start
39
+ * must never launch the legacy blob scan: concurrent isolates would all race
40
+ * the same repair and exhaust the shared database even if route readiness does
41
+ * not await it. Operators can run the app in a long-lived maintenance process
42
+ * against the target database to apply the name-tracked repair once.
43
+ */
44
+ export async function runChatThreadDataMigrations(
45
+ nitroApp: unknown,
46
+ ): Promise<"applied" | "skipped-serverless"> {
47
+ if (isServerlessRuntime()) return "skipped-serverless";
48
+ const migrate = runMigrations(CHAT_THREADS_MIGRATIONS, {
49
+ table: CHAT_THREADS_MIGRATIONS_TABLE,
50
+ });
51
+ await migrate(nitroApp);
52
+ return "applied";
53
+ }
@@ -35,6 +35,10 @@ const REACT_ROUTER_BUILD_DEPENDENCIES = [
35
35
  "vite",
36
36
  ] as const;
37
37
  const MINIMUM_RELEASE_AGE_EXCLUDES = [
38
+ '"@modelcontextprotocol/client"',
39
+ '"@modelcontextprotocol/core"',
40
+ '"@modelcontextprotocol/node"',
41
+ '"@modelcontextprotocol/server"',
38
42
  '"@typescript/*"',
39
43
  '"@sentry/*"',
40
44
  "fast-xml-parser",
@@ -27,10 +27,18 @@ exported instructions only, with no MCP connector registration.
27
27
 
28
28
  ## Put Design Beside The Chat
29
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.
30
+ Prefer the interactive MCP App returned by \`open-visual-edit\` when the coding
31
+ host renders it. The user gets the Design canvas beside the conversation, and
32
+ **Apply design updates** can submit the bounded source-edit handoff back to the
33
+ current host conversation through the standard MCP Apps message bridge. The
34
+ host may ask the user to confirm the current conversation or choose a new one.
35
+
36
+ Otherwise, after \`open-visual-edit\` returns \`openUrl\`, open that URL in the
37
+ coding host's inline browser when one is available. This still keeps Design
38
+ beside the conversation, but an ordinary browser page has no trusted path into
39
+ the host's current composer. In that fallback surface, **Apply design updates**
40
+ uses Design's local agent; use **Copy prompt to your agent** to hand the same
41
+ structured edit batch to the coding agent.
34
42
 
35
43
  - In Codex Desktop, use the in-app Browser tool to open \`openUrl\`. The built-in
36
44
  browser is the right surface for localhost and public pages that should stay
@@ -42,14 +50,13 @@ screens as the agent, and iterate without switching apps.
42
50
  sessions may not expose one. If the inline surface is unavailable or disabled,
43
51
  return the normal **Open design** link instead of claiming it opened.
44
52
 
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.
53
+ Prefer the MCP App surface for a connected Design plugin, then the host's
54
+ browser/preview tool as the universal fallback. Keep the canvas beside chat
55
+ when the host supports rearrangeable panes.
48
56
 
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.
57
+ Inside Design, use **Show/Hide UI** from the \`Cmd+K\` menu or press Figma's
58
+ \`Shift+\\\` shortcut to toggle all editing chrome so only the canvas remains.
59
+ The same action is available from Design's empty-canvas context menu.
53
60
 
54
61
  ## Core Model
55
62
 
@@ -57,8 +64,16 @@ Design's empty-canvas context menu.
57
64
  - Each screen keeps URL metadata: \`connectionId\`, \`routeId\`, \`path\`,
58
65
  \`url\`, \`bridgeUrl\`, title, and viewport size.
59
66
  - Localhost Edit mode renders the running app through the local bridge as a live
60
- iframe with the same editor bridge used by HTML designs. It is not a frozen
61
- static DOM snapshot.
67
+ iframe with the same editor bridge used by HTML designs. It is never a frozen
68
+ static DOM snapshot. Editing is direct DOM manipulation against that live
69
+ document; the parallel \`/snapshot\` fetch feeds the editable source model only
70
+ and must never be rendered in the frame.
71
+ - A viewer holding the connection's \`previewToken\` gets the proxied
72
+ \`/live-edit\` document with editor chrome. A viewer without one — a signed-out
73
+ session, a public link, or an inline browser with no cookies — gets the plain
74
+ dev-server URL: still live, but with no editor chrome, no layers, and no
75
+ editing. If the canvas looks right but selection and the layers panel do
76
+ nothing, the frame is unbridged; sign in rather than assuming Design is broken.
62
77
  - The live editor is same-origin through the local bridge proxy. This boots
63
78
  CSR apps and root-relative assets, but it is still a localhost editing proxy:
64
79
  app-origin cookies, WebSockets/HMR, SSE, and non-GET app API calls may need a
@@ -336,9 +351,11 @@ Fallback, only when \`open-visual-edit\` is unavailable:
336
351
  ## Applying Visual Edits Back To Source
337
352
 
338
353
  Canvas edits on a localhost screen do not write source as you make them. They
339
- accumulate as pending edits and the editor shows an "Apply with Design agent"
340
- button in the bottom-right corner of the canvas. Clicking it hands a structured
341
- prompt to the Design agent chat, which performs the real source write.
354
+ accumulate as pending edits and the editor shows an **Apply design updates**
355
+ button on the canvas. In an MCP App, clicking it hands the bounded structured
356
+ prompt to the current host coding conversation. In an ordinary browser or
357
+ standalone Design page, it falls back to the local Design agent. The dropdown's
358
+ **Copy prompt to your agent** action is the universal manual fallback.
342
359
 
343
360
  - Style, text, and drag/drop structure edits all collect into the same pending
344
361
  batch, so the user can make several changes and apply once.
@@ -410,6 +427,9 @@ the connected app's text/code files through the bridge
410
427
  - The Design editor opens in overview mode.
411
428
  - Every requested screen renders the intended localhost URL, showing real app
412
429
  content rather than an endless loading spinner.
430
+ - The screen iframe carries a \`src\`, not a \`srcdoc\`. A localhost screen with a
431
+ \`srcdoc\` is a bug, not a slow load — check it in the browser devtools before
432
+ reporting the canvas as working.
413
433
  - Alt-dragging a screen copies the URL-backed frame, not an inline HTML clone.
414
434
  - A query/path edit changes only the target screen's URL metadata and iframe.
415
435
  - The Code tab shows a local-files root for the connection and opens its files.
@@ -1173,6 +1173,7 @@ function writeSkillFolder(
1173
1173
  `${JSON.stringify(metadata, null, 2)}\n`,
1174
1174
  "utf-8",
1175
1175
  );
1176
+ assertSkillFolderIsNotSymlink(dir);
1176
1177
  fs.rmSync(dir, { recursive: true, force: true });
1177
1178
  fs.renameSync(tempDir, dir);
1178
1179
  } catch (error: any) {
@@ -1186,6 +1187,21 @@ function writeSkillFolder(
1186
1187
  }
1187
1188
  }
1188
1189
 
1190
+ function assertSkillFolderIsNotSymlink(dir: string): void {
1191
+ let stat: fs.Stats;
1192
+ try {
1193
+ stat = fs.lstatSync(dir);
1194
+ } catch (error: any) {
1195
+ if (error?.code === "ENOENT") return;
1196
+ throw error;
1197
+ }
1198
+ if (stat.isSymbolicLink()) {
1199
+ throw new Error(
1200
+ `Refusing to replace symlinked Agent Native skill folder ${dir}. Update the linked source or remove the symlink before installing.`,
1201
+ );
1202
+ }
1203
+ }
1204
+
1189
1205
  function isJsonRecord(value: unknown): value is Record<string, unknown> {
1190
1206
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
1191
1207
  }