@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
@@ -1,11 +1,14 @@
1
1
  import { sendToAgentChat, useT } from "@agent-native/core/client";
2
2
  import {
3
+ IconAlertTriangle,
4
+ IconBolt,
5
+ IconCircleCheck,
3
6
  IconMessage,
4
7
  IconMessageCheck,
5
8
  IconSend,
6
9
  IconX,
7
10
  } from "@tabler/icons-react";
8
- import { useCallback, useEffect, useRef, useState } from "react";
11
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
9
12
 
10
13
  import { Button } from "@/components/ui/button";
11
14
  import { Textarea } from "@/components/ui/textarea";
@@ -23,10 +26,14 @@ export interface CanvasPin {
23
26
  yPct: number;
24
27
  /** Optional CSS selector of the element under the click, for context */
25
28
  targetSelector?: string;
29
+ /** Best-effort stable canvas/code-layer id when the clicked layer exposes one. */
30
+ targetAnchorId?: string;
26
31
  /** Optional snippet of text content the user clicked near */
27
32
  targetText?: string;
28
33
  /** Pending comment text the user is composing */
29
34
  draft?: string;
35
+ /** Held locally until the user batch-applies queued comments. */
36
+ queued?: boolean;
30
37
  /** Submitted state — the marker stays visible as confirmation. */
31
38
  submitted?: boolean;
32
39
  }
@@ -34,8 +41,16 @@ export interface CanvasPin {
34
41
  interface CanvasCommentPinsProps {
35
42
  /** Whether the pin tool is active. When true, clicks drop pins. */
36
43
  active: boolean;
44
+ /** In queue mode, pin Send adds to the shared annotation batch. */
45
+ submitMode?: "direct" | "queue";
37
46
  /** Disable / exit the pin mode (called on Escape, after submit, etc.) */
38
47
  onClose: () => void;
48
+ /** Mirrors local pins to a parent that can submit them with other annotations. */
49
+ onPinsChange?: (pins: CanvasPin[]) => void;
50
+ /** Increment to mark queued pins as submitted by a parent action. */
51
+ submitQueuedSignal?: number;
52
+ /** Keep the click plane below a sibling draw toolbar in combined annotate mode. */
53
+ clickPlaneUnderToolbar?: boolean;
39
54
  /**
40
55
  * Selector for the canvas surface (e.g. `.slide-content`). Pins are anchored
41
56
  * to this element's bounding rect; clicks outside are ignored.
@@ -49,6 +64,210 @@ interface CanvasCommentPinsProps {
49
64
  contextLabel?: string;
50
65
  }
51
66
 
67
+ type PinCapabilityStatus =
68
+ | "deterministic"
69
+ | "needs-agent"
70
+ | "conflict"
71
+ | "unsupported";
72
+
73
+ interface PinStatusMeta {
74
+ status: PinCapabilityStatus;
75
+ label: string;
76
+ shortLabel: string;
77
+ detail: string;
78
+ markerClassName: string;
79
+ badgeClassName: string;
80
+ }
81
+
82
+ const STATUS_META: Record<PinCapabilityStatus, PinStatusMeta> = {
83
+ deterministic: {
84
+ status: "deterministic",
85
+ label: "",
86
+ shortLabel: "",
87
+ detail: "",
88
+ markerClassName: "bg-emerald-500 text-white ring-emerald-200",
89
+ badgeClassName:
90
+ "border-emerald-500/30 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300",
91
+ },
92
+ "needs-agent": {
93
+ status: "needs-agent",
94
+ label: "",
95
+ shortLabel: "",
96
+ detail: "",
97
+ markerClassName: "bg-amber-400 text-amber-950 ring-amber-200",
98
+ badgeClassName:
99
+ "border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300",
100
+ },
101
+ conflict: {
102
+ status: "conflict",
103
+ label: "",
104
+ shortLabel: "",
105
+ detail: "",
106
+ markerClassName:
107
+ "bg-destructive text-destructive-foreground ring-destructive/30",
108
+ badgeClassName: "border-destructive/30 bg-destructive/10 text-destructive",
109
+ },
110
+ unsupported: {
111
+ status: "unsupported",
112
+ label: "",
113
+ shortLabel: "",
114
+ detail: "",
115
+ markerClassName: "bg-muted text-muted-foreground ring-border",
116
+ badgeClassName: "border-border bg-muted text-muted-foreground",
117
+ },
118
+ };
119
+
120
+ function localizePinStatus(
121
+ status: PinStatusMeta,
122
+ t: (key: string, options?: Record<string, unknown>) => string,
123
+ ): PinStatusMeta {
124
+ return {
125
+ ...status,
126
+ label: t(`visualEditor.pinStatus.${status.status}.label`),
127
+ shortLabel: t(`visualEditor.pinStatus.${status.status}.shortLabel`),
128
+ detail: t(`visualEditor.pinStatus.${status.status}.detail`),
129
+ };
130
+ }
131
+
132
+ function escapeAttributeValue(value: string): string {
133
+ return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
134
+ }
135
+
136
+ function escapeCssIdentifier(value: string): string {
137
+ if (typeof CSS !== "undefined" && typeof CSS.escape === "function") {
138
+ return CSS.escape(value);
139
+ }
140
+ return value.replace(/[^a-zA-Z0-9_-]/g, "\\$&");
141
+ }
142
+
143
+ function getTargetAnchor(target?: HTMLElement | null): {
144
+ targetSelector?: string;
145
+ targetAnchorId?: string;
146
+ } {
147
+ const anchor = target?.closest(
148
+ "[data-agent-native-node-id], [data-builder-id], [data-loc], [id]",
149
+ );
150
+ if (!(anchor instanceof HTMLElement)) return {};
151
+
152
+ for (const attribute of [
153
+ "data-agent-native-node-id",
154
+ "data-builder-id",
155
+ "data-loc",
156
+ ]) {
157
+ const value = anchor.getAttribute(attribute);
158
+ if (value) {
159
+ return {
160
+ targetSelector: `[${attribute}="${escapeAttributeValue(value)}"]`,
161
+ targetAnchorId: value,
162
+ };
163
+ }
164
+ }
165
+
166
+ if (anchor.id) {
167
+ return {
168
+ targetSelector: `#${escapeCssIdentifier(anchor.id)}`,
169
+ targetAnchorId: anchor.id,
170
+ };
171
+ }
172
+
173
+ return {};
174
+ }
175
+
176
+ function wordsIncludePair(
177
+ text: string,
178
+ first: string,
179
+ second: string,
180
+ ): boolean {
181
+ return (
182
+ new RegExp(`\\b${first}\\b`, "i").test(text) &&
183
+ new RegExp(`\\b${second}\\b`, "i").test(text)
184
+ );
185
+ }
186
+
187
+ function hasContradictoryLanguage(text: string): boolean {
188
+ return [
189
+ ["bigger", "smaller"],
190
+ ["larger", "smaller"],
191
+ ["hide", "show"],
192
+ ["remove", "keep"],
193
+ ["delete", "keep"],
194
+ ["left", "right"],
195
+ ["top", "bottom"],
196
+ ["dark", "light"],
197
+ ].some(([first, second]) => wordsIncludePair(text, first, second));
198
+ }
199
+
200
+ function pinsLikelyOverlap(pin: CanvasPin, other: CanvasPin): boolean {
201
+ if (pin.id === other.id || other.submitted) return false;
202
+ if (pin.targetSelector && pin.targetSelector === other.targetSelector)
203
+ return true;
204
+ const xDelta = Math.abs(pin.xPct - other.xPct);
205
+ const yDelta = Math.abs(pin.yPct - other.yPct);
206
+ return xDelta <= 4 && yDelta <= 4;
207
+ }
208
+
209
+ function derivePinStatus(pin: CanvasPin, pins: CanvasPin[]): PinStatusMeta {
210
+ const text = (pin.draft || "").toLowerCase();
211
+ const anchored = Boolean(pin.targetSelector || pin.targetAnchorId);
212
+ const unsupported =
213
+ /\b(api|backend|database|server|auth|login|oauth|stripe|payment|email|webhook|permission|role|roles|deploy|domain|routing|route|video|audio|3d|three\.js|pdf|spreadsheet)\b/i.test(
214
+ text,
215
+ );
216
+ if (unsupported) return STATUS_META.unsupported;
217
+
218
+ const overlaps = pins.some(
219
+ (other) =>
220
+ pinsLikelyOverlap(pin, other) &&
221
+ (pin.draft || "").trim() &&
222
+ (other.draft || "").trim() &&
223
+ (pin.draft || "").trim() !== (other.draft || "").trim(),
224
+ );
225
+ if (overlaps || hasContradictoryLanguage(text)) {
226
+ return STATUS_META.conflict;
227
+ }
228
+
229
+ const directEdit =
230
+ /\b(color|font|copy|text|label|spacing|gap|margin|padding|radius|rounded|border|align|center|move|resize|width|height|background|image|button|headline|section|swap|replace)\b/i.test(
231
+ text,
232
+ );
233
+ const vagueInstruction =
234
+ /\b(polish|improve|better|nice|clean up|fix it|make it work|decide|surprise me)\b/i.test(
235
+ text,
236
+ );
237
+
238
+ if (anchored && directEdit && !vagueInstruction) {
239
+ return STATUS_META.deterministic;
240
+ }
241
+
242
+ return STATUS_META["needs-agent"];
243
+ }
244
+
245
+ function PinStatusBadge({ status }: { status: PinStatusMeta }) {
246
+ const Icon =
247
+ status.status === "deterministic"
248
+ ? IconCircleCheck
249
+ : status.status === "unsupported" || status.status === "conflict"
250
+ ? IconAlertTriangle
251
+ : IconBolt;
252
+
253
+ return (
254
+ <Tooltip>
255
+ <TooltipTrigger asChild>
256
+ <span
257
+ className={cn(
258
+ "inline-flex items-center gap-1 rounded-full border px-1.5 py-0.5 text-[10px] font-medium leading-none",
259
+ status.badgeClassName,
260
+ )}
261
+ >
262
+ <Icon className="size-3" />
263
+ {status.label}
264
+ </span>
265
+ </TooltipTrigger>
266
+ <TooltipContent>{status.detail}</TooltipContent>
267
+ </Tooltip>
268
+ );
269
+ }
270
+
52
271
  /**
53
272
  * Click-to-comment pins anchored to the canvas.
54
273
  *
@@ -67,7 +286,11 @@ interface CanvasCommentPinsProps {
67
286
  */
68
287
  export function CanvasCommentPins({
69
288
  active,
289
+ submitMode = "direct",
70
290
  onClose,
291
+ onPinsChange,
292
+ submitQueuedSignal,
293
+ clickPlaneUnderToolbar = false,
71
294
  canvasSelector,
72
295
  contextId,
73
296
  contextLabel,
@@ -76,6 +299,7 @@ export function CanvasCommentPins({
76
299
  const [pins, setPins] = useState<CanvasPin[]>([]);
77
300
  const [activePinId, setActivePinId] = useState<string | null>(null);
78
301
  const containerRef = useRef<HTMLElement | null>(null);
302
+ const lastSubmitQueuedSignalRef = useRef(submitQueuedSignal);
79
303
  const [canvasEl, setCanvasEl] = useState<HTMLElement | null>(null);
80
304
 
81
305
  // Reset pins when the context (slide) changes — they're scoped to one view.
@@ -113,12 +337,7 @@ export function CanvasCommentPins({
113
337
  // Build a best-effort selector for parent-DOM canvases. For iframe
114
338
  // canvases the transparent overlay captures the click, so target details
115
339
  // are intentionally omitted but the precise position is preserved.
116
- let targetSelector: string | undefined;
117
- const builderId = target
118
- ?.closest("[data-builder-id]")
119
- ?.getAttribute("data-builder-id");
120
- if (builderId) targetSelector = `[data-builder-id="${builderId}"]`;
121
-
340
+ const { targetSelector, targetAnchorId } = getTargetAnchor(target);
122
341
  const targetText = target?.textContent?.trim().slice(0, 80) || undefined;
123
342
 
124
343
  const newPin: CanvasPin = {
@@ -126,6 +345,7 @@ export function CanvasCommentPins({
126
345
  xPct,
127
346
  yPct,
128
347
  targetSelector,
348
+ targetAnchorId,
129
349
  targetText,
130
350
  draft: "",
131
351
  };
@@ -181,34 +401,140 @@ export function CanvasCommentPins({
181
401
  if (activePinId === id) setActivePinId(null);
182
402
  };
183
403
 
184
- const submitPin = (pin: CanvasPin) => {
185
- const text = (pin.draft || "").trim();
186
- if (!text) {
187
- removePin(pin.id);
404
+ const queuedPins = useMemo(
405
+ () =>
406
+ pins.filter(
407
+ (pin) => pin.queued && !pin.submitted && (pin.draft || "").trim(),
408
+ ),
409
+ [pins],
410
+ );
411
+
412
+ useEffect(() => {
413
+ onPinsChange?.(pins);
414
+ }, [onPinsChange, pins]);
415
+
416
+ useEffect(() => {
417
+ if (
418
+ submitQueuedSignal === undefined ||
419
+ submitQueuedSignal === lastSubmitQueuedSignalRef.current
420
+ ) {
188
421
  return;
189
422
  }
423
+ lastSubmitQueuedSignalRef.current = submitQueuedSignal;
424
+ if (queuedPins.length === 0) return;
425
+ const submittedIds = new Set(queuedPins.map((pin) => pin.id));
426
+ setPins((prev) =>
427
+ prev.map((pin) =>
428
+ submittedIds.has(pin.id)
429
+ ? { ...pin, queued: false, submitted: true }
430
+ : pin,
431
+ ),
432
+ );
433
+ setActivePinId(null);
434
+ }, [queuedPins, submitQueuedSignal]);
435
+
436
+ const submittedCount = pins.filter((pin) => pin.submitted).length;
437
+ const statusCounts = useMemo(
438
+ () =>
439
+ pins.reduce<Record<PinCapabilityStatus, number>>(
440
+ (counts, pin) => {
441
+ const status = derivePinStatus(pin, pins).status;
442
+ counts[status] += 1;
443
+ return counts;
444
+ },
445
+ {
446
+ deterministic: 0,
447
+ "needs-agent": 0,
448
+ conflict: 0,
449
+ unsupported: 0,
450
+ },
451
+ ),
452
+ [pins],
453
+ );
454
+
455
+ const buildPinLines = (pin: CanvasPin, index?: number) => {
456
+ const status = localizePinStatus(derivePinStatus(pin, pins), t);
190
457
  const lines = [
191
- `[Comment pin on ${contextLabel || contextId}]`,
458
+ index === undefined
459
+ ? `[Comment pin on ${contextLabel || contextId}]`
460
+ : `[${index + 1}] Comment pin on ${contextLabel || contextId}`,
192
461
  `Position: ${pin.xPct.toFixed(1)}% from left, ${pin.yPct.toFixed(1)}% from top`,
462
+ `Capability: ${status.label} - ${status.detail}`,
193
463
  ];
464
+ if (pin.targetAnchorId) lines.push(`Anchor id: ${pin.targetAnchorId}`);
194
465
  if (pin.targetSelector) lines.push(`Element: ${pin.targetSelector}`);
195
466
  if (pin.targetText) lines.push(`Nearby text: "${pin.targetText}"`);
196
467
  lines.push("");
197
- lines.push(text);
468
+ lines.push((pin.draft || "").trim());
469
+ return lines;
470
+ };
471
+
472
+ const sendPinsToAgent = (targetPins: CanvasPin[], batch = false) => {
473
+ const message = batch
474
+ ? [
475
+ `[Comment batch on ${contextLabel || contextId}]`,
476
+ `Annotations: ${targetPins.length}`,
477
+ "",
478
+ ...targetPins.flatMap((pin, index) => [
479
+ ...buildPinLines(pin, index),
480
+ "",
481
+ ]),
482
+ ].join("\n")
483
+ : buildPinLines(targetPins[0]!).join("\n");
484
+
198
485
  try {
199
486
  // Use `sendToAgentChat` (not the shared `agentChat.submit`) so the
200
487
  // request routes correctly when design is embedded in Builder/Frame
201
488
  // and so the agent sidebar is reliably opened via the `agent-panel:open`
202
489
  // custom event even if the user has it collapsed.
203
490
  sendToAgentChat({
204
- message: lines.join("\n"),
491
+ message,
205
492
  submit: true,
206
493
  openSidebar: true,
207
494
  });
208
495
  } catch (err) {
209
496
  console.error("[CanvasCommentPins] failed to send to agent:", err);
210
497
  }
211
- updatePin(pin.id, { submitted: true });
498
+ };
499
+
500
+ const queuePin = (pin: CanvasPin) => {
501
+ const text = (pin.draft || "").trim();
502
+ if (!text) {
503
+ removePin(pin.id);
504
+ return;
505
+ }
506
+ updatePin(pin.id, { draft: text, queued: true });
507
+ setActivePinId(null);
508
+ };
509
+
510
+ const submitPin = (pin: CanvasPin) => {
511
+ const text = (pin.draft || "").trim();
512
+ if (!text) {
513
+ removePin(pin.id);
514
+ return;
515
+ }
516
+ if (submitMode === "queue") {
517
+ queuePin(pin);
518
+ return;
519
+ }
520
+ const nextPin = { ...pin, draft: text };
521
+ sendPinsToAgent([nextPin]);
522
+ updatePin(pin.id, { draft: text, queued: false, submitted: true });
523
+ setActivePinId(null);
524
+ };
525
+
526
+ const submitQueuedPins = () => {
527
+ if (queuedPins.length === 0) return;
528
+ if (submitMode === "queue") return;
529
+ sendPinsToAgent(queuedPins, true);
530
+ const submittedIds = new Set(queuedPins.map((pin) => pin.id));
531
+ setPins((prev) =>
532
+ prev.map((pin) =>
533
+ submittedIds.has(pin.id)
534
+ ? { ...pin, queued: false, submitted: true }
535
+ : pin,
536
+ ),
537
+ );
212
538
  setActivePinId(null);
213
539
  };
214
540
 
@@ -218,6 +544,8 @@ export function CanvasCommentPins({
218
544
  const canvas = containerRef.current ?? canvasEl;
219
545
  if (!canvas) return null;
220
546
  const rect = canvas.getBoundingClientRect();
547
+ const summaryLeft = Math.min(rect.right - 8, window.innerWidth - 8);
548
+ const summaryTop = Math.max(rect.top + 8, 72);
221
549
 
222
550
  return (
223
551
  <>
@@ -226,7 +554,10 @@ export function CanvasCommentPins({
226
554
  {active && (
227
555
  <div
228
556
  data-pin-click-overlay
229
- className="fixed z-[54] cursor-crosshair"
557
+ className={cn(
558
+ "fixed cursor-crosshair",
559
+ clickPlaneUnderToolbar ? "z-[20]" : "z-[54]",
560
+ )}
230
561
  style={{
231
562
  left: rect.left,
232
563
  top: rect.top,
@@ -261,12 +592,73 @@ export function CanvasCommentPins({
261
592
  </div>
262
593
  )}
263
594
 
595
+ {/* Compact queue/result summary for local annotation batching. */}
596
+ {pins.length > 0 && (
597
+ <div
598
+ data-pin-popover
599
+ className="fixed z-[56] w-64 -translate-x-full rounded-lg border border-border bg-popover p-3 shadow-xl"
600
+ style={{ left: summaryLeft, top: summaryTop }}
601
+ >
602
+ <div className="mb-2 flex items-center justify-between gap-2">
603
+ <div className="min-w-0">
604
+ <p className="truncate text-xs font-semibold text-foreground">
605
+ {t("visualEditor.annotationQueue")}
606
+ </p>
607
+ <p className="text-[10px] text-muted-foreground">
608
+ {t("visualEditor.annotationQueueCounts", {
609
+ queued: queuedPins.length,
610
+ sent: submittedCount,
611
+ })}
612
+ </p>
613
+ </div>
614
+ {submitMode === "direct" ? (
615
+ <Button
616
+ size="sm"
617
+ className="h-7 gap-1 px-2 text-[10px]"
618
+ onClick={submitQueuedPins}
619
+ disabled={queuedPins.length === 0}
620
+ >
621
+ <IconBolt className="size-3" />
622
+ {t("visualEditor.batchApply")}
623
+ </Button>
624
+ ) : (
625
+ <span className="rounded-md bg-muted px-2 py-1 text-[10px] font-medium text-muted-foreground">
626
+ {t("visualEditor.queued")}
627
+ </span>
628
+ )}
629
+ </div>
630
+ <div className="grid grid-cols-2 gap-1 text-[10px]">
631
+ <span className="rounded-md bg-muted/45 px-2 py-1 text-muted-foreground">
632
+ {t("visualEditor.pinStatusCount.direct", {
633
+ count: statusCounts.deterministic,
634
+ })}
635
+ </span>
636
+ <span className="rounded-md bg-muted/45 px-2 py-1 text-muted-foreground">
637
+ {t("visualEditor.pinStatusCount.agent", {
638
+ count: statusCounts["needs-agent"],
639
+ })}
640
+ </span>
641
+ <span className="rounded-md bg-muted/45 px-2 py-1 text-muted-foreground">
642
+ {t("visualEditor.pinStatusCount.conflict", {
643
+ count: statusCounts.conflict,
644
+ })}
645
+ </span>
646
+ <span className="rounded-md bg-muted/45 px-2 py-1 text-muted-foreground">
647
+ {t("visualEditor.pinStatusCount.blocked", {
648
+ count: statusCounts.unsupported,
649
+ })}
650
+ </span>
651
+ </div>
652
+ </div>
653
+ )}
654
+
264
655
  {/* Pin overlays */}
265
656
  {pins.map((pin) => {
266
657
  const left = rect.left + (pin.xPct / 100) * rect.width;
267
658
  const top = rect.top + (pin.yPct / 100) * rect.height;
268
659
  const isActive = activePinId === pin.id;
269
660
  const PinIcon = pin.submitted ? IconMessageCheck : IconMessage;
661
+ const status = localizePinStatus(derivePinStatus(pin, pins), t);
270
662
  return (
271
663
  <div
272
664
  key={pin.id}
@@ -288,23 +680,37 @@ export function CanvasCommentPins({
288
680
  if (!pin.submitted) setActivePinId(pin.id);
289
681
  }}
290
682
  className={cn(
291
- "absolute -translate-x-1/2 -translate-y-full -mt-1 flex items-center justify-center w-7 h-7 rounded-full rounded-bl-none shadow-lg cursor-pointer",
292
- pin.submitted
293
- ? "bg-emerald-500 text-white"
294
- : "bg-[#609FF8] text-black",
295
- "hover:scale-110 transition-transform",
683
+ "absolute -mt-1 flex size-7 -translate-x-1/2 -translate-y-full cursor-pointer items-center justify-center rounded-full rounded-bl-none shadow-lg ring-2 transition-transform hover:scale-110",
684
+ status.markerClassName,
685
+ pin.submitted && "opacity-95",
296
686
  )}
297
687
  >
298
- <PinIcon className="w-3.5 h-3.5" />
688
+ <PinIcon className="size-3.5" />
299
689
  </button>
300
690
  </TooltipTrigger>
301
691
  <TooltipContent className="pointer-events-none">
302
- {pin.draft ||
303
- (pin.submitted
304
- ? t("visualEditor.commentSent")
305
- : t("visualEditor.comment"))}
692
+ {pin.queued
693
+ ? t("visualEditor.queuedStatus", { status: status.label })
694
+ : pin.draft ||
695
+ (pin.submitted
696
+ ? t("visualEditor.commentSentStatus", {
697
+ status: status.label,
698
+ })
699
+ : t("visualEditor.commentStatus", {
700
+ status: status.label,
701
+ }))}
306
702
  </TooltipContent>
307
703
  </Tooltip>
704
+ <span
705
+ className={cn(
706
+ "pointer-events-none absolute left-3 -top-10 rounded-full border px-1.5 py-0.5 text-[9px] font-medium leading-none shadow-sm",
707
+ status.badgeClassName,
708
+ )}
709
+ >
710
+ {pin.queued && !pin.submitted
711
+ ? t("visualEditor.queued")
712
+ : status.shortLabel}
713
+ </span>
308
714
 
309
715
  {/* Inline composer. z-[260] keeps it above the shadcn floating-UI
310
716
  * tier (z-[250] — Tooltip, Popover, Dialog overlay, etc.) so a
@@ -314,13 +720,21 @@ export function CanvasCommentPins({
314
720
  data-pin-popover
315
721
  className="absolute z-[260] left-3 top-1 w-72 rounded-lg border border-border bg-popover shadow-xl p-2"
316
722
  >
317
- <p className="mb-2 text-xs font-semibold text-foreground">
318
- {t("visualEditor.editDesign")}
319
- </p>
723
+ <div className="mb-2 flex items-center justify-between gap-2">
724
+ <p className="text-xs font-semibold text-foreground">
725
+ {t("visualEditor.editDesign")}
726
+ </p>
727
+ <PinStatusBadge status={status} />
728
+ </div>
320
729
  <Textarea
321
730
  autoFocus
322
731
  value={pin.draft || ""}
323
- onChange={(e) => updatePin(pin.id, { draft: e.target.value })}
732
+ onChange={(e) =>
733
+ updatePin(pin.id, {
734
+ draft: e.target.value,
735
+ queued: false,
736
+ })
737
+ }
324
738
  onKeyDown={(e) => {
325
739
  if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
326
740
  e.preventDefault();
@@ -334,15 +748,28 @@ export function CanvasCommentPins({
334
748
  placeholder={t("visualEditor.tellAgentWhatToChange")}
335
749
  className="resize-none text-xs min-h-[60px]"
336
750
  />
751
+ <p className="mt-1 text-[10px] leading-4 text-muted-foreground">
752
+ {status.detail}
753
+ </p>
754
+ {pin.targetAnchorId && (
755
+ <div className="mt-1 truncate rounded-md bg-muted/45 px-2 py-1 text-[10px] text-muted-foreground">
756
+ {t("visualEditor.anchorLabel", {
757
+ id: pin.targetAnchorId,
758
+ })}
759
+ </div>
760
+ )}
337
761
  {pin.targetText && (
338
762
  <div className="text-[10px] text-muted-foreground mt-1 italic line-clamp-1">
339
- near "{pin.targetText}"
763
+ {t("visualEditor.nearText", { text: pin.targetText })}
340
764
  </div>
341
765
  )}
342
766
  <div className="flex items-center justify-between mt-2">
343
767
  <span className="text-[10px] text-muted-foreground">
344
- {/Mac|iPhone|iPad/.test(navigator.userAgent) ? "⌘" : "Ctrl"}
345
- +Enter to submit
768
+ {t("visualEditor.submitShortcut", {
769
+ mod: /Mac|iPhone|iPad/.test(navigator.userAgent)
770
+ ? "⌘"
771
+ : "Ctrl",
772
+ })}
346
773
  </span>
347
774
  <div className="flex gap-1">
348
775
  <Button
@@ -355,13 +782,24 @@ export function CanvasCommentPins({
355
782
  </Button>
356
783
  <Button
357
784
  size="sm"
785
+ variant="outline"
358
786
  className="h-6 gap-1 px-2 text-[10px] cursor-pointer"
359
- onClick={() => submitPin(pin)}
787
+ onClick={() => queuePin(pin)}
360
788
  disabled={!(pin.draft || "").trim()}
361
789
  >
362
- <IconSend className="w-3 h-3" />
363
- {t("visualEditor.send")}
790
+ {t("visualEditor.queue")}
364
791
  </Button>
792
+ {submitMode === "direct" && (
793
+ <Button
794
+ size="sm"
795
+ className="h-6 gap-1 px-2 text-[10px] cursor-pointer"
796
+ onClick={() => submitPin(pin)}
797
+ disabled={!(pin.draft || "").trim()}
798
+ >
799
+ <IconSend className="w-3 h-3" />
800
+ {t("visualEditor.send")}
801
+ </Button>
802
+ )}
365
803
  </div>
366
804
  </div>
367
805
  </div>