@agent-native/core 0.79.27 → 0.80.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (497) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +34 -0
  3. package/corpus/core/docs/content/locales/ar-SA/skills-guide.mdx +5 -0
  4. package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +55 -1
  5. package/corpus/core/docs/content/locales/de-DE/skills-guide.mdx +5 -0
  6. package/corpus/core/docs/content/locales/de-DE/template-design.mdx +66 -1
  7. package/corpus/core/docs/content/locales/es-ES/skills-guide.mdx +5 -0
  8. package/corpus/core/docs/content/locales/es-ES/template-design.mdx +65 -1
  9. package/corpus/core/docs/content/locales/fr-FR/skills-guide.mdx +5 -0
  10. package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +64 -1
  11. package/corpus/core/docs/content/locales/hi-IN/skills-guide.mdx +5 -0
  12. package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +59 -1
  13. package/corpus/core/docs/content/locales/ja-JP/skills-guide.mdx +5 -0
  14. package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +62 -1
  15. package/corpus/core/docs/content/locales/ko-KR/skills-guide.mdx +5 -0
  16. package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +58 -1
  17. package/corpus/core/docs/content/locales/pt-BR/skills-guide.mdx +5 -0
  18. package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +62 -1
  19. package/corpus/core/docs/content/locales/zh-CN/skills-guide.mdx +5 -0
  20. package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +50 -1
  21. package/corpus/core/docs/content/locales/zh-TW/skills-guide.mdx +5 -0
  22. package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +52 -1
  23. package/corpus/core/docs/content/skills-guide.mdx +5 -0
  24. package/corpus/core/docs/content/template-design.mdx +59 -1
  25. package/corpus/core/package.json +2 -1
  26. package/corpus/core/src/agent/engine/index.ts +1 -0
  27. package/corpus/core/src/agent/engine/registry.ts +40 -0
  28. package/corpus/core/src/agent/production-agent.ts +6 -2
  29. package/corpus/core/src/application-state/handlers.ts +1 -1
  30. package/corpus/core/src/brand-kit/index.ts +1 -1
  31. package/corpus/core/src/cli/design-connect.ts +490 -0
  32. package/corpus/core/src/cli/index.ts +16 -0
  33. package/corpus/core/src/cli/skills.ts +144 -3
  34. package/corpus/core/src/client/AgentPanel.tsx +1 -1
  35. package/corpus/core/src/client/AssistantChat.tsx +43 -7
  36. package/corpus/core/src/client/MultiTabAssistantChat.tsx +1 -1
  37. package/corpus/core/src/client/agent-chat.ts +27 -3
  38. package/corpus/core/src/client/blocks/library/MermaidBlock.tsx +1 -1
  39. package/corpus/core/src/client/blocks/library/diagram.tsx +2 -2
  40. package/corpus/core/src/client/blocks/library/wireframe.tsx +1 -1
  41. package/corpus/core/src/client/chat/message-components.tsx +1 -1
  42. package/corpus/core/src/client/chat-model-groups.ts +1 -2
  43. package/corpus/core/src/client/components/LiveCursorOverlay.tsx +33 -66
  44. package/corpus/core/src/client/composer/TiptapComposer.tsx +99 -24
  45. package/corpus/core/src/client/composer/useVoiceDictation.ts +429 -260
  46. package/corpus/core/src/client/extensions/portable-extension.ts +1 -1
  47. package/corpus/core/src/client/frame-protocol.ts +17 -2
  48. package/corpus/core/src/client/rich-markdown-editor/RegistryBlockNode.tsx +2 -2
  49. package/corpus/core/src/client/sharing/ShareButton.tsx +20 -15
  50. package/corpus/core/src/client/use-agent-engine-configured.ts +80 -28
  51. package/corpus/core/src/code-agents/transcript-normalizer.ts +1 -1
  52. package/corpus/core/src/extensions/path.ts +1 -4
  53. package/corpus/core/src/integrations/a2a-continuation-processor.ts +1 -1
  54. package/corpus/core/src/mcp/build-server.ts +1 -1
  55. package/corpus/core/src/org/handlers.ts +5 -5
  56. package/corpus/core/src/org/plugin.ts +2 -2
  57. package/corpus/core/src/scripts/call-agent.ts +1 -1
  58. package/corpus/core/src/scripts/db/safety.ts +1 -1
  59. package/corpus/core/src/server/auth.ts +3 -0
  60. package/corpus/core/src/server/builder-design-systems.ts +308 -0
  61. package/corpus/core/src/server/core-routes-plugin.ts +29 -3
  62. package/corpus/core/src/server/index.ts +8 -0
  63. package/corpus/core/src/server/transcribe-voice.ts +57 -22
  64. package/corpus/core/src/shared/mcp-embed-headers.ts +23 -1
  65. package/corpus/core/src/styles/agent-native.css +60 -4
  66. package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +10 -0
  67. package/corpus/core/src/usage/store.ts +2 -2
  68. package/corpus/core/src/vite/client.ts +2 -0
  69. package/corpus/core/src/voice/index.ts +18 -0
  70. package/corpus/core/src/voice/voice-cleanup-prompt.ts +38 -0
  71. package/corpus/core/src/voice/voice-context.ts +217 -0
  72. package/corpus/core/src/voice/voice-replacements.ts +75 -0
  73. package/corpus/templates/analytics/AGENTS.md +4 -3
  74. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +298 -15
  75. package/corpus/templates/analytics/actions/get-sql-dashboard.ts +9 -4
  76. package/corpus/templates/analytics/actions/list-session-recordings.ts +6 -1
  77. package/corpus/templates/analytics/actions/mutate-dashboard.ts +18 -2
  78. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +12 -2
  79. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +557 -400
  80. package/corpus/templates/analytics/app/global.css +0 -4
  81. package/corpus/templates/analytics/app/hooks/use-replay-storage-status.ts +66 -0
  82. package/corpus/templates/analytics/app/i18n/zh-TW.ts +39 -0
  83. package/corpus/templates/analytics/app/i18n-data.ts +424 -0
  84. package/corpus/templates/analytics/app/pages/Settings.tsx +333 -0
  85. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +2 -1
  86. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +121 -3
  87. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +82 -34
  88. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +7 -0
  89. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +144 -36
  90. package/corpus/templates/analytics/changelog/2026-06-28-ask-tab-now-matches-the-darker-app-background.md +6 -0
  91. package/corpus/templates/analytics/changelog/2026-06-28-dashboard-email-reports-now-use-cleaner-light-mode-snapshots.md +6 -0
  92. package/corpus/templates/analytics/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  93. package/corpus/templates/analytics/changelog/2026-06-28-sessions-now-show-only-signed-in-recordings-with-playable-re.md +6 -0
  94. package/corpus/templates/analytics/changelog/2026-06-29-analytics-agents-can-now-place-new-charts-into-requested-das.md +6 -0
  95. package/corpus/templates/analytics/changelog/2026-06-29-analytics-queries-now-report-failed-source-query-errors-inst.md +6 -0
  96. package/corpus/templates/analytics/changelog/2026-06-29-charts-can-now-be-dropped-between-full-dashboard-rows-to-cre.md +6 -0
  97. package/corpus/templates/analytics/changelog/2026-06-29-dashboard-email-reports-include-the-full-dashboard-image-wit.md +6 -0
  98. package/corpus/templates/analytics/changelog/2026-06-29-main-surface-border-reaches-the-top.md +6 -0
  99. package/corpus/templates/analytics/changelog/2026-06-29-session-replay-now-records-playable-sessions-in-production-a.md +6 -0
  100. package/corpus/templates/analytics/changelog/2026-06-29-set-up-session-replay-storage-from-settings-connect-builder-.md +6 -0
  101. package/corpus/templates/analytics/scripts/cleanup-empty-session-recordings.ts +102 -0
  102. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +3 -3
  103. package/corpus/templates/analytics/server/lib/dashboard-report.ts +75 -30
  104. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +5 -2
  105. package/corpus/templates/analytics/server/lib/real-data-actions.ts +81 -20
  106. package/corpus/templates/analytics/server/lib/replay-storage.ts +79 -0
  107. package/corpus/templates/analytics/server/lib/s3-upload-provider.ts +255 -0
  108. package/corpus/templates/analytics/server/lib/session-replay.ts +53 -12
  109. package/corpus/templates/analytics/server/plugins/agent-chat.ts +11 -2
  110. package/corpus/templates/analytics/server/plugins/onboarding.ts +97 -0
  111. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +4 -4
  112. package/corpus/templates/assets/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  113. package/corpus/templates/brain/app/components/layout/Layout.tsx +29 -2
  114. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +131 -42
  115. package/corpus/templates/brain/app/i18n/zh-TW.ts +2 -0
  116. package/corpus/templates/brain/app/i18n-data.ts +20 -0
  117. package/corpus/templates/brain/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  118. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +29 -1
  119. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +417 -299
  120. package/corpus/templates/calendar/app/i18n/zh-TW.ts +2 -0
  121. package/corpus/templates/calendar/app/i18n-data.ts +20 -0
  122. package/corpus/templates/calendar/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  123. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +6 -19
  124. package/corpus/templates/chat/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  125. package/corpus/templates/clips/AGENTS.md +4 -0
  126. package/corpus/templates/clips/actions/cleanup-transcript.ts +39 -9
  127. package/corpus/templates/clips/actions/finalize-meeting.ts +81 -12
  128. package/corpus/templates/clips/actions/lib/agents-md-context.ts +4 -1
  129. package/corpus/templates/clips/app/components/library/library-layout.tsx +3 -3
  130. package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +1 -1
  131. package/corpus/templates/clips/app/components/player/share-dialog.tsx +2 -2
  132. package/corpus/templates/clips/changelog/2026-06-28-left-sidebar-footer-controls-use-less-divider-chrome.md +6 -0
  133. package/corpus/templates/clips/desktop/src/lib/personal-vocabulary.ts +13 -8
  134. package/corpus/templates/clips/desktop/src/lib/recorder.ts +24 -0
  135. package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +105 -5
  136. package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +60 -1
  137. package/corpus/templates/content/actions/set-image-alt-text.ts +1 -1
  138. package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +1 -1
  139. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +1 -1
  140. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +5 -5
  141. package/corpus/templates/content/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  142. package/corpus/templates/content/shared/document-export.ts +1 -1
  143. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +8 -18
  144. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +154 -0
  145. package/corpus/templates/design/AGENTS.md +95 -5
  146. package/corpus/templates/design/DESIGN.md +82 -0
  147. package/corpus/templates/design/DEVELOPING.md +43 -0
  148. package/corpus/templates/design/actions/add-localhost-screens.ts +453 -0
  149. package/corpus/templates/design/actions/apply-shader.ts +277 -0
  150. package/corpus/templates/design/actions/apply-visual-edit.ts +303 -0
  151. package/corpus/templates/design/actions/connect-localhost.ts +183 -0
  152. package/corpus/templates/design/actions/edit-design.ts +195 -42
  153. package/corpus/templates/design/actions/generate-design.ts +71 -1
  154. package/corpus/templates/design/actions/generate-screens.ts +193 -0
  155. package/corpus/templates/design/actions/get-code-layer-projection.ts +191 -0
  156. package/corpus/templates/design/actions/get-shader.ts +119 -0
  157. package/corpus/templates/design/actions/index-design-system-with-builder.ts +259 -0
  158. package/corpus/templates/design/actions/list-localhost-connections.ts +95 -0
  159. package/corpus/templates/design/actions/navigate.ts +55 -2
  160. package/corpus/templates/design/actions/update-file.ts +9 -2
  161. package/corpus/templates/design/actions/view-screen.ts +68 -1
  162. package/corpus/templates/design/agent-native.app-skill.json +10 -0
  163. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +719 -0
  164. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +2120 -103
  165. package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +74 -38
  166. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +401 -0
  167. package/corpus/templates/design/app/components/design/EditPanel.tsx +3966 -440
  168. package/corpus/templates/design/app/components/design/LayersPanel.tsx +1473 -0
  169. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +3940 -147
  170. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +700 -13
  171. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +105 -63
  172. package/corpus/templates/design/app/components/design/index.ts +0 -5
  173. package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +353 -0
  174. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +1589 -0
  175. package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +511 -0
  176. package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +395 -0
  177. package/corpus/templates/design/app/components/design/inspector/FigmaColorPicker.tsx +2010 -0
  178. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +601 -0
  179. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +242 -0
  180. package/corpus/templates/design/app/components/design/inspector/SHADER_INTEGRATION.md +420 -0
  181. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +238 -0
  182. package/corpus/templates/design/app/components/design/inspector/ShaderControls.stories.tsx +71 -0
  183. package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +575 -0
  184. package/corpus/templates/design/app/components/design/inspector/ShaderEffectRow.tsx +106 -0
  185. package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +423 -0
  186. package/corpus/templates/design/app/components/design/inspector/figma-icons.tsx +741 -0
  187. package/corpus/templates/design/app/components/design/inspector/index.ts +87 -0
  188. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +201 -0
  189. package/corpus/templates/design/app/components/design/types.ts +23 -0
  190. package/corpus/templates/design/app/components/layout/Layout.tsx +24 -13
  191. package/corpus/templates/design/app/components/layout/Sidebar.tsx +4 -4
  192. package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +474 -36
  193. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +22 -5
  194. package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +24 -11
  195. package/corpus/templates/design/app/global.css +149 -5
  196. package/corpus/templates/design/app/hooks/use-agent-generating.ts +4 -0
  197. package/corpus/templates/design/app/hooks/use-navigation-state.ts +130 -8
  198. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +329 -0
  199. package/corpus/templates/design/app/i18n/zh-TW.ts +277 -0
  200. package/corpus/templates/design/app/i18n-data.ts +3028 -1
  201. package/corpus/templates/design/app/pages/DesignEditor.tsx +5831 -904
  202. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +57 -221
  203. package/corpus/templates/design/changelog/2026-06-28-annotate-mode-now-combines-drawing-and-comment-pins-in-one-c.md +6 -0
  204. package/corpus/templates/design/changelog/2026-06-28-design-editor-panel-borders-are-cleaner-so-the-canvas-edge-s.md +6 -0
  205. package/corpus/templates/design/changelog/2026-06-28-drawing-prompts-now-reliably-open-and-submit-to-the-design-a.md +6 -0
  206. package/corpus/templates/design/changelog/2026-06-28-editor-app-menus-now-use-an-outline-agent-native-mark-with-b.md +6 -0
  207. package/corpus/templates/design/changelog/2026-06-28-figma-style-code-design-mode.md +6 -0
  208. package/corpus/templates/design/changelog/2026-06-28-layer-selection-now-updates-chat-context-without-opening-the.md +6 -0
  209. package/corpus/templates/design/changelog/2026-06-28-layer-selections-now-preserve-hidden-and-locked-canvas-state.md +6 -0
  210. package/corpus/templates/design/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  211. package/corpus/templates/design/changelog/2026-06-28-live-cursors-now-keep-names-beside-a-cleaner-pointer-marker.md +6 -0
  212. package/corpus/templates/design/changelog/2026-06-28-mode-switching-now-lives-in-a-compact-bottom-right-icon-dock.md +6 -0
  213. package/corpus/templates/design/changelog/2026-06-28-screen-overview-now-handles-zooming-drawing-opening-and-dele.md +6 -0
  214. package/corpus/templates/design/changelog/2026-06-28-screen-overview-now-selects-screens-on-click-and-opens-them-.md +6 -0
  215. package/corpus/templates/design/changelog/2026-06-28-screen-overview-zooms-into-the-active-screen-with-smoother-e.md +6 -0
  216. package/corpus/templates/design/changelog/2026-06-28-selected-element-chips-in-chat-are-shorter-and-easier-to-sca.md +6 -0
  217. package/corpus/templates/design/changelog/2026-06-28-the-design-editor-toolbar-is-more-compact-and-the-app-menu-m.md +6 -0
  218. package/corpus/templates/design/changelog/2026-06-28-tweaks-now-live-at-the-top-of-the-design-sidebar-instead-of-.md +6 -0
  219. package/corpus/templates/design/changelog/2026-06-28-tweaks-now-live-in-the-right-inspector-beside-the-design-tab.md +6 -0
  220. package/corpus/templates/design/changelog/2026-06-29-active-sidebar-rows-use-soft-highlights.md +6 -0
  221. package/corpus/templates/design/changelog/2026-06-29-agents-can-now-open-screen-overview-focus-screens-and-add.md +6 -0
  222. package/corpus/templates/design/changelog/2026-06-29-canvas-selection-no-longer-flashes-broken-prototype-html-whe.md +6 -0
  223. package/corpus/templates/design/changelog/2026-06-29-command-menu-selections-are-clearer-in-dark-mode.md +6 -0
  224. package/corpus/templates/design/changelog/2026-06-29-design-agents-now-edit-broad-copy-changes-more-reliably.md +6 -0
  225. package/corpus/templates/design/changelog/2026-06-29-design-editor-extensions-now-run-inline-beside-the-artboard.md +6 -0
  226. package/corpus/templates/design/changelog/2026-06-29-design-mode-top-chrome-now-groups-collaborators-preview-shar.md +6 -0
  227. package/corpus/templates/design/changelog/2026-06-29-element-selection-now-stays-on-the-intended-layer-after-sele.md +6 -0
  228. package/corpus/templates/design/changelog/2026-06-29-screen-overview-full-view-controls-now-sit-above-frames-inst.md +6 -0
  229. package/corpus/templates/design/changelog/2026-06-29-screen-overview-tools-can-draw-shapes-create-screens-and-kee.md +6 -0
  230. package/corpus/templates/design/changelog/2026-06-29-sidebars-use-darker-chrome-and-chat-warns-immediately.md +6 -0
  231. package/corpus/templates/design/changelog/2026-06-29-the-pen-tool-now-creates-anchor-based-bezier-vectors-with-ha.md +6 -0
  232. package/corpus/templates/design/changelog/2026-06-29-visual-edit-can-open-localhost-routes-as-url-backed-screens.md +6 -0
  233. package/corpus/templates/design/package.json +1 -0
  234. package/corpus/templates/design/server/db/schema.ts +26 -0
  235. package/corpus/templates/design/server/handlers/import-figma-system.ts +38 -85
  236. package/corpus/templates/design/server/lib/design-snapshot.ts +9 -1
  237. package/corpus/templates/design/server/plugins/agent-chat.ts +3 -0
  238. package/corpus/templates/design/shared/api.ts +27 -0
  239. package/corpus/templates/design/shared/canvas-frames.ts +103 -0
  240. package/corpus/templates/design/shared/canvas-math.ts +1058 -0
  241. package/corpus/templates/design/shared/code-layer.ts +2412 -0
  242. package/corpus/templates/design/shared/color-utils.ts +180 -0
  243. package/corpus/templates/design/shared/generation-session.ts +61 -0
  244. package/corpus/templates/design/shared/html-content.ts +21 -0
  245. package/corpus/templates/design/shared/pen-path.ts +207 -0
  246. package/corpus/templates/design/shared/shader-presets.ts +782 -0
  247. package/corpus/templates/design/shared/shader-safety.ts +137 -0
  248. package/corpus/templates/design/shared/source-mode.ts +237 -0
  249. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +149 -6
  250. package/corpus/templates/forms/app/i18n/ar-SA.ts +2 -0
  251. package/corpus/templates/forms/app/i18n/de-DE.ts +2 -0
  252. package/corpus/templates/forms/app/i18n/en-US.ts +2 -0
  253. package/corpus/templates/forms/app/i18n/es-ES.ts +2 -0
  254. package/corpus/templates/forms/app/i18n/fr-FR.ts +2 -0
  255. package/corpus/templates/forms/app/i18n/hi-IN.ts +2 -0
  256. package/corpus/templates/forms/app/i18n/ja-JP.ts +2 -0
  257. package/corpus/templates/forms/app/i18n/ko-KR.ts +2 -0
  258. package/corpus/templates/forms/app/i18n/pt-BR.ts +2 -0
  259. package/corpus/templates/forms/app/i18n/zh-CN.ts +2 -0
  260. package/corpus/templates/forms/app/i18n/zh-TW.ts +2 -0
  261. package/corpus/templates/forms/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  262. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +2 -2
  263. package/corpus/templates/macros/changelog/2026-06-28-left-sidebar-footer-controls-use-less-divider-chrome.md +6 -0
  264. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +408 -247
  265. package/corpus/templates/mail/app/i18n/ar-SA.ts +4 -0
  266. package/corpus/templates/mail/app/i18n/de-DE.ts +4 -0
  267. package/corpus/templates/mail/app/i18n/en-US.ts +4 -0
  268. package/corpus/templates/mail/app/i18n/es-ES.ts +4 -0
  269. package/corpus/templates/mail/app/i18n/fr-FR.ts +4 -0
  270. package/corpus/templates/mail/app/i18n/hi-IN.ts +4 -0
  271. package/corpus/templates/mail/app/i18n/ja-JP.ts +4 -0
  272. package/corpus/templates/mail/app/i18n/ko-KR.ts +4 -0
  273. package/corpus/templates/mail/app/i18n/pt-BR.ts +4 -0
  274. package/corpus/templates/mail/app/i18n/zh-CN.ts +4 -0
  275. package/corpus/templates/mail/app/i18n/zh-TW.ts +4 -0
  276. package/corpus/templates/mail/app/lib/utils.ts +2 -2
  277. package/corpus/templates/mail/changelog/2026-06-28-pinned-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  278. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +6 -8
  279. package/corpus/templates/plan/app/components/plan/wireframe/Wireframe.tsx +1 -1
  280. package/corpus/templates/plan/app/global.css +61 -78
  281. package/corpus/templates/plan/app/pages/PlansPage.tsx +8 -0
  282. package/corpus/templates/plan/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  283. package/corpus/templates/plan/changelog/2026-06-28-plans-use-the-shared-neutral-light-and-dark-theme.md +6 -0
  284. package/corpus/templates/plan/changelog/2026-06-28-sending-open-feedback-from-a-plan-now-opens-the-inline-plan-.md +6 -0
  285. package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +9 -10
  286. package/corpus/templates/slides/AGENTS.md +3 -2
  287. package/corpus/templates/slides/actions/import-file.ts +26 -17
  288. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +259 -0
  289. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +35 -167
  290. package/corpus/templates/slides/app/components/design-system/fig-import-response.ts +9 -13
  291. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +5 -5
  292. package/corpus/templates/slides/app/context/DeckContext.tsx +1 -1
  293. package/corpus/templates/slides/app/i18n/ar-SA.ts +9 -37
  294. package/corpus/templates/slides/app/i18n/de-DE.ts +10 -25
  295. package/corpus/templates/slides/app/i18n/en-US.ts +9 -26
  296. package/corpus/templates/slides/app/i18n/es-ES.ts +10 -28
  297. package/corpus/templates/slides/app/i18n/fr-FR.ts +10 -28
  298. package/corpus/templates/slides/app/i18n/hi-IN.ts +9 -26
  299. package/corpus/templates/slides/app/i18n/ja-JP.ts +10 -22
  300. package/corpus/templates/slides/app/i18n/ko-KR.ts +9 -23
  301. package/corpus/templates/slides/app/i18n/pt-BR.ts +10 -28
  302. package/corpus/templates/slides/app/i18n/zh-CN.ts +9 -22
  303. package/corpus/templates/slides/app/i18n/zh-TW.ts +9 -22
  304. package/corpus/templates/slides/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  305. package/corpus/templates/slides/server/handlers/import-figma-system.ts +44 -12
  306. package/corpus/templates/slides/server/lib/chat-attachments.ts +1 -1
  307. package/corpus/templates/videos/app/components/NewCompositionPopover.tsx +1 -1
  308. package/corpus/templates/videos/app/components/Sidebar.tsx +2 -2
  309. package/corpus/templates/videos/app/components/layout/Layout.tsx +29 -2
  310. package/corpus/templates/videos/app/components/layout/NavSidebar.tsx +113 -30
  311. package/corpus/templates/videos/app/i18n/ar-SA.ts +2 -0
  312. package/corpus/templates/videos/app/i18n/de-DE.ts +2 -0
  313. package/corpus/templates/videos/app/i18n/en-US.ts +2 -0
  314. package/corpus/templates/videos/app/i18n/es-ES.ts +2 -0
  315. package/corpus/templates/videos/app/i18n/fr-FR.ts +2 -0
  316. package/corpus/templates/videos/app/i18n/hi-IN.ts +2 -0
  317. package/corpus/templates/videos/app/i18n/ja-JP.ts +2 -0
  318. package/corpus/templates/videos/app/i18n/ko-KR.ts +2 -0
  319. package/corpus/templates/videos/app/i18n/pt-BR.ts +2 -0
  320. package/corpus/templates/videos/app/i18n/zh-CN.ts +2 -0
  321. package/corpus/templates/videos/app/i18n/zh-TW.ts +2 -0
  322. package/corpus/templates/videos/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  323. package/dist/agent/engine/index.d.ts +1 -1
  324. package/dist/agent/engine/index.d.ts.map +1 -1
  325. package/dist/agent/engine/index.js +1 -1
  326. package/dist/agent/engine/index.js.map +1 -1
  327. package/dist/agent/engine/registry.d.ts +9 -0
  328. package/dist/agent/engine/registry.d.ts.map +1 -1
  329. package/dist/agent/engine/registry.js +37 -0
  330. package/dist/agent/engine/registry.js.map +1 -1
  331. package/dist/agent/production-agent.d.ts.map +1 -1
  332. package/dist/agent/production-agent.js +4 -3
  333. package/dist/agent/production-agent.js.map +1 -1
  334. package/dist/application-state/handlers.js +1 -1
  335. package/dist/application-state/handlers.js.map +1 -1
  336. package/dist/brand-kit/index.d.ts +1 -1
  337. package/dist/brand-kit/index.js +1 -1
  338. package/dist/brand-kit/index.js.map +1 -1
  339. package/dist/cli/design-connect.d.ts +52 -0
  340. package/dist/cli/design-connect.d.ts.map +1 -0
  341. package/dist/cli/design-connect.js +409 -0
  342. package/dist/cli/design-connect.js.map +1 -0
  343. package/dist/cli/index.js +15 -0
  344. package/dist/cli/index.js.map +1 -1
  345. package/dist/cli/skills.d.ts +3 -0
  346. package/dist/cli/skills.d.ts.map +1 -1
  347. package/dist/cli/skills.js +139 -3
  348. package/dist/cli/skills.js.map +1 -1
  349. package/dist/client/AgentPanel.js +1 -1
  350. package/dist/client/AgentPanel.js.map +1 -1
  351. package/dist/client/AssistantChat.d.ts.map +1 -1
  352. package/dist/client/AssistantChat.js +38 -8
  353. package/dist/client/AssistantChat.js.map +1 -1
  354. package/dist/client/MultiTabAssistantChat.js +1 -1
  355. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  356. package/dist/client/agent-chat.d.ts +6 -0
  357. package/dist/client/agent-chat.d.ts.map +1 -1
  358. package/dist/client/agent-chat.js +17 -3
  359. package/dist/client/agent-chat.js.map +1 -1
  360. package/dist/client/blocks/library/MermaidBlock.js +1 -1
  361. package/dist/client/blocks/library/MermaidBlock.js.map +1 -1
  362. package/dist/client/blocks/library/diagram.js +1 -1
  363. package/dist/client/blocks/library/diagram.js.map +1 -1
  364. package/dist/client/blocks/library/wireframe.js +1 -1
  365. package/dist/client/blocks/library/wireframe.js.map +1 -1
  366. package/dist/client/chat/message-components.js +1 -1
  367. package/dist/client/chat/message-components.js.map +1 -1
  368. package/dist/client/chat-model-groups.d.ts.map +1 -1
  369. package/dist/client/chat-model-groups.js +1 -2
  370. package/dist/client/chat-model-groups.js.map +1 -1
  371. package/dist/client/components/LiveCursorOverlay.d.ts +1 -2
  372. package/dist/client/components/LiveCursorOverlay.d.ts.map +1 -1
  373. package/dist/client/components/LiveCursorOverlay.js +19 -40
  374. package/dist/client/components/LiveCursorOverlay.js.map +1 -1
  375. package/dist/client/composer/TiptapComposer.d.ts +3 -1
  376. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  377. package/dist/client/composer/TiptapComposer.js +86 -24
  378. package/dist/client/composer/TiptapComposer.js.map +1 -1
  379. package/dist/client/composer/useVoiceDictation.d.ts +9 -0
  380. package/dist/client/composer/useVoiceDictation.d.ts.map +1 -1
  381. package/dist/client/composer/useVoiceDictation.js +154 -32
  382. package/dist/client/composer/useVoiceDictation.js.map +1 -1
  383. package/dist/client/extensions/portable-extension.d.ts +1 -1
  384. package/dist/client/extensions/portable-extension.d.ts.map +1 -1
  385. package/dist/client/extensions/portable-extension.js.map +1 -1
  386. package/dist/client/frame-protocol.d.ts +17 -2
  387. package/dist/client/frame-protocol.d.ts.map +1 -1
  388. package/dist/client/frame-protocol.js.map +1 -1
  389. package/dist/client/rich-markdown-editor/RegistryBlockNode.js +2 -2
  390. package/dist/client/rich-markdown-editor/RegistryBlockNode.js.map +1 -1
  391. package/dist/client/sharing/ShareButton.d.ts +2 -0
  392. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  393. package/dist/client/sharing/ShareButton.js +7 -6
  394. package/dist/client/sharing/ShareButton.js.map +1 -1
  395. package/dist/client/use-agent-engine-configured.d.ts +5 -0
  396. package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
  397. package/dist/client/use-agent-engine-configured.js +51 -25
  398. package/dist/client/use-agent-engine-configured.js.map +1 -1
  399. package/dist/code-agents/transcript-normalizer.js +1 -1
  400. package/dist/code-agents/transcript-normalizer.js.map +1 -1
  401. package/dist/collab/routes.d.ts +1 -1
  402. package/dist/extensions/path.d.ts +1 -1
  403. package/dist/extensions/path.d.ts.map +1 -1
  404. package/dist/extensions/path.js.map +1 -1
  405. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  406. package/dist/integrations/a2a-continuation-processor.js +1 -1
  407. package/dist/integrations/a2a-continuation-processor.js.map +1 -1
  408. package/dist/mcp/build-server.d.ts +1 -1
  409. package/dist/mcp/build-server.d.ts.map +1 -1
  410. package/dist/mcp/build-server.js.map +1 -1
  411. package/dist/notifications/routes.d.ts +3 -3
  412. package/dist/observability/routes.d.ts +5 -5
  413. package/dist/org/handlers.js +5 -5
  414. package/dist/org/handlers.js.map +1 -1
  415. package/dist/org/plugin.js +2 -2
  416. package/dist/org/plugin.js.map +1 -1
  417. package/dist/scripts/call-agent.js +1 -1
  418. package/dist/scripts/call-agent.js.map +1 -1
  419. package/dist/scripts/db/safety.js +1 -1
  420. package/dist/scripts/db/safety.js.map +1 -1
  421. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  422. package/dist/server/auth.d.ts.map +1 -1
  423. package/dist/server/auth.js +3 -0
  424. package/dist/server/auth.js.map +1 -1
  425. package/dist/server/builder-design-systems.d.ts +28 -0
  426. package/dist/server/builder-design-systems.d.ts.map +1 -0
  427. package/dist/server/builder-design-systems.js +217 -0
  428. package/dist/server/builder-design-systems.js.map +1 -0
  429. package/dist/server/core-routes-plugin.d.ts +1 -0
  430. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  431. package/dist/server/core-routes-plugin.js +20 -3
  432. package/dist/server/core-routes-plugin.js.map +1 -1
  433. package/dist/server/index.d.ts +1 -0
  434. package/dist/server/index.d.ts.map +1 -1
  435. package/dist/server/index.js +1 -0
  436. package/dist/server/index.js.map +1 -1
  437. package/dist/server/transcribe-voice.d.ts +1 -1
  438. package/dist/server/transcribe-voice.d.ts.map +1 -1
  439. package/dist/server/transcribe-voice.js +40 -24
  440. package/dist/server/transcribe-voice.js.map +1 -1
  441. package/dist/shared/mcp-embed-headers.d.ts +1 -0
  442. package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
  443. package/dist/shared/mcp-embed-headers.js +20 -1
  444. package/dist/shared/mcp-embed-headers.js.map +1 -1
  445. package/dist/styles/agent-native.css +60 -4
  446. package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +10 -0
  447. package/dist/usage/store.js +2 -2
  448. package/dist/usage/store.js.map +1 -1
  449. package/dist/vite/client.d.ts.map +1 -1
  450. package/dist/vite/client.js +2 -0
  451. package/dist/vite/client.js.map +1 -1
  452. package/dist/voice/index.d.ts +5 -0
  453. package/dist/voice/index.d.ts.map +1 -0
  454. package/dist/voice/index.js +4 -0
  455. package/dist/voice/index.js.map +1 -0
  456. package/dist/voice/voice-cleanup-prompt.d.ts +6 -0
  457. package/dist/voice/voice-cleanup-prompt.d.ts.map +1 -0
  458. package/dist/voice/voice-cleanup-prompt.js +26 -0
  459. package/dist/voice/voice-cleanup-prompt.js.map +1 -0
  460. package/dist/voice/voice-context.d.ts +25 -0
  461. package/dist/voice/voice-context.d.ts.map +1 -0
  462. package/dist/voice/voice-context.js +156 -0
  463. package/dist/voice/voice-context.js.map +1 -0
  464. package/dist/voice/voice-replacements.d.ts +4 -0
  465. package/dist/voice/voice-replacements.d.ts.map +1 -0
  466. package/dist/voice/voice-replacements.js +52 -0
  467. package/dist/voice/voice-replacements.js.map +1 -0
  468. package/docs/content/locales/ar-SA/skills-guide.mdx +5 -0
  469. package/docs/content/locales/ar-SA/template-design.mdx +55 -1
  470. package/docs/content/locales/de-DE/skills-guide.mdx +5 -0
  471. package/docs/content/locales/de-DE/template-design.mdx +66 -1
  472. package/docs/content/locales/es-ES/skills-guide.mdx +5 -0
  473. package/docs/content/locales/es-ES/template-design.mdx +65 -1
  474. package/docs/content/locales/fr-FR/skills-guide.mdx +5 -0
  475. package/docs/content/locales/fr-FR/template-design.mdx +64 -1
  476. package/docs/content/locales/hi-IN/skills-guide.mdx +5 -0
  477. package/docs/content/locales/hi-IN/template-design.mdx +59 -1
  478. package/docs/content/locales/ja-JP/skills-guide.mdx +5 -0
  479. package/docs/content/locales/ja-JP/template-design.mdx +62 -1
  480. package/docs/content/locales/ko-KR/skills-guide.mdx +5 -0
  481. package/docs/content/locales/ko-KR/template-design.mdx +58 -1
  482. package/docs/content/locales/pt-BR/skills-guide.mdx +5 -0
  483. package/docs/content/locales/pt-BR/template-design.mdx +62 -1
  484. package/docs/content/locales/zh-CN/skills-guide.mdx +5 -0
  485. package/docs/content/locales/zh-CN/template-design.mdx +50 -1
  486. package/docs/content/locales/zh-TW/skills-guide.mdx +5 -0
  487. package/docs/content/locales/zh-TW/template-design.mdx +52 -1
  488. package/docs/content/skills-guide.mdx +5 -0
  489. package/docs/content/template-design.mdx +59 -1
  490. package/package.json +2 -1
  491. package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +10 -0
  492. package/corpus/templates/design/actions/import-figma-file.ts +0 -166
  493. package/corpus/templates/design/app/components/design/DesignToolbar.tsx +0 -339
  494. package/corpus/templates/design/app/components/design/PresentMode.tsx +0 -68
  495. package/corpus/templates/design/app/components/design/ViewportTabs.tsx +0 -149
  496. package/corpus/templates/design/app/components/design/ZoomControls.tsx +0 -157
  497. package/corpus/templates/slides/server/lib/fig-design-system.ts +0 -110
@@ -0,0 +1,255 @@
1
+ /**
2
+ * S3-compatible file upload provider.
3
+ *
4
+ * Works with AWS S3, Cloudflare R2, DigitalOcean Spaces, MinIO, Backblaze B2,
5
+ * and any other S3-compatible object storage. Uses SigV4 signing via Web Crypto
6
+ * — no SDK dependency.
7
+ *
8
+ * Env vars (S3_* or R2_* prefix, first found wins):
9
+ * S3_BUCKET | R2_BUCKET — required
10
+ * S3_ACCESS_KEY_ID | R2_ACCESS_KEY_ID — required
11
+ * S3_SECRET_ACCESS_KEY | R2_SECRET_ACCESS_KEY — required
12
+ * S3_ENDPOINT | R2_ENDPOINT — required (e.g. https://s3.us-east-1.amazonaws.com
13
+ * or https://<acct>.r2.cloudflarestorage.com)
14
+ * S3_REGION | R2_REGION — optional, default "auto"
15
+ * S3_PUBLIC_BASE_URL | R2_PUBLIC_BASE_URL — optional (for public read URLs)
16
+ */
17
+
18
+ import type { FileUploadProvider } from "@agent-native/core/file-upload";
19
+ import { resolveSecret } from "@agent-native/core/server";
20
+
21
+ interface S3Config {
22
+ region: string;
23
+ bucket: string;
24
+ accessKeyId: string;
25
+ secretAccessKey: string;
26
+ endpoint: string;
27
+ publicBaseUrl: string | null;
28
+ }
29
+
30
+ function cleanValue(value: string | null | undefined): string | undefined {
31
+ const cleaned = value?.trim();
32
+ return cleaned ? cleaned : undefined;
33
+ }
34
+
35
+ function buildS3Config(values: {
36
+ bucket?: string;
37
+ accessKeyId?: string;
38
+ secretAccessKey?: string;
39
+ endpoint?: string;
40
+ region?: string;
41
+ publicBaseUrl?: string;
42
+ }): S3Config | null {
43
+ const bucket = cleanValue(values.bucket);
44
+ const accessKeyId = cleanValue(values.accessKeyId);
45
+ const secretAccessKey = cleanValue(values.secretAccessKey);
46
+ const endpoint = cleanValue(values.endpoint);
47
+ if (!bucket || !accessKeyId || !secretAccessKey || !endpoint) return null;
48
+ return {
49
+ region: cleanValue(values.region) ?? "auto",
50
+ bucket,
51
+ accessKeyId,
52
+ secretAccessKey,
53
+ endpoint: endpoint.replace(/\/+$/, ""),
54
+ publicBaseUrl:
55
+ cleanValue(values.publicBaseUrl)?.replace(/\/+$/, "") ?? null,
56
+ };
57
+ }
58
+
59
+ function readS3EnvConfig(): S3Config | null {
60
+ const env = process.env;
61
+ return buildS3Config({
62
+ bucket: env.S3_BUCKET || env.R2_BUCKET,
63
+ accessKeyId: env.S3_ACCESS_KEY_ID || env.R2_ACCESS_KEY_ID,
64
+ secretAccessKey: env.S3_SECRET_ACCESS_KEY || env.R2_SECRET_ACCESS_KEY,
65
+ endpoint: env.S3_ENDPOINT || env.R2_ENDPOINT,
66
+ region: env.S3_REGION || env.R2_REGION,
67
+ publicBaseUrl: env.S3_PUBLIC_BASE_URL || env.R2_PUBLIC_BASE_URL,
68
+ });
69
+ }
70
+
71
+ async function resolveS3Secret(primary: string, fallback: string) {
72
+ return (
73
+ cleanValue(await resolveSecret(primary).catch(() => null)) ??
74
+ cleanValue(await resolveSecret(fallback).catch(() => null))
75
+ );
76
+ }
77
+
78
+ async function readS3Config(): Promise<S3Config | null> {
79
+ return buildS3Config({
80
+ bucket: await resolveS3Secret("S3_BUCKET", "R2_BUCKET"),
81
+ accessKeyId: await resolveS3Secret("S3_ACCESS_KEY_ID", "R2_ACCESS_KEY_ID"),
82
+ secretAccessKey: await resolveS3Secret(
83
+ "S3_SECRET_ACCESS_KEY",
84
+ "R2_SECRET_ACCESS_KEY",
85
+ ),
86
+ endpoint: await resolveS3Secret("S3_ENDPOINT", "R2_ENDPOINT"),
87
+ region: await resolveS3Secret("S3_REGION", "R2_REGION"),
88
+ publicBaseUrl: await resolveS3Secret(
89
+ "S3_PUBLIC_BASE_URL",
90
+ "R2_PUBLIC_BASE_URL",
91
+ ),
92
+ });
93
+ }
94
+
95
+ // ── SigV4 helpers (Web Crypto, no SDK) ────────────────────────────────
96
+
97
+ async function hmac(key: ArrayBuffer, msg: string): Promise<ArrayBuffer> {
98
+ const k = await crypto.subtle.importKey(
99
+ "raw",
100
+ key,
101
+ { name: "HMAC", hash: "SHA-256" },
102
+ false,
103
+ ["sign"],
104
+ );
105
+ return crypto.subtle.sign("HMAC", k, new TextEncoder().encode(msg));
106
+ }
107
+
108
+ async function sha256(data: Uint8Array): Promise<string> {
109
+ const ab = new ArrayBuffer(data.byteLength);
110
+ new Uint8Array(ab).set(data);
111
+ const buf = await crypto.subtle.digest("SHA-256", ab);
112
+ return toHex(buf);
113
+ }
114
+
115
+ function toHex(buf: ArrayBuffer): string {
116
+ const bytes = new Uint8Array(buf);
117
+ let out = "";
118
+ for (let i = 0; i < bytes.length; i++) {
119
+ out += bytes[i].toString(16).padStart(2, "0");
120
+ }
121
+ return out;
122
+ }
123
+
124
+ async function deriveSigningKey(
125
+ secret: string,
126
+ dateStamp: string,
127
+ region: string,
128
+ ): Promise<ArrayBuffer> {
129
+ const kSecret = new TextEncoder().encode(`AWS4${secret}`);
130
+ const kDate = await hmac(kSecret.buffer as ArrayBuffer, dateStamp);
131
+ const kRegion = await hmac(kDate, region);
132
+ const kService = await hmac(kRegion, "s3");
133
+ return hmac(kService, "aws4_request");
134
+ }
135
+
136
+ function rfc3986(str: string): string {
137
+ return encodeURIComponent(str).replace(
138
+ /[!'()*]/g,
139
+ (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase(),
140
+ );
141
+ }
142
+
143
+ async function putObject(
144
+ cfg: S3Config,
145
+ key: string,
146
+ body: Uint8Array,
147
+ contentType: string,
148
+ ): Promise<string> {
149
+ const now = new Date();
150
+ const amzDate =
151
+ now
152
+ .toISOString()
153
+ .replace(/[:-]|\.\d{3}/g, "")
154
+ .slice(0, 15) + "Z";
155
+ const dateStamp = amzDate.slice(0, 8);
156
+ const credentialScope = `${dateStamp}/${cfg.region}/s3/aws4_request`;
157
+
158
+ const hostUrl = new URL(cfg.endpoint);
159
+ const host = hostUrl.host;
160
+ const canonicalUri = `/${cfg.bucket}/${key.split("/").map(rfc3986).join("/")}`;
161
+
162
+ const payloadHash = await sha256(body);
163
+
164
+ const headers: Record<string, string> = {
165
+ host,
166
+ "content-type": contentType,
167
+ "x-amz-content-sha256": payloadHash,
168
+ "x-amz-date": amzDate,
169
+ };
170
+
171
+ const signedHeaderKeys = Object.keys(headers).sort();
172
+ const signedHeaders = signedHeaderKeys.join(";");
173
+ const canonicalHeaders =
174
+ signedHeaderKeys.map((k) => `${k}:${headers[k]}`).join("\n") + "\n";
175
+
176
+ const canonicalRequest = [
177
+ "PUT",
178
+ canonicalUri,
179
+ "", // no query string
180
+ canonicalHeaders,
181
+ signedHeaders,
182
+ payloadHash,
183
+ ].join("\n");
184
+
185
+ const crHash = await sha256(new TextEncoder().encode(canonicalRequest));
186
+ const stringToSign = [
187
+ "AWS4-HMAC-SHA256",
188
+ amzDate,
189
+ credentialScope,
190
+ crHash,
191
+ ].join("\n");
192
+
193
+ const signingKey = await deriveSigningKey(
194
+ cfg.secretAccessKey,
195
+ dateStamp,
196
+ cfg.region,
197
+ );
198
+ const signature = toHex(await hmac(signingKey, stringToSign));
199
+
200
+ const authorization =
201
+ `AWS4-HMAC-SHA256 Credential=${cfg.accessKeyId}/${credentialScope}, ` +
202
+ `SignedHeaders=${signedHeaders}, Signature=${signature}`;
203
+
204
+ const url = `${cfg.endpoint}${canonicalUri}`;
205
+ const res = await fetch(url, {
206
+ method: "PUT",
207
+ headers: {
208
+ ...headers,
209
+ Authorization: authorization,
210
+ "Content-Length": String(body.byteLength),
211
+ },
212
+ body: body.buffer.slice(
213
+ body.byteOffset,
214
+ body.byteOffset + body.byteLength,
215
+ ) as BodyInit,
216
+ });
217
+
218
+ if (!res.ok) {
219
+ const text = await res.text().catch(() => "");
220
+ throw new Error(
221
+ `S3 PutObject failed (${res.status}): ${text || res.statusText}`,
222
+ );
223
+ }
224
+
225
+ return cfg.publicBaseUrl
226
+ ? `${cfg.publicBaseUrl}/${key}`
227
+ : `${cfg.endpoint}/${cfg.bucket}/${key}`;
228
+ }
229
+
230
+ // ── Provider ──────────────────────────────────────────────────────────
231
+
232
+ export const s3FileUploadProvider: FileUploadProvider = {
233
+ id: "s3",
234
+ name: "S3-compatible storage",
235
+ isConfigured: () => readS3EnvConfig() !== null,
236
+ isConfiguredForRequest: async () => (await readS3Config()) !== null,
237
+ upload: async ({ data, filename, mimeType }) => {
238
+ const cfg = await readS3Config();
239
+ if (!cfg) throw new Error("S3 credentials are not configured");
240
+
241
+ const ext = filename?.split(".").pop() ?? "bin";
242
+ const stamp = Date.now();
243
+ const rand = Math.random().toString(36).slice(2, 10);
244
+ const objectKey = `replays/${stamp}-${rand}.${ext}`;
245
+ const contentType = mimeType || "application/octet-stream";
246
+
247
+ const bytes =
248
+ data instanceof Uint8Array
249
+ ? data
250
+ : new Uint8Array(data as unknown as ArrayBuffer);
251
+
252
+ const publicUrl = await putObject(cfg, objectKey, bytes, contentType);
253
+ return { url: publicUrl, provider: "s3" };
254
+ },
255
+ };
@@ -8,7 +8,7 @@ import {
8
8
  readPrivateBlob,
9
9
  type PrivateBlobHandle,
10
10
  } from "@agent-native/core/private-blob";
11
- import { recordChange } from "@agent-native/core/server";
11
+ import { recordChange, runWithRequestContext } from "@agent-native/core/server";
12
12
  import {
13
13
  accessFilter,
14
14
  resolveAccess,
@@ -988,11 +988,21 @@ function rowToSessionRecordingSummary(
988
988
  }
989
989
 
990
990
  function hasVisibleSessionRecordingIdentity(row: any): boolean {
991
- return Boolean(replayEmail(row.userId) || replayString(row.anonymousId));
991
+ // /sessions intentionally lists signed-in, email-backed recordings only (see
992
+ // analytics CLAUDE.md + the "rejects anonymous recordings" spec). Keep this in
993
+ // sync with replayVisibleIdentityCondition().
994
+ return Boolean(replayEmail(row.userId) || replayEmail(row.userKey));
995
+ }
996
+
997
+ function hasPlayableSessionRecordingEvents(row: any): boolean {
998
+ return Number(row.chunkCount ?? 0) > 0 && Number(row.eventCount ?? 0) > 0;
992
999
  }
993
1000
 
994
1001
  function isVisibleSessionRecording(row: any): boolean {
995
- return hasVisibleSessionRecordingIdentity(row);
1002
+ return (
1003
+ hasVisibleSessionRecordingIdentity(row) &&
1004
+ hasPlayableSessionRecordingEvents(row)
1005
+ );
996
1006
  }
997
1007
 
998
1008
  function mergeReplayMetadata(
@@ -1043,9 +1053,18 @@ function replayTextContains(column: unknown, query: string) {
1043
1053
  }
1044
1054
 
1045
1055
  function replayVisibleIdentityCondition() {
1056
+ // Email-backed identity only — /sessions lists signed-in recordings (see
1057
+ // analytics CLAUDE.md). Mirror of hasVisibleSessionRecordingIdentity().
1046
1058
  return or(
1047
1059
  replayTextContains(schema.sessionRecordings.userId, "@"),
1048
- sql`nullif(trim(coalesce(${schema.sessionRecordings.anonymousId}, '')), '') is not null`,
1060
+ replayTextContains(schema.sessionRecordings.userKey, "@"),
1061
+ );
1062
+ }
1063
+
1064
+ function replayPlayableEventsCondition() {
1065
+ return and(
1066
+ gte(schema.sessionRecordings.chunkCount, 1),
1067
+ gte(schema.sessionRecordings.eventCount, 1),
1049
1068
  );
1050
1069
  }
1051
1070
 
@@ -1126,7 +1145,12 @@ export async function recordSessionReplayChunks(
1126
1145
  lastIngestedAt: ingestedAt,
1127
1146
  ownerEmail: key.ownerEmail,
1128
1147
  orgId: key.orgId,
1129
- visibility: "private",
1148
+ // Session replay is an org-analytics surface: a recording captured under
1149
+ // an org-scoped analytics key must be visible to everyone in that org
1150
+ // (via accessFilter's "org" branch), not only the key owner. Without an
1151
+ // org we fall back to owner-private. This is what makes /sessions show
1152
+ // recordings to teammates instead of only the single key owner.
1153
+ visibility: key.orgId ? "org" : "private",
1130
1154
  })
1131
1155
  .onConflictDoNothing();
1132
1156
 
@@ -1190,12 +1214,23 @@ export async function recordSessionReplayChunks(
1190
1214
  413,
1191
1215
  );
1192
1216
  }
1193
- const chunk = await storeReplayChunkBlob(rawChunk, {
1194
- publicKeyId: key.id,
1195
- recordingId: recording.id,
1196
- ownerEmail: key.ownerEmail,
1197
- orgId: key.orgId,
1198
- });
1217
+ // Replay ingest is anonymous + cross-origin (no session), so blob storage
1218
+ // would otherwise have no request context and `resolveBuilderPrivateKey()`
1219
+ // (and any S3 provider's scoped-secret lookup) would resolve nothing —
1220
+ // every chunk upload then 503s and recordings persist as empty shells.
1221
+ // Run the upload in the public key owner's user/org scope so the org's
1222
+ // connected Builder (or S3) credential in `app_secrets` resolves. Mirrors
1223
+ // the resources upload precedent (core resources/handlers.ts).
1224
+ const chunk = await runWithRequestContext(
1225
+ { userEmail: key.ownerEmail, orgId: key.orgId ?? undefined },
1226
+ () =>
1227
+ storeReplayChunkBlob(rawChunk, {
1228
+ publicKeyId: key.id,
1229
+ recordingId: recording.id,
1230
+ ownerEmail: key.ownerEmail,
1231
+ orgId: key.orgId,
1232
+ }),
1233
+ );
1199
1234
  if (rawChunk.storageKind !== "blob" && chunk.storageKind === "blob") {
1200
1235
  const ref = decodeReplayBlobRef(chunk.storageRef);
1201
1236
  if (ref) uploadedBlobHandles.push(ref.handle);
@@ -1353,6 +1388,7 @@ export async function listSessionRecordings(
1353
1388
  orgId: scope.orgId ?? undefined,
1354
1389
  }),
1355
1390
  replayVisibleIdentityCondition(),
1391
+ replayPlayableEventsCondition(),
1356
1392
  ];
1357
1393
  if (filters.app)
1358
1394
  conditions.push(eq(schema.sessionRecordings.app, filters.app));
@@ -1363,7 +1399,12 @@ export async function listSessionRecordings(
1363
1399
  conditions.push(eq(schema.sessionRecordings.sessionId, filters.sessionId));
1364
1400
  }
1365
1401
  if (filters.userId) {
1366
- conditions.push(eq(schema.sessionRecordings.userId, filters.userId));
1402
+ conditions.push(
1403
+ or(
1404
+ eq(schema.sessionRecordings.userId, filters.userId),
1405
+ eq(schema.sessionRecordings.userKey, filters.userId),
1406
+ ),
1407
+ );
1367
1408
  }
1368
1409
  if (filters.anonymousId) {
1369
1410
  conditions.push(
@@ -9,6 +9,7 @@ import {
9
9
  import actionsRegistry from "../../.generated/actions-registry.js";
10
10
  import { renderDataDictionary } from "../lib/data-dictionary-context";
11
11
  import {
12
+ failedDataQueryAttemptMessage,
12
13
  hasExplicitPartialDisclosure,
13
14
  hasFailedCorpusWorkflowEvidence,
14
15
  hasDataQueryAttempt,
@@ -39,6 +40,7 @@ const INITIAL_TOOL_NAMES = [
39
40
  "get-sql-dashboard",
40
41
  "mutate-dashboard",
41
42
  "generate-chart",
43
+ "query-agent-native-analytics",
42
44
  "bigquery",
43
45
  "search-bigquery-schema",
44
46
  "bigquery-table-info",
@@ -139,6 +141,13 @@ function realDataFinalGuard(context: AgentLoopFinalResponseGuardContext) {
139
141
  }
140
142
  if (hasDataQueryAttempt(context.toolResults)) return null;
141
143
  if (isSafeNoDataAnalyticsResponse(context.text)) return null;
144
+ const failedQueryMessage = failedDataQueryAttemptMessage(context.toolResults);
145
+ if (failedQueryMessage) {
146
+ return {
147
+ retryMessage: failedQueryMessage,
148
+ fallbackMessage: failedQueryMessage,
149
+ };
150
+ }
142
151
 
143
152
  return {
144
153
  retryMessage:
@@ -175,8 +184,8 @@ export default createAgentChatPlugin({
175
184
  "SURFACE DIFFERENTIATION — You are the analytics assistant for definitions, deep-dive analysis, and action. For questions about what a metric, model, or table means, use the Data Dictionary and configured schema tools first. For trends, comparisons, anomalies, current data, or anything that requires querying live data, answer directly in chat with the relevant provider query, dashboard analysis, and inline charts when useful. " +
176
185
  "DASHBOARD CREATION RULE — You may create dashboards, analyses, SQL panels, or other resources only when the user explicitly asks you to (e.g. 'build me a dashboard for...', 'create a new analysis', 'add a chart for...'). Never create any resource proactively during research, trend analysis, or answering questions. If you think a dashboard would be useful, suggest it and wait for explicit confirmation before creating anything. Never add new items to the sidebar or modify existing dashboards without an explicit user directive. " +
177
186
  "DASHBOARD MUTATION RULE — For dashboard edits, default to `mutate-dashboard` with the typed `dashboard.*` script API so the main payload is a string and avoids native-array serialization traps. It can move panels by id, edit titles/SQL/config, insert, duplicate, remove, and patch dashboard fields in one atomic save. The script API is constrained: no variables/imports/loops/functions, only JSON-compatible arguments on documented dashboard methods. Do not count shifting `/panels/<index>` positions for ordinary dashboard edits unless the user specifically asks for low-level JSON-pointer operations. " +
178
- "DASHBOARD READ RULE — `get-sql-dashboard` is compact by default: use its `panels` summaries plus `layout.panelOrder` and `layout.firstPanelIds` for orientation and verification. Pass `includeConfig: true` only when you truly need full panel SQL/config. " +
179
- 'DASHBOARD REORDER RULE — For simple chart/section moves, use `mutate-dashboard` code such as `dashboard.panels(["panel-a","panel-b"]).moveToTop();`. Never count shifting `/panels/<index>` positions for ordinary \'move this chart\' requests. Use `get-sql-dashboard.layout.firstPanelIds` or `mutate-dashboard.panelOrder` as proof of placement. ' +
187
+ "DASHBOARD READ RULE — `get-sql-dashboard` is compact by default: use its `panels` summaries plus `layout.panelOrder`, `layout.firstPanelIds`, and `layout.groups[].rows[].rowNumber/panelIds` for orientation and verification. Pass `includeConfig: true` only when you truly need full panel SQL/config. " +
188
+ 'DASHBOARD REORDER RULE — For simple chart/section moves, use `mutate-dashboard` code such as `dashboard.panels(["panel-a","panel-b"]).moveToTop();`. For visible placement requests like "second row" or "next to return rates", use row-aware placement such as `dashboard.insertPanel({...}).nextTo("retention-over-time")`, `.atRow(2)`, or `dashboard.panel("panel-a").moveNextTo("panel-b")`; these keep panels in the intended rendered row and expand/rebalance that row when needed. Never count shifting `/panels/<index>` positions for ordinary \'move this chart\' requests. Use `get-sql-dashboard.layout.groups[].rows` as proof of visible row placement, not only flat `panelOrder`. ' +
180
189
  "Use configured data sources and actions only. Call `data-source-status` when you need to know which providers are connected, and treat provider actions as unavailable for analysis if they return missing credentials, permission, syntax, quota, or network errors. " +
181
190
  "The built-in `demo` dashboard source is a demo-environment Prometheus source reserved for the Node Exporter demo. It must never satisfy REAL_DATA_REQUIRED or be cited as user analytics evidence unless the user explicitly asks to inspect the demo dashboard. " +
182
191
  "When the user names a provider or tool such as Jira, Pylon, HubSpot, Gong, Slack, Sentry, GA4, or BigQuery, that named source is authoritative for the turn: use that provider's real tool/API surface, not a warehouse or different-provider substitute, unless the user explicitly asks for the copy/fallback. For bounded lookups where a first-class action fully models the requested source, object, filter, and pagination need, that shortcut is fine. For broad provider searches, cross-source joins, corpus-wide counts, exact cohort coverage, or any answer where absence matters, do not start and stop with shortcuts; use the broad provider API/MCP and corpus/code workflow as the primary path. " +
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Custom onboarding plugin for Analytics.
3
+ *
4
+ * Overrides the framework's default onboarding plugin to add an optional
5
+ * "Session replay storage" step and register the S3 file upload provider. Must
6
+ * live in server/plugins/ so the framework skips its default onboarding plugin,
7
+ * and all registrations share the same module context as the onboarding route
8
+ * handlers (which read from the same in-memory Map).
9
+ *
10
+ * The step is `required: false` because session replay is opt-in: capturing
11
+ * replays only matters once a site embeds the tracking SDK with replay enabled,
12
+ * so we surface storage setup without forcing it into the onboarding checklist.
13
+ */
14
+
15
+ import { registerFileUploadProvider } from "@agent-native/core/file-upload";
16
+ import {
17
+ createOnboardingPlugin,
18
+ registerOnboardingStep,
19
+ } from "@agent-native/core/onboarding";
20
+
21
+ import { hasRequestReplayStorage } from "../lib/replay-storage.js";
22
+ import { s3FileUploadProvider } from "../lib/s3-upload-provider.js";
23
+
24
+ const basePlugin = createOnboardingPlugin();
25
+
26
+ export default async (nitroApp: any): Promise<void> => {
27
+ // Mount the framework's default onboarding plugin (routes + default steps).
28
+ await basePlugin(nitroApp);
29
+
30
+ // Register S3-compatible file upload provider for session-replay chunks.
31
+ registerFileUploadProvider(s3FileUploadProvider);
32
+
33
+ // Add the optional "Session replay storage" onboarding step.
34
+ registerOnboardingStep({
35
+ id: "replay-storage",
36
+ order: 15,
37
+ required: false,
38
+ title: "Session replay storage",
39
+ description:
40
+ "Store session replay recordings with Builder.io or S3-compatible storage.",
41
+ methods: [
42
+ {
43
+ id: "builder",
44
+ kind: "builder-cli-auth",
45
+ label: "Connect Builder.io",
46
+ description:
47
+ "Builder.io's free tier includes object storage for replay chunks.",
48
+ primary: true,
49
+ badge: "free",
50
+ payload: { scope: "browser" },
51
+ },
52
+ {
53
+ id: "s3",
54
+ kind: "form",
55
+ label: "Use S3-compatible storage",
56
+ description:
57
+ "AWS S3, Cloudflare R2, DigitalOcean Spaces, MinIO, or any S3-compatible service.",
58
+ payload: {
59
+ writeScope: "workspace",
60
+ fields: [
61
+ {
62
+ key: "S3_ENDPOINT",
63
+ label: "Endpoint URL",
64
+ placeholder: "https://s3.us-east-1.amazonaws.com",
65
+ },
66
+ {
67
+ key: "S3_BUCKET",
68
+ label: "Bucket name",
69
+ placeholder: "my-replays-bucket",
70
+ },
71
+ {
72
+ key: "S3_ACCESS_KEY_ID",
73
+ label: "Access key ID",
74
+ placeholder: "AKIA...",
75
+ },
76
+ {
77
+ key: "S3_SECRET_ACCESS_KEY",
78
+ label: "Secret access key",
79
+ secret: true,
80
+ },
81
+ {
82
+ key: "S3_REGION",
83
+ label: "Region (optional)",
84
+ placeholder: "us-east-1",
85
+ },
86
+ {
87
+ key: "S3_PUBLIC_BASE_URL",
88
+ label: "Public base URL (optional)",
89
+ placeholder: "https://cdn.example.com",
90
+ },
91
+ ],
92
+ },
93
+ },
94
+ ],
95
+ isComplete: hasRequestReplayStorage,
96
+ });
97
+ };
@@ -425,7 +425,7 @@ export function Sidebar() {
425
425
  return (
426
426
  <aside
427
427
  className={cn(
428
- "flex h-full min-w-0 shrink-0 flex-col overflow-hidden border-e border-border bg-sidebar text-sidebar-foreground",
428
+ "flex h-full min-w-0 shrink-0 flex-col overflow-hidden border-e border-border bg-sidebar text-sidebar-foreground transition-[width] duration-200 ease-out",
429
429
  collapsed ? "w-14" : "w-56",
430
430
  )}
431
431
  >
@@ -553,15 +553,15 @@ export function Sidebar() {
553
553
 
554
554
  {!collapsed && (
555
555
  <div className="mt-auto shrink-0">
556
- <div className="border-t border-border px-2 py-1">
556
+ <div className="px-2 py-1">
557
557
  <ExtensionsSidebarSection />
558
558
  </div>
559
559
 
560
- <div className="border-t border-border px-3 py-2">
560
+ <div className="px-3 py-2">
561
561
  <OrgSwitcher />
562
562
  </div>
563
563
 
564
- <div className="border-t border-border px-3 py-2">
564
+ <div className="px-3 py-2">
565
565
  <DevDatabaseLink />
566
566
  <FeedbackButton />
567
567
  </div>
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-06-28
4
+ ---
5
+
6
+ Left sidebar collapse motion and footer controls now feel smoother and use less divider chrome.
@@ -20,11 +20,24 @@ import {
20
20
  } from "@/components/ui/sheet";
21
21
  import { TAB_ID } from "@/lib/tab-id";
22
22
 
23
+ const SIDEBAR_COLLAPSE_KEY = "brain.sidebar.collapsed";
24
+
25
+ function readSidebarCollapsed() {
26
+ if (typeof window === "undefined") return false;
27
+ try {
28
+ return window.localStorage.getItem(SIDEBAR_COLLAPSE_KEY) === "1";
29
+ } catch {
30
+ return false;
31
+ }
32
+ }
33
+
23
34
  export function Layout({ children }: { children: React.ReactNode }) {
24
35
  const location = useLocation();
25
36
  const navigate = useNavigate();
26
37
  const t = useT();
27
38
  const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
39
+ const [sidebarCollapsed, setSidebarCollapsed] =
40
+ useState(readSidebarCollapsed);
28
41
  const isAskRoute = location.pathname === "/";
29
42
  const chatHomeHandoffActive = useAgentChatHomeHandoff({
30
43
  storageKey: "brain",
@@ -37,10 +50,24 @@ export function Layout({ children }: { children: React.ReactNode }) {
37
50
  setMobileSidebarOpen(false);
38
51
  }, [location.pathname]);
39
52
 
53
+ useEffect(() => {
54
+ try {
55
+ window.localStorage.setItem(
56
+ SIDEBAR_COLLAPSE_KEY,
57
+ sidebarCollapsed ? "1" : "0",
58
+ );
59
+ } catch {
60
+ // Ignore storage failures; the in-memory preference still works.
61
+ }
62
+ }, [sidebarCollapsed]);
63
+
40
64
  const sidebarFrame = (
41
65
  <>
42
66
  <div className="agent-layout-left-drawer hidden md:block">
43
- <Sidebar />
67
+ <Sidebar
68
+ collapsed={sidebarCollapsed}
69
+ onCollapsedChange={setSidebarCollapsed}
70
+ />
44
71
  </div>
45
72
  <Sheet open={mobileSidebarOpen} onOpenChange={setMobileSidebarOpen}>
46
73
  <SheetContent side="left" className="w-[min(18rem,88vw)] p-0">
@@ -50,7 +77,7 @@ export function Layout({ children }: { children: React.ReactNode }) {
50
77
  <SheetDescription className="sr-only">
51
78
  {t("navigation.brainNavigationDescription")}
52
79
  </SheetDescription>
53
- <Sidebar />
80
+ <Sidebar collapsed={false} collapsible={false} />
54
81
  </SheetContent>
55
82
  </Sheet>
56
83
  </>