@agent-native/core 0.169.0 → 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 (496) 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/bigquery-table-info.ts +3 -2
  6. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
  7. package/corpus/templates/analytics/actions/search-bigquery-schema.ts +130 -4
  8. package/corpus/templates/analytics/agent-native.config.ts +1 -0
  9. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +36 -23
  10. package/corpus/templates/analytics/app/i18n-data.ts +28 -0
  11. package/corpus/templates/analytics/app/lib/dashboard-visibility.ts +41 -0
  12. package/corpus/templates/analytics/app/pages/Agents.tsx +25 -1
  13. package/corpus/templates/analytics/app/pages/DashboardOverview.tsx +34 -9
  14. package/corpus/templates/analytics/app/routes/$.tsx +10 -0
  15. package/corpus/templates/analytics/app/routes.ts +3 -1
  16. package/corpus/templates/analytics/changelog/2026-08-21-dashboard-filters-keep-other-users-dashboards-out-of-mine.md +6 -0
  17. package/corpus/templates/analytics/changelog/2026-08-22-fixed-the-agent-native-templates-first-party-dashboard-panel.md +6 -0
  18. package/corpus/templates/analytics/changelog/2026-08-22-org-admin-panels-no-longer-report-a-database-error-as-a-per.md +9 -0
  19. package/corpus/templates/analytics/changelog/2026-08-22-slack-requests-report-invalid-inputs.md +6 -0
  20. package/corpus/templates/analytics/changelog/2026-08-22-unknown-analytics-links-now-return-a-real-not-found-status.md +6 -0
  21. package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +2 -1
  22. package/corpus/templates/analytics/docs/schemas/tracked-events.md +2 -0
  23. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +29 -7
  24. package/corpus/templates/analytics/server/handlers/slack.ts +59 -5
  25. package/corpus/templates/analytics/server/lib/db-admin-connections.ts +11 -6
  26. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +132 -2
  27. package/corpus/templates/analytics/server/lib/real-data-actions.ts +14 -3
  28. package/corpus/templates/analytics/server/lib/slack.ts +4 -2
  29. package/corpus/templates/analytics/server/plugins/agent-chat.ts +33 -3
  30. package/corpus/templates/analytics/vitest.config.ts +6 -1
  31. package/corpus/templates/assets/.agents/skills/secrets/SKILL.md +11 -4
  32. package/corpus/templates/assets/app/routes/library.tsx +5 -3
  33. package/corpus/templates/assets/app/routes.ts +3 -1
  34. package/corpus/templates/assets/changelog/2026-08-22-library-page-loads-again-instead-of-crashing-on-open.md +6 -0
  35. package/corpus/templates/assets/vitest.config.ts +6 -1
  36. package/corpus/templates/brain/.agents/skills/secrets/SKILL.md +11 -4
  37. package/corpus/templates/brain/app/components/ui/pointer-lock.ts +1 -0
  38. package/corpus/templates/brain/app/routes/sources.tsx +8 -3
  39. package/corpus/templates/brain/changelog/2026-08-22-tuning-or-adding-a-source-no-longer-leaves-the-sources-page.md +6 -0
  40. package/corpus/templates/brain/server/lib/brain.ts +27 -2
  41. package/corpus/templates/brain/vitest.config.ts +1 -0
  42. package/corpus/templates/calendar/.agents/skills/secrets/SKILL.md +11 -4
  43. package/corpus/templates/calendar/actions/list-booking-links.ts +83 -4
  44. package/corpus/templates/calendar/actions/update-booking-link.ts +4 -3
  45. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +11 -3
  46. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +1 -1
  47. package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +103 -44
  48. package/corpus/templates/calendar/app/components/calendar/OutOfOfficeEvent.tsx +28 -24
  49. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +9 -2
  50. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +47 -58
  51. package/corpus/templates/calendar/app/hooks/use-booking-links.ts +5 -1
  52. package/corpus/templates/calendar/app/lib/event-layout.ts +52 -26
  53. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +126 -98
  54. package/corpus/templates/calendar/app/pages/CalendarView.tsx +1 -0
  55. package/corpus/templates/calendar/app/pages/Settings.tsx +88 -81
  56. package/corpus/templates/calendar/app/routes.ts +3 -1
  57. package/corpus/templates/calendar/changelog/2026-08-22-booking-link-visibility-respects-shared-access.md +6 -0
  58. package/corpus/templates/calendar/changelog/2026-08-22-clicking-an-out-of-office-event-s-marker-no-longer-creates-a.md +6 -0
  59. package/corpus/templates/calendar/changelog/2026-08-22-event-detail-views-now-show-your-calendar-timezone.md +6 -0
  60. package/corpus/templates/calendar/changelog/2026-08-22-google-calendar-can-now-connect-with-the-shared-google-oauth.md +6 -0
  61. package/corpus/templates/calendar/changelog/2026-08-22-overlapping-events-now-show-each-others-boundaries.md +6 -0
  62. package/corpus/templates/calendar/changelog/2026-08-22-public-booking-pages-now-offer-time-slots-from-the-host-s-we.md +6 -0
  63. package/corpus/templates/calendar/server/handlers/bookings.ts +5 -7
  64. package/corpus/templates/calendar/server/handlers/google-auth.ts +10 -2
  65. package/corpus/templates/calendar/server/lib/google-calendar.ts +139 -14
  66. package/corpus/templates/calendar/server/onboarding.ts +85 -0
  67. package/corpus/templates/calendar/server/plugins/agent-chat.ts +2 -0
  68. package/corpus/templates/calendar/shared/api.ts +9 -1
  69. package/corpus/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
  70. package/corpus/templates/chat/app/routes.ts +3 -1
  71. package/corpus/templates/chat/vitest.config.ts +8 -0
  72. package/corpus/templates/clips/.agents/skills/secrets/SKILL.md +11 -4
  73. package/corpus/templates/clips/actions/get-meeting.ts +9 -4
  74. package/corpus/templates/clips/actions/list-recordings.ts +16 -3
  75. package/corpus/templates/clips/actions/search-meetings.ts +1 -0
  76. package/corpus/templates/clips/actions/stop-meeting-recording.ts +87 -6
  77. package/corpus/templates/clips/actions/view-screen.ts +8 -1
  78. package/corpus/templates/clips/app/components/library/search-bar.tsx +1 -1
  79. package/corpus/templates/clips/app/components/meetings/meeting-history-row.tsx +32 -1
  80. package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +1 -1
  81. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +29 -1
  82. package/corpus/templates/clips/app/i18n/en-US.ts +5 -0
  83. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +33 -4
  84. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +1 -0
  85. package/corpus/templates/clips/app/routes/access-request.approve.tsx +16 -9
  86. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +17 -7
  87. package/corpus/templates/clips/app/routes/share.$shareId.tsx +17 -7
  88. package/corpus/templates/clips/changelog/2026-08-21-camera-bubble-black-circle.md +6 -0
  89. package/corpus/templates/clips/changelog/2026-08-22-screen-recordings-respect-the-microphone-toggle.md +6 -0
  90. package/corpus/templates/clips/changelog/2026-08-22-the-recordings-library-no-longer-fails-right-after-server-start.md +6 -0
  91. package/corpus/templates/clips/changelog/2026-08-23-the-agent-can-see-your-library-right-after-server-start.md +6 -0
  92. package/corpus/templates/clips/chrome-extension/src/background.ts +1 -2
  93. package/corpus/templates/clips/chrome-extension/src/native-transcription.ts +39 -7
  94. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +21 -25
  95. package/corpus/templates/clips/desktop/src/app.tsx +53 -24
  96. package/corpus/templates/clips/desktop/src/lib/bubble-playback.ts +68 -0
  97. package/corpus/templates/clips/desktop/src/lib/recorder.ts +3 -0
  98. package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +72 -14
  99. package/corpus/templates/clips/desktop/src/lib/updater.ts +8 -3
  100. package/corpus/templates/clips/desktop/src/overlays/bubble.tsx +162 -20
  101. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +43 -6
  102. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +150 -13
  103. package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +12 -0
  104. package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +28 -3
  105. package/corpus/templates/clips/server/lib/emails.ts +17 -33
  106. package/corpus/templates/content/.agents/skills/secrets/SKILL.md +11 -4
  107. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +140 -15
  108. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +12 -14
  109. package/corpus/templates/content/app/components/ui/pointer-lock.ts +1 -0
  110. package/corpus/templates/content/app/hooks/use-content-database.ts +18 -2
  111. package/corpus/templates/content/app/hooks/use-local-storage.ts +38 -22
  112. package/corpus/templates/content/app/i18n-data.ts +25 -0
  113. package/corpus/templates/content/app/routes.ts +3 -1
  114. package/corpus/templates/content/changelog/2026-08-22-code-blocks-inserted-from-the-slash-menu-no-longer-get-stuck.md +6 -0
  115. package/corpus/templates/content/changelog/2026-08-22-the-sidebar-page-tree-no-longer-flashes-empty-after-creating-a-page.md +6 -0
  116. package/corpus/templates/content/docs/solutions/2026-08-21-content-mermaid-rendering-shape.md +233 -0
  117. package/corpus/templates/content/server/plugins/agent-chat.ts +9 -2
  118. package/corpus/templates/content/vitest.config.ts +7 -1
  119. package/corpus/templates/crm/.agents/skills/secrets/SKILL.md +11 -4
  120. package/corpus/templates/design/.agents/skills/secrets/SKILL.md +11 -4
  121. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +1386 -92
  122. package/corpus/templates/design/actions/generate-design.ts +98 -47
  123. package/corpus/templates/design/actions/get-design-system.ts +6 -1
  124. package/corpus/templates/design/actions/refresh-design-system-with-builder.ts +146 -0
  125. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +70 -26
  126. package/corpus/templates/design/app/components/design/EditPanel.tsx +15 -47
  127. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +284 -136
  128. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +2060 -144
  129. package/corpus/templates/design/app/components/design/editor/DesignBottomToolbar.tsx +6 -2
  130. package/corpus/templates/design/app/components/design/editor/DesignWorkspaceRail.tsx +4 -4
  131. package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +10 -8
  132. package/corpus/templates/design/app/components/design/multi-screen/alt-hover-measurement.ts +19 -2
  133. package/corpus/templates/design/app/components/design/multi-screen/types.ts +9 -2
  134. package/corpus/templates/design/app/components/layout/Header.tsx +15 -0
  135. package/corpus/templates/design/app/components/layout/Layout.tsx +7 -2
  136. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +13 -8
  137. package/corpus/templates/design/app/i18n-data.ts +11 -10
  138. package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +12 -0
  139. package/corpus/templates/design/app/lib/design-system-data.ts +68 -0
  140. package/corpus/templates/design/app/pages/DesignEditor.tsx +99 -57
  141. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +39 -8
  142. package/corpus/templates/design/app/pages/DesignSystems.tsx +137 -43
  143. package/corpus/templates/design/app/pages/Index.tsx +3 -1
  144. package/corpus/templates/design/app/pages/Templates.tsx +0 -10
  145. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +10 -0
  146. package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +50 -0
  147. package/corpus/templates/design/app/pages/design-editor/commands/apply-design-editor-command.ts +1 -1
  148. package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +10 -8
  149. package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +6 -6
  150. package/corpus/templates/design/app/pages/design-editor/commands/apply-pending-visual-styles-with-agent.ts +1 -1
  151. package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +18 -7
  152. package/corpus/templates/design/app/pages/design-editor/commands/escape-hotkey.ts +4 -90
  153. package/corpus/templates/design/app/pages/design-editor/commands/layer-marquee-selection-change.ts +2 -1
  154. package/corpus/templates/design/app/pages/design-editor/commands/layer-selection-change.ts +4 -3
  155. package/corpus/templates/design/app/pages/design-editor/commands/screen-element-select.ts +12 -2
  156. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-style-change.ts +9 -2
  157. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-move-semantic-handoff.ts +1 -1
  158. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-semantic-handoff.ts +1 -1
  159. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-state-semantic-handoff.ts +1 -1
  160. package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +1 -1
  161. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +11 -1
  162. package/corpus/templates/design/app/pages/design-editor/effects/adopt-db-file-content.ts +11 -19
  163. package/corpus/templates/design/app/pages/design-editor/effects/observe-collab-text.ts +6 -6
  164. package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +1 -1
  165. package/corpus/templates/design/app/pages/design-editor/effects/seed-collab-content.ts +12 -15
  166. package/corpus/templates/design/app/pages/design-editor/preview-navigation.ts +25 -0
  167. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +5 -59
  168. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +8 -0
  169. package/corpus/templates/design/app/pages/design-editor/types.ts +3 -3
  170. package/corpus/templates/design/app/routes.ts +3 -1
  171. package/corpus/templates/design/changelog/2026-08-20-canvas-edits-patch-the-frame-instead-of-rebuilding-it.md +6 -0
  172. package/corpus/templates/design/changelog/2026-08-21-builder-design-system-imports-reconcile-after-indexing.md +6 -0
  173. package/corpus/templates/design/changelog/2026-08-21-draw-mode-needs-shift-y.md +6 -0
  174. package/corpus/templates/design/changelog/2026-08-21-eyedropper-shortcut.md +6 -0
  175. package/corpus/templates/design/changelog/2026-08-21-figma-style-alignment-guides-and-snapping.md +6 -0
  176. package/corpus/templates/design/changelog/2026-08-21-group-transforms-keep-the-selection.md +6 -0
  177. package/corpus/templates/design/changelog/2026-08-21-inspector-fields-keep-focus-on-enter.md +6 -0
  178. package/corpus/templates/design/changelog/2026-08-21-pen-alt-keeps-the-incoming-handle.md +6 -0
  179. package/corpus/templates/design/changelog/2026-08-21-pen-on-the-board-creates-one-vector.md +6 -0
  180. package/corpus/templates/design/changelog/2026-08-21-scale-a-multi-selection-from-the-group-handles.md +6 -0
  181. package/corpus/templates/design/changelog/2026-08-21-scale-resizes-text-with-the-object.md +6 -0
  182. package/corpus/templates/design/changelog/2026-08-21-selecting-another-object-keeps-the-scale-tool-armed.md +6 -0
  183. package/corpus/templates/design/changelog/2026-08-21-the-shape-tool-remembers-the-shape-you-picked.md +6 -0
  184. package/corpus/templates/design/changelog/2026-08-21-vectors-drawn-in-a-frame-land-where-you-drew-them.md +6 -0
  185. package/corpus/templates/design/changelog/2026-08-22-multi-screen-generation-no-longer-loses-a-saved-screens-layo.md +6 -0
  186. package/corpus/templates/design/changelog/2026-08-22-rename-and-search-fields-are-labeled-for-screen-readers.md +6 -0
  187. package/corpus/templates/design/package.json +2 -0
  188. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +311 -0
  189. package/corpus/templates/design/shared/canvas-math.ts +612 -206
  190. package/corpus/templates/design/shared/pen-path.ts +37 -0
  191. package/corpus/templates/design/vitest.config.ts +7 -1
  192. package/corpus/templates/dispatch/.agents/skills/secrets/SKILL.md +11 -4
  193. package/corpus/templates/dispatch/actions/list-workspace-connections.ts +34 -3
  194. package/corpus/templates/dispatch/app/routes/integrations.tsx +55 -21
  195. package/corpus/templates/dispatch/app/routes.ts +3 -1
  196. package/corpus/templates/factory/.agents/skills/secrets/SKILL.md +11 -4
  197. package/corpus/templates/factory/.env.example +2 -7
  198. package/corpus/templates/factory/AGENTS.md +3 -0
  199. package/corpus/templates/factory/README.md +5 -3
  200. package/corpus/templates/factory/actions/create-factory.ts +16 -3
  201. package/corpus/templates/factory/actions/get-slack-feedback-context.ts +2 -0
  202. package/corpus/templates/factory/actions/get-triage-item.ts +2 -0
  203. package/corpus/templates/factory/actions/list-factory-audit.ts +116 -36
  204. package/corpus/templates/factory/actions/list-factory-automations.ts +2 -1
  205. package/corpus/templates/factory/actions/list-triage-items.ts +22 -19
  206. package/corpus/templates/factory/actions/run-factory-automation.ts +7 -3
  207. package/corpus/templates/factory/actions/save-factory-automation.ts +5 -2
  208. package/corpus/templates/factory/actions/save-triage-config.ts +2 -8
  209. package/corpus/templates/factory/actions/start-builder-for-item.ts +21 -0
  210. package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +229 -297
  211. package/corpus/templates/factory/app/components/factory/FactorySettingsView.tsx +397 -247
  212. package/corpus/templates/factory/app/components/factory/FactorySourceSettingsGroup.tsx +33 -0
  213. package/corpus/templates/factory/app/components/factory/NewFactoryForm.tsx +202 -162
  214. package/corpus/templates/factory/app/i18n/en-US.ts +32 -4
  215. package/corpus/templates/factory/app/routes/factory.tsx +84 -11
  216. package/corpus/templates/factory/app/routes.ts +3 -1
  217. package/corpus/templates/factory/changelog/2026-08-21-activity-runs-use-automation-display-names.md +6 -0
  218. package/corpus/templates/factory/changelog/2026-08-21-create-and-settings-source-cards.md +6 -0
  219. package/corpus/templates/factory/changelog/2026-08-21-keep-automations-visible-while-running.md +6 -0
  220. package/corpus/templates/factory/changelog/2026-08-21-nested-factory-automations-can-poll.md +6 -0
  221. package/corpus/templates/factory/changelog/2026-08-21-settings-sticky-unsaved-bar.md +6 -0
  222. package/corpus/templates/factory/server/connectors/credentials.ts +10 -5
  223. package/corpus/templates/factory/server/lib/factory-audit-report.ts +412 -0
  224. package/corpus/templates/factory/server/lib/factory-config-reconcile.ts +321 -0
  225. package/corpus/templates/factory/server/lib/factory-scope.ts +25 -2
  226. package/corpus/templates/factory/server/lib/require-factory-automation.ts +13 -4
  227. package/corpus/templates/factory/server/plugins/factory-migrations.ts +148 -4
  228. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +4 -6
  229. package/corpus/templates/factory/vitest.config.ts +17 -2
  230. package/corpus/templates/forms/.agents/skills/secrets/SKILL.md +11 -4
  231. package/corpus/templates/forms/app/routes/_app.settings.tsx +4 -1
  232. package/corpus/templates/forms/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
  233. package/corpus/templates/forms/server/lib/public-form-ssr.ts +11 -1
  234. package/corpus/templates/forms/vitest.config.ts +1 -0
  235. package/corpus/templates/macros/.agents/skills/secrets/SKILL.md +11 -4
  236. package/corpus/templates/macros/app/routes.ts +3 -1
  237. package/corpus/templates/macros/vitest.config.ts +6 -1
  238. package/corpus/templates/mail/.agents/skills/secrets/SKILL.md +11 -4
  239. package/corpus/templates/mail/actions/manage-gmail-filters.ts +10 -2
  240. package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +100 -37
  241. package/corpus/templates/mail/app/components/email/IntegrationsSidebar.tsx +14 -2
  242. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +66 -36
  243. package/corpus/templates/mail/app/hooks/use-emails.ts +13 -3
  244. package/corpus/templates/mail/app/hooks/use-google-auth.ts +2 -0
  245. package/corpus/templates/mail/app/lib/google-oauth-setup.ts +17 -0
  246. package/corpus/templates/mail/app/pages/InboxPage.tsx +69 -9
  247. package/corpus/templates/mail/app/routes/$.tsx +9 -0
  248. package/corpus/templates/mail/app/routes/$view.$threadId.tsx +23 -1
  249. package/corpus/templates/mail/app/routes/$view.tsx +47 -1
  250. package/corpus/templates/mail/app/routes.ts +3 -1
  251. package/corpus/templates/mail/changelog/2026-08-22-gmail-can-now-connect-with-the-shared-google-oauth.md +6 -0
  252. package/corpus/templates/mail/changelog/2026-08-22-gmail-filters-now-shows-the-real-error.md +6 -0
  253. package/corpus/templates/mail/changelog/2026-08-22-unknown-mail-urls-now-show-the-404-page.md +6 -0
  254. package/corpus/templates/mail/server/handlers/google-auth.ts +11 -2
  255. package/corpus/templates/mail/server/lib/google-auth.ts +92 -12
  256. package/corpus/templates/mail/server/onboarding.ts +66 -18
  257. package/corpus/templates/mail/vitest.config.ts +6 -1
  258. package/corpus/templates/plan/.agents/skills/secrets/SKILL.md +11 -4
  259. package/corpus/templates/plan/app/routes/settings.tsx +4 -1
  260. package/corpus/templates/plan/app/routes.ts +3 -1
  261. package/corpus/templates/plan/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
  262. package/corpus/templates/plan/netlify.toml +1 -1
  263. package/corpus/templates/slides/.agents/skills/secrets/SKILL.md +11 -4
  264. package/corpus/templates/slides/actions/patch-deck.ts +79 -10
  265. package/corpus/templates/slides/actions/update-slide.ts +11 -1
  266. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +14 -4
  267. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +10 -52
  268. package/corpus/templates/slides/app/components/editor/GoogleDocImportHint.tsx +8 -53
  269. package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +9 -75
  270. package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +8 -60
  271. package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +10 -2
  272. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +19 -7
  273. package/corpus/templates/slides/app/lib/sanitize-slide-html.ts +49 -36
  274. package/corpus/templates/slides/app/routes/access-request.approve.tsx +16 -9
  275. package/corpus/templates/slides/app/routes.ts +3 -1
  276. package/corpus/templates/slides/changelog/2026-08-22-already-uploaded-chat-images-are-no-longer-dropped.md +6 -0
  277. package/corpus/templates/slides/changelog/2026-08-22-google-drive-and-slides-can-now-connect-with-the-shared-google-oauth.md +6 -0
  278. package/corpus/templates/slides/changelog/2026-08-22-multi-slide-repairs-now-report-slides-that-still-overflow.md +6 -0
  279. package/corpus/templates/slides/changelog/2026-08-22-update-slide-now-reports-which-batched-edit-was-skipped.md +6 -0
  280. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +52 -1
  281. package/corpus/templates/slides/server/lib/chat-attachments.ts +29 -3
  282. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +66 -16
  283. package/corpus/templates/slides/server/lib/slide-content-patch.ts +13 -2
  284. package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -2
  285. package/corpus/templates/slides/tsconfig.json +5 -0
  286. package/corpus/templates/slides/vitest.config.ts +6 -1
  287. package/corpus/templates/tasks/.agents/skills/secrets/SKILL.md +11 -4
  288. package/corpus/templates/tasks/app/routes/settings.tsx +4 -1
  289. package/corpus/templates/tasks/app/routes.ts +3 -1
  290. package/corpus/templates/tasks/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
  291. package/corpus/templates/tasks/vitest.config.ts +7 -1
  292. package/dist/action.d.ts +91 -0
  293. package/dist/action.js +50 -0
  294. package/dist/agent/abort-reasons.d.ts +38 -0
  295. package/dist/agent/abort-reasons.js +49 -0
  296. package/dist/agent/engine/ai-sdk-engine.js +8 -5
  297. package/dist/agent/engine/anthropic-engine.js +7 -5
  298. package/dist/agent/engine/credential-errors.d.ts +1 -1
  299. package/dist/agent/engine/credential-errors.js +2 -2
  300. package/dist/agent/engine/first-event-timeout.d.ts +42 -17
  301. package/dist/agent/engine/first-event-timeout.js +67 -25
  302. package/dist/agent/production-agent.d.ts +23 -0
  303. package/dist/agent/production-agent.js +107 -102
  304. package/dist/agent/run-loop-with-resume.d.ts +2 -28
  305. package/dist/agent/run-loop-with-resume.js +25 -40
  306. package/dist/agent/run-manager.js +5 -4
  307. package/dist/agent/run-store.d.ts +55 -0
  308. package/dist/agent/run-store.js +124 -1
  309. package/dist/agent/tool-search.js +2 -1
  310. package/dist/agent/types.d.ts +9 -4
  311. package/dist/app-config/configuration-error.d.ts +11 -0
  312. package/dist/app-config/configuration-error.js +14 -0
  313. package/dist/app-config/index.d.ts +1 -0
  314. package/dist/app-config/index.js +1 -0
  315. package/dist/app-config/integrations.d.ts +1 -0
  316. package/dist/app-config/integrations.js +10 -0
  317. package/dist/app-config/plugins.d.ts +34 -0
  318. package/dist/app-config/plugins.js +39 -0
  319. package/dist/app-config/run-lifecycle-invariants.d.ts +18 -9
  320. package/dist/app-config/run-lifecycle-invariants.js +18 -25
  321. package/dist/app-config/schema.d.ts +16 -0
  322. package/dist/app-config/schema.js +2 -0
  323. package/dist/chat-threads/schema-migrations.js +20 -0
  324. package/dist/chat-threads/store.js +21 -4
  325. package/dist/cli/native-dependencies.d.ts +4 -0
  326. package/dist/cli/native-dependencies.js +15 -0
  327. package/dist/client/AssistantChat.js +47 -15
  328. package/dist/client/ConnectBuilderCard.d.ts +3 -1
  329. package/dist/client/ConnectBuilderCard.js +6 -3
  330. package/dist/client/EnvironmentBadge.d.ts +1 -1
  331. package/dist/client/EnvironmentBadge.js +40 -5
  332. package/dist/client/MultiTabAssistantChat.d.ts +1 -1
  333. package/dist/client/MultiTabAssistantChat.js +35 -14
  334. package/dist/client/agent-chat/index.d.ts +1 -1
  335. package/dist/client/agent-chat/index.js +1 -1
  336. package/dist/client/agent-page/use-jobs.d.ts +2 -1
  337. package/dist/client/agent-page/use-jobs.js +3 -5
  338. package/dist/client/agent-sidebar-state.js +3 -1
  339. package/dist/client/blocks/library/code-tabs.js +5 -0
  340. package/dist/client/blocks/library/code.js +1 -0
  341. package/dist/client/chat/message-components.d.ts +7 -0
  342. package/dist/client/chat/message-components.js +1 -1
  343. package/dist/client/chat/run-recovery.js +5 -2
  344. package/dist/client/chat/tool-call-display.js +9 -3
  345. package/dist/client/chat-first/apps-rail.js +2 -2
  346. package/dist/client/chat-model-groups.d.ts +12 -0
  347. package/dist/client/chat-model-groups.js +3 -2
  348. package/dist/client/error-format.js +12 -0
  349. package/dist/client/integrations/GoogleProductLogo.d.ts +5 -0
  350. package/dist/client/integrations/GoogleProductLogo.js +45 -0
  351. package/dist/client/integrations/index.d.ts +2 -0
  352. package/dist/client/integrations/index.js +2 -0
  353. package/dist/client/integrations/workspace-provider-oauth.d.ts +8 -0
  354. package/dist/client/integrations/workspace-provider-oauth.js +13 -0
  355. package/dist/client/navigation/index.d.ts +1 -0
  356. package/dist/client/navigation/index.js +1 -0
  357. package/dist/client/resources/mcp-integration-catalog.js +0 -29
  358. package/dist/client/route-state.js +6 -0
  359. package/dist/client/settings/SettingsTabsPage.js +10 -6
  360. package/dist/client/sharing/ShareButton.js +11 -2
  361. package/dist/client/use-chat-models.d.ts +6 -0
  362. package/dist/client/use-chat-models.js +10 -0
  363. package/dist/client/use-db-sync.js +27 -9
  364. package/dist/client/workspace-app-navigation.d.ts +10 -0
  365. package/dist/client/workspace-app-navigation.js +38 -0
  366. package/dist/collab/struct-routes.d.ts +1 -1
  367. package/dist/connections/catalog.d.ts +111 -9
  368. package/dist/connections/catalog.js +86 -30
  369. package/dist/db/create-get-db.js +18 -0
  370. package/dist/db/ddl-guard.d.ts +0 -4
  371. package/dist/db/ddl-guard.js +46 -0
  372. package/dist/deploy/build.d.ts +32 -0
  373. package/dist/deploy/build.js +241 -16
  374. package/dist/deploy/function-bundle.d.ts +45 -0
  375. package/dist/deploy/function-bundle.js +337 -0
  376. package/dist/deploy/workspace-deploy.js +19 -1
  377. package/dist/eject/workspace-connections.js +4 -0
  378. package/dist/email-catalog/registry.d.ts +4 -0
  379. package/dist/email-catalog/registry.js +79 -14
  380. package/dist/extensions/content-patch.js +14 -2
  381. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  382. package/dist/integrations/plugin.d.ts +10 -0
  383. package/dist/integrations/plugin.js +40 -6
  384. package/dist/jobs/actions/run-automation-now.d.ts +2 -1
  385. package/dist/jobs/actions/run-automation-now.js +11 -5
  386. package/dist/jobs/frontmatter.js +53 -2
  387. package/dist/jobs/run-now.d.ts +11 -1
  388. package/dist/jobs/run-now.js +42 -7
  389. package/dist/jobs/scheduler.d.ts +1 -0
  390. package/dist/jobs/scheduler.js +2 -1
  391. package/dist/localization/core-messages/ar-SA.js +4 -1
  392. package/dist/localization/core-messages/de-DE.js +4 -1
  393. package/dist/localization/core-messages/en-US.d.ts +4 -1
  394. package/dist/localization/core-messages/en-US.js +4 -1
  395. package/dist/localization/core-messages/es-ES.js +4 -1
  396. package/dist/localization/core-messages/fr-FR.js +4 -1
  397. package/dist/localization/core-messages/hi-IN.js +4 -1
  398. package/dist/localization/core-messages/ja-JP.js +4 -1
  399. package/dist/localization/core-messages/ko-KR.js +4 -1
  400. package/dist/localization/core-messages/pt-BR.js +4 -1
  401. package/dist/localization/core-messages/zh-CN.js +4 -1
  402. package/dist/localization/core-messages/zh-TW.js +4 -1
  403. package/dist/localization/core-messages.d.ts +4 -1
  404. package/dist/localization/default-messages.d.ts +2 -5
  405. package/dist/localization/default-messages.js +2 -5
  406. package/dist/mcp/build-server.d.ts +9 -0
  407. package/dist/mcp/build-server.js +37 -8
  408. package/dist/mcp-client/oauth-client.d.ts +7 -0
  409. package/dist/mcp-client/oauth-client.js +12 -1
  410. package/dist/notifications/routes.d.ts +1 -1
  411. package/dist/oauth-tokens/index.d.ts +1 -1
  412. package/dist/oauth-tokens/index.js +1 -1
  413. package/dist/oauth-tokens/lifecycle.d.ts +11 -0
  414. package/dist/oauth-tokens/lifecycle.js +17 -0
  415. package/dist/oauth-tokens/store.js +7 -0
  416. package/dist/observability/posthog-ai.d.ts +15 -1
  417. package/dist/observability/posthog-ai.js +24 -12
  418. package/dist/observability/traces.js +158 -28
  419. package/dist/onboarding/app-profile.js +2 -2
  420. package/dist/onboarding/plugin.js +10 -2
  421. package/dist/onboarding/types.d.ts +2 -0
  422. package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
  423. package/dist/provider-api/actions/provider-api.d.ts +11 -11
  424. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  425. package/dist/provider-api/index.js +2 -0
  426. package/dist/resources/handlers.d.ts +1 -1
  427. package/dist/resources/store.js +13 -4
  428. package/dist/scripts/agent-engines/list-agent-engines.js +29 -3
  429. package/dist/scripts/db/check-scoping.js +9 -6
  430. package/dist/secrets/register-framework-secrets.js +1 -1
  431. package/dist/secrets/routes.d.ts +6 -6
  432. package/dist/server/action-discovery.js +5 -0
  433. package/dist/server/agent-chat/action-filters-a2a.d.ts +27 -3
  434. package/dist/server/agent-chat/action-filters-a2a.js +48 -9
  435. package/dist/server/agent-chat-plugin.js +36 -9
  436. package/dist/server/agent-discovery.js +43 -20
  437. package/dist/server/auth.js +18 -16
  438. package/dist/server/beta-opt-out-html.js +45 -4
  439. package/dist/server/better-auth-instance.d.ts +2 -1
  440. package/dist/server/better-auth-instance.js +23 -7
  441. package/dist/server/builder-browser.d.ts +4 -0
  442. package/dist/server/builder-browser.js +23 -1
  443. package/dist/server/builder-design-systems.d.ts +4 -1
  444. package/dist/server/builder-design-systems.js +87 -6
  445. package/dist/server/builder-oauth.d.ts +1 -7
  446. package/dist/server/builder-oauth.js +80 -163
  447. package/dist/server/core-routes-plugin.d.ts +29 -0
  448. package/dist/server/core-routes-plugin.js +113 -21
  449. package/dist/server/default-plugins.d.ts +18 -0
  450. package/dist/server/default-plugins.js +22 -0
  451. package/dist/server/edge.d.ts +1 -0
  452. package/dist/server/edge.js +1 -0
  453. package/dist/server/framework-request-handler.js +31 -3
  454. package/dist/server/google-oauth.d.ts +3 -0
  455. package/dist/server/google-oauth.js +3 -0
  456. package/dist/server/index.d.ts +4 -4
  457. package/dist/server/index.js +3 -3
  458. package/dist/server/onboarding-html.js +37 -3
  459. package/dist/server/workspace-provider-oauth.d.ts +6 -1
  460. package/dist/server/workspace-provider-oauth.js +72 -20
  461. package/dist/shared/agent-sidebar-url.d.ts +1 -0
  462. package/dist/shared/agent-sidebar-url.js +1 -0
  463. package/dist/shared/environment-lanes.d.ts +2 -0
  464. package/dist/shared/environment-lanes.js +3 -1
  465. package/dist/shared/index.d.ts +3 -1
  466. package/dist/shared/index.js +3 -1
  467. package/dist/shared/surface-visibility.d.ts +31 -0
  468. package/dist/shared/surface-visibility.js +57 -0
  469. package/dist/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
  470. package/dist/templates/chat/app/routes.ts +3 -1
  471. package/dist/templates/chat/vitest.config.ts +8 -0
  472. package/dist/templates/default/.agents/skills/secrets/SKILL.md +11 -4
  473. package/dist/templates/default/app/routes.ts +3 -1
  474. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
  475. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
  476. package/dist/tracking/registry.d.ts +11 -0
  477. package/dist/tracking/registry.js +5 -2
  478. package/dist/triggers/actions.js +10 -3
  479. package/dist/usage/store.js +23 -3
  480. package/dist/user-profile/actions/get-auth-methods.js +18 -5
  481. package/dist/vite/client.js +24 -5
  482. package/docs/content/actions-access-control.mdx +43 -4
  483. package/docs/content/actions-defining.mdx +16 -0
  484. package/docs/content/template-clips-capture-everywhere.mdx +29 -30
  485. package/docs/content/template-clips-developers.mdx +4 -4
  486. package/docs/content/template-clips.mdx +3 -1
  487. package/package.json +3 -3
  488. package/src/eject/workspace-connections.ts +4 -0
  489. package/src/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
  490. package/src/templates/chat/app/routes.ts +3 -1
  491. package/src/templates/chat/vitest.config.ts +8 -0
  492. package/src/templates/default/.agents/skills/secrets/SKILL.md +11 -4
  493. package/src/templates/default/app/routes.ts +3 -1
  494. package/src/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
  495. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
  496. /package/corpus/templates/dispatch/app/routes/{apps.$appId.tsx → apps.$appId.$.tsx} +0 -0
@@ -26,6 +26,7 @@ import {
26
26
  useCallback,
27
27
  useEffect,
28
28
  useMemo,
29
+ useRef,
29
30
  useState,
30
31
  type ReactNode,
31
32
  } from "react";
@@ -72,6 +73,12 @@ import {
72
73
  } from "@/lib/design-system-preview";
73
74
 
74
75
  import { QueryErrorState } from "../components/QueryErrorState";
76
+ import {
77
+ builderRefreshKey,
78
+ parseDesignSystemData,
79
+ shouldRefreshBuilderDesignSystem,
80
+ type DesignSystemData,
81
+ } from "../lib/design-system-data";
75
82
 
76
83
  interface DesignSystem {
77
84
  id: string;
@@ -88,29 +95,21 @@ interface DesignSystem {
88
95
  updatedAt?: string;
89
96
  }
90
97
 
91
- interface DesignSystemData {
92
- colors?: {
93
- primary?: unknown;
94
- secondary?: unknown;
95
- accent?: unknown;
96
- background?: unknown;
97
- surface?: unknown;
98
- text?: unknown;
99
- textMuted?: unknown;
100
- };
101
- typography?: {
102
- headingFont?: unknown;
103
- bodyFont?: unknown;
104
- headingWeight?: unknown;
105
- bodyWeight?: unknown;
106
- };
107
- spacing?: Record<string, unknown>;
108
- borders?: Record<string, unknown>;
109
- logos?: Array<{ url?: string; name?: string; variant?: string }>;
110
- defaults?: Record<string, unknown>;
111
- notes?: unknown;
112
- /** The source system's own named vocabulary; absent on kits predating it. */
113
- tokens?: unknown;
98
+ type BuilderRefreshResult = {
99
+ synced: boolean;
100
+ status?: string;
101
+ rejectedTokenCount?: number;
102
+ };
103
+
104
+ function isTerminalBuilderStatus(status?: string): boolean {
105
+ return (
106
+ status === "ready" ||
107
+ status === "complete" ||
108
+ status === "completed" ||
109
+ status === "error" ||
110
+ status === "failed" ||
111
+ status === "cancelled"
112
+ );
114
113
  }
115
114
 
116
115
  export default function DesignSystems() {
@@ -132,6 +131,19 @@ export default function DesignSystems() {
132
131
  const setDefaultMutation = useActionMutation("set-default-design-system");
133
132
  const deleteMutation = useActionMutation("delete-design-system");
134
133
  const updateMutation = useActionMutation("update-design-system");
134
+ const refreshBuilderSystemMutation = useActionMutation<
135
+ BuilderRefreshResult,
136
+ { id: string }
137
+ >("refresh-design-system-with-builder", {
138
+ skipActionQueryInvalidation: true,
139
+ });
140
+ const refreshBuilderSystemRef = useRef(
141
+ refreshBuilderSystemMutation.mutateAsync,
142
+ );
143
+ refreshBuilderSystemRef.current = refreshBuilderSystemMutation.mutateAsync;
144
+ const settledBuilderRefreshesRef = useRef(new Set<string>());
145
+ const stoppedBuilderRefreshesRef = useRef(new Set<string>());
146
+ const activeBuilderRefreshesRef = useRef(new Set<string>());
135
147
 
136
148
  const designSystems = data?.designSystems ?? [];
137
149
  const selectedDesignSystemId = searchParams.get("designSystemId");
@@ -362,13 +374,107 @@ export default function DesignSystems() {
362
374
  });
363
375
  }, [selectedSystemIds, queryClient, exitSelectionMode, deleteMutation, t]);
364
376
 
365
- const parseData = (dataStr: string): DesignSystemData | null => {
366
- try {
367
- return JSON.parse(dataStr);
368
- } catch {
369
- return null;
377
+ useEffect(() => {
378
+ const builderSystemEntries = designSystems
379
+ .filter(shouldRefreshBuilderDesignSystem)
380
+ .map((system) => ({
381
+ id: system.id,
382
+ key: builderRefreshKey(system),
383
+ }))
384
+ .filter(
385
+ ({ key }) =>
386
+ !settledBuilderRefreshesRef.current.has(key) &&
387
+ !stoppedBuilderRefreshesRef.current.has(key) &&
388
+ !activeBuilderRefreshesRef.current.has(key),
389
+ );
390
+ if (builderSystemEntries.length === 0) return;
391
+
392
+ let disposed = false;
393
+ const timers: Array<ReturnType<typeof setTimeout>> = [];
394
+ const maxAttempts = 5;
395
+ const maxPolls = 3;
396
+ const retryDelayMs = 5_000;
397
+ const retryPollDelayMs = 30_000;
398
+
399
+ const scheduleRetry = (
400
+ entry: { id: string; key: string },
401
+ delayMs: number,
402
+ attempt: number,
403
+ pollCount: number,
404
+ ): void => {
405
+ if (disposed) return;
406
+ timers.push(
407
+ setTimeout(() => {
408
+ void refresh(entry, attempt, pollCount);
409
+ }, delayMs),
410
+ );
411
+ };
412
+
413
+ const refresh = async (
414
+ entry: { id: string; key: string },
415
+ attempt: number,
416
+ pollCount: number,
417
+ ): Promise<void> => {
418
+ try {
419
+ const result = await refreshBuilderSystemRef.current({ id: entry.id });
420
+ if (disposed) return;
421
+ if (result.synced) {
422
+ activeBuilderRefreshesRef.current.delete(entry.key);
423
+ settledBuilderRefreshesRef.current.add(entry.key);
424
+ await queryClient.invalidateQueries({
425
+ queryKey: ["action", "list-design-systems"],
426
+ });
427
+ return;
428
+ }
429
+ if (result.status === "conflict") {
430
+ activeBuilderRefreshesRef.current.delete(entry.key);
431
+ stoppedBuilderRefreshesRef.current.add(entry.key);
432
+ await queryClient.invalidateQueries({
433
+ queryKey: ["action", "list-design-systems"],
434
+ });
435
+ return;
436
+ }
437
+ if (result.status === "incomplete" || result.rejectedTokenCount) {
438
+ activeBuilderRefreshesRef.current.delete(entry.key);
439
+ stoppedBuilderRefreshesRef.current.add(entry.key);
440
+ return;
441
+ }
442
+ if (isTerminalBuilderStatus(result.status)) {
443
+ activeBuilderRefreshesRef.current.delete(entry.key);
444
+ settledBuilderRefreshesRef.current.add(entry.key);
445
+ return;
446
+ }
447
+ } catch {
448
+ if (disposed) return;
449
+ }
450
+ if (disposed) return;
451
+ const exhausted = attempt >= maxAttempts;
452
+ if (exhausted && pollCount >= maxPolls) {
453
+ activeBuilderRefreshesRef.current.delete(entry.key);
454
+ stoppedBuilderRefreshesRef.current.add(entry.key);
455
+ return;
456
+ }
457
+ scheduleRetry(
458
+ entry,
459
+ exhausted ? retryPollDelayMs : retryDelayMs,
460
+ exhausted ? 0 : attempt + 1,
461
+ exhausted ? pollCount + 1 : pollCount,
462
+ );
463
+ };
464
+
465
+ for (const entry of builderSystemEntries) {
466
+ activeBuilderRefreshesRef.current.add(entry.key);
467
+ void refresh(entry, 0, 0);
370
468
  }
371
- };
469
+
470
+ return () => {
471
+ disposed = true;
472
+ for (const timer of timers) clearTimeout(timer);
473
+ for (const entry of builderSystemEntries) {
474
+ activeBuilderRefreshesRef.current.delete(entry.key);
475
+ }
476
+ };
477
+ }, [designSystems, queryClient]);
372
478
 
373
479
  useSetPageTitle(t("navigation.designSystems"));
374
480
 
@@ -486,7 +592,7 @@ export default function DesignSystems() {
486
592
 
487
593
  {/* Design system cards */}
488
594
  {designSystems.map((ds) => {
489
- const parsed = parseData(ds.data);
595
+ const parsed = parseDesignSystemData(ds.data);
490
596
  const colors = parsed?.colors;
491
597
  const primaryColor = getCssColorToken(colors?.primary);
492
598
  const secondaryColor = getCssColorToken(colors?.secondary);
@@ -699,7 +805,7 @@ export default function DesignSystems() {
699
805
  </AlertDialogCancel>
700
806
  <AlertDialogAction
701
807
  onClick={bulkDeleteOpen ? handleBulkDelete : handleDelete}
702
- className="bg-red-600 hover:bg-red-700 cursor-pointer"
808
+ className="bg-destructive text-destructive-foreground hover:bg-destructive/90 cursor-pointer"
703
809
  >
704
810
  {t("designSystems.actions.delete")}
705
811
  </AlertDialogAction>
@@ -997,18 +1103,6 @@ function EmptyPreviewLine({
997
1103
  );
998
1104
  }
999
1105
 
1000
- function parseDesignSystemData(dataStr: string): DesignSystemData | null {
1001
- try {
1002
- const parsed = JSON.parse(dataStr);
1003
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1004
- return null;
1005
- }
1006
- return parsed as DesignSystemData;
1007
- } catch {
1008
- return null;
1009
- }
1010
- }
1011
-
1012
1106
  function parseDesignSystemAssets(
1013
1107
  assetsStr?: string | null,
1014
1108
  ): Array<{ name?: string; url?: string; variant?: string }> {
@@ -864,6 +864,7 @@ export default function Index() {
864
864
  value={search}
865
865
  onChange={(e) => handleSearchChange(e.target.value)}
866
866
  placeholder={t("home.searchPlaceholder")}
867
+ aria-label={t("home.searchPlaceholder")}
867
868
  className="ps-8 h-8 w-48 bg-accent/50 border-border text-sm text-foreground/90 placeholder:text-muted-foreground/70"
868
869
  />
869
870
  </div>
@@ -1232,7 +1233,7 @@ export default function Index() {
1232
1233
  </AlertDialogCancel>
1233
1234
  <AlertDialogAction
1234
1235
  onClick={bulkDeleteOpen ? handleBulkDelete : handleDelete}
1235
- className="bg-red-600 hover:bg-red-700 cursor-pointer"
1236
+ className="bg-destructive text-destructive-foreground hover:bg-destructive/90 cursor-pointer"
1236
1237
  >
1237
1238
  {t("home.delete")}
1238
1239
  </AlertDialogAction>
@@ -1262,6 +1263,7 @@ export default function Index() {
1262
1263
  }
1263
1264
  }}
1264
1265
  placeholder={t("home.designName")}
1266
+ aria-label={t("home.designName")}
1265
1267
  className="h-9 text-sm"
1266
1268
  />
1267
1269
  <AlertDialogFooter>
@@ -302,16 +302,6 @@ export default function Templates() {
302
302
  </p>
303
303
  </div>
304
304
 
305
- <div className="relative mb-6 md:hidden">
306
- <IconSearch className="absolute start-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground/70" />
307
- <Input
308
- value={search}
309
- onChange={(event) => setSearch(event.target.value)}
310
- placeholder={t("templatesPage.searchPlaceholder")}
311
- className="h-9 w-full bg-accent/50 ps-8 text-sm"
312
- />
313
- </div>
314
-
315
305
  {isLoading ? (
316
306
  <TemplateGridSkeleton />
317
307
  ) : isError ? (
@@ -1134,6 +1134,16 @@ export function removeEmptyGeneratedGroupWrappers(
1134
1134
  candidateParentAttrIds: ReadonlySet<string>,
1135
1135
  ): string {
1136
1136
  if (candidateParentAttrIds.size === 0) return content;
1137
+ // Both are necessary conditions for isGeneratedGroupWrapperNode to ever
1138
+ // match. Checking them on the raw string first keeps a document with no
1139
+ // generated groups — the common case — from paying for a full projection of
1140
+ // post-edit content on every structural edit.
1141
+ if (
1142
+ !content.includes("data-agent-native-layer-name") ||
1143
+ !content.includes("Group")
1144
+ ) {
1145
+ return content;
1146
+ }
1137
1147
  let next = content;
1138
1148
  // Loop: removing one empty wrapper can itself empty out ITS parent (e.g.
1139
1149
  // ungrouping down a chain of nested generated groups), so keep sweeping
@@ -1,4 +1,8 @@
1
1
  import { shouldUseLiveFileContent } from "@shared/html-content";
2
+ import DiffMatchPatch from "diff-match-patch";
3
+ import type * as Y from "yjs";
4
+
5
+ const { DIFF_DELETE, DIFF_EQUAL } = DiffMatchPatch;
2
6
 
3
7
  export function shouldRebaseCollabDocFromStoredContent({
4
8
  liveContent,
@@ -56,3 +60,49 @@ export function shouldApplyRemotePreviewContent({
56
60
  }): boolean {
57
61
  return !isLocalEdit && nextContent !== previousContent;
58
62
  }
63
+
64
+ const diffMatchPatch = new DiffMatchPatch();
65
+
66
+ /**
67
+ * Replace the collab document's text with `next` as the smallest set of
68
+ * disjoint splices, and report whether anything changed.
69
+ *
70
+ * Never `delete(0, length) + insert(0, next)`. That shape ships the whole
71
+ * document on every edit, the UndoManager pins every replaced copy so the doc
72
+ * grows without bound within a session, and it is wrong under concurrency:
73
+ * two peers each rewriting the whole text merge into a duplicated document
74
+ * instead of both edits.
75
+ *
76
+ * Disjoint rather than one prefix/suffix splice, because a single splice spans
77
+ * everything between the first and last changed character. An agent rewrite
78
+ * touching two ends of a screen would delete the untouched middle and take a
79
+ * concurrent edit inside it with it. This mirrors the server's own
80
+ * `applyTextToYDoc`, which has always diffed this way.
81
+ */
82
+ export function writeCollabText(
83
+ ydoc: Y.Doc,
84
+ ytext: Y.Text,
85
+ next: string,
86
+ origin: unknown,
87
+ ): boolean {
88
+ const current = ytext.toString();
89
+ if (current === next) return false;
90
+ // No cleanup pass: diff_cleanupEfficiency merges edits across equal runs
91
+ // shorter than Diff_EditCost (4), which deletes up to three untouched
92
+ // characters and takes any concurrent edit anchored in them along with it.
93
+ const diffs = diffMatchPatch.diff_main(current, next);
94
+ ydoc.transact(() => {
95
+ let cursor = 0;
96
+ for (const [operation, text] of diffs) {
97
+ if (operation === DIFF_EQUAL) {
98
+ cursor += text.length;
99
+ } else if (operation === DIFF_DELETE) {
100
+ ytext.delete(cursor, text.length);
101
+ } else {
102
+ ytext.insert(cursor, text);
103
+ cursor += text.length;
104
+ }
105
+ }
106
+ }, origin);
107
+ return true;
108
+ }
@@ -37,7 +37,7 @@ export interface ApplyDesignEditorCommandArgs {
37
37
  overviewScreens: OverviewScreen[];
38
38
  setActiveFileId: Dispatch<SetStateAction<string | null>>;
39
39
  setActiveInspectorTab: Dispatch<SetStateAction<InspectorTab>>;
40
- setActiveLeftPanel: Dispatch<SetStateAction<DesignLeftPanel>>;
40
+ setActiveLeftPanel: Dispatch<SetStateAction<DesignLeftPanel | null>>;
41
41
  setActiveTool: Dispatch<SetStateAction<DesignTool>>;
42
42
  setDrawMode: Dispatch<SetStateAction<boolean>>;
43
43
  setInteractDeviceName: Dispatch<SetStateAction<string>>;
@@ -10,7 +10,10 @@ import {
10
10
  waitForShaderWriteToSettle,
11
11
  } from "@/components/design/inspector/GlslShaderPanel";
12
12
  import type { ClipboardContentMutationPublication } from "@/lib/clipboard-content-lineage";
13
- import { resolveScreenCollabSyncTarget } from "@/pages/design-editor/collab-sync";
13
+ import {
14
+ resolveScreenCollabSyncTarget,
15
+ writeCollabText,
16
+ } from "@/pages/design-editor/collab-sync";
14
17
  import { TAB_ID } from "@/pages/design-editor/editor-session";
15
18
  import type { FileContentSaveRequest } from "@/pages/design-editor/editor-state";
16
19
  import type { ContentHistoryEntry } from "@/pages/design-editor/history";
@@ -218,13 +221,12 @@ export function runApplyFileContentUpdate(
218
221
  overviewDocConnected: !!(overviewYdoc && overviewIsSynced),
219
222
  });
220
223
  if (writeLiveDoc && overviewYdoc) {
221
- const ytext = overviewYdoc.getText("content");
222
- if (ytext.toString() !== nextContent) {
223
- overviewYdoc.transact(() => {
224
- ytext.delete(0, ytext.length);
225
- ytext.insert(0, nextContent);
226
- }, TAB_ID);
227
- }
224
+ writeCollabText(
225
+ overviewYdoc,
226
+ overviewYdoc.getText("content"),
227
+ nextContent,
228
+ TAB_ID,
229
+ );
228
230
  }
229
231
  if (options.persist === false) {
230
232
  cancelQueuedFileContentSave(fileId);
@@ -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
  }