@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
@@ -31,6 +31,7 @@ import { getDb, schema } from "../server/db/index.js";
31
31
  import { mutateDesignData } from "../server/lib/design-data-mutation.js";
32
32
  import {
33
33
  readLiveSourceFile,
34
+ SourceWorkspaceEditConflictError,
34
35
  writeInlineSourceFile,
35
36
  type SourceWorkspaceFile,
36
37
  } from "../server/source-workspace.js";
@@ -48,6 +49,7 @@ import {
48
49
  assertDesignHtmlCreateIntegrity,
49
50
  describeDesignHtmlIntegrityIssue,
50
51
  inspectDesignHtmlDocumentIntegrity,
52
+ isDesignHtmlIntegrityError,
51
53
  } from "../shared/html-integrity.js";
52
54
  import { assertLockedLayersPreserved } from "../shared/locked-layers.js";
53
55
  import { widthToPrefix } from "../shared/responsive-classes.js";
@@ -488,6 +490,9 @@ const generateDesignAction = defineAction({
488
490
  "The agent calls this after generating HTML/CSS/JSX content to persist it " +
489
491
  "as files in the design project. Creates or updates files as needed. " +
490
492
  "Returns the saved files and design URL path for iframe rendering. " +
493
+ "A file rejected by a concurrent edit or an HTML-integrity check does not " +
494
+ "fail the whole call — it is listed in `fileErrors` instead, while every " +
495
+ "other file in the same call still saves; resend just the named file(s). " +
491
496
  "Keep the first save compact and working; for large designs, persist a minimal " +
492
497
  "version then refine individual files with `edit-design` (search/replace) rather " +
493
498
  "than resending a big multi-file payload — a single oversized payload can get cut " +
@@ -793,14 +798,23 @@ const generateDesignAction = defineAction({
793
798
  // takes the lenient edit transition instead, so a legacy-malformed screen
794
799
  // stays repairable — but its advisories are still reported, or the same
795
800
  // content would warn as a new file and save silently as a regeneration.
796
- const advisory =
797
- !existing || becomesHtml
798
- ? assertDesignHtmlCreateIntegrity({
799
- content: file.content,
800
- fileType: "html",
801
- filename: file.filename,
802
- })
803
- : (inspectDesignHtmlDocumentIntegrity(file.content).advisory ?? []);
801
+ let advisory: ReturnType<typeof assertDesignHtmlCreateIntegrity>;
802
+ if (!existing || becomesHtml) {
803
+ advisory = assertDesignHtmlCreateIntegrity({
804
+ content: file.content,
805
+ fileType: "html",
806
+ filename: file.filename,
807
+ });
808
+ } else {
809
+ // `inspectDesignHtmlDocumentIntegrity` only sets `.advisory` when
810
+ // valid:true; an invalid existing file's issues live in `.detail`
811
+ // instead, so `.advisory ?? []` was silently dropping them — the
812
+ // opposite of the comment above promising they are still reported.
813
+ const inspected = inspectDesignHtmlDocumentIntegrity(file.content);
814
+ advisory = inspected.valid
815
+ ? (inspected.advisory ?? [])
816
+ : (inspected.detail ?? []);
817
+ }
804
818
  for (const entry of advisory) {
805
819
  integrityWarnings.push({
806
820
  filename: file.filename,
@@ -809,6 +823,10 @@ const generateDesignAction = defineAction({
809
823
  }
810
824
  }
811
825
 
826
+ // Populated when a per-file write is rejected below (conflict or
827
+ // integrity failure); surfaced in the return payload so a partial batch
828
+ // is reported as partial, never silently read back as complete.
829
+ const fileErrors: Array<{ filename: string; message: string }> = [];
812
830
  for (const file of annotatedFiles) {
813
831
  const existing = existingByName.get(file.filename);
814
832
  if (existing) {
@@ -820,49 +838,79 @@ const generateDesignAction = defineAction({
820
838
  });
821
839
 
822
840
  try {
823
- // `file.content` here is LLM-generated content produced upstream of
824
- // this action call, so there can be a large async window (the full
825
- // generation time) between whenever this file's content was last
826
- // known and this write. Read the LIVE base (collab text when
827
- // present, else the SQL row) right before persisting and carry its
828
- // versionHash through to writeInlineSourceFile, which re-reads the
829
- // live text immediately before its own applyText/DB write and
830
- // rejects if it no longer matches — closing the race window where a
831
- // concurrent editor/agent write lands mid-generation. See
832
- // insert-design-native-asset.ts and insert-asset.ts for the
833
- // identical pattern.
834
- const workspaceFile: SourceWorkspaceFile = {
835
- id: existing.id,
836
- designId: existing.designId,
837
- filename: existing.filename ?? "",
838
- fileType: existing.fileType ?? "html",
839
- content: existing.content,
840
- createdAt: null,
841
- updatedAt: null,
842
- };
843
- const live = await readLiveSourceFile(workspaceFile);
841
+ try {
842
+ // `file.content` here is LLM-generated content produced upstream of
843
+ // this action call, so there can be a large async window (the full
844
+ // generation time) between whenever this file's content was last
845
+ // known and this write. Read the LIVE base (collab text when
846
+ // present, else the SQL row) right before persisting and carry its
847
+ // versionHash through to writeInlineSourceFile, which re-reads the
848
+ // live text immediately before its own applyText/DB write and
849
+ // rejects if it no longer matches — closing the race window where a
850
+ // concurrent editor/agent write lands mid-generation. See
851
+ // insert-design-native-asset.ts and insert-asset.ts for the
852
+ // identical pattern.
853
+ const workspaceFile: SourceWorkspaceFile = {
854
+ id: existing.id,
855
+ designId: existing.designId,
856
+ filename: existing.filename ?? "",
857
+ fileType: existing.fileType ?? "html",
858
+ content: existing.content,
859
+ createdAt: null,
860
+ updatedAt: null,
861
+ };
862
+ const live = await readLiveSourceFile(workspaceFile);
844
863
 
845
- assertLockedLayersPreserved(live.content, file.content);
864
+ assertLockedLayersPreserved(live.content, file.content);
846
865
 
847
- await writeInlineSourceFile({
848
- designId: existing.designId,
849
- file: workspaceFile,
850
- content: file.content,
851
- expectedVersionHash: live.versionHash,
852
- });
866
+ await writeInlineSourceFile({
867
+ designId: existing.designId,
868
+ file: workspaceFile,
869
+ content: file.content,
870
+ expectedVersionHash: live.versionHash,
871
+ });
853
872
 
854
- // writeInlineSourceFile only persists content/updatedAt; keep
855
- // fileType in sync separately when the caller changed it (e.g.
856
- // html -> jsx), matching the original update behavior.
857
- const nextFileType = file.fileType ?? "html";
858
- if (nextFileType !== (existing.fileType ?? "html")) {
859
- await db
860
- .update(schema.designFiles)
861
- .set({ fileType: nextFileType, updatedAt: now })
862
- .where(eq(schema.designFiles.id, existing.id));
873
+ // writeInlineSourceFile only persists content/updatedAt; keep
874
+ // fileType in sync separately when the caller changed it (e.g.
875
+ // html -> jsx), matching the original update behavior.
876
+ const nextFileType = file.fileType ?? "html";
877
+ if (nextFileType !== (existing.fileType ?? "html")) {
878
+ await db
879
+ .update(schema.designFiles)
880
+ .set({ fileType: nextFileType, updatedAt: now })
881
+ .where(eq(schema.designFiles.id, existing.id));
882
+ }
883
+ } finally {
884
+ agentLeaveDocument(existing.id);
863
885
  }
864
- } finally {
865
- agentLeaveDocument(existing.id);
886
+ } catch (error) {
887
+ // Only the two rejection reasons the tool description above
888
+ // promises — a version-hash conflict and an HTML-integrity
889
+ // rejection — are reported per-file. Anything else (a DB/provider
890
+ // failure from the read, the write, or the follow-up fileType
891
+ // update) is not a caller-diagnosable rejection of THIS file's
892
+ // content; swallowing it here would report a transient
893
+ // infrastructure failure as an ordinary "resend this file"
894
+ // outcome, or hide that the content write actually succeeded and
895
+ // only the fileType update failed. Rethrow so it fails the whole
896
+ // call loud instead.
897
+ if (
898
+ !(error instanceof SourceWorkspaceEditConflictError) &&
899
+ !isDesignHtmlIntegrityError(error)
900
+ ) {
901
+ throw error;
902
+ }
903
+ // A legitimate optimistic-concurrency conflict or an HTML-integrity
904
+ // rejection on THIS file must not discard files earlier in this
905
+ // batch that already committed durably, and must not disappear
906
+ // either — record it as a distinct, loud failure so the caller can
907
+ // tell "saved" from "failed" and retry just this file, instead of a
908
+ // later read seeing a mixed batch with no marker explaining why.
909
+ fileErrors.push({
910
+ filename: file.filename,
911
+ message: error instanceof Error ? error.message : String(error),
912
+ });
913
+ continue;
866
914
  }
867
915
 
868
916
  savedFiles.push({
@@ -1241,6 +1289,9 @@ const generateDesignAction = defineAction({
1241
1289
  // Non-blocking: a well-formed screen with no Tailwind runtime renders
1242
1290
  // unstyled, which reads as a layout bug rather than a missing runtime.
1243
1291
  ...(integrityWarnings.length > 0 ? { warnings: integrityWarnings } : {}),
1292
+ // Per-file conflicts/rejections caught above: these files were NOT
1293
+ // saved and still need a retry, unlike everything in `savedFiles`.
1294
+ ...(fileErrors.length > 0 ? { fileErrors } : {}),
1244
1295
  ...creativeContextProvenance,
1245
1296
  };
1246
1297
  },
@@ -114,6 +114,7 @@ function buildDesignSystemAgentContext({
114
114
  assets,
115
115
  customInstructions,
116
116
  builder,
117
+ canRefreshBuilder,
117
118
  }: {
118
119
  id: string;
119
120
  title: string;
@@ -122,6 +123,7 @@ function buildDesignSystemAgentContext({
122
123
  assets?: string | null;
123
124
  customInstructions?: string | null;
124
125
  builder: BuilderGenerationContext | null;
126
+ canRefreshBuilder: boolean;
125
127
  }): string {
126
128
  const lines: string[] = [
127
129
  "## Selected Design System Context",
@@ -154,7 +156,9 @@ function buildDesignSystemAgentContext({
154
156
  builder.builderUrl ? `- URL: ${builder.builderUrl}` : "",
155
157
  builder.builderStatus ? `- Status: ${builder.builderStatus}` : "",
156
158
  "- Builder DSI docs and token values override local proxy placeholders.",
157
- "- Do not substitute a generic style if DSI docs or tokens are unavailable; call get-design-system again or tell the user Builder indexing is not ready.",
159
+ canRefreshBuilder
160
+ ? "- If no usable DSI docs or tokens are returned, call refresh-design-system-with-builder once, then call get-design-system again before generating; if it is still empty, tell the user Builder indexing is not ready."
161
+ : "- If no usable DSI docs or tokens are returned, tell the user Builder indexing is not ready; refreshing the shared system requires editor access.",
158
162
  );
159
163
 
160
164
  if (builder.warning) {
@@ -297,6 +301,7 @@ export default defineAction({
297
301
  data: row.data,
298
302
  assets: row.assets,
299
303
  customInstructions: row.customInstructions,
304
+ canRefreshBuilder: ["owner", "admin", "editor"].includes(access.role),
300
305
  builder,
301
306
  }),
302
307
  };
@@ -0,0 +1,146 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import {
3
+ hydrateBuilderDesignSystemReference,
4
+ parseBuilderDesignSystemProxyReference,
5
+ } from "@agent-native/core/server";
6
+ import { assertAccess, resolveAccess } from "@agent-native/core/sharing";
7
+ import { and, eq } from "drizzle-orm";
8
+ import { z } from "zod";
9
+
10
+ import { getDb, schema } from "../server/db/index.js";
11
+ import { reconcileBuilderProxyData } from "../server/lib/builder-design-system-proxy.js";
12
+
13
+ function persistedBuilderSyncMatches(data: unknown, syncedAt: string): boolean {
14
+ if (typeof data !== "string") return false;
15
+ try {
16
+ const parsed = JSON.parse(data) as Record<string, unknown>;
17
+ return (
18
+ parsed.builderStatus === "ready" && parsed.builderSyncedAt === syncedAt
19
+ );
20
+ } catch {
21
+ throw new Error(
22
+ "The design system data became invalid while Builder DSI was syncing.",
23
+ );
24
+ }
25
+ }
26
+
27
+ export default defineAction({
28
+ description:
29
+ "Refresh a Builder-backed design-system proxy after DSI indexing finishes. " +
30
+ "Requires editor access. If Builder is still processing, returns synced=false " +
31
+ "without replacing the local proxy with partial data.",
32
+ schema: z.object({
33
+ id: z.string().min(1).describe("Local design system id"),
34
+ }),
35
+ run: async ({ id }) => {
36
+ await assertAccess("design-system", id, "editor");
37
+ const access = await resolveAccess("design-system", id);
38
+ if (!access) throw new Error("Design system not found");
39
+
40
+ const reference = parseBuilderDesignSystemProxyReference(
41
+ access.resource.data,
42
+ );
43
+ if (!reference) {
44
+ throw new Error("This design system is not a Builder-backed proxy.");
45
+ }
46
+
47
+ const hydrated = await hydrateBuilderDesignSystemReference(reference);
48
+ const syncedAt = new Date().toISOString();
49
+ const reconciliation = reconcileBuilderProxyData(
50
+ access.resource.data,
51
+ hydrated,
52
+ syncedAt,
53
+ );
54
+ if (!reconciliation) {
55
+ return {
56
+ id,
57
+ synced: false,
58
+ status:
59
+ hydrated.builderStatus ?? reference.builderStatus ?? "in-progress",
60
+ docCount: hydrated.docCount,
61
+ tokenCount: 0,
62
+ message: "Builder DSI has not returned usable token values yet.",
63
+ };
64
+ }
65
+
66
+ if (reconciliation.rejectedTokenCount > 0) {
67
+ return {
68
+ id,
69
+ synced: false,
70
+ status: "incomplete",
71
+ docCount: hydrated.docCount,
72
+ tokenCount: reconciliation.tokenCount,
73
+ rejectedTokenCount: reconciliation.rejectedTokenCount,
74
+ message: `Builder DSI returned ${reconciliation.rejectedTokenCount} token(s) that could not be safely imported.`,
75
+ };
76
+ }
77
+
78
+ if (!reconciliation.completionConfirmed) {
79
+ return {
80
+ id,
81
+ synced: false,
82
+ status:
83
+ hydrated.builderStatus ?? reference.builderStatus ?? "in-progress",
84
+ docCount: hydrated.docCount,
85
+ tokenCount: reconciliation.tokenCount,
86
+ rejectedTokenCount: 0,
87
+ message:
88
+ "Builder DSI returned token values without confirming that indexing is complete. Retry after Builder reports completion.",
89
+ };
90
+ }
91
+
92
+ await assertAccess("design-system", id, "editor");
93
+ const latestAccess = await resolveAccess("design-system", id);
94
+ if (!latestAccess) throw new Error("Design system not found");
95
+ if (
96
+ latestAccess.resource.id !== access.resource.id ||
97
+ latestAccess.resource.data !== access.resource.data
98
+ ) {
99
+ return {
100
+ id,
101
+ synced: false,
102
+ status: "conflict",
103
+ docCount: hydrated.docCount,
104
+ tokenCount: reconciliation.tokenCount,
105
+ rejectedTokenCount: 0,
106
+ message:
107
+ "The design system changed while Builder DSI was syncing. Retry the refresh.",
108
+ };
109
+ }
110
+
111
+ const db = getDb();
112
+ await db
113
+ .update(schema.designSystems)
114
+ .set({ data: reconciliation.data, updatedAt: syncedAt })
115
+ .where(
116
+ and(
117
+ eq(schema.designSystems.id, latestAccess.resource.id),
118
+ eq(schema.designSystems.data, latestAccess.resource.data),
119
+ ),
120
+ );
121
+
122
+ const persisted = await resolveAccess("design-system", id);
123
+ if (!persistedBuilderSyncMatches(persisted?.resource?.data, syncedAt)) {
124
+ return {
125
+ id,
126
+ synced: false,
127
+ status: "conflict",
128
+ docCount: hydrated.docCount,
129
+ tokenCount: reconciliation.tokenCount,
130
+ rejectedTokenCount: 0,
131
+ message:
132
+ "The design system changed while Builder DSI was syncing. Retry the refresh.",
133
+ };
134
+ }
135
+
136
+ return {
137
+ id,
138
+ synced: true,
139
+ status: "ready",
140
+ docCount: hydrated.docCount,
141
+ tokenCount: reconciliation.tokenCount,
142
+ rejectedTokenCount: reconciliation.rejectedTokenCount,
143
+ syncedAt,
144
+ };
145
+ },
146
+ });
@@ -20,10 +20,12 @@ import {
20
20
  closePenPath,
21
21
  constrainPointTo45Degrees,
22
22
  createCornerNode,
23
- createSmoothNode,
23
+ createPenCuspLatch,
24
+ createPenDragNode,
24
25
  isPenCloseTarget,
25
26
  serializePenPath,
26
27
  translatePenPath,
28
+ type PenCuspLatch,
27
29
  type PenPath,
28
30
  type PenPoint,
29
31
  } from "@shared/pen-path";
@@ -494,7 +496,10 @@ interface DesignCanvasProps {
494
496
  selector: string,
495
497
  styles: Record<string, string>,
496
498
  info?: ElementInfo,
497
- metadata?: { originalStyles?: Record<string, string> },
499
+ metadata?: {
500
+ originalStyles?: Record<string, string>;
501
+ preserveSelection?: boolean;
502
+ },
498
503
  ) => void;
499
504
  onTextContentChange?: (
500
505
  selector: string,
@@ -956,6 +961,16 @@ function originFromUrl(value: string | undefined): string | null {
956
961
  }
957
962
  }
958
963
 
964
+ /**
965
+ * JSON for embedding inside an inline `<script>`. A bare `JSON.stringify` keeps
966
+ * `</script>` verbatim, and the HTML parser closes the surrounding script the
967
+ * moment it sees that sequence — truncating the bridge for any design whose
968
+ * head legitimately contains one (JSON-LD, a templating snippet).
969
+ */
970
+ function inlineScriptJson(value: string): string {
971
+ return JSON.stringify(value).replace(/</g, "\\u003c");
972
+ }
973
+
959
974
  function buildEditorChromeBridgeScript(args: {
960
975
  readOnly: boolean;
961
976
  editMode: boolean;
@@ -966,6 +981,7 @@ function buildEditorChromeBridgeScript(args: {
966
981
  contentOffsetX: number;
967
982
  contentOffsetY: number;
968
983
  runtimeLayerSnapshotEnabled: boolean;
984
+ initialSourceHead: string;
969
985
  }) {
970
986
  return (
971
987
  createEditorBridgeThemeScript(readEditorBridgeThemeVars()) +
@@ -1001,9 +1017,18 @@ function buildEditorChromeBridgeScript(args: {
1001
1017
  "__SELECTED_LAYER_DRAG_PRIORITY__",
1002
1018
  SELECTED_LAYER_DRAG_PRIORITY_ENABLED ? "true" : "false",
1003
1019
  )
1020
+ .replace(/__INITIAL_SOURCE_HEAD__/g, () =>
1021
+ inlineScriptJson(args.initialSourceHead),
1022
+ )
1004
1023
  );
1005
1024
  }
1006
1025
 
1026
+ /** The `<head>` the bridge's own srcdoc will render, so its first in-place
1027
+ * patch diffs against what is actually in the document. */
1028
+ function sourceHeadInnerHtml(html: string): string {
1029
+ return /<head\b[^>]*>([\s\S]*?)<\/head\s*>/i.exec(html)?.[1] ?? "";
1030
+ }
1031
+
1007
1032
  function contentHash(value: string): string {
1008
1033
  let hash = 0;
1009
1034
  for (let index = 0; index < value.length; index += 1) {
@@ -1015,27 +1040,30 @@ function contentHash(value: string): string {
1015
1040
  const SCRIPT_ELEMENT_RE = /<script\b[^>]*>[\s\S]*?<\/script\s*>/gi; // i18n-ignore non-UI regex
1016
1041
 
1017
1042
  /**
1018
- * Runtime document replacement uses `head.innerHTML` / `body.innerHTML`, which
1019
- * intentionally preserves the iframe browsing context but cannot execute
1020
- * newly inserted or changed scripts. Reload only when source script elements
1021
- * change; ordinary markup/style edits continue through the no-flash bridge.
1043
+ * Runtime document replacement morphs the live DOM, which preserves the iframe
1044
+ * browsing context but cannot execute newly inserted or changed scripts.
1045
+ * Reload only when source script elements change.
1046
+ *
1047
+ * A changed `<head>` is NOT a reload trigger: the bridge swaps only the nodes
1048
+ * the previous source head contributed (replaceSourceHeadNodes), leaving what
1049
+ * the page's own runtime injected in place. Treating any head edit as a reload
1050
+ * meant every breakpoint override, motion track and token write — all of which
1051
+ * persist into a managed `<style>` in the head — reloaded the whole frame.
1022
1052
  */
1023
1053
  function runtimeDocumentNeedsReload(
1024
1054
  previousContent: string,
1025
1055
  nextContent: string,
1026
1056
  ): boolean {
1027
- const scriptSignature = (html: string) =>
1028
- Array.from(html.matchAll(SCRIPT_ELEMENT_RE), (match) => match[0]).join(
1029
- "\n",
1030
- );
1031
- // A changed <head> is replaced wholesale, which drops whatever the page's own
1032
- // runtime injected there and cannot re-run the scripts that produced it.
1033
- const headSignature = (html: string) =>
1034
- /<head\b[^>]*>([\s\S]*?)<\/head\s*>/i.exec(html)?.[1] ?? "";
1035
- return (
1036
- scriptSignature(previousContent) !== scriptSignature(nextContent) ||
1037
- headSignature(previousContent) !== headSignature(nextContent)
1038
- );
1057
+ const scriptSignature = (html: string) => {
1058
+ const headEnd = html.search(/<\/head\s*>/i);
1059
+ const boundary = headEnd === -1 ? 0 : headEnd;
1060
+ return Array.from(
1061
+ html.matchAll(SCRIPT_ELEMENT_RE),
1062
+ (match) =>
1063
+ `${(match.index ?? 0) < boundary ? "head" : "body"}:${match[0]}`,
1064
+ ).join("\n");
1065
+ };
1066
+ return scriptSignature(previousContent) !== scriptSignature(nextContent);
1039
1067
  }
1040
1068
 
1041
1069
  /**
@@ -1465,6 +1493,9 @@ export function DesignCanvas({
1465
1493
  contentOffsetX: embeddedFrame?.contentOffsetX ?? 0,
1466
1494
  contentOffsetY: embeddedFrame?.contentOffsetY ?? 0,
1467
1495
  runtimeLayerSnapshotEnabled,
1496
+ // A live/localhost screen's document is the running app, not content
1497
+ // this canvas rendered, so there is no source head to diff against.
1498
+ initialSourceHead: "",
1468
1499
  }),
1469
1500
  // eslint-disable-next-line react-hooks/exhaustive-deps
1470
1501
  [boardSurface, contentKey, runtimeLayerSnapshotEnabled, screenId],
@@ -2329,6 +2360,7 @@ export function DesignCanvas({
2329
2360
  // keyed bridge registration is pending. The loading surface waits without
2330
2361
  // mounting an iframe, then mounts the real `src` exactly once.
2331
2362
  if (rawExternalPreviewUrl) return undefined;
2363
+ const localizedContent = withLocalRuntimes(iframeRenderContent);
2332
2364
  const editorChromeBridge = interactMode
2333
2365
  ? ""
2334
2366
  : createEditorBridgeThemeScript(readEditorBridgeThemeVars()) +
@@ -2369,6 +2401,9 @@ export function DesignCanvas({
2369
2401
  .replace(
2370
2402
  "__SELECTED_LAYER_DRAG_PRIORITY__",
2371
2403
  SELECTED_LAYER_DRAG_PRIORITY_ENABLED ? "true" : "false",
2404
+ )
2405
+ .replace(/__INITIAL_SOURCE_HEAD__/g, () =>
2406
+ inlineScriptJson(sourceHeadInnerHtml(localizedContent)),
2372
2407
  );
2373
2408
  // ALWAYS injected (like the other always-on bridges above) so
2374
2409
  // MultiScreenCanvas's cross-screen drag hit-testing
@@ -2389,7 +2424,7 @@ export function DesignCanvas({
2389
2424
  editorChromeBridge +
2390
2425
  imageDiagBridge;
2391
2426
  const frameContent = getEmbeddedFrameDocumentContent({
2392
- content: withLocalRuntimes(iframeRenderContent),
2427
+ content: localizedContent,
2393
2428
  embeddedFrameBackground,
2394
2429
  transparentBackground,
2395
2430
  contentOffsetX: embeddedFrame?.contentOffsetX ?? 0,
@@ -2410,7 +2445,7 @@ export function DesignCanvas({
2410
2445
  embeddedFrame?.contentOffsetY ?? 0,
2411
2446
  ),
2412
2447
  ].join("");
2413
- frameDocument = `<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">${frameStyle}</head><body>${withLocalRuntimes(iframeRenderContent)}${bridgeToInject}</body></html>`;
2448
+ frameDocument = `<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">${frameStyle}</head><body>${localizedContent}${bridgeToInject}</body></html>`;
2414
2449
  }
2415
2450
  // Overview frames report their own content height so the canvas can
2416
2451
  // content-fit them (Framer-style). Embedded (overview) frames only — a
@@ -2730,6 +2765,7 @@ export function DesignCanvas({
2730
2765
  isElementInfoPayload(e.data.payload) ? e.data.payload : undefined,
2731
2766
  {
2732
2767
  originalStyles,
2768
+ preserveSelection: e.data.preserveSelection === true,
2733
2769
  },
2734
2770
  );
2735
2771
  }
@@ -5110,6 +5146,7 @@ interface SingleScreenPenGestureState {
5110
5146
  pathBefore: PenPath | null;
5111
5147
  moved: boolean;
5112
5148
  closing: boolean;
5149
+ cuspLatch: PenCuspLatch;
5113
5150
  }
5114
5151
 
5115
5152
  const SINGLE_SCREEN_PEN_HIT_RADIUS_PX = 10;
@@ -5342,6 +5379,7 @@ function SingleScreenCreationOverlay({
5342
5379
  pathBefore,
5343
5380
  moved: false,
5344
5381
  closing,
5382
+ cuspLatch: createPenCuspLatch(),
5345
5383
  };
5346
5384
  const initialPath = closing
5347
5385
  ? closePenPath(pathBefore!)
@@ -5400,9 +5438,12 @@ function SingleScreenCreationOverlay({
5400
5438
  : appendPenNode(
5401
5439
  gesture.pathBefore,
5402
5440
  moved
5403
- ? createSmoothNode(gesture.anchor, handleOut, {
5404
- breakSymmetry: e.altKey,
5405
- })
5441
+ ? createPenDragNode(
5442
+ gesture.anchor,
5443
+ handleOut,
5444
+ gesture.cuspLatch,
5445
+ e.altKey,
5446
+ )
5406
5447
  : createCornerNode(gesture.anchor),
5407
5448
  );
5408
5449
  updatePenPath(nextPath);
@@ -5454,9 +5495,12 @@ function SingleScreenCreationOverlay({
5454
5495
  : appendPenNode(
5455
5496
  gesture.pathBefore,
5456
5497
  moved
5457
- ? createSmoothNode(gesture.anchor, handleOut, {
5458
- breakSymmetry: e.altKey,
5459
- })
5498
+ ? createPenDragNode(
5499
+ gesture.anchor,
5500
+ handleOut,
5501
+ gesture.cuspLatch,
5502
+ e.altKey,
5503
+ )
5460
5504
  : createCornerNode(gesture.anchor),
5461
5505
  );
5462
5506
  penGestureRef.current = null;