@agent-native/core 0.80.7 → 0.80.9

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 (302) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +18 -0
  3. package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +6 -0
  4. package/corpus/core/docs/content/locales/de-DE/template-design.mdx +8 -0
  5. package/corpus/core/docs/content/locales/es-ES/template-design.mdx +10 -2
  6. package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +10 -2
  7. package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +7 -0
  8. package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +7 -0
  9. package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +7 -0
  10. package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +9 -2
  11. package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +6 -0
  12. package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +6 -0
  13. package/corpus/core/docs/content/template-design.mdx +9 -2
  14. package/corpus/core/package.json +1 -1
  15. package/corpus/core/src/cli/mcp.ts +10 -0
  16. package/corpus/core/src/cli/skills.ts +58 -12
  17. package/corpus/core/src/client/AssistantChat.tsx +70 -27
  18. package/corpus/core/src/client/analytics.ts +3 -1
  19. package/corpus/core/src/client/error-format.ts +25 -0
  20. package/corpus/core/src/client/extensions/ExtensionViewer.tsx +13 -11
  21. package/corpus/core/src/client/guided-questions.tsx +32 -4
  22. package/corpus/core/src/client/onboarding/OnboardingPanel.tsx +33 -1
  23. package/corpus/core/src/client/resources/BuiltinCapabilityDetail.tsx +8 -0
  24. package/corpus/core/src/client/resources/use-builtin-capabilities.ts +4 -2
  25. package/corpus/core/src/client/session-replay.ts +34 -0
  26. package/corpus/core/src/client/sharing/ShareButton.tsx +106 -21
  27. package/corpus/core/src/coding-tools/index.ts +1 -1
  28. package/corpus/core/src/mcp/index.ts +2 -0
  29. package/corpus/core/src/mcp/screen-memory-stdio.ts +290 -0
  30. package/corpus/core/src/mcp-client/builtin-capabilities.ts +13 -1
  31. package/corpus/core/src/mcp-client/index.ts +9 -0
  32. package/corpus/core/src/mcp-client/screen-memory-local.ts +461 -0
  33. package/corpus/core/src/onboarding/types.ts +7 -0
  34. package/corpus/core/src/server/agent-chat-plugin.ts +25 -0
  35. package/corpus/core/src/server/agents-bundle.ts +35 -7
  36. package/corpus/core/src/styles/agent-native.css +5 -0
  37. package/corpus/core/src/templates/default/app/global.css +35 -35
  38. package/corpus/templates/analytics/AGENTS.md +6 -0
  39. package/corpus/templates/analytics/actions/github-repo-files.ts +9 -0
  40. package/corpus/templates/analytics/app/components/layout/Layout.tsx +4 -4
  41. package/corpus/templates/analytics/app/global.css +144 -40
  42. package/corpus/templates/analytics/app/pages/adhoc/explorer/index.tsx +1 -1
  43. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/ChartCard.tsx +1 -1
  44. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +1 -1
  45. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +4 -4
  46. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +9 -9
  47. package/corpus/templates/analytics/changelog/2026-06-29-agents-can-search-and-read-connected-github-repositories-whe.md +6 -0
  48. package/corpus/templates/analytics/changelog/2026-06-29-sessions-and-explorer-layouts-adapt-when-the-agent-sidebar-is.md +6 -0
  49. package/corpus/templates/assets/app/components/layout/Layout.tsx +3 -1
  50. package/corpus/templates/assets/app/components/library/LibraryPresetGrid.tsx +1 -1
  51. package/corpus/templates/assets/app/global.css +99 -35
  52. package/corpus/templates/assets/app/routes/asset.$id.tsx +2 -2
  53. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +4 -4
  54. package/corpus/templates/assets/app/routes/library.tsx +4 -4
  55. package/corpus/templates/assets/changelog/2026-06-29-asset-library-and-detail-layouts-adapt-when-the-agent-sidebar.md +6 -0
  56. package/corpus/templates/brain/app/components/layout/Layout.tsx +1 -1
  57. package/corpus/templates/brain/app/global.css +63 -35
  58. package/corpus/templates/brain/app/routes/search.tsx +1 -1
  59. package/corpus/templates/brain/app/routes/settings.tsx +1 -1
  60. package/corpus/templates/brain/app/routes/sources.tsx +2 -2
  61. package/corpus/templates/brain/changelog/2026-06-29-search-settings-and-source-layouts-adapt-when-the-agent-sidebar.md +6 -0
  62. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +4 -4
  63. package/corpus/templates/calendar/app/components/calendar/FindTimePanel.tsx +3 -2
  64. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +4 -2
  65. package/corpus/templates/calendar/app/global.css +69 -35
  66. package/corpus/templates/calendar/changelog/2026-06-29-event-and-find-time-layouts-adapt-when-the-agent-sidebar-is.md +6 -0
  67. package/corpus/templates/chat/app/components/layout/Layout.tsx +1 -1
  68. package/corpus/templates/chat/app/global.css +35 -35
  69. package/corpus/templates/chat/changelog/2026-06-29-chat-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
  70. package/corpus/templates/clips/AGENTS.md +13 -0
  71. package/corpus/templates/clips/actions/get-screen-memory-status.ts +12 -0
  72. package/corpus/templates/clips/actions/query-screen-memory-context.ts +29 -0
  73. package/corpus/templates/clips/actions/view-screen.ts +2 -2
  74. package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -1
  75. package/corpus/templates/clips/app/global.css +47 -35
  76. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +3 -3
  77. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +45 -18
  78. package/corpus/templates/clips/changelog/2026-06-29-meeting-detail-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
  79. package/corpus/templates/clips/changelog/2026-06-29-screen-memory-keeps-a-local-rolling-screen-buffer-for-agent-context.md +5 -0
  80. package/corpus/templates/clips/changelog/2026-06-29-video-chat-is-easier-to-find-on-recording-pages-and-s3-setup.md +6 -0
  81. package/corpus/templates/clips/chrome-extension/src/styles.css +39 -39
  82. package/corpus/templates/clips/desktop/src/app.tsx +290 -1
  83. package/corpus/templates/clips/desktop/src/shared/config.ts +83 -0
  84. package/corpus/templates/clips/desktop/src/styles.css +67 -52
  85. package/corpus/templates/clips/desktop/src-tauri/src/config.rs +50 -0
  86. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +17 -0
  87. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +13 -13
  88. package/corpus/templates/clips/desktop/src-tauri/src/screen_memory.rs +990 -0
  89. package/corpus/templates/clips/server/plugins/onboarding.ts +2 -0
  90. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +69 -16
  91. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +3 -3
  92. package/corpus/templates/content/app/components/layout/Layout.tsx +1 -1
  93. package/corpus/templates/content/app/global.css +29 -15
  94. package/corpus/templates/content/changelog/2026-06-29-database-gallery-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
  95. package/corpus/templates/content/changelog/2026-06-29-read-only-pages-no-longer-try-to-autosave-or-open-editor-onl.md +6 -0
  96. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +25 -20
  97. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +8 -0
  98. package/corpus/templates/design/.agents/skills/export-handoff/SKILL.md +8 -0
  99. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +13 -0
  100. package/corpus/templates/design/AGENTS.md +24 -14
  101. package/corpus/templates/design/CODE_NATIVE_DESIGN_STUDIO_IMPLEMENTATION_PLAN.md +1054 -0
  102. package/corpus/templates/design/actions/apply-visual-edit.ts +24 -4
  103. package/corpus/templates/design/actions/edit-design.ts +6 -3
  104. package/corpus/templates/design/actions/export-coding-handoff.ts +12 -4
  105. package/corpus/templates/design/actions/generate-design.ts +6 -21
  106. package/corpus/templates/design/actions/generate-screens.ts +48 -5
  107. package/corpus/templates/design/actions/get-design.ts +1 -0
  108. package/corpus/templates/design/actions/present-design-variants.ts +355 -30
  109. package/corpus/templates/design/actions/update-design.ts +47 -10
  110. package/corpus/templates/design/actions/update-file.ts +33 -8
  111. package/corpus/templates/design/actions/view-screen.ts +89 -31
  112. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +389 -71
  113. package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +1 -1
  114. package/corpus/templates/design/app/components/design/EditPanel.tsx +596 -95
  115. package/corpus/templates/design/app/components/design/LayersPanel.tsx +428 -221
  116. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +1197 -228
  117. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +94 -217
  118. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +28 -14
  119. package/corpus/templates/design/app/components/design/index.ts +0 -1
  120. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +228 -170
  121. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +140 -13
  122. package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +39 -8
  123. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +4 -2
  124. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +75 -5
  125. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +37 -12
  126. package/corpus/templates/design/app/components/design/inspector/index.ts +1 -0
  127. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +17 -4
  128. package/corpus/templates/design/app/components/design/types.ts +9 -0
  129. package/corpus/templates/design/app/components/layout/Layout.tsx +23 -5
  130. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +448 -259
  131. package/corpus/templates/design/app/global.css +77 -49
  132. package/corpus/templates/design/app/hooks/use-question-flow.ts +2 -2
  133. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +8 -1
  134. package/corpus/templates/design/app/i18n/zh-TW.ts +4 -0
  135. package/corpus/templates/design/app/i18n-data.ts +55 -3
  136. package/corpus/templates/design/app/pages/DesignEditor.tsx +2783 -658
  137. package/corpus/templates/design/app/root.tsx +1 -1
  138. package/corpus/templates/design/changelog/2026-06-29-agent-edits-to-a-design-are-no-longer-occasionally-dropped-o.md +6 -0
  139. package/corpus/templates/design/changelog/2026-06-29-box-shadow-and-gradient-colors-keep-named-css-colors-like-re.md +6 -0
  140. package/corpus/templates/design/changelog/2026-06-29-containers-no-longer-block-selecting-nested-elements-and-nor.md +6 -0
  141. package/corpus/templates/design/changelog/2026-06-29-cut-cmd-ctrl-x-now-removes-the-selected-element-to-the-clipb.md +6 -0
  142. package/corpus/templates/design/changelog/2026-06-29-deleting-with-multiple-layers-selected-in-the-layers-panel-n.md +6 -0
  143. package/corpus/templates/design/changelog/2026-06-29-design-agents-now-generate-and-refine-variants-from-stronger.md +6 -0
  144. package/corpus/templates/design/changelog/2026-06-29-design-inspector-controls-now-match-figmas-softer-dark-chrome.md +6 -0
  145. package/corpus/templates/design/changelog/2026-06-29-design-questions-now-appear-as-a-cleaner-canvas-intake-with-.md +6 -0
  146. package/corpus/templates/design/changelog/2026-06-29-design-variant-directions-now-appear-as-board-screens-with-chat-buttons.md +5 -0
  147. package/corpus/templates/design/changelog/2026-06-29-duplicating-a-screen-now-gives-the-copy-its-own-layer-ids-so.md +6 -0
  148. package/corpus/templates/design/changelog/2026-06-29-element-selection-no-longer-snaps-back-to-the-previous-layer.md +6 -0
  149. package/corpus/templates/design/changelog/2026-06-29-frame-resize-measurements-now-stay-beside-the-cursor-while-d.md +6 -0
  150. package/corpus/templates/design/changelog/2026-06-29-hiding-and-re-showing-a-gradient-fill-now-preserves-each-sto.md +6 -0
  151. package/corpus/templates/design/changelog/2026-06-29-inspector-number-fields-have-cleaner-tooltips-and-draggable-.md +6 -0
  152. package/corpus/templates/design/changelog/2026-06-29-layer-locking-layer-nesting-generated-question-intake-and-im.md +6 -0
  153. package/corpus/templates/design/changelog/2026-06-29-layer-names-in-the-sidebar-can-scroll-horizontally-instead-o.md +6 -0
  154. package/corpus/templates/design/changelog/2026-06-29-layer-nesting-in-the-sidebar-now-uses-tighter-spacing-so-nam.md +6 -0
  155. package/corpus/templates/design/changelog/2026-06-29-layers-no-longer-repeat-document-wrapper-rows-when-a-screen-.md +6 -0
  156. package/corpus/templates/design/changelog/2026-06-29-overview-previews-now-keep-element-hover-and-selection-tied-.md +6 -0
  157. package/corpus/templates/design/changelog/2026-06-29-picking-a-design-direction-now-submits-to-the-agent-right-aw.md +6 -0
  158. package/corpus/templates/design/changelog/2026-06-29-pressing-escape-now-cancels-a-stuck-screen-drag-in-the-overv.md +6 -0
  159. package/corpus/templates/design/changelog/2026-06-29-screen-overview-is-easier-to-find-and-named-screens-open-dir.md +6 -0
  160. package/corpus/templates/design/changelog/2026-06-29-screen-overview-only-highlights-screens-when-the-frame-or-ti.md +6 -0
  161. package/corpus/templates/design/changelog/2026-06-29-screen-overview-previews-now-resize-to-match-the-selected-de.md +6 -0
  162. package/corpus/templates/design/changelog/2026-06-29-screen-overview-selection-now-uses-a-pointer-cursor-instead-.md +6 -0
  163. package/corpus/templates/design/changelog/2026-06-29-screen-overview-selection-outlines-now-stay-locked-to-the-se.md +6 -0
  164. package/corpus/templates/design/changelog/2026-06-29-screen-overview-zoom-now-reports-real-screen-scale-separatel.md +6 -0
  165. package/corpus/templates/design/changelog/2026-06-29-screen-overview-zooming-feels-smoother-and-selection-outline.md +6 -0
  166. package/corpus/templates/design/changelog/2026-06-29-screen-overview-zooming-now-stays-on-the-overview-canvas-ins.md +6 -0
  167. package/corpus/templates/design/changelog/2026-06-29-selecting-a-nested-layer-from-all-screens-now-keeps-you-in-a.md +6 -0
  168. package/corpus/templates/design/changelog/2026-06-29-share-now-groups-link-sharing-exports-and-agent-handoff.md +6 -0
  169. package/corpus/templates/design/changelog/2026-06-29-style-changes-that-set-several-properties-at-once-fixed-size.md +6 -0
  170. package/corpus/templates/design/changelog/2026-06-29-the-design-editor-loading-skeleton-now-uses-a-softer-charcoa.md +6 -0
  171. package/corpus/templates/design/changelog/2026-06-29-the-device-preview-menu-now-sits-next-to-the-preview-button-.md +6 -0
  172. package/corpus/templates/design/changelog/2026-06-29-the-editor-no-longer-crashes-when-a-screen-ends-up-with-dupl.md +6 -0
  173. package/corpus/templates/design/changelog/2026-06-29-the-inspector-stays-read-only-while-an-empty-design-is-still.md +6 -0
  174. package/corpus/templates/design/changelog/2026-06-29-the-missing-design-view-now-matches-the-rest-of-the-editor-c.md +6 -0
  175. package/corpus/templates/design/changelog/2026-06-29-the-pen-tool-icon-and-tool-option-menus-better-match-the-edi.md +6 -0
  176. package/corpus/templates/design/changelog/2026-06-29-typography-controls-now-keep-the-font-name-visible-and-move-.md +6 -0
  177. package/corpus/templates/design/e2e/README.md +4 -3
  178. package/corpus/templates/design/e2e/global-setup.ts +24 -23
  179. package/corpus/templates/design/e2e/helpers.ts +122 -11
  180. package/corpus/templates/design/playwright.config.ts +19 -4
  181. package/corpus/templates/design/server/lib/coding-handoff.ts +126 -2
  182. package/corpus/templates/design/server/plugins/core-routes.ts +1 -2
  183. package/corpus/templates/design/server/routes/api/design-handoff/[id].zip.get.ts +86 -0
  184. package/corpus/templates/design/shared/code-layer.ts +125 -22
  185. package/corpus/templates/design/shared/color-utils.ts +159 -0
  186. package/corpus/templates/design/shared/generation-session.ts +42 -0
  187. package/corpus/templates/dispatch/app/global.css +79 -35
  188. package/corpus/templates/dispatch/app/routes/integrations.tsx +8 -7
  189. package/corpus/templates/dispatch/changelog/2026-06-29-integration-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
  190. package/corpus/templates/forms/app/components/layout/Layout.tsx +6 -2
  191. package/corpus/templates/forms/app/global.css +64 -35
  192. package/corpus/templates/forms/app/pages/FormsListPage.tsx +2 -2
  193. package/corpus/templates/forms/app/pages/ResponseInsightsPage.tsx +3 -3
  194. package/corpus/templates/forms/changelog/2026-06-29-form-list-and-insight-layouts-adapt-when-the-agent-sidebar.md +6 -0
  195. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +3 -1
  196. package/corpus/templates/macros/app/global.css +25 -9
  197. package/corpus/templates/macros/changelog/2026-06-29-macro-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
  198. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +6 -2
  199. package/corpus/templates/mail/app/global.css +42 -36
  200. package/corpus/templates/mail/app/pages/InboxPage.tsx +1 -1
  201. package/corpus/templates/mail/changelog/2026-06-29-the-contact-panel-now-adapts-to-the-available-mail-pane-width.md +6 -0
  202. package/corpus/templates/plan/app/components/layout/Layout.tsx +3 -1
  203. package/corpus/templates/plan/app/components/plan/DocumentArea.tsx +6 -7
  204. package/corpus/templates/plan/app/global.css +74 -42
  205. package/corpus/templates/plan/changelog/2026-06-29-plan-document-blocks-adapt-to-the-available-document-width.md +6 -0
  206. package/corpus/templates/plan/changelog/2026-06-29-plan-titles-and-summaries-can-be-edited-inline-without-focus.md +6 -0
  207. package/corpus/templates/slides/app/components/layout/Layout.tsx +3 -1
  208. package/corpus/templates/slides/app/global.css +49 -33
  209. package/corpus/templates/slides/changelog/2026-06-29-slide-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
  210. package/corpus/templates/videos/app/components/layout/Layout.tsx +3 -1
  211. package/corpus/templates/videos/app/global.css +35 -35
  212. package/corpus/templates/videos/changelog/2026-06-29-video-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
  213. package/dist/cli/mcp.d.ts.map +1 -1
  214. package/dist/cli/mcp.js +10 -0
  215. package/dist/cli/mcp.js.map +1 -1
  216. package/dist/cli/skills.d.ts.map +1 -1
  217. package/dist/cli/skills.js +58 -12
  218. package/dist/cli/skills.js.map +1 -1
  219. package/dist/client/AssistantChat.d.ts.map +1 -1
  220. package/dist/client/AssistantChat.js +54 -24
  221. package/dist/client/AssistantChat.js.map +1 -1
  222. package/dist/client/analytics.d.ts.map +1 -1
  223. package/dist/client/analytics.js +2 -1
  224. package/dist/client/analytics.js.map +1 -1
  225. package/dist/client/error-format.d.ts.map +1 -1
  226. package/dist/client/error-format.js +17 -0
  227. package/dist/client/error-format.js.map +1 -1
  228. package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
  229. package/dist/client/extensions/ExtensionViewer.js +3 -4
  230. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  231. package/dist/client/guided-questions.d.ts +4 -0
  232. package/dist/client/guided-questions.d.ts.map +1 -1
  233. package/dist/client/guided-questions.js +16 -7
  234. package/dist/client/guided-questions.js.map +1 -1
  235. package/dist/client/onboarding/OnboardingPanel.js +26 -1
  236. package/dist/client/onboarding/OnboardingPanel.js.map +1 -1
  237. package/dist/client/resources/BuiltinCapabilityDetail.d.ts.map +1 -1
  238. package/dist/client/resources/BuiltinCapabilityDetail.js +1 -1
  239. package/dist/client/resources/BuiltinCapabilityDetail.js.map +1 -1
  240. package/dist/client/resources/use-builtin-capabilities.d.ts +1 -1
  241. package/dist/client/resources/use-builtin-capabilities.d.ts.map +1 -1
  242. package/dist/client/resources/use-builtin-capabilities.js +2 -1
  243. package/dist/client/resources/use-builtin-capabilities.js.map +1 -1
  244. package/dist/client/session-replay.d.ts.map +1 -1
  245. package/dist/client/session-replay.js +31 -0
  246. package/dist/client/session-replay.js.map +1 -1
  247. package/dist/client/sharing/ShareButton.d.ts +14 -0
  248. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  249. package/dist/client/sharing/ShareButton.js +36 -7
  250. package/dist/client/sharing/ShareButton.js.map +1 -1
  251. package/dist/coding-tools/index.js +1 -1
  252. package/dist/coding-tools/index.js.map +1 -1
  253. package/dist/collab/routes.d.ts +1 -1
  254. package/dist/mcp/index.d.ts +2 -0
  255. package/dist/mcp/index.d.ts.map +1 -1
  256. package/dist/mcp/index.js +1 -0
  257. package/dist/mcp/index.js.map +1 -1
  258. package/dist/mcp/screen-memory-stdio.d.ts +6 -0
  259. package/dist/mcp/screen-memory-stdio.d.ts.map +1 -0
  260. package/dist/mcp/screen-memory-stdio.js +213 -0
  261. package/dist/mcp/screen-memory-stdio.js.map +1 -0
  262. package/dist/mcp-client/builtin-capabilities.d.ts +1 -1
  263. package/dist/mcp-client/builtin-capabilities.d.ts.map +1 -1
  264. package/dist/mcp-client/builtin-capabilities.js +10 -0
  265. package/dist/mcp-client/builtin-capabilities.js.map +1 -1
  266. package/dist/mcp-client/index.d.ts +1 -0
  267. package/dist/mcp-client/index.d.ts.map +1 -1
  268. package/dist/mcp-client/index.js +1 -0
  269. package/dist/mcp-client/index.js.map +1 -1
  270. package/dist/mcp-client/screen-memory-local.d.ts +61 -0
  271. package/dist/mcp-client/screen-memory-local.d.ts.map +1 -0
  272. package/dist/mcp-client/screen-memory-local.js +336 -0
  273. package/dist/mcp-client/screen-memory-local.js.map +1 -0
  274. package/dist/onboarding/types.d.ts +7 -0
  275. package/dist/onboarding/types.d.ts.map +1 -1
  276. package/dist/onboarding/types.js.map +1 -1
  277. package/dist/resources/handlers.d.ts +2 -2
  278. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  279. package/dist/server/agent-chat-plugin.js +26 -0
  280. package/dist/server/agent-chat-plugin.js.map +1 -1
  281. package/dist/server/agents-bundle.d.ts.map +1 -1
  282. package/dist/server/agents-bundle.js +22 -7
  283. package/dist/server/agents-bundle.js.map +1 -1
  284. package/dist/server/transcribe-voice.d.ts +1 -1
  285. package/dist/styles/agent-native.css +5 -0
  286. package/dist/templates/default/app/global.css +35 -35
  287. package/docs/content/locales/ar-SA/template-design.mdx +6 -0
  288. package/docs/content/locales/de-DE/template-design.mdx +8 -0
  289. package/docs/content/locales/es-ES/template-design.mdx +10 -2
  290. package/docs/content/locales/fr-FR/template-design.mdx +10 -2
  291. package/docs/content/locales/hi-IN/template-design.mdx +7 -0
  292. package/docs/content/locales/ja-JP/template-design.mdx +7 -0
  293. package/docs/content/locales/ko-KR/template-design.mdx +7 -0
  294. package/docs/content/locales/pt-BR/template-design.mdx +9 -2
  295. package/docs/content/locales/zh-CN/template-design.mdx +6 -0
  296. package/docs/content/locales/zh-TW/template-design.mdx +6 -0
  297. package/docs/content/template-design.mdx +9 -2
  298. package/package.json +1 -1
  299. package/src/templates/default/app/global.css +35 -35
  300. package/corpus/templates/design/app/components/design/VariantGrid.tsx +0 -189
  301. package/corpus/templates/design/app/components/design/VariantHandoffCard.tsx +0 -115
  302. package/corpus/templates/design/app/hooks/use-variant-flow.ts +0 -258
@@ -228,6 +228,7 @@ function createUserMessageRunConfig(
228
228
 
229
229
  const PENDING_SELECTION_KEY = "pending-selection-context";
230
230
  const ACTIVE_RUN_CLEAR_TIMEOUT_MS = 5_000;
231
+ const ACTIVE_RUN_STUCK_THRESHOLD_MS = 90_000;
231
232
  const ACTIVE_RUN_POLL_INTERVAL_MS = 150;
232
233
  const SUBMIT_ENGINE_STATUS_TIMEOUT_MS = 1000;
233
234
 
@@ -237,15 +238,27 @@ type ActiveRunLookup = {
237
238
  threadId?: string;
238
239
  status?: string;
239
240
  heartbeatAt?: number | null;
241
+ lastProgressAt?: number | null;
242
+ serverNow?: number;
240
243
  };
241
244
 
242
245
  function activeRunLooksStale(runInfo: ActiveRunLookup): boolean {
243
- const heartbeatAt =
244
- typeof runInfo.heartbeatAt === "number" ? runInfo.heartbeatAt : null;
246
+ const lastProgressAt =
247
+ typeof runInfo.lastProgressAt === "number" ? runInfo.lastProgressAt : null;
248
+ const nowMs =
249
+ typeof runInfo.serverNow === "number" ? runInfo.serverNow : Date.now();
245
250
  return (
246
251
  runInfo.status === "running" &&
247
- heartbeatAt != null &&
248
- Date.now() - heartbeatAt > 5000
252
+ lastProgressAt != null &&
253
+ nowMs - lastProgressAt > ACTIVE_RUN_STUCK_THRESHOLD_MS
254
+ );
255
+ }
256
+
257
+ function isAssistantUiDuplicateMessageIdError(error: unknown): boolean {
258
+ const message = error instanceof Error ? error.message : String(error ?? "");
259
+ return (
260
+ message.includes("MessageRepository") &&
261
+ message.includes("same id already exists")
249
262
  );
250
263
  }
251
264
 
@@ -295,14 +308,13 @@ async function waitForThreadRunToClear(apiUrl: string, threadId?: string) {
295
308
  `${apiUrl}/runs/active?threadId=${encodeURIComponent(threadId)}`,
296
309
  );
297
310
  if (res.ok) {
298
- const info = await res.json();
299
- const heartbeatAt =
300
- typeof info?.heartbeatAt === "number" ? info.heartbeatAt : null;
301
- const stale =
302
- info?.status === "running" &&
303
- heartbeatAt != null &&
304
- Date.now() - heartbeatAt > 5000;
305
- if (!info?.active || info?.status !== "running" || stale) return;
311
+ const info = (await res.json()) as ActiveRunLookup;
312
+ if (
313
+ !info?.active ||
314
+ info?.status !== "running" ||
315
+ activeRunLooksStale(info)
316
+ )
317
+ return;
306
318
  }
307
319
  } catch {
308
320
  // Transient poll failure — try again until the short grace period ends.
@@ -1467,9 +1479,40 @@ const AssistantChatInner = forwardRef<
1467
1479
  }
1468
1480
  }, [apiUrl, importThreadData, loadHistoryRepository, threadId]);
1469
1481
 
1482
+ const exportCleanThreadRepo = useCallback(
1483
+ () =>
1484
+ ensureMessageMetadata(normalizeThreadRepository(threadRuntime.export())),
1485
+ [threadRuntime],
1486
+ );
1487
+
1488
+ const appendThreadMessage = useCallback(
1489
+ (message: Parameters<typeof threadRuntime.append>[0]) => {
1490
+ try {
1491
+ threadRuntime.append(message);
1492
+ return;
1493
+ } catch (error) {
1494
+ if (!isAssistantUiDuplicateMessageIdError(error)) throw error;
1495
+ }
1496
+
1497
+ try {
1498
+ threadRuntime.import(exportCleanThreadRepo());
1499
+ } catch {
1500
+ // Best effort cleanup; retry below handles the still-duplicated case.
1501
+ }
1502
+
1503
+ try {
1504
+ threadRuntime.append(message);
1505
+ } catch (retryError) {
1506
+ if (isAssistantUiDuplicateMessageIdError(retryError)) return;
1507
+ throw retryError;
1508
+ }
1509
+ },
1510
+ [exportCleanThreadRepo, threadRuntime],
1511
+ );
1512
+
1470
1513
  const cacheCurrentThreadSnapshot = useCallback(() => {
1471
1514
  if (!threadId || messages.length === 0) return;
1472
- const repo = threadRuntime.export();
1515
+ const repo = exportCleanThreadRepo();
1473
1516
  const threadData = JSON.stringify(stripBase64FromRepo(repo));
1474
1517
  const { title, preview } = extractThreadMeta(repo);
1475
1518
  writeCachedThreadSnapshot(apiUrl, threadId, {
@@ -1478,7 +1521,7 @@ const AssistantChatInner = forwardRef<
1478
1521
  preview,
1479
1522
  messageCount: messages.length,
1480
1523
  });
1481
- }, [apiUrl, messages.length, threadId, threadRuntime]);
1524
+ }, [apiUrl, exportCleanThreadRepo, messages.length, threadId]);
1482
1525
 
1483
1526
  useBrowserLayoutEffect(() => {
1484
1527
  if (hasImportedInitialCachedSnapshotRef.current) return;
@@ -1975,7 +2018,7 @@ const AssistantChatInner = forwardRef<
1975
2018
  const timeSinceLastSave = now - lastSaveTimeRef.current;
1976
2019
  if (timeSinceLastSave < 5000) return;
1977
2020
 
1978
- const repo = threadRuntime.export();
2021
+ const repo = exportCleanThreadRepo();
1979
2022
  const { title, preview } = extractThreadMeta(repo);
1980
2023
  const threadData = JSON.stringify(stripBase64FromRepo(repo));
1981
2024
  const snapshot = {
@@ -1989,7 +2032,7 @@ const AssistantChatInner = forwardRef<
1989
2032
  savedTitleRef.current = title;
1990
2033
  writeCachedThreadSnapshot(apiUrl, threadId, snapshot);
1991
2034
  onSaveThreadRef.current(threadId, snapshot);
1992
- }, [apiUrl, messages, isRunning, threadId, threadRuntime]);
2035
+ }, [apiUrl, exportCleanThreadRepo, messages, isRunning, threadId]);
1993
2036
 
1994
2037
  // Persist full thread data after each completed response
1995
2038
  useEffect(() => {
@@ -1997,7 +2040,7 @@ const AssistantChatInner = forwardRef<
1997
2040
  if (isRunning) return;
1998
2041
  if (messages.length === 0) return;
1999
2042
 
2000
- const repo = threadRuntime.export();
2043
+ const repo = exportCleanThreadRepo();
2001
2044
 
2002
2045
  if (threadId && onSaveThreadRef.current) {
2003
2046
  // Save to server via the hook callback
@@ -2019,7 +2062,7 @@ const AssistantChatInner = forwardRef<
2019
2062
  sessionStorage.setItem(storageKey, JSON.stringify(repo));
2020
2063
  } catch {}
2021
2064
  }
2022
- }, [apiUrl, messages, isRunning, threadId, tabId, threadRuntime]);
2065
+ }, [apiUrl, exportCleanThreadRepo, messages, isRunning, threadId, tabId]);
2023
2066
 
2024
2067
  useEffect(() => {
2025
2068
  onMessageCountChange?.(messages.length);
@@ -2280,7 +2323,7 @@ const AssistantChatInner = forwardRef<
2280
2323
  next.attachments && next.attachments.length > 0
2281
2324
  ? next.attachments
2282
2325
  : (imageAttachments ?? []);
2283
- threadRuntime.append({
2326
+ appendThreadMessage({
2284
2327
  role: "user",
2285
2328
  content: [{ type: "text", text: next.text }],
2286
2329
  ...(messageAttachments.length > 0
@@ -2334,12 +2377,12 @@ const AssistantChatInner = forwardRef<
2334
2377
  };
2335
2378
  }, [
2336
2379
  apiUrl,
2380
+ appendThreadMessage,
2337
2381
  applyLocalQueuedMessages,
2338
2382
  isRestoring,
2339
2383
  isRunning,
2340
2384
  queuedMessages,
2341
2385
  threadId,
2342
- threadRuntime,
2343
2386
  ]);
2344
2387
 
2345
2388
  // Clear frozen reconnect content + forceStopped only on the false→true
@@ -2683,7 +2726,7 @@ const AssistantChatInner = forwardRef<
2683
2726
  },
2684
2727
  ]);
2685
2728
  } else {
2686
- threadRuntime.append({
2729
+ appendThreadMessage({
2687
2730
  role: "user",
2688
2731
  content: [{ type: "text", text: submittedText }],
2689
2732
  ...(messageAttachments.length > 0
@@ -2708,7 +2751,7 @@ const AssistantChatInner = forwardRef<
2708
2751
  execMode,
2709
2752
  isRunning,
2710
2753
  materializeFrozenReconnectContent,
2711
- threadRuntime,
2754
+ appendThreadMessage,
2712
2755
  updateComposerContextItems,
2713
2756
  ],
2714
2757
  );
@@ -2774,7 +2817,7 @@ const AssistantChatInner = forwardRef<
2774
2817
  },
2775
2818
  exportThreadSnapshot() {
2776
2819
  if (messages.length === 0) return null;
2777
- const repo = threadRuntime.export();
2820
+ const repo = exportCleanThreadRepo();
2778
2821
  const { title, preview } = extractThreadMeta(repo);
2779
2822
  return {
2780
2823
  threadData: JSON.stringify(repo),
@@ -2786,10 +2829,10 @@ const AssistantChatInner = forwardRef<
2786
2829
  }),
2787
2830
  [
2788
2831
  addToQueue,
2832
+ exportCleanThreadRepo,
2789
2833
  messages.length,
2790
2834
  stageComposerContextItem,
2791
2835
  thread.isRunning,
2792
- threadRuntime,
2793
2836
  ],
2794
2837
  );
2795
2838
 
@@ -2986,7 +3029,7 @@ const AssistantChatInner = forwardRef<
2986
3029
  const approvalCtx = useMemo<ApprovalContextValue>(
2987
3030
  () => ({
2988
3031
  onApprove: (approvalKey: string) => {
2989
- threadRuntime.append({
3032
+ appendThreadMessage({
2990
3033
  role: "user",
2991
3034
  content: [
2992
3035
  {
@@ -3008,7 +3051,7 @@ const AssistantChatInner = forwardRef<
3008
3051
  } as Parameters<typeof threadRuntime.append>[0]);
3009
3052
  },
3010
3053
  }),
3011
- [threadRuntime, execMode],
3054
+ [appendThreadMessage, execMode],
3012
3055
  );
3013
3056
 
3014
3057
  return (
@@ -3201,7 +3244,7 @@ const AssistantChatInner = forwardRef<
3201
3244
  setMissingKeyBouncePulse((p) => p + 1);
3202
3245
  return;
3203
3246
  }
3204
- threadRuntime.append({
3247
+ appendThreadMessage({
3205
3248
  role: "user",
3206
3249
  content: [{ type: "text", text: suggestion }],
3207
3250
  });
@@ -610,7 +610,9 @@ function isAgentNativeDocsUrl(url: string): boolean {
610
610
 
611
611
  function shouldDropBrowserSentryNoise(event: Sentry.Event): boolean {
612
612
  const exceptionValues = event.exception?.values ?? [];
613
- const requestUrl = event.request?.url?.toLowerCase() ?? "";
613
+ const taggedUrl =
614
+ typeof event.tags?.url === "string" ? event.tags.url : undefined;
615
+ const requestUrl = (event.request?.url ?? taggedUrl ?? "").toLowerCase();
614
616
  const isDocsPage = isAgentNativeDocsUrl(requestUrl);
615
617
  // AgentAutoContinueSignal is a control-flow sentinel thrown to bubble
616
618
  // out of the SSE stream parser when the agent run needs to be
@@ -81,6 +81,23 @@ function isProviderRateLimit(text: string, errorCode?: string): boolean {
81
81
  );
82
82
  }
83
83
 
84
+ function isProviderAuthenticationError(
85
+ text: string,
86
+ errorCode?: string,
87
+ ): boolean {
88
+ const code = normalizeErrorCode(errorCode);
89
+ const lower = text.toLowerCase();
90
+ return (
91
+ code === "authentication_error" ||
92
+ code === "http_401" ||
93
+ lower.includes("invalid x-api-key") ||
94
+ lower.includes("invalid api key") ||
95
+ lower.includes("incorrect api key") ||
96
+ lower.includes("api key is invalid") ||
97
+ (lower.includes("authentication_error") && lower.includes("api"))
98
+ );
99
+ }
100
+
84
101
  export function normalizeChatError(
85
102
  errorMessage: string,
86
103
  errorCode?: string,
@@ -97,6 +114,14 @@ export function normalizeChatError(
97
114
  };
98
115
  }
99
116
 
117
+ if (isProviderAuthenticationError(text, errorCode)) {
118
+ return {
119
+ message:
120
+ "The model provider rejected the saved API key. Update the key in API Keys & Connections, then retry.",
121
+ details: text,
122
+ };
123
+ }
124
+
100
125
  if (/^Gateway error \(no detail; raw event:/i.test(text)) {
101
126
  // The previous copy promised auto-recovery and suggested switching models,
102
127
  // but neither helps for this code: the server already retried once and
@@ -2,7 +2,7 @@ import {
2
2
  IconArrowLeft,
3
3
  IconArrowBackUp,
4
4
  IconChevronRight,
5
- IconDots,
5
+ IconDotsVertical,
6
6
  IconHistory,
7
7
  IconLoader2,
8
8
  IconPencil,
@@ -33,7 +33,6 @@ import {
33
33
  } from "../components/ui/tooltip.js";
34
34
  import { PromptComposer } from "../composer/PromptComposer.js";
35
35
  import { isEmbedMcpChatBridgeActive } from "../embed-auth.js";
36
- import { NotificationsBell } from "../notifications/NotificationsBell.js";
37
36
  import { ShareButton } from "../sharing/ShareButton.js";
38
37
  import {
39
38
  deleteOrHideExtension,
@@ -1162,6 +1161,17 @@ export function ExtensionViewer({ extensionId }: ExtensionViewerProps) {
1162
1161
  extension={extension}
1163
1162
  onOpenChange={onPopoverOpenChange}
1164
1163
  />
1164
+ </>
1165
+ )}
1166
+ <ToolMoreMenu
1167
+ extensionId={extensionId}
1168
+ toolName={extension.name}
1169
+ canDelete={extension.canDelete}
1170
+ sourceMode={extension.source?.mode}
1171
+ onOpenChange={onPopoverOpenChange}
1172
+ />
1173
+ {!isLocalExtension && (
1174
+ <>
1165
1175
  <ShareButton
1166
1176
  resourceType="extension"
1167
1177
  resourceId={extensionId}
@@ -1177,14 +1187,6 @@ export function ExtensionViewer({ extensionId }: ExtensionViewerProps) {
1177
1187
  />
1178
1188
  </>
1179
1189
  )}
1180
- <ToolMoreMenu
1181
- extensionId={extensionId}
1182
- toolName={extension.name}
1183
- canDelete={extension.canDelete}
1184
- sourceMode={extension.source?.mode}
1185
- onOpenChange={onPopoverOpenChange}
1186
- />
1187
- <NotificationsBell onOpenChange={onPopoverOpenChange} />
1188
1190
  <AgentToggleButton />
1189
1191
  </div>
1190
1192
  </div>
@@ -1320,7 +1322,7 @@ function ToolMoreMenu({
1320
1322
  className="inline-flex items-center justify-center rounded-md h-8 w-8 text-muted-foreground hover:bg-accent hover:text-accent-foreground cursor-pointer"
1321
1323
  aria-label="More options"
1322
1324
  >
1323
- <IconDots className="h-4 w-4" />
1325
+ <IconDotsVertical className="h-4 w-4" />
1324
1326
  </button>
1325
1327
  </PopoverTrigger>
1326
1328
  </TooltipTrigger>
@@ -50,6 +50,8 @@ export interface GuidedQuestion {
50
50
  allowOther?: boolean;
51
51
  includeExplore?: boolean;
52
52
  includeDecide?: boolean;
53
+ /** Submit immediately when a single-select option is clicked. */
54
+ submitOnSelect?: boolean;
53
55
  }
54
56
 
55
57
  export type GuidedQuestionAnswers = Record<string, unknown>;
@@ -60,6 +62,8 @@ export interface GuidedQuestionPayload {
60
62
  description?: string;
61
63
  skipLabel?: string;
62
64
  submitLabel?: string;
65
+ submitMessage?: string;
66
+ skipMessage?: string;
63
67
  /**
64
68
  * @internal Set by {@link askUserQuestion} for client-initiated questions.
65
69
  * When present, `useGuidedQuestionFlow` resolves the matching in-memory
@@ -374,6 +378,7 @@ export function guidedQuestionsFingerprint(
374
378
  allowOther: question.allowOther ?? null,
375
379
  includeExplore: question.includeExplore ?? null,
376
380
  includeDecide: question.includeDecide ?? null,
381
+ submitOnSelect: question.submitOnSelect ?? false,
377
382
  min: question.min ?? null,
378
383
  max: question.max ?? null,
379
384
  step: question.step ?? null,
@@ -447,6 +452,11 @@ export function GuidedQuestionFlow({
447
452
  const setAnswer = useCallback((id: string, value: unknown) => {
448
453
  setAnswers((prev) => ({ ...prev, [id]: value }));
449
454
  }, []);
455
+ const submitAnswers = useCallback(
456
+ (nextAnswers: GuidedQuestionAnswers = answers) =>
457
+ onSubmit(normalizeGuidedAnswers(nextAnswers)),
458
+ [answers, onSubmit],
459
+ );
450
460
 
451
461
  const allRequiredAnswered = questions
452
462
  .filter((question) => question.required)
@@ -484,6 +494,9 @@ export function GuidedQuestionFlow({
484
494
  question={question}
485
495
  value={answers[question.id]}
486
496
  onChange={(value) => setAnswer(question.id, value)}
497
+ onSubmitAnswer={(value) =>
498
+ submitAnswers({ ...answers, [question.id]: value })
499
+ }
487
500
  />
488
501
  ))}
489
502
  </div>
@@ -512,7 +525,7 @@ export function GuidedQuestionFlow({
512
525
  </button>
513
526
  <button
514
527
  type="button"
515
- onClick={() => onSubmit(normalizeGuidedAnswers(answers))}
528
+ onClick={() => submitAnswers()}
516
529
  disabled={!allRequiredAnswered}
517
530
  className="inline-flex cursor-pointer items-center gap-2 rounded-md bg-primary px-3.5 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-45"
518
531
  >
@@ -531,11 +544,13 @@ function QuestionCard({
531
544
  question,
532
545
  value,
533
546
  onChange,
547
+ onSubmitAnswer,
534
548
  }: {
535
549
  index: number;
536
550
  question: GuidedQuestion;
537
551
  value: unknown;
538
552
  onChange: (value: unknown) => void;
553
+ onSubmitAnswer: (value: unknown) => void;
539
554
  }) {
540
555
  return (
541
556
  <section className="rounded-lg border border-border bg-card/65 p-4 shadow-sm">
@@ -564,7 +579,12 @@ function QuestionCard({
564
579
  </div>
565
580
 
566
581
  {question.type === "text-options" && (
567
- <TextOptions question={question} value={value} onChange={onChange} />
582
+ <TextOptions
583
+ question={question}
584
+ value={value}
585
+ onChange={onChange}
586
+ onSubmitAnswer={onSubmitAnswer}
587
+ />
568
588
  )}
569
589
  {question.type === "color-options" && (
570
590
  <ColorOptions question={question} value={value} onChange={onChange} />
@@ -591,10 +611,12 @@ function TextOptions({
591
611
  question,
592
612
  value,
593
613
  onChange,
614
+ onSubmitAnswer,
594
615
  }: {
595
616
  question: GuidedQuestion;
596
617
  value: unknown;
597
618
  onChange: (value: unknown) => void;
619
+ onSubmitAnswer: (value: unknown) => void;
598
620
  }) {
599
621
  const options = useMemo(() => withDefaultOptions(question), [question]);
600
622
  const multiSelect = question.multiSelect === true;
@@ -612,6 +634,7 @@ function TextOptions({
612
634
  const toggleOption = (optionValue: string) => {
613
635
  if (!multiSelect) {
614
636
  onChange(optionValue);
637
+ if (question.submitOnSelect) onSubmitAnswer(optionValue);
615
638
  return;
616
639
  }
617
640
  const next = selectedValues.includes(optionValue)
@@ -1060,6 +1083,7 @@ export function useGuidedQuestionFlow({
1060
1083
  return;
1061
1084
  }
1062
1085
  const formattedAnswers = formatGuidedAnswersForAgent(answers);
1086
+ const resolvedSubmitMessage = payload?.submitMessage ?? submitMessage;
1063
1087
  const context =
1064
1088
  buildSubmitContext?.({ answers, formattedAnswers }) ??
1065
1089
  [
@@ -1068,7 +1092,11 @@ export function useGuidedQuestionFlow({
1068
1092
  "Answers:",
1069
1093
  formattedAnswers,
1070
1094
  ].join("\n");
1071
- sendToAgentChat({ message: submitMessage, context, submit: true });
1095
+ sendToAgentChat({
1096
+ message: resolvedSubmitMessage,
1097
+ context,
1098
+ submit: true,
1099
+ });
1072
1100
  clear();
1073
1101
  },
1074
1102
  [buildSubmitContext, clear, payload, submitMessage],
@@ -1082,7 +1110,7 @@ export function useGuidedQuestionFlow({
1082
1110
  return;
1083
1111
  }
1084
1112
  sendToAgentChat({
1085
- message: skipMessage,
1113
+ message: payload?.skipMessage ?? skipMessage,
1086
1114
  context: buildSkipContext?.(),
1087
1115
  submit: true,
1088
1116
  });
@@ -570,7 +570,7 @@ function FormMethod({
570
570
  method: Extract<OnboardingMethod, { kind: "form" }>;
571
571
  onCompleted: () => Promise<void>;
572
572
  }) {
573
- const { fields, writeScope } = method.payload;
573
+ const { fields, writeScope, saveTo, secretDescription } = method.payload;
574
574
  const [values, setValues] = useState<Record<string, string>>({});
575
575
  const [saving, setSaving] = useState(false);
576
576
  const [err, setErr] = useState<string | null>(null);
@@ -587,6 +587,38 @@ function FormMethod({
587
587
  setErr("Enter a value first.");
588
588
  return;
589
589
  }
590
+ if (saveTo === "scoped-secrets") {
591
+ const secretScope =
592
+ writeScope === "workspace" || writeScope === "app"
593
+ ? "workspace"
594
+ : "user";
595
+ for (const entry of vars) {
596
+ const res = await fetch(
597
+ agentNativePath("/_agent-native/secrets/adhoc"),
598
+ {
599
+ method: "POST",
600
+ headers: { "Content-Type": "application/json" },
601
+ body: JSON.stringify({
602
+ name: entry.key,
603
+ value: entry.value,
604
+ scope: secretScope,
605
+ description:
606
+ secretDescription ?? method.description ?? "Setup key",
607
+ }),
608
+ },
609
+ );
610
+ if (!res.ok) {
611
+ const data = await res.json().catch(() => ({}));
612
+ throw new Error(
613
+ (data as { error?: string }).error ??
614
+ `Save failed: ${res.status}`,
615
+ );
616
+ }
617
+ }
618
+ setValues({});
619
+ await onCompleted();
620
+ return;
621
+ }
590
622
  const res = await fetch(agentNativePath("/_agent-native/env-vars"), {
591
623
  method: "POST",
592
624
  headers: { "Content-Type": "application/json" },
@@ -151,6 +151,14 @@ export function BuiltinCapabilityDetail({
151
151
  existing login.
152
152
  </p>
153
153
  )}
154
+
155
+ {capability.id === "screen-memory" && (
156
+ <p className="mt-6 rounded-md border border-border bg-muted/40 p-2.5 text-[11px] leading-relaxed text-muted-foreground">
157
+ Screen Memory only reads local Clips desktop context on this
158
+ machine. Turn it on from Clips desktop Settings before expecting
159
+ recent context results.
160
+ </p>
161
+ )}
154
162
  </div>
155
163
  </div>
156
164
  );
@@ -6,7 +6,8 @@ import type { McpServerScope } from "./use-mcp-servers.js";
6
6
  export type BuiltinCapabilityId =
7
7
  | "browser-chrome-devtools"
8
8
  | "browser-playwright"
9
- | "computer-use";
9
+ | "computer-use"
10
+ | "screen-memory";
10
11
 
11
12
  export interface BuiltinCapability {
12
13
  id: BuiltinCapabilityId;
@@ -103,7 +104,8 @@ export function parseMcpBuiltinVirtualId(
103
104
  if (
104
105
  capabilityId !== "browser-chrome-devtools" &&
105
106
  capabilityId !== "browser-playwright" &&
106
- capabilityId !== "computer-use"
107
+ capabilityId !== "computer-use" &&
108
+ capabilityId !== "screen-memory"
107
109
  ) {
108
110
  return null;
109
111
  }
@@ -191,6 +191,7 @@ const DEFAULT_FLUSH_INTERVAL_MS = 5000;
191
191
  const DEFAULT_MAX_DURATION_MS = 30 * 60 * 1000;
192
192
  const DEFAULT_MAX_EVENTS_PER_BATCH = 50;
193
193
  const DEFAULT_MAX_BATCH_BYTES = 256 * 1024;
194
+ const MAX_KEEPALIVE_REPLAY_UPLOAD_BYTES = 60 * 1024;
194
195
  const URL_LIKE_KEYS = new Set([
195
196
  "url",
196
197
  "uri",
@@ -729,6 +730,24 @@ interface ReplayUploadBody {
729
730
  compressed: boolean;
730
731
  }
731
732
 
733
+ function isCrossOriginReplayEndpoint(endpoint: string): boolean {
734
+ if (typeof window === "undefined") return false;
735
+ try {
736
+ return (
737
+ new URL(endpoint, window.location.href).origin !== window.location.origin
738
+ );
739
+ } catch {
740
+ return false;
741
+ }
742
+ }
743
+
744
+ function replayUploadByteLength(body: string): number {
745
+ if (typeof TextEncoder !== "undefined") {
746
+ return new TextEncoder().encode(body).byteLength;
747
+ }
748
+ return body.length;
749
+ }
750
+
732
751
  async function gzipReplayBody(body: string): Promise<Blob | null> {
733
752
  if (
734
753
  typeof CompressionStream === "undefined" ||
@@ -773,6 +792,21 @@ async function sendReplayUpload(
773
792
  options: NormalizedSessionReplayOptions,
774
793
  body: string,
775
794
  ): Promise<void> {
795
+ if (isCrossOriginReplayEndpoint(options.endpoint)) {
796
+ if (navigator.sendBeacon) {
797
+ const sent = navigator.sendBeacon(options.endpoint, body);
798
+ if (sent) return;
799
+ }
800
+ await fetch(options.endpoint, {
801
+ method: "POST",
802
+ body,
803
+ keepalive:
804
+ replayUploadByteLength(body) <= MAX_KEEPALIVE_REPLAY_UPLOAD_BYTES,
805
+ headers: { "Content-Type": "text/plain;charset=UTF-8" },
806
+ }).catch(() => {});
807
+ return;
808
+ }
809
+
776
810
  const upload = await buildReplayUploadBody(body);
777
811
  if (!upload.compressed && navigator.sendBeacon) {
778
812
  const sent = navigator.sendBeacon(options.endpoint, body);