@agent-native/core 0.128.3 → 0.129.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 (350) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +91 -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/legacy-chart-shorthand.tsx +479 -0
  22. package/corpus/core/src/client/chat/markdown-renderer.tsx +23 -3
  23. package/corpus/core/src/client/chat/message-components.tsx +12 -5
  24. package/corpus/core/src/client/chat/runtime.ts +2 -1
  25. package/corpus/core/src/client/chat/tool-call-display.tsx +25 -2
  26. package/corpus/core/src/client/chat-model-groups.ts +3 -0
  27. package/corpus/core/src/client/client-status-requests.ts +161 -0
  28. package/corpus/core/src/client/settings/VoiceTranscriptionSection.tsx +2 -2
  29. package/corpus/core/src/client/sse-event-processor.ts +15 -3
  30. package/corpus/core/src/client/use-agent-engine-configured.ts +54 -50
  31. package/corpus/core/src/client/use-chat-models.ts +16 -11
  32. package/corpus/core/src/client/use-chat-threads.ts +32 -9
  33. package/corpus/core/src/client/use-session.ts +4 -5
  34. package/corpus/core/src/db/client.ts +83 -8
  35. package/corpus/core/src/db/ensure-additive-columns.ts +31 -20
  36. package/corpus/core/src/db/migrations.ts +22 -2
  37. package/corpus/core/src/extensions/actions.ts +1 -1
  38. package/corpus/core/src/mcp/approval-store.ts +99 -0
  39. package/corpus/core/src/mcp/build-server.ts +579 -303
  40. package/corpus/core/src/mcp/embed-app.ts +1 -1
  41. package/corpus/core/src/mcp/oauth-client-metadata.ts +380 -0
  42. package/corpus/core/src/mcp/oauth-route.ts +57 -52
  43. package/corpus/core/src/mcp/screen-memory-stdio.ts +400 -378
  44. package/corpus/core/src/mcp/server.ts +29 -145
  45. package/corpus/core/src/mcp/stdio.ts +72 -80
  46. package/corpus/core/src/mcp-client/manager.ts +6 -10
  47. package/corpus/core/src/mcp-client/oauth-client.ts +127 -36
  48. package/corpus/core/src/mcp-client/oauth-routes.ts +16 -6
  49. package/corpus/core/src/mcp-client/routes.ts +6 -5
  50. package/corpus/core/src/server/agent-capabilities.ts +20 -0
  51. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +27 -0
  52. package/corpus/core/src/server/agent-chat-plugin.ts +18 -0
  53. package/corpus/core/src/server/transcribe-voice.ts +14 -5
  54. package/corpus/core/src/templates/default/.agents/skills/security/SKILL.md +13 -2
  55. package/corpus/core/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +5 -2
  56. package/corpus/core/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +18 -0
  57. package/corpus/core/src/templates/workspace-core/.agents/skills/security/SKILL.md +13 -2
  58. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +12 -0
  59. package/corpus/templates/analytics/.agents/skills/security/SKILL.md +13 -2
  60. package/corpus/templates/analytics/actions/generate-chart.ts +2 -2
  61. package/corpus/templates/analytics/app/components/dashboard/DashboardPanelSkeleton.tsx +1 -10
  62. package/corpus/templates/analytics/app/global.css +0 -31
  63. package/corpus/templates/analytics/app/lib/sql-query.ts +46 -20
  64. package/corpus/templates/analytics/changelog/2026-07-28-analytics-dashboard-loading-states-now-use-a-simpler-standar.md +6 -0
  65. package/corpus/templates/analytics/changelog/2026-07-28-analytics-dashboards-now-load-first-party-charts-reliably-in.md +6 -0
  66. package/corpus/templates/analytics/server/lib/first-party-analytics-cache.ts +42 -16
  67. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +4 -2
  68. package/corpus/templates/analytics/shared/sql-query-limits.ts +1 -0
  69. package/corpus/templates/assets/.agents/skills/security/SKILL.md +13 -2
  70. package/corpus/templates/brain/.agents/skills/security/SKILL.md +13 -2
  71. package/corpus/templates/calendar/.agents/skills/security/SKILL.md +13 -2
  72. package/corpus/templates/chat/.agents/skills/security/SKILL.md +13 -2
  73. package/corpus/templates/clips/.agents/skills/security/SKILL.md +13 -2
  74. package/corpus/templates/clips/app/components/player/player-controls.tsx +3 -6
  75. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +6 -2
  76. package/corpus/templates/clips/app/routes/share.$shareId.tsx +3 -1
  77. package/corpus/templates/clips/changelog/2026-07-28-copied-share-links-no-longer-leave-an-unnecessary-confirmati.md +6 -0
  78. package/corpus/templates/clips/changelog/2026-07-28-playback-skip-controls-no-longer-show-overlapping-numbers.md +6 -0
  79. package/corpus/templates/clips/changelog/2026-07-28-public-clips-share-buttons-now-use-a-clean-text-only-label.md +6 -0
  80. package/corpus/templates/clips/desktop/src/app.tsx +14 -17
  81. package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +3 -1
  82. package/corpus/templates/clips/desktop/src/styles.css +13 -10
  83. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +2 -2
  84. package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +36 -0
  85. package/corpus/templates/content/.agents/skills/security/SKILL.md +13 -2
  86. package/corpus/templates/content/actions/_builder-cms-read-client.ts +155 -34
  87. package/corpus/templates/content/actions/_builder-docs-client.ts +151 -30
  88. package/corpus/templates/content/actions/stage-builder-source-bulk-update.ts +5 -2
  89. package/corpus/templates/content/app/root.tsx +35 -14
  90. package/corpus/templates/content/changelog/2026-07-28-builder-backed-files-media-fields-now-accept-direct-file-url.md +6 -0
  91. package/corpus/templates/content/changelog/2026-07-28-builder-content-reads-now-negotiate-the-newest-mcp-protocol-.md +6 -0
  92. package/corpus/templates/content/changelog/2026-07-28-public-content-pages-load-faster-before-the-optional-ask-sid.md +6 -0
  93. package/corpus/templates/design/.agents/skills/security/SKILL.md +13 -2
  94. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +36 -16
  95. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +42 -3
  96. package/corpus/templates/design/actions/open-visual-edit.ts +2 -1
  97. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +2 -2
  98. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +14 -15
  99. package/corpus/templates/design/app/components/design/ResponsiveInteractBar.tsx +314 -0
  100. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +88 -3
  101. package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +1 -1
  102. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +7 -6
  103. package/corpus/templates/design/app/i18n-data.ts +56 -11
  104. package/corpus/templates/design/app/i18n-responsive-interact.ts +183 -0
  105. package/corpus/templates/design/app/lib/agent-chat.ts +60 -0
  106. package/corpus/templates/design/app/pages/design-editor/responsive-interact.ts +89 -0
  107. package/corpus/templates/design/changelog/2026-07-28-design-edits-can-be-applied-through-the-host-coding-agent-fr.md +6 -0
  108. package/corpus/templates/design/changelog/2026-07-28-interact-mode-can-preview-designs-in-responsive-device-sizes.md +6 -0
  109. package/corpus/templates/design/changelog/2026-07-28-interact-mode-now-opens-a-full-screen-responsive-preview-wit.md +6 -0
  110. package/corpus/templates/design/changelog/2026-07-28-show-or-hide-design-editing-chrome-with-cmd-on-apple-devices.md +2 -2
  111. package/corpus/templates/design/changelog/2026-07-28-visual-edit-now-always-shows-the-live-running-app-in-the-can.md +6 -0
  112. package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +13 -2
  113. package/corpus/templates/forms/.agents/skills/security/SKILL.md +13 -2
  114. package/corpus/templates/macros/.agents/skills/security/SKILL.md +13 -2
  115. package/corpus/templates/mail/.agents/skills/security/SKILL.md +13 -2
  116. package/corpus/templates/plan/.agents/skills/security/SKILL.md +13 -2
  117. package/corpus/templates/slides/.agents/skills/security/SKILL.md +13 -2
  118. package/corpus/templates/tasks/.agents/skills/security/SKILL.md +13 -2
  119. package/corpus/toolkit/CHANGELOG.md +13 -0
  120. package/corpus/toolkit/package.json +1 -1
  121. package/corpus/toolkit/src/chat-history.css +1 -2
  122. package/corpus/toolkit/src/composer/TiptapComposer.tsx +45 -0
  123. package/dist/a2a/client.d.ts +7 -0
  124. package/dist/a2a/client.d.ts.map +1 -1
  125. package/dist/a2a/client.js +8 -3
  126. package/dist/a2a/client.js.map +1 -1
  127. package/dist/a2a/server.d.ts.map +1 -1
  128. package/dist/a2a/server.js +18 -3
  129. package/dist/a2a/server.js.map +1 -1
  130. package/dist/a2a/types.d.ts +7 -0
  131. package/dist/a2a/types.d.ts.map +1 -1
  132. package/dist/a2a/types.js.map +1 -1
  133. package/dist/action.d.ts +15 -1
  134. package/dist/action.d.ts.map +1 -1
  135. package/dist/action.js +39 -16
  136. package/dist/action.js.map +1 -1
  137. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  138. package/dist/agent/engine/ai-sdk-engine.js +14 -10
  139. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  140. package/dist/agent/production-agent.d.ts.map +1 -1
  141. package/dist/agent/production-agent.js +35 -7
  142. package/dist/agent/production-agent.js.map +1 -1
  143. package/dist/agent/thread-data-builder.d.ts +2 -0
  144. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  145. package/dist/agent/thread-data-builder.js +3 -0
  146. package/dist/agent/thread-data-builder.js.map +1 -1
  147. package/dist/chat-threads/migrations.d.ts +21 -0
  148. package/dist/chat-threads/migrations.d.ts.map +1 -0
  149. package/dist/chat-threads/migrations.js +45 -0
  150. package/dist/chat-threads/migrations.js.map +1 -0
  151. package/dist/cli/create.d.ts.map +1 -1
  152. package/dist/cli/create.js +4 -0
  153. package/dist/cli/create.js.map +1 -1
  154. package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
  155. package/dist/cli/skills-content/design-visual-edit-skill.d.ts.map +1 -1
  156. package/dist/cli/skills-content/design-visual-edit-skill.js +36 -16
  157. package/dist/cli/skills-content/design-visual-edit-skill.js.map +1 -1
  158. package/dist/cli/skills.d.ts.map +1 -1
  159. package/dist/cli/skills.js +15 -0
  160. package/dist/cli/skills.js.map +1 -1
  161. package/dist/client/AgentPanel.d.ts.map +1 -1
  162. package/dist/client/AgentPanel.js +6 -5
  163. package/dist/client/AgentPanel.js.map +1 -1
  164. package/dist/client/AssistantChat.d.ts +37 -0
  165. package/dist/client/AssistantChat.d.ts.map +1 -1
  166. package/dist/client/AssistantChat.js +41 -8
  167. package/dist/client/AssistantChat.js.map +1 -1
  168. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  169. package/dist/client/MultiTabAssistantChat.js +11 -10
  170. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  171. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  172. package/dist/client/agent-chat-adapter.js +19 -3
  173. package/dist/client/agent-chat-adapter.js.map +1 -1
  174. package/dist/client/analytics.d.ts.map +1 -1
  175. package/dist/client/analytics.js +150 -101
  176. package/dist/client/analytics.js.map +1 -1
  177. package/dist/client/chat/legacy-chart-shorthand.d.ts +29 -0
  178. package/dist/client/chat/legacy-chart-shorthand.d.ts.map +1 -0
  179. package/dist/client/chat/legacy-chart-shorthand.js +330 -0
  180. package/dist/client/chat/legacy-chart-shorthand.js.map +1 -0
  181. package/dist/client/chat/markdown-renderer.d.ts.map +1 -1
  182. package/dist/client/chat/markdown-renderer.js +8 -2
  183. package/dist/client/chat/markdown-renderer.js.map +1 -1
  184. package/dist/client/chat/message-components.d.ts +2 -1
  185. package/dist/client/chat/message-components.d.ts.map +1 -1
  186. package/dist/client/chat/message-components.js +11 -4
  187. package/dist/client/chat/message-components.js.map +1 -1
  188. package/dist/client/chat/runtime.d.ts.map +1 -1
  189. package/dist/client/chat/runtime.js +2 -1
  190. package/dist/client/chat/runtime.js.map +1 -1
  191. package/dist/client/chat/tool-call-display.d.ts +4 -1
  192. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  193. package/dist/client/chat/tool-call-display.js +14 -8
  194. package/dist/client/chat/tool-call-display.js.map +1 -1
  195. package/dist/client/chat-model-groups.d.ts.map +1 -1
  196. package/dist/client/chat-model-groups.js +3 -0
  197. package/dist/client/chat-model-groups.js.map +1 -1
  198. package/dist/client/client-status-requests.d.ts +14 -0
  199. package/dist/client/client-status-requests.d.ts.map +1 -0
  200. package/dist/client/client-status-requests.js +126 -0
  201. package/dist/client/client-status-requests.js.map +1 -0
  202. package/dist/client/settings/VoiceTranscriptionSection.js +1 -1
  203. package/dist/client/settings/VoiceTranscriptionSection.js.map +1 -1
  204. package/dist/client/sse-event-processor.d.ts +7 -0
  205. package/dist/client/sse-event-processor.d.ts.map +1 -1
  206. package/dist/client/sse-event-processor.js +8 -3
  207. package/dist/client/sse-event-processor.js.map +1 -1
  208. package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
  209. package/dist/client/use-agent-engine-configured.js +29 -43
  210. package/dist/client/use-agent-engine-configured.js.map +1 -1
  211. package/dist/client/use-chat-models.d.ts.map +1 -1
  212. package/dist/client/use-chat-models.js +11 -11
  213. package/dist/client/use-chat-models.js.map +1 -1
  214. package/dist/client/use-chat-threads.d.ts.map +1 -1
  215. package/dist/client/use-chat-threads.js +23 -7
  216. package/dist/client/use-chat-threads.js.map +1 -1
  217. package/dist/client/use-session.d.ts.map +1 -1
  218. package/dist/client/use-session.js +4 -4
  219. package/dist/client/use-session.js.map +1 -1
  220. package/dist/collab/awareness.d.ts +2 -2
  221. package/dist/collab/awareness.d.ts.map +1 -1
  222. package/dist/db/client.d.ts.map +1 -1
  223. package/dist/db/client.js +48 -4
  224. package/dist/db/client.js.map +1 -1
  225. package/dist/db/ensure-additive-columns.d.ts.map +1 -1
  226. package/dist/db/ensure-additive-columns.js +32 -21
  227. package/dist/db/ensure-additive-columns.js.map +1 -1
  228. package/dist/db/migrations.d.ts +9 -0
  229. package/dist/db/migrations.d.ts.map +1 -1
  230. package/dist/db/migrations.js +14 -3
  231. package/dist/db/migrations.js.map +1 -1
  232. package/dist/extensions/actions.js +1 -1
  233. package/dist/extensions/actions.js.map +1 -1
  234. package/dist/mcp/approval-store.d.ts +16 -0
  235. package/dist/mcp/approval-store.d.ts.map +1 -0
  236. package/dist/mcp/approval-store.js +85 -0
  237. package/dist/mcp/approval-store.js.map +1 -0
  238. package/dist/mcp/build-server.d.ts +1 -34
  239. package/dist/mcp/build-server.d.ts.map +1 -1
  240. package/dist/mcp/build-server.js +220 -23
  241. package/dist/mcp/build-server.js.map +1 -1
  242. package/dist/mcp/embed-app.js +1 -1
  243. package/dist/mcp/embed-app.js.map +1 -1
  244. package/dist/mcp/oauth-client-metadata.d.ts +15 -0
  245. package/dist/mcp/oauth-client-metadata.d.ts.map +1 -0
  246. package/dist/mcp/oauth-client-metadata.js +297 -0
  247. package/dist/mcp/oauth-client-metadata.js.map +1 -0
  248. package/dist/mcp/oauth-route.d.ts.map +1 -1
  249. package/dist/mcp/oauth-route.js +39 -53
  250. package/dist/mcp/oauth-route.js.map +1 -1
  251. package/dist/mcp/screen-memory-stdio.d.ts.map +1 -1
  252. package/dist/mcp/screen-memory-stdio.js +304 -296
  253. package/dist/mcp/screen-memory-stdio.js.map +1 -1
  254. package/dist/mcp/server.d.ts +12 -25
  255. package/dist/mcp/server.d.ts.map +1 -1
  256. package/dist/mcp/server.js +24 -133
  257. package/dist/mcp/server.js.map +1 -1
  258. package/dist/mcp/stdio.d.ts.map +1 -1
  259. package/dist/mcp/stdio.js +36 -35
  260. package/dist/mcp/stdio.js.map +1 -1
  261. package/dist/mcp-client/manager.d.ts.map +1 -1
  262. package/dist/mcp-client/manager.js +6 -6
  263. package/dist/mcp-client/manager.js.map +1 -1
  264. package/dist/mcp-client/oauth-client.d.ts +13 -17
  265. package/dist/mcp-client/oauth-client.d.ts.map +1 -1
  266. package/dist/mcp-client/oauth-client.js +74 -16
  267. package/dist/mcp-client/oauth-client.js.map +1 -1
  268. package/dist/mcp-client/oauth-routes.d.ts +2 -2
  269. package/dist/mcp-client/oauth-routes.d.ts.map +1 -1
  270. package/dist/mcp-client/oauth-routes.js +16 -6
  271. package/dist/mcp-client/oauth-routes.js.map +1 -1
  272. package/dist/mcp-client/routes.js +5 -5
  273. package/dist/mcp-client/routes.js.map +1 -1
  274. package/dist/notifications/routes.d.ts +1 -1
  275. package/dist/progress/routes.d.ts +1 -1
  276. package/dist/resources/handlers.d.ts +1 -1
  277. package/dist/secrets/routes.d.ts +9 -9
  278. package/dist/server/agent-capabilities.d.ts.map +1 -1
  279. package/dist/server/agent-capabilities.js +21 -0
  280. package/dist/server/agent-capabilities.js.map +1 -1
  281. package/dist/server/agent-chat/action-filters-a2a.d.ts +14 -0
  282. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
  283. package/dist/server/agent-chat/action-filters-a2a.js +16 -0
  284. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
  285. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  286. package/dist/server/agent-chat-plugin.js +11 -1
  287. package/dist/server/agent-chat-plugin.js.map +1 -1
  288. package/dist/server/transcribe-voice.js +12 -6
  289. package/dist/server/transcribe-voice.js.map +1 -1
  290. package/dist/templates/chat/.agents/skills/security/SKILL.md +13 -2
  291. package/dist/templates/default/.agents/skills/security/SKILL.md +13 -2
  292. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +5 -2
  293. package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +18 -0
  294. package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +13 -2
  295. package/docs/content/template-design-collaboration-and-full-apps.mdx +3 -1
  296. package/package.json +7 -4
  297. package/src/a2a/client.ts +18 -4
  298. package/src/a2a/server.ts +19 -3
  299. package/src/a2a/types.ts +7 -0
  300. package/src/action.ts +43 -16
  301. package/src/agent/engine/ai-sdk-engine.ts +14 -10
  302. package/src/agent/production-agent.ts +41 -3
  303. package/src/agent/thread-data-builder.ts +5 -0
  304. package/src/chat-threads/migrations.ts +53 -0
  305. package/src/cli/create.ts +4 -0
  306. package/src/cli/skills-content/design-visual-edit-skill.ts +36 -16
  307. package/src/cli/skills.ts +16 -0
  308. package/src/client/AgentPanel.tsx +9 -5
  309. package/src/client/AssistantChat.tsx +138 -46
  310. package/src/client/MultiTabAssistantChat.tsx +16 -10
  311. package/src/client/agent-chat-adapter.ts +21 -3
  312. package/src/client/analytics.ts +159 -102
  313. package/src/client/chat/legacy-chart-shorthand.tsx +479 -0
  314. package/src/client/chat/markdown-renderer.tsx +23 -3
  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/settings/VoiceTranscriptionSection.tsx +2 -2
  321. package/src/client/sse-event-processor.ts +15 -3
  322. package/src/client/use-agent-engine-configured.ts +54 -50
  323. package/src/client/use-chat-models.ts +16 -11
  324. package/src/client/use-chat-threads.ts +32 -9
  325. package/src/client/use-session.ts +4 -5
  326. package/src/db/client.ts +83 -8
  327. package/src/db/ensure-additive-columns.ts +31 -20
  328. package/src/db/migrations.ts +22 -2
  329. package/src/extensions/actions.ts +1 -1
  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/default/.agents/skills/security/SKILL.md +13 -2
  348. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +5 -2
  349. package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +18 -0
  350. package/src/templates/workspace-core/.agents/skills/security/SKILL.md +13 -2
@@ -163,7 +163,9 @@ private UI after the shell loads. See the `authentication` skill and
163
163
  proves *someone* is signed in. To restrict an operation to some teammates, set
164
164
  `authorize` on the `defineAction`. It wraps `run`, so it applies at every
165
165
  dispatch site (agent tool, HTTP, frontend, MCP, A2A, CLI) — unlike
166
- `needsApproval`, which is honoured only in the agent loop.
166
+ `needsApproval`, which is honored by the agent loop and MCP 2026 hosts that
167
+ support elicitation, but is not an authorization boundary for every dispatch
168
+ site.
167
169
 
168
170
  ```ts
169
171
  import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
@@ -203,7 +205,16 @@ export default defineAction({
203
205
  });
204
206
  ```
205
207
 
206
- When the gate is truthy and the call is not yet approved, the loop emits an `approval_required` event and **stops the turn — `run()` never executes**. The human approves via the chat UI's Approve affordance, which re-issues the turn with the call's stable `approvalKey`; only then does the action run. A predicate gates conditionally (e.g. only external recipients) and **fails closed** — a throw is treated as "approval required".
208
+ When the gate is truthy and the call is not yet approved, the agent loop emits
209
+ an `approval_required` event and **stops the turn — `run()` never executes**.
210
+ The human approves via the chat UI's Approve affordance, which re-issues the
211
+ turn with the call's stable `approvalKey`; only then does the action run. MCP
212
+ 2026 hosts receive an `input_required` approval request bound to the exact
213
+ caller, action, and arguments. The signed response state is backed by a durable,
214
+ single-use grant, so denial, expiry, replay, missing host support, or invalid
215
+ state fails closed before `run()`. A predicate gates conditionally (e.g. only
216
+ external recipients) and **fails closed** — a throw is treated as "approval
217
+ required".
207
218
 
208
219
  Rules:
209
220
 
@@ -71,11 +71,11 @@ function errorMessage(error: unknown): string {
71
71
  * those flows have full data in hand before they call here.
72
72
  */
73
73
  const CHART_FALLBACK_HINT =
74
- "If you're answering an in-chat data question, do not retry generate-chart. Switch to the live /chart embed instead — it accepts a SqlPanel object directly and doesn't require pre-stringified JSON params. See the data-querying skill's \"Inline Charts In Chat\" section for the embed syntax. Only use generate-chart when you're building a save-analysis artifact.";
74
+ "If you're answering an in-chat data question, do not retry generate-chart, and do not type this action's title/labels/data/type parameters as plain chat text (e.g. `/chart type=bar title=... labels=[...] data=[...]`) — that is not the supported syntax and only a best-effort compatibility fallback may recover a chart from it. Switch to the live /chart embed instead — it accepts a SqlPanel object directly and doesn't require pre-stringified JSON params. See the data-querying skill's \"Inline Charts In Chat\" section for the exact ```embed fence syntax. Only use generate-chart when you're building a save-analysis artifact.";
75
75
 
76
76
  export default defineAction({
77
77
  description:
78
- 'Render a static chart image to the media directory **for save-analysis artifacts only**. Uses PNG when the native renderer is available and a portable SVG fallback otherwise. For an in-chat answer to a data question, do NOT call this — emit a live `/chart` embed instead (see the data-querying skill\'s "Inline Charts In Chat" section for the embed syntax). The static image path exists for analyses that need to render outside this app (exports, archived reports). If validation here fails, switch to the live embed rather than retrying.',
78
+ "Render a static chart image to the media directory **for save-analysis artifacts only**. Uses PNG when the native renderer is available and a portable SVG fallback otherwise. For an in-chat answer to a data question, do NOT call this — emit a live `/chart` embed instead (see the data-querying skill's \"Inline Charts In Chat\" section for the embed syntax). Never write this action's `title`/`labels`/`data`/`type` parameters as literal chat text (e.g. `/chart type=bar title=... labels=[...] data=[...]`) — that is not the supported syntax; a best-effort compatibility fallback may recover a simple chart from it, but it rejects malformed input and never re-queries live data like the embed does. The static image path exists for analyses that need to render outside this app (exports, archived reports). If validation here fails, switch to the live embed rather than retrying.",
79
79
  schema: z.object({
80
80
  title: z.string().optional().describe("Chart title (required)"),
81
81
  labels: z.string().optional().describe("JSON array of x-axis labels"),
@@ -1,19 +1,10 @@
1
1
  import type { ComponentProps } from "react";
2
2
 
3
3
  import { Skeleton } from "@/components/ui/skeleton";
4
- import { cn } from "@/lib/utils";
5
4
 
6
5
  export function DashboardPanelSkeleton({
7
6
  className,
8
7
  ...props
9
8
  }: ComponentProps<typeof Skeleton>) {
10
- return (
11
- <Skeleton
12
- {...props}
13
- className={cn(
14
- "dashboard-panel-skeleton bg-muted-foreground/14",
15
- className,
16
- )}
17
- />
18
- );
9
+ return <Skeleton {...props} className={className} />;
19
10
  }
@@ -138,37 +138,6 @@
138
138
  }
139
139
  }
140
140
 
141
- .dashboard-panel-skeleton {
142
- background-color: hsl(var(--muted-foreground) / 0.14);
143
- background-image: linear-gradient(
144
- 105deg,
145
- transparent 28%,
146
- hsl(var(--foreground) / 0.025) 44%,
147
- hsl(var(--foreground) / 0.06) 50%,
148
- hsl(var(--foreground) / 0.025) 56%,
149
- transparent 72%
150
- );
151
- background-size: 28rem 100%;
152
- background-repeat: repeat;
153
- animation: dashboard-panel-skeleton-shimmer 2.6s linear infinite;
154
- }
155
-
156
- @keyframes dashboard-panel-skeleton-shimmer {
157
- 0% {
158
- background-position: 0 0;
159
- }
160
-
161
- 100% {
162
- background-position: 28rem 0;
163
- }
164
- }
165
-
166
- @media (prefers-reduced-motion: reduce) {
167
- .dashboard-panel-skeleton {
168
- animation: none;
169
- }
170
- }
171
-
172
141
  .analytics-mobile-nav {
173
142
  height: 2.75rem;
174
143
  min-height: 2.75rem;
@@ -1,6 +1,9 @@
1
1
  import { callAction } from "@agent-native/core/client/hooks";
2
2
  import { DASHBOARD_REPORT_ACTION_TIMEOUT_MS } from "@shared/dashboard-report-timeouts";
3
- import { MAX_CONCURRENT_SQL_QUERIES } from "@shared/sql-query-limits";
3
+ import {
4
+ MAX_CONCURRENT_FIRST_PARTY_SQL_QUERIES,
5
+ MAX_CONCURRENT_SQL_QUERIES,
6
+ } from "@shared/sql-query-limits";
4
7
  import { useQuery } from "@tanstack/react-query";
5
8
 
6
9
  import type { DataSourceType } from "@/pages/adhoc/sql-dashboard/types";
@@ -22,8 +25,30 @@ type PendingSqlQuerySlot = {
22
25
  onAbort: () => void;
23
26
  };
24
27
 
25
- let activeSqlQueries = 0;
26
- const pendingSqlQuerySlots: PendingSqlQuerySlot[] = [];
28
+ type SqlQueryLane = "first-party" | "external";
29
+
30
+ type SqlQuerySlotPool = {
31
+ active: number;
32
+ limit: number;
33
+ pending: PendingSqlQuerySlot[];
34
+ };
35
+
36
+ const sqlQuerySlotPools: Record<SqlQueryLane, SqlQuerySlotPool> = {
37
+ "first-party": {
38
+ active: 0,
39
+ limit: MAX_CONCURRENT_FIRST_PARTY_SQL_QUERIES,
40
+ pending: [],
41
+ },
42
+ external: {
43
+ active: 0,
44
+ limit: MAX_CONCURRENT_SQL_QUERIES,
45
+ pending: [],
46
+ },
47
+ };
48
+
49
+ function sqlQueryLane(source: DataSourceType): SqlQueryLane {
50
+ return source === "first-party" ? "first-party" : "external";
51
+ }
27
52
 
28
53
  function createAbortError(): Error {
29
54
  if (typeof DOMException !== "undefined") {
@@ -34,49 +59,50 @@ function createAbortError(): Error {
34
59
  return error;
35
60
  }
36
61
 
37
- function createSqlQueryRelease(): () => void {
62
+ function createSqlQueryRelease(pool: SqlQuerySlotPool): () => void {
38
63
  let released = false;
39
64
  return () => {
40
65
  if (released) return;
41
66
  released = true;
42
- activeSqlQueries = Math.max(0, activeSqlQueries - 1);
43
- drainSqlQuerySlots();
67
+ pool.active = Math.max(0, pool.active - 1);
68
+ drainSqlQuerySlots(pool);
44
69
  };
45
70
  }
46
71
 
47
- function drainSqlQuerySlots(): void {
48
- while (
49
- activeSqlQueries < MAX_CONCURRENT_SQL_QUERIES &&
50
- pendingSqlQuerySlots.length > 0
51
- ) {
52
- const pending = pendingSqlQuerySlots.shift();
72
+ function drainSqlQuerySlots(pool: SqlQuerySlotPool): void {
73
+ while (pool.active < pool.limit && pool.pending.length > 0) {
74
+ const pending = pool.pending.shift();
53
75
  if (!pending) return;
54
76
  pending.signal?.removeEventListener("abort", pending.onAbort);
55
77
  if (pending.signal?.aborted) {
56
78
  pending.reject(createAbortError());
57
79
  continue;
58
80
  }
59
- activeSqlQueries += 1;
60
- pending.resolve(createSqlQueryRelease());
81
+ pool.active += 1;
82
+ pending.resolve(createSqlQueryRelease(pool));
61
83
  }
62
84
  }
63
85
 
64
- async function acquireSqlQuerySlot(signal?: AbortSignal): Promise<() => void> {
86
+ async function acquireSqlQuerySlot(
87
+ source: DataSourceType,
88
+ signal?: AbortSignal,
89
+ ): Promise<() => void> {
65
90
  if (signal?.aborted) throw createAbortError();
91
+ const pool = sqlQuerySlotPools[sqlQueryLane(source)];
66
92
  return new Promise((resolve, reject) => {
67
93
  const pending: PendingSqlQuerySlot = {
68
94
  resolve,
69
95
  reject,
70
96
  signal,
71
97
  onAbort: () => {
72
- const index = pendingSqlQuerySlots.indexOf(pending);
73
- if (index >= 0) pendingSqlQuerySlots.splice(index, 1);
98
+ const index = pool.pending.indexOf(pending);
99
+ if (index >= 0) pool.pending.splice(index, 1);
74
100
  reject(createAbortError());
75
101
  },
76
102
  };
77
103
  signal?.addEventListener("abort", pending.onAbort, { once: true });
78
- pendingSqlQuerySlots.push(pending);
79
- drainSqlQuerySlots();
104
+ pool.pending.push(pending);
105
+ drainSqlQuerySlots(pool);
80
106
  });
81
107
  }
82
108
 
@@ -91,7 +117,7 @@ export async function executeSqlQuery(
91
117
  signal?: AbortSignal,
92
118
  options?: { reportScreenshot?: boolean },
93
119
  ): Promise<SqlQueryResult> {
94
- const release = await acquireSqlQuerySlot(signal);
120
+ const release = await acquireSqlQuerySlot(source, signal);
95
121
  let data: DashboardPanelQueryResponse;
96
122
  try {
97
123
  data = await callAction<DashboardPanelQueryResponse>(
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-28
4
+ ---
5
+
6
+ Analytics dashboard loading states now use a simpler standard placeholder.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-28
4
+ ---
5
+
6
+ Analytics dashboards now load first-party charts reliably instead of timing out under concurrent load.
@@ -26,6 +26,7 @@ interface L1Entry {
26
26
 
27
27
  const CACHE_TTL_MS = 5 * 60 * 1000;
28
28
  const MAX_L1_ENTRIES = 500;
29
+ const CACHE_IO_TIMEOUT_MS = 1_000;
29
30
 
30
31
  const l1Cache = new Map<string, L1Entry>();
31
32
  // De-dupes identical concurrent cache misses (e.g. the same panel query fired
@@ -70,7 +71,7 @@ function setL1(key: string, result: AnalyticsQueryResult): void {
70
71
 
71
72
  async function getL2(
72
73
  key: string,
73
- timeoutMs?: number,
74
+ deadlineAt: number,
74
75
  ): Promise<AnalyticsQueryResult | null> {
75
76
  try {
76
77
  const db = getDbExec();
@@ -78,7 +79,8 @@ async function getL2(
78
79
  const { rows } = await db.execute({
79
80
  sql: "SELECT result FROM first_party_analytics_cache WHERE key = ? AND expires_at > ?",
80
81
  args: [key, nowIso],
81
- timeoutMs,
82
+ timeoutMs: cacheIoTimeoutMs(deadlineAt),
83
+ maxAttempts: 1,
82
84
  });
83
85
  if (!rows.length) return null;
84
86
  const raw = (rows[0] as { result: string }).result;
@@ -93,23 +95,24 @@ async function setL2(
93
95
  key: string,
94
96
  sql: string,
95
97
  result: AnalyticsQueryResult,
96
- timeoutMs?: number,
98
+ deadlineAt: number,
97
99
  ): Promise<void> {
98
100
  try {
99
101
  const db = getDbExec();
100
102
  const now = new Date();
101
103
  const expiresAt = new Date(now.getTime() + CACHE_TTL_MS);
102
104
  const serialized = JSON.stringify(result);
103
- // Upsert via delete+insert to stay dialect-agnostic (SQLite/Postgres).
104
105
  await db.execute({
105
- sql: "DELETE FROM first_party_analytics_cache WHERE key = ?",
106
- args: [key],
107
- timeoutMs,
108
- });
109
- await db.execute({
110
- sql: "INSERT INTO first_party_analytics_cache (key, sql, result, created_at, expires_at) VALUES (?, ?, ?, ?, ?)",
106
+ sql: `INSERT INTO first_party_analytics_cache (key, sql, result, created_at, expires_at)
107
+ VALUES (?, ?, ?, ?, ?)
108
+ ON CONFLICT(key) DO UPDATE SET
109
+ sql = excluded.sql,
110
+ result = excluded.result,
111
+ created_at = excluded.created_at,
112
+ expires_at = excluded.expires_at`,
111
113
  args: [key, sql, serialized, now.toISOString(), expiresAt.toISOString()],
112
- timeoutMs,
114
+ timeoutMs: cacheIoTimeoutMs(deadlineAt),
115
+ maxAttempts: 1,
113
116
  });
114
117
  // Opportunistically prune expired rows so the table doesn't grow
115
118
  // unbounded — the keyspace is effectively every distinct panel/filter
@@ -118,7 +121,8 @@ async function setL2(
118
121
  await db.execute({
119
122
  sql: "DELETE FROM first_party_analytics_cache WHERE expires_at <= ?",
120
123
  args: [now.toISOString()],
121
- timeoutMs,
124
+ timeoutMs: cacheIoTimeoutMs(deadlineAt),
125
+ maxAttempts: 1,
122
126
  });
123
127
  }
124
128
  } catch (err) {
@@ -126,6 +130,17 @@ async function setL2(
126
130
  }
127
131
  }
128
132
 
133
+ function remainingTimeoutMs(deadlineAt: number): number {
134
+ return Math.max(0, deadlineAt - Date.now());
135
+ }
136
+
137
+ function cacheIoTimeoutMs(deadlineAt: number): number {
138
+ return Math.max(
139
+ 1,
140
+ Math.min(CACHE_IO_TIMEOUT_MS, remainingTimeoutMs(deadlineAt)),
141
+ );
142
+ }
143
+
129
144
  /**
130
145
  * Returns a cached result for (key, sql) if fresh, otherwise runs `compute`
131
146
  * exactly once — even under concurrent callers with the same key — and
@@ -134,12 +149,15 @@ async function setL2(
134
149
  export async function withFirstPartyCache(
135
150
  key: string,
136
151
  sql: string,
137
- compute: () => Promise<AnalyticsQueryResult>,
152
+ compute: (timeoutMs: number) => Promise<AnalyticsQueryResult>,
138
153
  options: FirstPartyCacheOptions = {},
139
154
  ): Promise<AnalyticsQueryResult> {
140
155
  const l1Hit = getL1(key);
141
156
  if (l1Hit) return l1Hit;
142
157
 
158
+ const timeoutMs = Math.max(1, options.timeoutMs ?? CACHE_IO_TIMEOUT_MS);
159
+ const deadlineAt = Date.now() + timeoutMs;
160
+
143
161
  // A report prewarm may have a shorter deadline than a normal panel request;
144
162
  // never let those callers inherit one another's database timeout.
145
163
  const requestKey = inFlightKey(key, options.timeoutMs);
@@ -150,14 +168,22 @@ export async function withFirstPartyCache(
150
168
  // callers racing on the same key can't both slip past the check above and
151
169
  // both hit L2/compute.
152
170
  const promise = (async () => {
153
- const l2Hit = await getL2(key, options.timeoutMs);
171
+ const l2Hit = await getL2(key, deadlineAt);
154
172
  if (l2Hit) {
155
173
  setL1(key, l2Hit);
156
174
  return l2Hit;
157
175
  }
158
- const result = await compute();
176
+ const queryTimeoutMs = remainingTimeoutMs(deadlineAt);
177
+ if (queryTimeoutMs <= 0) {
178
+ throw new Error(
179
+ `First-party analytics query timed out after ${timeoutMs}ms`,
180
+ );
181
+ }
182
+ const result = await compute(queryTimeoutMs);
159
183
  setL1(key, result);
160
- await setL2(key, sql, result, options.timeoutMs);
184
+ // Cache persistence is best-effort. A successful panel query must not miss
185
+ // its delivery deadline because the cache table is slow or unavailable.
186
+ void setL2(key, sql, result, deadlineAt);
161
187
  return result;
162
188
  })().finally(() => {
163
189
  inFlight.delete(requestKey);
@@ -660,12 +660,14 @@ export async function queryFirstPartyAnalytics(
660
660
  // org_id/owner_email (see scopeClause) — a cache hit can only ever return
661
661
  // rows the same tenant was already entitled to query.
662
662
  const cacheKey = firstPartyCacheKey(wrappedSql, scoped.args);
663
- const compute = async (): Promise<AnalyticsQueryResult> => {
663
+ const compute = async (
664
+ queryTimeoutMs = timeoutMs,
665
+ ): Promise<AnalyticsQueryResult> => {
664
666
  const exec = getDbExec();
665
667
  const result = await exec.execute({
666
668
  sql: wrappedSql,
667
669
  args: scoped.args,
668
- timeoutMs,
670
+ timeoutMs: queryTimeoutMs,
669
671
  maxAttempts: 1,
670
672
  });
671
673
  const rows = result.rows as Record<string, unknown>[];
@@ -1 +1,2 @@
1
1
  export const MAX_CONCURRENT_SQL_QUERIES = 4;
2
+ export const MAX_CONCURRENT_FIRST_PARTY_SQL_QUERIES = 1;
@@ -163,7 +163,9 @@ private UI after the shell loads. See the `authentication` skill and
163
163
  proves *someone* is signed in. To restrict an operation to some teammates, set
164
164
  `authorize` on the `defineAction`. It wraps `run`, so it applies at every
165
165
  dispatch site (agent tool, HTTP, frontend, MCP, A2A, CLI) — unlike
166
- `needsApproval`, which is honoured only in the agent loop.
166
+ `needsApproval`, which is honored by the agent loop and MCP 2026 hosts that
167
+ support elicitation, but is not an authorization boundary for every dispatch
168
+ site.
167
169
 
168
170
  ```ts
169
171
  import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
@@ -203,7 +205,16 @@ export default defineAction({
203
205
  });
204
206
  ```
205
207
 
206
- When the gate is truthy and the call is not yet approved, the loop emits an `approval_required` event and **stops the turn — `run()` never executes**. The human approves via the chat UI's Approve affordance, which re-issues the turn with the call's stable `approvalKey`; only then does the action run. A predicate gates conditionally (e.g. only external recipients) and **fails closed** — a throw is treated as "approval required".
208
+ When the gate is truthy and the call is not yet approved, the agent loop emits
209
+ an `approval_required` event and **stops the turn — `run()` never executes**.
210
+ The human approves via the chat UI's Approve affordance, which re-issues the
211
+ turn with the call's stable `approvalKey`; only then does the action run. MCP
212
+ 2026 hosts receive an `input_required` approval request bound to the exact
213
+ caller, action, and arguments. The signed response state is backed by a durable,
214
+ single-use grant, so denial, expiry, replay, missing host support, or invalid
215
+ state fails closed before `run()`. A predicate gates conditionally (e.g. only
216
+ external recipients) and **fails closed** — a throw is treated as "approval
217
+ required".
207
218
 
208
219
  Rules:
209
220
 
@@ -163,7 +163,9 @@ private UI after the shell loads. See the `authentication` skill and
163
163
  proves *someone* is signed in. To restrict an operation to some teammates, set
164
164
  `authorize` on the `defineAction`. It wraps `run`, so it applies at every
165
165
  dispatch site (agent tool, HTTP, frontend, MCP, A2A, CLI) — unlike
166
- `needsApproval`, which is honoured only in the agent loop.
166
+ `needsApproval`, which is honored by the agent loop and MCP 2026 hosts that
167
+ support elicitation, but is not an authorization boundary for every dispatch
168
+ site.
167
169
 
168
170
  ```ts
169
171
  import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
@@ -203,7 +205,16 @@ export default defineAction({
203
205
  });
204
206
  ```
205
207
 
206
- When the gate is truthy and the call is not yet approved, the loop emits an `approval_required` event and **stops the turn — `run()` never executes**. The human approves via the chat UI's Approve affordance, which re-issues the turn with the call's stable `approvalKey`; only then does the action run. A predicate gates conditionally (e.g. only external recipients) and **fails closed** — a throw is treated as "approval required".
208
+ When the gate is truthy and the call is not yet approved, the agent loop emits
209
+ an `approval_required` event and **stops the turn — `run()` never executes**.
210
+ The human approves via the chat UI's Approve affordance, which re-issues the
211
+ turn with the call's stable `approvalKey`; only then does the action run. MCP
212
+ 2026 hosts receive an `input_required` approval request bound to the exact
213
+ caller, action, and arguments. The signed response state is backed by a durable,
214
+ single-use grant, so denial, expiry, replay, missing host support, or invalid
215
+ state fails closed before `run()`. A predicate gates conditionally (e.g. only
216
+ external recipients) and **fails closed** — a throw is treated as "approval
217
+ required".
207
218
 
208
219
  Rules:
209
220
 
@@ -163,7 +163,9 @@ private UI after the shell loads. See the `authentication` skill and
163
163
  proves *someone* is signed in. To restrict an operation to some teammates, set
164
164
  `authorize` on the `defineAction`. It wraps `run`, so it applies at every
165
165
  dispatch site (agent tool, HTTP, frontend, MCP, A2A, CLI) — unlike
166
- `needsApproval`, which is honoured only in the agent loop.
166
+ `needsApproval`, which is honored by the agent loop and MCP 2026 hosts that
167
+ support elicitation, but is not an authorization boundary for every dispatch
168
+ site.
167
169
 
168
170
  ```ts
169
171
  import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
@@ -203,7 +205,16 @@ export default defineAction({
203
205
  });
204
206
  ```
205
207
 
206
- When the gate is truthy and the call is not yet approved, the loop emits an `approval_required` event and **stops the turn — `run()` never executes**. The human approves via the chat UI's Approve affordance, which re-issues the turn with the call's stable `approvalKey`; only then does the action run. A predicate gates conditionally (e.g. only external recipients) and **fails closed** — a throw is treated as "approval required".
208
+ When the gate is truthy and the call is not yet approved, the agent loop emits
209
+ an `approval_required` event and **stops the turn — `run()` never executes**.
210
+ The human approves via the chat UI's Approve affordance, which re-issues the
211
+ turn with the call's stable `approvalKey`; only then does the action run. MCP
212
+ 2026 hosts receive an `input_required` approval request bound to the exact
213
+ caller, action, and arguments. The signed response state is backed by a durable,
214
+ single-use grant, so denial, expiry, replay, missing host support, or invalid
215
+ state fails closed before `run()`. A predicate gates conditionally (e.g. only
216
+ external recipients) and **fails closed** — a throw is treated as "approval
217
+ required".
207
218
 
208
219
  Rules:
209
220
 
@@ -163,7 +163,9 @@ private UI after the shell loads. See the `authentication` skill and
163
163
  proves *someone* is signed in. To restrict an operation to some teammates, set
164
164
  `authorize` on the `defineAction`. It wraps `run`, so it applies at every
165
165
  dispatch site (agent tool, HTTP, frontend, MCP, A2A, CLI) — unlike
166
- `needsApproval`, which is honoured only in the agent loop.
166
+ `needsApproval`, which is honored by the agent loop and MCP 2026 hosts that
167
+ support elicitation, but is not an authorization boundary for every dispatch
168
+ site.
167
169
 
168
170
  ```ts
169
171
  import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
@@ -203,7 +205,16 @@ export default defineAction({
203
205
  });
204
206
  ```
205
207
 
206
- When the gate is truthy and the call is not yet approved, the loop emits an `approval_required` event and **stops the turn — `run()` never executes**. The human approves via the chat UI's Approve affordance, which re-issues the turn with the call's stable `approvalKey`; only then does the action run. A predicate gates conditionally (e.g. only external recipients) and **fails closed** — a throw is treated as "approval required".
208
+ When the gate is truthy and the call is not yet approved, the agent loop emits
209
+ an `approval_required` event and **stops the turn — `run()` never executes**.
210
+ The human approves via the chat UI's Approve affordance, which re-issues the
211
+ turn with the call's stable `approvalKey`; only then does the action run. MCP
212
+ 2026 hosts receive an `input_required` approval request bound to the exact
213
+ caller, action, and arguments. The signed response state is backed by a durable,
214
+ single-use grant, so denial, expiry, replay, missing host support, or invalid
215
+ state fails closed before `run()`. A predicate gates conditionally (e.g. only
216
+ external recipients) and **fails closed** — a throw is treated as "approval
217
+ required".
207
218
 
208
219
  Rules:
209
220
 
@@ -163,7 +163,9 @@ private UI after the shell loads. See the `authentication` skill and
163
163
  proves *someone* is signed in. To restrict an operation to some teammates, set
164
164
  `authorize` on the `defineAction`. It wraps `run`, so it applies at every
165
165
  dispatch site (agent tool, HTTP, frontend, MCP, A2A, CLI) — unlike
166
- `needsApproval`, which is honoured only in the agent loop.
166
+ `needsApproval`, which is honored by the agent loop and MCP 2026 hosts that
167
+ support elicitation, but is not an authorization boundary for every dispatch
168
+ site.
167
169
 
168
170
  ```ts
169
171
  import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
@@ -203,7 +205,16 @@ export default defineAction({
203
205
  });
204
206
  ```
205
207
 
206
- When the gate is truthy and the call is not yet approved, the loop emits an `approval_required` event and **stops the turn — `run()` never executes**. The human approves via the chat UI's Approve affordance, which re-issues the turn with the call's stable `approvalKey`; only then does the action run. A predicate gates conditionally (e.g. only external recipients) and **fails closed** — a throw is treated as "approval required".
208
+ When the gate is truthy and the call is not yet approved, the agent loop emits
209
+ an `approval_required` event and **stops the turn — `run()` never executes**.
210
+ The human approves via the chat UI's Approve affordance, which re-issues the
211
+ turn with the call's stable `approvalKey`; only then does the action run. MCP
212
+ 2026 hosts receive an `input_required` approval request bound to the exact
213
+ caller, action, and arguments. The signed response state is backed by a durable,
214
+ single-use grant, so denial, expiry, replay, missing host support, or invalid
215
+ state fails closed before `run()`. A predicate gates conditionally (e.g. only
216
+ external recipients) and **fails closed** — a throw is treated as "approval
217
+ required".
207
218
 
208
219
  Rules:
209
220
 
@@ -323,11 +323,8 @@ function IconBtn({
323
323
 
324
324
  function SkipIcon({ direction }: { direction: "back" | "forward" }) {
325
325
  return (
326
- <span className="relative flex h-5 w-5 items-center justify-center">
327
- <IconPlayerSkipForward
328
- className={cn("h-5 w-5", direction === "back" && "rotate-180")}
329
- />
330
- <span className="absolute text-[7px] font-bold leading-none">5</span>
331
- </span>
326
+ <IconPlayerSkipForward
327
+ className={cn("h-5 w-5", direction === "back" && "rotate-180")}
328
+ />
332
329
  );
333
330
  }
@@ -973,7 +973,9 @@ export default function RecordingPage() {
973
973
  hasPassword={Boolean(recording.hasPassword)}
974
974
  >
975
975
  <Button className="shrink-0 gap-1.5" size="sm">
976
- <IconShare3 className="h-4 w-4" />
976
+ {recording.visibility !== "public" ? (
977
+ <IconShare3 className="h-4 w-4" />
978
+ ) : null}
977
979
  {t("recordingPage.share")}
978
980
  </Button>
979
981
  </ShareRecordingPopover>
@@ -1547,7 +1549,9 @@ export default function RecordingPage() {
1547
1549
  className="shrink-0 gap-1.5 bg-primary text-primary-foreground hover:bg-primary/90"
1548
1550
  size="sm"
1549
1551
  >
1550
- <IconShare3 className="h-4 w-4" />
1552
+ {recording.visibility !== "public" ? (
1553
+ <IconShare3 className="h-4 w-4" />
1554
+ ) : null}
1551
1555
  {t("recordingPage.share")}
1552
1556
  </Button>
1553
1557
  </ShareRecordingPopover>
@@ -966,7 +966,9 @@ export default function ShareRoute() {
966
966
  hasPassword={Boolean(recording.hasPassword)}
967
967
  >
968
968
  <Button size="sm" className="shrink-0 gap-1.5">
969
- <IconShare3 className="h-4 w-4" />
969
+ {recording.visibility !== "public" ? (
970
+ <IconShare3 className="h-4 w-4" />
971
+ ) : null}
970
972
  {t("sharePage.share")}
971
973
  </Button>
972
974
  </ShareRecordingPopover>
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-28
4
+ ---
5
+
6
+ Copied share links no longer leave an unnecessary confirmation banner in the desktop popover.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-28
4
+ ---
5
+
6
+ Playback skip controls no longer show overlapping numbers.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-28
4
+ ---
5
+
6
+ Public Clips share buttons now use a clean text-only label