@agent-native/core 0.169.1 → 0.170.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (459) hide show
  1. package/agent-native.eject.json +4 -1
  2. package/bin/agent-native.js +23 -5
  3. package/corpus/README.md +1 -1
  4. package/corpus/templates/analytics/.agents/skills/secrets/SKILL.md +11 -4
  5. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
  6. package/corpus/templates/analytics/app/i18n-data.ts +28 -0
  7. package/corpus/templates/analytics/app/pages/Agents.tsx +25 -1
  8. package/corpus/templates/analytics/app/routes/$.tsx +10 -0
  9. package/corpus/templates/analytics/app/routes.ts +3 -1
  10. package/corpus/templates/analytics/changelog/2026-08-22-fixed-the-agent-native-templates-first-party-dashboard-panel.md +6 -0
  11. package/corpus/templates/analytics/changelog/2026-08-22-org-admin-panels-no-longer-report-a-database-error-as-a-per.md +9 -0
  12. package/corpus/templates/analytics/changelog/2026-08-22-slack-requests-report-invalid-inputs.md +6 -0
  13. package/corpus/templates/analytics/changelog/2026-08-22-unknown-analytics-links-now-return-a-real-not-found-status.md +6 -0
  14. package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +2 -1
  15. package/corpus/templates/analytics/docs/schemas/tracked-events.md +2 -0
  16. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +29 -7
  17. package/corpus/templates/analytics/server/handlers/slack.ts +59 -5
  18. package/corpus/templates/analytics/server/lib/db-admin-connections.ts +11 -6
  19. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +132 -2
  20. package/corpus/templates/analytics/server/lib/slack.ts +4 -2
  21. package/corpus/templates/analytics/vitest.config.ts +6 -1
  22. package/corpus/templates/assets/.agents/skills/secrets/SKILL.md +11 -4
  23. package/corpus/templates/assets/app/routes/library.tsx +5 -3
  24. package/corpus/templates/assets/app/routes.ts +3 -1
  25. package/corpus/templates/assets/changelog/2026-08-22-library-page-loads-again-instead-of-crashing-on-open.md +6 -0
  26. package/corpus/templates/assets/vitest.config.ts +6 -1
  27. package/corpus/templates/brain/.agents/skills/secrets/SKILL.md +11 -4
  28. package/corpus/templates/brain/app/components/ui/pointer-lock.ts +1 -0
  29. package/corpus/templates/brain/app/routes/sources.tsx +8 -3
  30. package/corpus/templates/brain/changelog/2026-08-22-tuning-or-adding-a-source-no-longer-leaves-the-sources-page.md +6 -0
  31. package/corpus/templates/brain/vitest.config.ts +1 -0
  32. package/corpus/templates/calendar/.agents/skills/secrets/SKILL.md +11 -4
  33. package/corpus/templates/calendar/actions/list-booking-links.ts +83 -4
  34. package/corpus/templates/calendar/actions/update-booking-link.ts +4 -3
  35. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +11 -3
  36. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +1 -1
  37. package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +103 -44
  38. package/corpus/templates/calendar/app/components/calendar/OutOfOfficeEvent.tsx +28 -24
  39. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +9 -2
  40. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +47 -58
  41. package/corpus/templates/calendar/app/hooks/use-booking-links.ts +5 -1
  42. package/corpus/templates/calendar/app/lib/event-layout.ts +52 -26
  43. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +126 -98
  44. package/corpus/templates/calendar/app/pages/CalendarView.tsx +1 -0
  45. package/corpus/templates/calendar/app/pages/Settings.tsx +88 -81
  46. package/corpus/templates/calendar/app/routes.ts +3 -1
  47. package/corpus/templates/calendar/changelog/2026-08-22-booking-link-visibility-respects-shared-access.md +6 -0
  48. package/corpus/templates/calendar/changelog/2026-08-22-clicking-an-out-of-office-event-s-marker-no-longer-creates-a.md +6 -0
  49. package/corpus/templates/calendar/changelog/2026-08-22-event-detail-views-now-show-your-calendar-timezone.md +6 -0
  50. package/corpus/templates/calendar/changelog/2026-08-22-google-calendar-can-now-connect-with-the-shared-google-oauth.md +6 -0
  51. package/corpus/templates/calendar/changelog/2026-08-22-overlapping-events-now-show-each-others-boundaries.md +6 -0
  52. package/corpus/templates/calendar/changelog/2026-08-22-public-booking-pages-now-offer-time-slots-from-the-host-s-we.md +6 -0
  53. package/corpus/templates/calendar/server/handlers/bookings.ts +5 -7
  54. package/corpus/templates/calendar/server/handlers/google-auth.ts +10 -2
  55. package/corpus/templates/calendar/server/lib/google-calendar.ts +139 -14
  56. package/corpus/templates/calendar/server/onboarding.ts +85 -0
  57. package/corpus/templates/calendar/server/plugins/agent-chat.ts +2 -0
  58. package/corpus/templates/calendar/shared/api.ts +9 -1
  59. package/corpus/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
  60. package/corpus/templates/chat/app/routes.ts +3 -1
  61. package/corpus/templates/chat/vitest.config.ts +8 -0
  62. package/corpus/templates/clips/.agents/skills/secrets/SKILL.md +11 -4
  63. package/corpus/templates/clips/actions/get-meeting.ts +9 -4
  64. package/corpus/templates/clips/actions/list-recordings.ts +16 -3
  65. package/corpus/templates/clips/actions/search-meetings.ts +1 -0
  66. package/corpus/templates/clips/actions/view-screen.ts +8 -1
  67. package/corpus/templates/clips/app/components/meetings/meeting-history-row.tsx +32 -1
  68. package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +1 -1
  69. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +29 -1
  70. package/corpus/templates/clips/app/i18n/en-US.ts +5 -0
  71. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +33 -4
  72. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +1 -0
  73. package/corpus/templates/clips/app/routes/access-request.approve.tsx +16 -9
  74. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +17 -7
  75. package/corpus/templates/clips/app/routes/share.$shareId.tsx +17 -7
  76. package/corpus/templates/clips/changelog/2026-08-21-camera-bubble-black-circle.md +6 -0
  77. package/corpus/templates/clips/changelog/2026-08-22-screen-recordings-respect-the-microphone-toggle.md +6 -0
  78. package/corpus/templates/clips/changelog/2026-08-22-the-recordings-library-no-longer-fails-right-after-server-start.md +6 -0
  79. package/corpus/templates/clips/changelog/2026-08-23-the-agent-can-see-your-library-right-after-server-start.md +6 -0
  80. package/corpus/templates/clips/chrome-extension/src/background.ts +1 -2
  81. package/corpus/templates/clips/chrome-extension/src/native-transcription.ts +39 -7
  82. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +21 -25
  83. package/corpus/templates/clips/desktop/src/app.tsx +53 -24
  84. package/corpus/templates/clips/desktop/src/lib/bubble-playback.ts +68 -0
  85. package/corpus/templates/clips/desktop/src/lib/recorder.ts +3 -0
  86. package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +72 -14
  87. package/corpus/templates/clips/desktop/src/lib/updater.ts +8 -3
  88. package/corpus/templates/clips/desktop/src/overlays/bubble.tsx +162 -20
  89. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +43 -6
  90. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +150 -13
  91. package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +12 -0
  92. package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +28 -3
  93. package/corpus/templates/clips/server/lib/emails.ts +17 -33
  94. package/corpus/templates/content/.agents/skills/secrets/SKILL.md +11 -4
  95. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +140 -15
  96. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +12 -14
  97. package/corpus/templates/content/app/components/ui/pointer-lock.ts +1 -0
  98. package/corpus/templates/content/app/hooks/use-content-database.ts +18 -2
  99. package/corpus/templates/content/app/hooks/use-local-storage.ts +38 -22
  100. package/corpus/templates/content/app/i18n-data.ts +25 -0
  101. package/corpus/templates/content/app/routes.ts +3 -1
  102. package/corpus/templates/content/changelog/2026-08-22-code-blocks-inserted-from-the-slash-menu-no-longer-get-stuck.md +6 -0
  103. package/corpus/templates/content/changelog/2026-08-22-the-sidebar-page-tree-no-longer-flashes-empty-after-creating-a-page.md +6 -0
  104. package/corpus/templates/content/docs/solutions/2026-08-21-content-mermaid-rendering-shape.md +233 -0
  105. package/corpus/templates/content/server/plugins/agent-chat.ts +9 -2
  106. package/corpus/templates/content/vitest.config.ts +7 -1
  107. package/corpus/templates/crm/.agents/skills/secrets/SKILL.md +11 -4
  108. package/corpus/templates/design/.agents/skills/secrets/SKILL.md +11 -4
  109. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +1383 -88
  110. package/corpus/templates/design/actions/generate-design.ts +98 -47
  111. package/corpus/templates/design/actions/get-design-system.ts +6 -1
  112. package/corpus/templates/design/actions/refresh-design-system-with-builder.ts +146 -0
  113. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +70 -26
  114. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +284 -136
  115. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +2057 -141
  116. package/corpus/templates/design/app/components/design/editor/DesignBottomToolbar.tsx +6 -2
  117. package/corpus/templates/design/app/components/design/editor/DesignWorkspaceRail.tsx +4 -4
  118. package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +10 -1
  119. package/corpus/templates/design/app/components/design/multi-screen/alt-hover-measurement.ts +19 -2
  120. package/corpus/templates/design/app/components/design/multi-screen/types.ts +9 -2
  121. package/corpus/templates/design/app/components/layout/Header.tsx +15 -0
  122. package/corpus/templates/design/app/components/layout/Layout.tsx +7 -2
  123. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +11 -4
  124. package/corpus/templates/design/app/i18n-data.ts +1 -0
  125. package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +12 -0
  126. package/corpus/templates/design/app/lib/design-system-data.ts +68 -0
  127. package/corpus/templates/design/app/pages/DesignEditor.tsx +77 -35
  128. package/corpus/templates/design/app/pages/DesignSystems.tsx +136 -42
  129. package/corpus/templates/design/app/pages/Index.tsx +2 -0
  130. package/corpus/templates/design/app/pages/Templates.tsx +0 -10
  131. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +10 -0
  132. package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +50 -0
  133. package/corpus/templates/design/app/pages/design-editor/commands/apply-design-editor-command.ts +1 -1
  134. package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +10 -8
  135. package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +6 -6
  136. package/corpus/templates/design/app/pages/design-editor/commands/apply-pending-visual-styles-with-agent.ts +1 -1
  137. package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +18 -7
  138. package/corpus/templates/design/app/pages/design-editor/commands/escape-hotkey.ts +4 -90
  139. package/corpus/templates/design/app/pages/design-editor/commands/layer-marquee-selection-change.ts +2 -1
  140. package/corpus/templates/design/app/pages/design-editor/commands/layer-selection-change.ts +4 -3
  141. package/corpus/templates/design/app/pages/design-editor/commands/screen-element-select.ts +12 -2
  142. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-style-change.ts +9 -2
  143. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-move-semantic-handoff.ts +1 -1
  144. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-semantic-handoff.ts +1 -1
  145. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-state-semantic-handoff.ts +1 -1
  146. package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +1 -1
  147. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +11 -1
  148. package/corpus/templates/design/app/pages/design-editor/effects/adopt-db-file-content.ts +11 -19
  149. package/corpus/templates/design/app/pages/design-editor/effects/observe-collab-text.ts +6 -6
  150. package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +1 -1
  151. package/corpus/templates/design/app/pages/design-editor/effects/seed-collab-content.ts +12 -15
  152. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +5 -59
  153. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +8 -0
  154. package/corpus/templates/design/app/pages/design-editor/types.ts +3 -3
  155. package/corpus/templates/design/app/routes.ts +3 -1
  156. package/corpus/templates/design/changelog/2026-08-20-canvas-edits-patch-the-frame-instead-of-rebuilding-it.md +6 -0
  157. package/corpus/templates/design/changelog/2026-08-21-builder-design-system-imports-reconcile-after-indexing.md +6 -0
  158. package/corpus/templates/design/changelog/2026-08-21-draw-mode-needs-shift-y.md +6 -0
  159. package/corpus/templates/design/changelog/2026-08-21-eyedropper-shortcut.md +6 -0
  160. package/corpus/templates/design/changelog/2026-08-21-figma-style-alignment-guides-and-snapping.md +6 -0
  161. package/corpus/templates/design/changelog/2026-08-21-group-transforms-keep-the-selection.md +6 -0
  162. package/corpus/templates/design/changelog/2026-08-21-inspector-fields-keep-focus-on-enter.md +6 -0
  163. package/corpus/templates/design/changelog/2026-08-21-pen-alt-keeps-the-incoming-handle.md +6 -0
  164. package/corpus/templates/design/changelog/2026-08-21-pen-on-the-board-creates-one-vector.md +6 -0
  165. package/corpus/templates/design/changelog/2026-08-21-scale-a-multi-selection-from-the-group-handles.md +6 -0
  166. package/corpus/templates/design/changelog/2026-08-21-scale-resizes-text-with-the-object.md +6 -0
  167. package/corpus/templates/design/changelog/2026-08-21-selecting-another-object-keeps-the-scale-tool-armed.md +6 -0
  168. package/corpus/templates/design/changelog/2026-08-21-the-shape-tool-remembers-the-shape-you-picked.md +6 -0
  169. package/corpus/templates/design/changelog/2026-08-21-vectors-drawn-in-a-frame-land-where-you-drew-them.md +6 -0
  170. package/corpus/templates/design/changelog/2026-08-22-multi-screen-generation-no-longer-loses-a-saved-screens-layo.md +6 -0
  171. package/corpus/templates/design/changelog/2026-08-22-rename-and-search-fields-are-labeled-for-screen-readers.md +6 -0
  172. package/corpus/templates/design/package.json +2 -0
  173. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +311 -0
  174. package/corpus/templates/design/shared/canvas-math.ts +612 -206
  175. package/corpus/templates/design/shared/pen-path.ts +37 -0
  176. package/corpus/templates/design/vitest.config.ts +7 -1
  177. package/corpus/templates/dispatch/.agents/skills/secrets/SKILL.md +11 -4
  178. package/corpus/templates/dispatch/actions/list-workspace-connections.ts +34 -3
  179. package/corpus/templates/dispatch/app/routes/integrations.tsx +55 -21
  180. package/corpus/templates/dispatch/app/routes.ts +3 -1
  181. package/corpus/templates/factory/.agents/skills/secrets/SKILL.md +11 -4
  182. package/corpus/templates/factory/.env.example +2 -7
  183. package/corpus/templates/factory/AGENTS.md +3 -0
  184. package/corpus/templates/factory/README.md +5 -3
  185. package/corpus/templates/factory/actions/create-factory.ts +16 -3
  186. package/corpus/templates/factory/actions/get-slack-feedback-context.ts +2 -0
  187. package/corpus/templates/factory/actions/get-triage-item.ts +2 -0
  188. package/corpus/templates/factory/actions/list-factory-audit.ts +116 -36
  189. package/corpus/templates/factory/actions/list-factory-automations.ts +2 -1
  190. package/corpus/templates/factory/actions/list-triage-items.ts +22 -19
  191. package/corpus/templates/factory/actions/run-factory-automation.ts +7 -3
  192. package/corpus/templates/factory/actions/save-factory-automation.ts +5 -2
  193. package/corpus/templates/factory/actions/save-triage-config.ts +2 -8
  194. package/corpus/templates/factory/actions/start-builder-for-item.ts +21 -0
  195. package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +229 -297
  196. package/corpus/templates/factory/app/components/factory/FactorySettingsView.tsx +397 -247
  197. package/corpus/templates/factory/app/components/factory/FactorySourceSettingsGroup.tsx +33 -0
  198. package/corpus/templates/factory/app/components/factory/NewFactoryForm.tsx +202 -162
  199. package/corpus/templates/factory/app/i18n/en-US.ts +32 -4
  200. package/corpus/templates/factory/app/routes/factory.tsx +84 -11
  201. package/corpus/templates/factory/app/routes.ts +3 -1
  202. package/corpus/templates/factory/changelog/2026-08-21-activity-runs-use-automation-display-names.md +6 -0
  203. package/corpus/templates/factory/changelog/2026-08-21-create-and-settings-source-cards.md +6 -0
  204. package/corpus/templates/factory/changelog/2026-08-21-keep-automations-visible-while-running.md +6 -0
  205. package/corpus/templates/factory/changelog/2026-08-21-nested-factory-automations-can-poll.md +6 -0
  206. package/corpus/templates/factory/changelog/2026-08-21-settings-sticky-unsaved-bar.md +6 -0
  207. package/corpus/templates/factory/server/connectors/credentials.ts +10 -5
  208. package/corpus/templates/factory/server/lib/factory-audit-report.ts +412 -0
  209. package/corpus/templates/factory/server/lib/factory-config-reconcile.ts +321 -0
  210. package/corpus/templates/factory/server/lib/factory-scope.ts +25 -2
  211. package/corpus/templates/factory/server/lib/require-factory-automation.ts +13 -4
  212. package/corpus/templates/factory/server/plugins/factory-migrations.ts +148 -4
  213. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +4 -6
  214. package/corpus/templates/factory/vitest.config.ts +17 -2
  215. package/corpus/templates/forms/.agents/skills/secrets/SKILL.md +11 -4
  216. package/corpus/templates/forms/app/routes/_app.settings.tsx +4 -1
  217. package/corpus/templates/forms/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
  218. package/corpus/templates/forms/server/lib/public-form-ssr.ts +11 -1
  219. package/corpus/templates/forms/vitest.config.ts +1 -0
  220. package/corpus/templates/macros/.agents/skills/secrets/SKILL.md +11 -4
  221. package/corpus/templates/macros/app/routes.ts +3 -1
  222. package/corpus/templates/macros/vitest.config.ts +6 -1
  223. package/corpus/templates/mail/.agents/skills/secrets/SKILL.md +11 -4
  224. package/corpus/templates/mail/actions/manage-gmail-filters.ts +10 -2
  225. package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +100 -37
  226. package/corpus/templates/mail/app/components/email/IntegrationsSidebar.tsx +14 -2
  227. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +66 -36
  228. package/corpus/templates/mail/app/hooks/use-google-auth.ts +2 -0
  229. package/corpus/templates/mail/app/lib/google-oauth-setup.ts +17 -0
  230. package/corpus/templates/mail/app/pages/InboxPage.tsx +69 -9
  231. package/corpus/templates/mail/app/routes/$.tsx +9 -0
  232. package/corpus/templates/mail/app/routes/$view.$threadId.tsx +23 -1
  233. package/corpus/templates/mail/app/routes/$view.tsx +47 -1
  234. package/corpus/templates/mail/app/routes.ts +3 -1
  235. package/corpus/templates/mail/changelog/2026-08-22-gmail-can-now-connect-with-the-shared-google-oauth.md +6 -0
  236. package/corpus/templates/mail/changelog/2026-08-22-gmail-filters-now-shows-the-real-error.md +6 -0
  237. package/corpus/templates/mail/changelog/2026-08-22-unknown-mail-urls-now-show-the-404-page.md +6 -0
  238. package/corpus/templates/mail/server/handlers/google-auth.ts +11 -2
  239. package/corpus/templates/mail/server/lib/google-auth.ts +92 -12
  240. package/corpus/templates/mail/server/onboarding.ts +66 -18
  241. package/corpus/templates/mail/vitest.config.ts +6 -1
  242. package/corpus/templates/plan/.agents/skills/secrets/SKILL.md +11 -4
  243. package/corpus/templates/plan/app/routes/settings.tsx +4 -1
  244. package/corpus/templates/plan/app/routes.ts +3 -1
  245. package/corpus/templates/plan/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
  246. package/corpus/templates/plan/netlify.toml +1 -1
  247. package/corpus/templates/slides/.agents/skills/secrets/SKILL.md +11 -4
  248. package/corpus/templates/slides/actions/patch-deck.ts +79 -10
  249. package/corpus/templates/slides/actions/update-slide.ts +11 -1
  250. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +14 -4
  251. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +10 -52
  252. package/corpus/templates/slides/app/components/editor/GoogleDocImportHint.tsx +8 -53
  253. package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +9 -75
  254. package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +8 -60
  255. package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +10 -2
  256. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +19 -7
  257. package/corpus/templates/slides/app/lib/sanitize-slide-html.ts +49 -36
  258. package/corpus/templates/slides/app/routes/access-request.approve.tsx +16 -9
  259. package/corpus/templates/slides/app/routes.ts +3 -1
  260. package/corpus/templates/slides/changelog/2026-08-22-already-uploaded-chat-images-are-no-longer-dropped.md +6 -0
  261. package/corpus/templates/slides/changelog/2026-08-22-google-drive-and-slides-can-now-connect-with-the-shared-google-oauth.md +6 -0
  262. package/corpus/templates/slides/changelog/2026-08-22-multi-slide-repairs-now-report-slides-that-still-overflow.md +6 -0
  263. package/corpus/templates/slides/changelog/2026-08-22-update-slide-now-reports-which-batched-edit-was-skipped.md +6 -0
  264. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +52 -1
  265. package/corpus/templates/slides/server/lib/chat-attachments.ts +29 -3
  266. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +66 -16
  267. package/corpus/templates/slides/server/lib/slide-content-patch.ts +13 -2
  268. package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -2
  269. package/corpus/templates/slides/tsconfig.json +5 -0
  270. package/corpus/templates/slides/vitest.config.ts +6 -1
  271. package/corpus/templates/tasks/.agents/skills/secrets/SKILL.md +11 -4
  272. package/corpus/templates/tasks/app/routes/settings.tsx +4 -1
  273. package/corpus/templates/tasks/app/routes.ts +3 -1
  274. package/corpus/templates/tasks/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
  275. package/corpus/templates/tasks/vitest.config.ts +7 -1
  276. package/dist/action.d.ts +91 -0
  277. package/dist/action.js +50 -0
  278. package/dist/agent/abort-reasons.d.ts +38 -0
  279. package/dist/agent/abort-reasons.js +49 -0
  280. package/dist/agent/engine/ai-sdk-engine.js +8 -5
  281. package/dist/agent/engine/anthropic-engine.js +7 -5
  282. package/dist/agent/engine/first-event-timeout.d.ts +42 -17
  283. package/dist/agent/engine/first-event-timeout.js +67 -25
  284. package/dist/agent/production-agent.d.ts +23 -0
  285. package/dist/agent/production-agent.js +107 -102
  286. package/dist/agent/run-loop-with-resume.d.ts +2 -28
  287. package/dist/agent/run-loop-with-resume.js +25 -40
  288. package/dist/agent/run-manager.js +5 -4
  289. package/dist/agent/run-store.d.ts +55 -0
  290. package/dist/agent/run-store.js +124 -1
  291. package/dist/agent/tool-search.js +2 -1
  292. package/dist/agent/types.d.ts +9 -4
  293. package/dist/app-config/configuration-error.d.ts +11 -0
  294. package/dist/app-config/configuration-error.js +14 -0
  295. package/dist/app-config/index.d.ts +1 -0
  296. package/dist/app-config/index.js +1 -0
  297. package/dist/app-config/integrations.d.ts +1 -0
  298. package/dist/app-config/integrations.js +10 -0
  299. package/dist/app-config/plugins.d.ts +34 -0
  300. package/dist/app-config/plugins.js +39 -0
  301. package/dist/app-config/run-lifecycle-invariants.d.ts +18 -9
  302. package/dist/app-config/run-lifecycle-invariants.js +18 -25
  303. package/dist/app-config/schema.d.ts +16 -0
  304. package/dist/app-config/schema.js +2 -0
  305. package/dist/chat-threads/schema-migrations.js +20 -0
  306. package/dist/chat-threads/store.js +21 -4
  307. package/dist/cli/native-dependencies.d.ts +4 -0
  308. package/dist/cli/native-dependencies.js +15 -0
  309. package/dist/client/EnvironmentBadge.d.ts +1 -1
  310. package/dist/client/EnvironmentBadge.js +40 -5
  311. package/dist/client/MultiTabAssistantChat.d.ts +1 -1
  312. package/dist/client/MultiTabAssistantChat.js +35 -14
  313. package/dist/client/agent-chat/index.d.ts +1 -1
  314. package/dist/client/agent-chat/index.js +1 -1
  315. package/dist/client/agent-page/use-jobs.d.ts +2 -1
  316. package/dist/client/agent-page/use-jobs.js +3 -5
  317. package/dist/client/agent-sidebar-state.js +3 -1
  318. package/dist/client/blocks/library/code-tabs.js +5 -0
  319. package/dist/client/blocks/library/code.js +1 -0
  320. package/dist/client/chat-first/apps-rail.js +2 -2
  321. package/dist/client/chat-model-groups.d.ts +12 -0
  322. package/dist/client/chat-model-groups.js +3 -2
  323. package/dist/client/integrations/GoogleProductLogo.d.ts +5 -0
  324. package/dist/client/integrations/GoogleProductLogo.js +45 -0
  325. package/dist/client/integrations/index.d.ts +2 -0
  326. package/dist/client/integrations/index.js +2 -0
  327. package/dist/client/integrations/workspace-provider-oauth.d.ts +8 -0
  328. package/dist/client/integrations/workspace-provider-oauth.js +13 -0
  329. package/dist/client/resources/mcp-integration-catalog.js +0 -29
  330. package/dist/client/settings/SettingsTabsPage.js +10 -6
  331. package/dist/client/sharing/ShareButton.js +11 -2
  332. package/dist/client/use-chat-models.d.ts +6 -0
  333. package/dist/client/use-chat-models.js +10 -0
  334. package/dist/client/use-db-sync.js +27 -9
  335. package/dist/connections/catalog.d.ts +111 -9
  336. package/dist/connections/catalog.js +86 -30
  337. package/dist/db/create-get-db.js +18 -0
  338. package/dist/db/ddl-guard.d.ts +0 -4
  339. package/dist/db/ddl-guard.js +46 -0
  340. package/dist/deploy/build.d.ts +19 -0
  341. package/dist/deploy/build.js +190 -16
  342. package/dist/deploy/function-bundle.d.ts +45 -0
  343. package/dist/deploy/function-bundle.js +337 -0
  344. package/dist/deploy/workspace-deploy.js +19 -1
  345. package/dist/eject/workspace-connections.js +4 -0
  346. package/dist/email-catalog/registry.d.ts +4 -0
  347. package/dist/email-catalog/registry.js +79 -14
  348. package/dist/extensions/content-patch.js +14 -2
  349. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  350. package/dist/integrations/plugin.d.ts +10 -0
  351. package/dist/integrations/plugin.js +40 -6
  352. package/dist/jobs/actions/run-automation-now.d.ts +2 -1
  353. package/dist/jobs/actions/run-automation-now.js +11 -5
  354. package/dist/jobs/frontmatter.js +53 -2
  355. package/dist/jobs/run-now.d.ts +11 -1
  356. package/dist/jobs/run-now.js +42 -7
  357. package/dist/jobs/scheduler.d.ts +1 -0
  358. package/dist/jobs/scheduler.js +2 -1
  359. package/dist/localization/core-messages/ar-SA.js +3 -0
  360. package/dist/localization/core-messages/de-DE.js +3 -0
  361. package/dist/localization/core-messages/en-US.d.ts +3 -0
  362. package/dist/localization/core-messages/en-US.js +3 -0
  363. package/dist/localization/core-messages/es-ES.js +3 -0
  364. package/dist/localization/core-messages/fr-FR.js +3 -0
  365. package/dist/localization/core-messages/hi-IN.js +3 -0
  366. package/dist/localization/core-messages/ja-JP.js +3 -0
  367. package/dist/localization/core-messages/ko-KR.js +3 -0
  368. package/dist/localization/core-messages/pt-BR.js +3 -0
  369. package/dist/localization/core-messages/zh-CN.js +3 -0
  370. package/dist/localization/core-messages/zh-TW.js +3 -0
  371. package/dist/localization/core-messages.d.ts +3 -0
  372. package/dist/localization/default-messages.d.ts +2 -5
  373. package/dist/localization/default-messages.js +2 -5
  374. package/dist/mcp/build-server.d.ts +9 -0
  375. package/dist/mcp/build-server.js +37 -8
  376. package/dist/mcp-client/oauth-client.d.ts +7 -0
  377. package/dist/mcp-client/oauth-client.js +12 -1
  378. package/dist/oauth-tokens/index.d.ts +1 -1
  379. package/dist/oauth-tokens/index.js +1 -1
  380. package/dist/oauth-tokens/lifecycle.d.ts +11 -0
  381. package/dist/oauth-tokens/lifecycle.js +17 -0
  382. package/dist/oauth-tokens/store.js +7 -0
  383. package/dist/observability/posthog-ai.d.ts +15 -1
  384. package/dist/observability/posthog-ai.js +24 -12
  385. package/dist/observability/routes.d.ts +3 -3
  386. package/dist/observability/traces.js +158 -28
  387. package/dist/onboarding/app-profile.js +2 -2
  388. package/dist/onboarding/plugin.js +10 -2
  389. package/dist/onboarding/types.d.ts +2 -0
  390. package/dist/provider-api/actions/custom-provider-registration.d.ts +1 -1
  391. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  392. package/dist/provider-api/index.js +2 -0
  393. package/dist/resources/store.js +13 -4
  394. package/dist/scripts/agent-engines/list-agent-engines.js +29 -3
  395. package/dist/secrets/register-framework-secrets.js +1 -1
  396. package/dist/server/action-discovery.js +5 -0
  397. package/dist/server/agent-chat/action-filters-a2a.d.ts +27 -3
  398. package/dist/server/agent-chat/action-filters-a2a.js +48 -9
  399. package/dist/server/agent-chat-plugin.js +36 -9
  400. package/dist/server/agent-discovery.js +43 -20
  401. package/dist/server/auth.js +18 -16
  402. package/dist/server/beta-opt-out-html.js +45 -4
  403. package/dist/server/better-auth-instance.d.ts +2 -1
  404. package/dist/server/better-auth-instance.js +23 -7
  405. package/dist/server/builder-design-systems.d.ts +4 -1
  406. package/dist/server/builder-design-systems.js +87 -6
  407. package/dist/server/builder-oauth.d.ts +1 -7
  408. package/dist/server/builder-oauth.js +80 -163
  409. package/dist/server/core-routes-plugin.d.ts +29 -0
  410. package/dist/server/core-routes-plugin.js +100 -20
  411. package/dist/server/default-plugins.d.ts +18 -0
  412. package/dist/server/default-plugins.js +22 -0
  413. package/dist/server/edge.d.ts +1 -0
  414. package/dist/server/edge.js +1 -0
  415. package/dist/server/framework-request-handler.js +31 -3
  416. package/dist/server/google-oauth.d.ts +3 -0
  417. package/dist/server/google-oauth.js +3 -0
  418. package/dist/server/index.d.ts +4 -4
  419. package/dist/server/index.js +3 -3
  420. package/dist/server/onboarding-html.js +37 -3
  421. package/dist/server/realtime-token.d.ts +1 -1
  422. package/dist/server/transcribe-voice.d.ts +1 -1
  423. package/dist/server/workspace-provider-oauth.d.ts +6 -1
  424. package/dist/server/workspace-provider-oauth.js +72 -20
  425. package/dist/shared/agent-sidebar-url.d.ts +1 -0
  426. package/dist/shared/agent-sidebar-url.js +1 -0
  427. package/dist/shared/environment-lanes.d.ts +2 -0
  428. package/dist/shared/environment-lanes.js +3 -1
  429. package/dist/shared/index.d.ts +3 -1
  430. package/dist/shared/index.js +3 -1
  431. package/dist/shared/surface-visibility.d.ts +31 -0
  432. package/dist/shared/surface-visibility.js +57 -0
  433. package/dist/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
  434. package/dist/templates/chat/app/routes.ts +3 -1
  435. package/dist/templates/chat/vitest.config.ts +8 -0
  436. package/dist/templates/default/.agents/skills/secrets/SKILL.md +11 -4
  437. package/dist/templates/default/app/routes.ts +3 -1
  438. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
  439. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
  440. package/dist/tracking/registry.d.ts +11 -0
  441. package/dist/tracking/registry.js +5 -2
  442. package/dist/triggers/actions.js +10 -3
  443. package/dist/usage/store.js +23 -3
  444. package/dist/user-profile/actions/get-auth-methods.js +18 -5
  445. package/dist/vite/client.js +24 -5
  446. package/docs/content/actions-access-control.mdx +43 -4
  447. package/docs/content/actions-defining.mdx +16 -0
  448. package/docs/content/template-clips-capture-everywhere.mdx +29 -30
  449. package/docs/content/template-clips-developers.mdx +4 -4
  450. package/docs/content/template-clips.mdx +3 -1
  451. package/package.json +2 -2
  452. package/src/eject/workspace-connections.ts +4 -0
  453. package/src/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
  454. package/src/templates/chat/app/routes.ts +3 -1
  455. package/src/templates/chat/vitest.config.ts +8 -0
  456. package/src/templates/default/.agents/skills/secrets/SKILL.md +11 -4
  457. package/src/templates/default/app/routes.ts +3 -1
  458. package/src/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
  459. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
@@ -7,6 +7,7 @@ import * as Y from "yjs";
7
7
 
8
8
  import { trace } from "@/components/design/design-trace";
9
9
  import type { ClipboardContentMutationPublication } from "@/lib/clipboard-content-lineage";
10
+ import { writeCollabText } from "@/pages/design-editor/collab-sync";
10
11
  import {
11
12
  LOCAL_EDIT_ORIGIN,
12
13
  TAB_ID,
@@ -289,17 +290,16 @@ export function runApplyLocalContentUpdate(
289
290
  const ytext = ydoc.getText("content");
290
291
  if (ytext.toString() !== nextContent) {
291
292
  if (!yjsHistoryAvailable) {
292
- // Untracked full rewrite (recordHistory:false callers such as the
293
+ // Untracked write (recordHistory:false callers such as the
293
294
  // code-layer id-stamping effect, or history-suppressed replays) —
294
295
  // see U1 note above: clear the undo stack so a stale tracked
295
296
  // delta can't be replayed against content it no longer matches.
296
297
  undoManagerRef.current?.clear(true, false);
297
298
  }
298
- ydoc.transact(
299
- () => {
300
- ytext.delete(0, ytext.length);
301
- ytext.insert(0, nextContent);
302
- },
299
+ writeCollabText(
300
+ ydoc,
301
+ ytext,
302
+ nextContent,
303
303
  yjsHistoryAvailable ? LOCAL_EDIT_ORIGIN : TAB_ID,
304
304
  );
305
305
  }
@@ -50,7 +50,7 @@ export interface ApplyPendingVisualStylesWithAgentArgs {
50
50
  pendingStructureVerificationStatus: PendingStructureVerificationStatus;
51
51
  pendingVisualStyleEdits: PendingVisualStyleEdit[];
52
52
  pendingVisualStylePrompt: string;
53
- setActiveLeftPanel: Dispatch<SetStateAction<DesignLeftPanel>>;
53
+ setActiveLeftPanel: Dispatch<SetStateAction<DesignLeftPanel | null>>;
54
54
  setApplyingViaHost: Dispatch<SetStateAction<boolean>>;
55
55
  setPendingAgentHandoffBusy: Dispatch<SetStateAction<boolean>>;
56
56
  setPendingStructureAckRequest: Dispatch<
@@ -25,6 +25,7 @@ import {
25
25
  resolveCodeLayerTargetFromBridge,
26
26
  resolveCodeLayerTargetFromElementInfo,
27
27
  } from "@/pages/design-editor/code-layer-state";
28
+ import { writeCollabText } from "@/pages/design-editor/collab-sync";
28
29
  import type {
29
30
  LiveScreenSnapshot,
30
31
  PatchProofState,
@@ -176,6 +177,9 @@ export function runCommitVisualStyles(
176
177
  elementInfo?: ElementInfo;
177
178
  /** Pre-gesture values, for the pending-edit revert stack. */
178
179
  originalStyles?: Record<string, string>;
180
+ /** The write is a side effect of a gesture on another element, so it must
181
+ * not move the selection onto the element it touched. */
182
+ preserveSelection?: boolean;
179
183
  } = {},
180
184
  ) {
181
185
  trace("persist", "commit-styles", {
@@ -657,17 +661,16 @@ export function runCommitVisualStyles(
657
661
  const ytext = ydoc.getText("content");
658
662
  if (ytext.toString() !== resolvedNextContent) {
659
663
  if (!yjsHistoryAvailable) {
660
- // Untracked full rewrite (overview mode with a still-live
664
+ // Untracked write (overview mode with a still-live
661
665
  // single-mode UndoManager, or history-suppressed replay) —
662
666
  // see U1 note: clear the undo stack so a stale tracked delta
663
667
  // can't be replayed against content it no longer matches.
664
668
  undoManagerRef.current?.clear(true, false);
665
669
  }
666
- ydoc.transact(
667
- () => {
668
- ytext.delete(0, ytext.length);
669
- ytext.insert(0, resolvedNextContent);
670
- },
670
+ writeCollabText(
671
+ ydoc,
672
+ ytext,
673
+ resolvedNextContent,
671
674
  yjsHistoryAvailable ? LOCAL_EDIT_ORIGIN : TAB_ID,
672
675
  );
673
676
  }
@@ -687,7 +690,15 @@ export function runCommitVisualStyles(
687
690
  setContentRenderRevision((revision) => revision + 1);
688
691
  }
689
692
  }
690
- if (resolvedNode) setSelectedLayerIdsState([resolvedNode.id]);
693
+ if (options.preserveSelection) return;
694
+ // A commit must never shrink the selection: a group transform commits one
695
+ // style change per member, so selecting the committed node keeps only the
696
+ // member that happened to commit last.
697
+ if (resolvedNode) {
698
+ setSelectedLayerIdsState((current) =>
699
+ current.includes(resolvedNode.id) ? current : [resolvedNode.id],
700
+ );
701
+ }
691
702
  setSelectedElement((prev) => {
692
703
  if (options.elementInfo) return options.elementInfo;
693
704
  if (!prev) return prev;
@@ -1,33 +1,13 @@
1
- import type { CodeLayerNode, CodeLayerTreeNode } from "@shared/code-layer";
2
1
  import type { Dispatch, RefObject, SetStateAction } from "react";
3
2
 
4
3
  import type { ElementInfo } from "@/components/design/types";
5
- import {
6
- collectCodeLayerAncestors,
7
- elementInfoFromCodeLayerNode,
8
- } from "@/pages/design-editor/code-layer-state";
9
- import {
10
- hasSelectableCodeLayerParent,
11
- resolveEscapePopSelectionAction,
12
- shouldEscapeToOverview,
13
- } from "@/pages/design-editor/selection-state";
4
+ import { shouldEscapeToOverview } from "@/pages/design-editor/selection-state";
14
5
  import type { DesignTool, EditorMode } from "@/pages/design-editor/types";
15
6
 
16
7
  export interface EscapeHotkeyArgs {
17
8
  activeBreakpointWidthStateRef: RefObject<number | undefined>;
18
9
  activeTool: DesignTool;
19
10
  cancelActiveEditorDrag: () => boolean;
20
- codeLayerOwnerByNodeIdRef: RefObject<
21
- Map<
22
- string,
23
- {
24
- fileId: string;
25
- node: CodeLayerNode;
26
- tree: CodeLayerTreeNode[];
27
- runtimeOnly: boolean;
28
- }
29
- >
30
- >;
31
11
  drawMode: boolean;
32
12
  enterOverviewFromZoom: (nextMode?: EditorMode) => void;
33
13
  focusedAnnotationSending: boolean;
@@ -40,11 +20,8 @@ export interface EscapeHotkeyArgs {
40
20
  overviewAnnotationSending: boolean;
41
21
  pinMode: boolean;
42
22
  selectedElement: ElementInfo | null;
43
- selectedLayerIdsState: string[];
44
- setActiveFileId: Dispatch<SetStateAction<string | null>>;
45
23
  setActiveTool: Dispatch<SetStateAction<DesignTool>>;
46
24
  setDrawMode: Dispatch<SetStateAction<boolean>>;
47
- setExpandedLayerIds: Dispatch<SetStateAction<string[]>>;
48
25
  setHoveredElement: Dispatch<SetStateAction<ElementInfo | null>>;
49
26
  setMode: Dispatch<SetStateAction<EditorMode>>;
50
27
  setOverviewClearSelectionRequest: Dispatch<SetStateAction<number>>;
@@ -59,7 +36,6 @@ export function runEscapeHotkey({
59
36
  activeBreakpointWidthStateRef,
60
37
  activeTool,
61
38
  cancelActiveEditorDrag,
62
- codeLayerOwnerByNodeIdRef,
63
39
  drawMode,
64
40
  enterOverviewFromZoom,
65
41
  focusedAnnotationSending,
@@ -72,11 +48,8 @@ export function runEscapeHotkey({
72
48
  overviewAnnotationSending,
73
49
  pinMode,
74
50
  selectedElement,
75
- selectedLayerIdsState,
76
- setActiveFileId,
77
51
  setActiveTool,
78
52
  setDrawMode,
79
- setExpandedLayerIds,
80
53
  setHoveredElement,
81
54
  setMode,
82
55
  setOverviewClearSelectionRequest,
@@ -133,68 +106,9 @@ export function runEscapeHotkey({
133
106
  enterOverviewFromZoom();
134
107
  return;
135
108
  }
136
- // Figma parity — pop the plain-canvas selection one level at a time
137
- // (child layer -> parent layer -> containing screen/frame -> fully
138
- // deselected) instead of deselecting everything on the first Escape.
139
- // The decision itself is a pure, unit-tested function
140
- // (resolveEscapePopSelectionAction in design-editor/selection-state.ts);
141
- // this reuses the same codeLayerOwnerByNodeIdRef/parentId ancestor walk
142
- // handleSelectParentLayer (Shift+Enter / "\\") already uses, inlined
143
- // here (rather than calling selectCodeLayerNodesForHotkey directly)
144
- // since that helper is declared later in this component and referencing
145
- // it from this callback's deps would hit its temporal-dead-zone before
146
- // this render's declarations run.
147
- const escapeSelectedLayerId =
148
- selectedLayerIdsState[selectedLayerIdsState.length - 1];
149
- const escapeOwner = escapeSelectedLayerId
150
- ? codeLayerOwnerByNodeIdRef.current.get(escapeSelectedLayerId)
151
- : undefined;
152
- // BUG-ESCAPE-SHELL: the flat codeLayerOwnerByNodeIdRef map (built from
153
- // projection.nodes) still contains <html>/<body> entries with real
154
- // parentId links even though the VISUAL layers tree collapses them away
155
- // (shared/code-layer.ts's isCollapsibleDocumentShellNode). A bare
156
- // Boolean(escapeOwner?.node.parentId) check treats a top-level layer's
157
- // collapsed <body> ancestor as a selectable parent, so popping from the
158
- // screen root would select <body> then <html> instead of stopping at the
159
- // screen/frame level. hasSelectableCodeLayerParent excludes those shell
160
- // nodes so the pop walk matches what the layers panel shows.
161
- const escapeParentOwner = escapeOwner?.node.parentId
162
- ? codeLayerOwnerByNodeIdRef.current.get(escapeOwner.node.parentId)
163
- : undefined;
164
- const popAction = resolveEscapePopSelectionAction({
165
- hasSelectedLayer: Boolean(escapeOwner),
166
- hasLayerParent: hasSelectableCodeLayerParent({
167
- parentNode: escapeParentOwner?.node,
168
- }),
169
- viewMode,
170
- });
171
- if (popAction.kind === "pop-to-parent-layer" && escapeOwner) {
172
- const parentOwner = escapeParentOwner;
173
- if (parentOwner && parentOwner.fileId === escapeOwner.fileId) {
174
- setActiveFileId(parentOwner.fileId);
175
- setOverviewSelectedScreenIds([]);
176
- setSelectedLayerIdsState([parentOwner.node.id]);
177
- setSelectedElement(elementInfoFromCodeLayerNode(parentOwner.node));
178
- setExpandedLayerIds((current) => {
179
- const next = new Set(current);
180
- next.add(parentOwner.fileId);
181
- collectCodeLayerAncestors(
182
- parentOwner.tree,
183
- parentOwner.node.id,
184
- ).forEach((ancestorId) => next.add(ancestorId));
185
- return next.size === current.length ? current : Array.from(next);
186
- });
187
- return;
188
- }
189
- // Parent couldn't be resolved (e.g. cross-file) — fall through to a
190
- // full deselect below rather than silently doing nothing.
191
- } else if (popAction.kind === "pop-to-screen-frame" && escapeOwner) {
192
- setSelectedElement(null);
193
- setSelectedLayerIdsState([]);
194
- setOverviewSelectedScreenIds([escapeOwner.fileId]);
195
- setOverviewClearSelectionRequest((request) => request + 1);
196
- return;
197
- }
109
+ // Figma's Esc is "select none". Walking up one ancestor per press belongs to
110
+ // Shift+Enter / "\\" (handleSelectParentLayer) — Escape must never leave
111
+ // something selected, or there is no keystroke that reaches an empty canvas.
198
112
  setSelectedElement(null);
199
113
  setHoveredElement(null);
200
114
  setOverviewSelectedScreenIds([]);
@@ -15,6 +15,7 @@ import {
15
15
  isScreenRootElementInfo,
16
16
  shouldClearBridgeSelectionOnEmptyMarquee,
17
17
  } from "@/pages/design-editor/selection-state";
18
+ import { resolveToolAfterSelection } from "@/pages/design-editor/tool-state";
18
19
  import type { DesignTool, EditorMode } from "@/pages/design-editor/types";
19
20
 
20
21
  export interface LayerMarqueeSelectionChangeArgs {
@@ -158,6 +159,6 @@ export function runLayerMarqueeSelectionChange(
158
159
  setOverviewClearSelectionRequest((request) => request + 1);
159
160
  }
160
161
 
161
- setActiveTool("move");
162
+ setActiveTool(resolveToolAfterSelection);
162
163
  setMode("edit");
163
164
  }
@@ -9,6 +9,7 @@ import {
9
9
  getOverviewScreenIdsFromLayerSelection,
10
10
  getSidebarCodeLayerSelectionState,
11
11
  } from "@/pages/design-editor/selection-state";
12
+ import { resolveToolAfterSelection } from "@/pages/design-editor/tool-state";
12
13
  import type {
13
14
  DesignFile,
14
15
  DesignTool,
@@ -130,13 +131,13 @@ export function runLayerSelectionChange(
130
131
  if (layerCanvasBlocked) {
131
132
  setSelectedElement(null);
132
133
  focusDesignInspectorForSelection();
133
- setActiveTool("move");
134
+ setActiveTool(resolveToolAfterSelection);
134
135
  setMode("edit");
135
136
  return;
136
137
  }
137
138
  setSelectedElement(elementInfoFromCodeLayerNode(codeLayerOwner.node));
138
139
  focusDesignInspectorForSelection();
139
- setActiveTool("move");
140
+ setActiveTool(resolveToolAfterSelection);
140
141
  setMode("edit");
141
142
  return;
142
143
  }
@@ -153,7 +154,7 @@ export function runLayerSelectionChange(
153
154
  ? nextLayerIds
154
155
  : [fileId],
155
156
  );
156
- setActiveTool("move");
157
+ setActiveTool(resolveToolAfterSelection);
157
158
  setMode("edit");
158
159
  viewModeRef.current = "overview";
159
160
  setViewMode("overview");
@@ -20,6 +20,7 @@ import {
20
20
  isScreenRootElementInfo,
21
21
  shouldIgnoreOverviewLayerCreationEcho,
22
22
  } from "@/pages/design-editor/selection-state";
23
+ import { resolveToolAfterSelection } from "@/pages/design-editor/tool-state";
23
24
  import type { DesignTool, EditorMode } from "@/pages/design-editor/types";
24
25
 
25
26
  export interface ScreenElementSelectArgs {
@@ -234,8 +235,17 @@ export function runScreenElementSelect(
234
235
  }
235
236
  return dedupeStringIds([...current, node.id]);
236
237
  });
238
+ } else if (node) {
239
+ // An intent-less select is the bridge re-anchoring after a content
240
+ // replace, not a user picking one object, so it must not collapse a live
241
+ // multi-selection down to the member it re-found.
242
+ setSelectedLayerIdsState((current) =>
243
+ !intent && current.length > 1 && current.includes(node.id)
244
+ ? current
245
+ : [node.id],
246
+ );
237
247
  } else {
238
- setSelectedLayerIdsState(node ? [node.id] : []);
248
+ setSelectedLayerIdsState([]);
239
249
  }
240
250
  if (viewModeRef.current === "overview") {
241
251
  setOverviewSelectedScreenIds([]);
@@ -256,7 +266,7 @@ export function runScreenElementSelect(
256
266
  handleBreakpointBarSelect(undefined);
257
267
  }
258
268
  }
259
- setActiveTool("move");
269
+ setActiveTool(resolveToolAfterSelection);
260
270
  setMode("edit");
261
271
  focusDesignInspectorForSelection();
262
272
  }
@@ -39,7 +39,10 @@ export interface ScreenVisualStyleChangeArgs {
39
39
  selector: string,
40
40
  styles: Record<string, string>,
41
41
  elementInfo?: ElementInfo,
42
- metadata?: { originalStyles?: Record<string, string> },
42
+ metadata?: {
43
+ originalStyles?: Record<string, string>;
44
+ preserveSelection?: boolean;
45
+ },
43
46
  ) => void;
44
47
  overviewScreens: OverviewScreen[];
45
48
  recordPendingVisualStyleEdit: (
@@ -49,6 +52,7 @@ export interface ScreenVisualStyleChangeArgs {
49
52
  elementInfo?: ElementInfo,
50
53
  metadata?: {
51
54
  originalStyles?: Record<string, string>;
55
+ preserveSelection?: boolean;
52
56
  interactionState?: InteractionState;
53
57
  },
54
58
  ) => void;
@@ -75,7 +79,10 @@ export function runScreenVisualStyleChange(
75
79
  selector: string,
76
80
  styles: Record<string, string>,
77
81
  elementInfo?: ElementInfo,
78
- metadata?: { originalStyles?: Record<string, string> },
82
+ metadata?: {
83
+ originalStyles?: Record<string, string>;
84
+ preserveSelection?: boolean;
85
+ },
79
86
  ) {
80
87
  if (screenId === activeFile?.id) {
81
88
  handleVisualStyleChange(selector, styles, elementInfo, metadata);
@@ -29,7 +29,7 @@ export interface SendRuntimeLayerMoveSemanticHandoffArgs {
29
29
  localhostConnectionRootPathByIdRef: RefObject<Map<string, string>>;
30
30
  overviewScreens: OverviewScreen[];
31
31
  runtimeLayerSnapshotsById: Record<string, RuntimeLayerSnapshot>;
32
- setActiveLeftPanel: Dispatch<SetStateAction<DesignLeftPanel>>;
32
+ setActiveLeftPanel: Dispatch<SetStateAction<DesignLeftPanel | null>>;
33
33
  t: (key: string, options?: Record<string, unknown>) => string;
34
34
  }
35
35
 
@@ -29,7 +29,7 @@ export interface SendRuntimeLayerSemanticHandoffArgs {
29
29
  localhostConnectionRootPathByIdRef: RefObject<Map<string, string>>;
30
30
  overviewScreens: OverviewScreen[];
31
31
  runtimeLayerSnapshotsById: Record<string, RuntimeLayerSnapshot>;
32
- setActiveLeftPanel: Dispatch<SetStateAction<DesignLeftPanel>>;
32
+ setActiveLeftPanel: Dispatch<SetStateAction<DesignLeftPanel | null>>;
33
33
  t: (key: string, options?: Record<string, unknown>) => string;
34
34
  }
35
35
 
@@ -32,7 +32,7 @@ export interface SendRuntimeLayerStateSemanticHandoffArgs {
32
32
  localhostConnectionRootPathByIdRef: RefObject<Map<string, string>>;
33
33
  overviewScreens: OverviewScreen[];
34
34
  runtimeLayerSnapshotsById: Record<string, RuntimeLayerSnapshot>;
35
- setActiveLeftPanel: Dispatch<SetStateAction<DesignLeftPanel>>;
35
+ setActiveLeftPanel: Dispatch<SetStateAction<DesignLeftPanel | null>>;
36
36
  t: (key: string, options?: Record<string, unknown>) => string;
37
37
  }
38
38
 
@@ -8,7 +8,7 @@ import type {
8
8
  import type { DesignLeftPanel } from "@/pages/design-editor/types";
9
9
 
10
10
  export interface StartSidebarResizeArgs {
11
- activeLeftPanel: DesignLeftPanel;
11
+ activeLeftPanel: DesignLeftPanel | null;
12
12
  leftSidebarContentRef: RefObject<HTMLDivElement | null>;
13
13
  leftSidebarWidth: number;
14
14
  rightSidebarContentRef: RefObject<HTMLDivElement | null>;
@@ -1,5 +1,7 @@
1
1
  import { isStandaloneHttpUrl } from "@shared/html-content";
2
2
 
3
+ import { trace } from "@/components/design/design-trace";
4
+
3
5
  import { normalizeDesignLeftPanel } from "./tool-state";
4
6
  import {
5
7
  type DesignFile,
@@ -24,10 +26,18 @@ export type PreviewContentReplaceResult =
24
26
  | "skipped-caller-owns-preview"
25
27
  | "unavailable";
26
28
 
29
+ /**
30
+ * True when the in-place bridge patch could not run and the caller must fall
31
+ * back to rebuilding srcdoc — a real iframe reload that re-executes the editor
32
+ * bridge, Tailwind and Alpine. Traced because it is the one escalation a user
33
+ * perceives as "the frame refreshed", and it is otherwise invisible.
34
+ */
27
35
  export function previewContentReplaceNeedsRenderFallback(
28
36
  result: PreviewContentReplaceResult,
29
37
  ): boolean {
30
- return result === "unavailable";
38
+ if (result !== "unavailable") return false;
39
+ trace("persist", "preview-bridge-unavailable-reload");
40
+ return true;
31
41
  }
32
42
 
33
43
  /**
@@ -3,6 +3,7 @@ import { sourceContentHash } from "@shared/source-workspace";
3
3
  import type { Dispatch, RefObject, SetStateAction } from "react";
4
4
  import * as Y from "yjs";
5
5
 
6
+ import { writeCollabText } from "@/pages/design-editor/collab-sync";
6
7
  import {
7
8
  TAB_ID,
8
9
  shouldAdoptExternalReconcileContent,
@@ -103,16 +104,13 @@ export function runAdoptDbFileContent({
103
104
  if (isLeadClient && ydoc) {
104
105
  const ytext = ydoc.getText("content");
105
106
  if (ytext.toString() !== dbContent) {
106
- // Untracked full rewrite (agent edit / external DB content
107
- // replacing a live doc that diverged) — clear the undo stack so a
108
- // stale tracked delta can't be replayed against content it no
109
- // longer matches (see U1: this is the primary corruption path —
110
- // agent edits, motion autosave, and id-stamping all land here).
107
+ // Untracked write (agent edit / external DB content replacing a
108
+ // live doc that diverged) — clear the undo stack so a stale
109
+ // tracked delta can't be replayed against content it no longer
110
+ // matches (see U1: this is the primary corruption path — agent
111
+ // edits, motion autosave, and id-stamping all land here).
111
112
  undoManagerRef.current?.clear(true, false);
112
- ydoc.transact(() => {
113
- ytext.delete(0, ytext.length);
114
- ytext.insert(0, dbContent);
115
- }, TAB_ID);
113
+ writeCollabText(ydoc, ytext, dbContent, TAB_ID);
116
114
  }
117
115
  }
118
116
  return;
@@ -182,12 +180,9 @@ export function runAdoptDbFileContent({
182
180
  if (isLeadClient && ydoc) {
183
181
  const ytext = ydoc.getText("content");
184
182
  if (ytext.toString() !== expectedContent) {
185
- // Untracked full rewrite — see U1 note above.
183
+ // Untracked write — see U1 note above.
186
184
  undoManagerRef.current?.clear(true, false);
187
- ydoc.transact(() => {
188
- ytext.delete(0, ytext.length);
189
- ytext.insert(0, expectedContent);
190
- }, TAB_ID);
185
+ writeCollabText(ydoc, ytext, expectedContent, TAB_ID);
191
186
  }
192
187
  }
193
188
  }, 1200);
@@ -258,13 +253,10 @@ export function runAdoptDbFileContent({
258
253
  if (isLeadClient && ydoc) {
259
254
  const ytext = ydoc.getText("content");
260
255
  if (ytext.toString() !== dbContent) {
261
- // Untracked full rewrite — see U1 note above. The view-appropriate
256
+ // Untracked write — see U1 note above. The view-appropriate
262
257
  // checkpoint recorded above (U21) is what Cmd+Z now falls back to.
263
258
  undoManagerRef.current?.clear(true, false);
264
- ydoc.transact(() => {
265
- ytext.delete(0, ytext.length);
266
- ytext.insert(0, dbContent);
267
- }, TAB_ID);
259
+ writeCollabText(ydoc, ytext, dbContent, TAB_ID);
268
260
  }
269
261
  }
270
262
  }
@@ -3,7 +3,10 @@ import * as Y from "yjs";
3
3
 
4
4
  import type { ElementInfo } from "@/components/design/types";
5
5
  import { refreshElementInfoFromContent } from "@/pages/design-editor/code-layer-state";
6
- import { shouldApplyRemotePreviewContent } from "@/pages/design-editor/collab-sync";
6
+ import {
7
+ shouldApplyRemotePreviewContent,
8
+ writeCollabText,
9
+ } from "@/pages/design-editor/collab-sync";
7
10
  import {
8
11
  LOCAL_EDIT_ORIGIN,
9
12
  TAB_ID,
@@ -120,12 +123,9 @@ export function runObserveCollabText({
120
123
  ) {
121
124
  setContentRenderRevision((revision) => revision + 1);
122
125
  }
123
- // Untracked full rewrite — see clear() note in the seed effect above.
126
+ // Untracked write — see clear() note in the seed effect above.
124
127
  undoManagerRef.current?.clear(true, false);
125
- ydoc.transact(() => {
126
- ytext.delete(0, ytext.length);
127
- ytext.insert(0, pendingLocalContent);
128
- }, TAB_ID);
128
+ writeCollabText(ydoc, ytext, pendingLocalContent, TAB_ID);
129
129
  return;
130
130
  }
131
131
  setCollabContent(next);
@@ -20,7 +20,7 @@ export interface PublishAgentSelectionContextArgs {
20
20
  activeCodeFile: CodeWorkbenchActiveFile | null;
21
21
  activeFile: DesignFile;
22
22
  activeInspectorTab: InspectorTab;
23
- activeLeftPanel: DesignLeftPanel;
23
+ activeLeftPanel: DesignLeftPanel | null;
24
24
  activeTool: DesignTool;
25
25
  design: DesignData | null;
26
26
  designDataJson: Record<string, unknown>;
@@ -1,7 +1,10 @@
1
1
  import type { Dispatch, RefObject, SetStateAction } from "react";
2
2
  import * as Y from "yjs";
3
3
 
4
- import { shouldRebaseCollabDocFromStoredContent } from "@/pages/design-editor/collab-sync";
4
+ import {
5
+ shouldRebaseCollabDocFromStoredContent,
6
+ writeCollabText,
7
+ } from "@/pages/design-editor/collab-sync";
5
8
  import { TAB_ID } from "@/pages/design-editor/editor-session";
6
9
  import type { PreviewContentReplaceResult } from "@/pages/design-editor/editor-state";
7
10
  import { previewContentReplaceNeedsRenderFallback } from "@/pages/design-editor/editor-state";
@@ -69,16 +72,13 @@ export function runSeedCollabContent({
69
72
  ) {
70
73
  setContentRenderRevision((revision) => revision + 1);
71
74
  }
72
- // Full delete+insert with an untracked origin: the UndoManager only
73
- // tracks LOCAL_EDIT_ORIGIN, so this rewrite is invisible to it. Clear
74
- // the undo stack so a subsequent Cmd+Z can't replay a tracked delta
75
- // from before this rewrite against content it no longer matches
76
- // (see the DE:5135-style mitigation below for the same hazard).
75
+ // Untracked origin: the UndoManager only tracks LOCAL_EDIT_ORIGIN, so
76
+ // this write is invisible to it. Clear the undo stack so a subsequent
77
+ // Cmd+Z can't replay a tracked delta from before it against content it
78
+ // no longer matches (see the DE:5135-style mitigation below for the
79
+ // same hazard).
77
80
  undoManagerRef.current?.clear(true, false);
78
- ydoc.transact(() => {
79
- ytext.delete(0, ytext.length);
80
- ytext.insert(0, pendingLocalContent);
81
- }, TAB_ID);
81
+ writeCollabText(ydoc, ytext, pendingLocalContent, TAB_ID);
82
82
  return;
83
83
  }
84
84
  if (text.length > 0) {
@@ -115,12 +115,9 @@ export function runSeedCollabContent({
115
115
  ) {
116
116
  setContentRenderRevision((revision) => revision + 1);
117
117
  }
118
- // Untracked full rewrite — see clear() note above.
118
+ // Untracked write — see clear() note above.
119
119
  undoManagerRef.current?.clear(true, false);
120
- ydoc.transact(() => {
121
- ytext.delete(0, ytext.length);
122
- ytext.insert(0, storedContent);
123
- }, TAB_ID);
120
+ writeCollabText(ydoc, ytext, storedContent, TAB_ID);
124
121
  return;
125
122
  }
126
123
  // Y.Doc snapshots are a render seed, not the SQL source of truth; the
@@ -401,15 +401,8 @@ export function shouldEscapeToOverview(args: {
401
401
  * node already carries `tag`/`layerNameSource` without needing a separate
402
402
  * lookup map.
403
403
  *
404
- * Both the Escape pop-one-level walk (`resolveEscapePopSelectionAction`) and
405
- * the shared Shift+Enter / "\\" select-parent walk (`handleSelectParentLayer`
406
- * in DesignEditor.tsx) must treat a parent that resolves to a document-shell
407
- * node as NO parent at all — otherwise popping from a top-level layer selects
408
- * the raw `<body>`/`<html>` DOM nodes instead of stopping at the screen/frame
409
- * level (or fully deselecting), which produces a permanently broken 0x0
410
- * inspector with no way back to a deselected state.
411
- *
412
- * Exported for unit testing.
404
+ * Select-parent must treat a document-shell parent as NO parent, or walking up
405
+ * from a top-level layer selects raw `<body>` and strands the inspector at 0x0.
413
406
  */
414
407
  export function isDocumentShellCodeLayerNode(node: {
415
408
  tag: string;
@@ -422,14 +415,9 @@ export function isDocumentShellCodeLayerNode(node: {
422
415
  }
423
416
 
424
417
  /**
425
- * True only when `parentNode` exists AND is not a document-shell node — see
426
- * `isDocumentShellCodeLayerNode`. Callers walking the flat code-layer
427
- * ownership map (Escape pop-one-level, Shift+Enter select-parent) must use
428
- * this instead of a bare `Boolean(parentNode)` truthiness check, or a
429
- * top-level layer's collapsed `<body>`/`<html>` ancestor gets treated as a
430
- * selectable parent layer.
431
- *
432
- * Exported for unit testing.
418
+ * Callers walking the flat code-layer ownership map must use this instead of a
419
+ * bare `Boolean(parentNode)` check, or a top-level layer's collapsed
420
+ * `<body>`/`<html>` ancestor gets treated as a selectable parent layer.
433
421
  */
434
422
  export function hasSelectableCodeLayerParent(args: {
435
423
  parentNode: { tag: string; layerNameSource: string } | null | undefined;
@@ -439,48 +427,6 @@ export function hasSelectableCodeLayerParent(args: {
439
427
  );
440
428
  }
441
429
 
442
- export type EscapePopSelectionAction =
443
- | { kind: "pop-to-parent-layer" }
444
- | { kind: "pop-to-screen-frame" }
445
- | { kind: "deselect" };
446
-
447
- /**
448
- * Figma parity — Escape on a plain canvas selection pops one level at a
449
- * time (child layer -> parent layer -> containing screen/frame -> fully
450
- * deselected) instead of deselecting everything on the first press.
451
- *
452
- * - A selected layer that has a code-layer parent (`hasLayerParent`) pops to
453
- * that parent, reusing the same ancestor-walk `handleSelectParentLayer`
454
- * (Shift+Enter / "\\") already uses via `codeLayerOwnerByNodeIdRef`.
455
- * - A selected TOP-level layer (no code-layer parent) in overview mode pops
456
- * to selecting its containing screen/frame — the same selection kind
457
- * (`overviewSelectedScreenIds`) clicking a frame directly in overview
458
- * already produces.
459
- * - Anything else — nothing selected, or a top-level layer in single-screen
460
- * mode where there's no separate "frame" to pop to (the screen already
461
- * fills the view, so top-level already reads as "the frame boundary") —
462
- * falls straight through to a full deselect, matching the previous
463
- * unconditional Escape behavior.
464
- *
465
- * Callers must have already handled every higher-priority Escape consumer
466
- * (an in-progress marquee/drag, an active breakpoint edit target,
467
- * `shouldEscapeToOverview`'s zoom-out-to-overview case) before calling this
468
- * — it only decides the remaining plain-canvas-selection case.
469
- *
470
- * Exported for unit testing.
471
- */
472
- export function resolveEscapePopSelectionAction(args: {
473
- hasSelectedLayer: boolean;
474
- hasLayerParent: boolean;
475
- viewMode: "single" | "overview";
476
- }): EscapePopSelectionAction {
477
- if (args.hasSelectedLayer) {
478
- if (args.hasLayerParent) return { kind: "pop-to-parent-layer" };
479
- if (args.viewMode === "overview") return { kind: "pop-to-screen-frame" };
480
- }
481
- return { kind: "deselect" };
482
- }
483
-
484
430
  /**
485
431
  * B5-1: an empty-canvas click (a marquee/hit-test that resolved to zero
486
432
  * elements) must deselect ANY current selection kind — a selected