@agent-native/core 0.141.7 → 0.144.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (371) hide show
  1. package/agent-native.eject.json +9 -0
  2. package/corpus/README.md +1 -1
  3. package/corpus/templates/analytics/.agents/skills/provider-api/SKILL.md +19 -0
  4. package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +296 -0
  5. package/corpus/templates/analytics/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  6. package/corpus/templates/analytics/.agents/skills/turn-into-skill/SKILL.md +112 -0
  7. package/corpus/templates/analytics/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  8. package/corpus/templates/analytics/AGENTS.md +35 -38
  9. package/corpus/templates/analytics/actions/ensure-native-v2-dashboards.ts +1 -1
  10. package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +17 -22
  11. package/corpus/templates/analytics/actions/migrate-first-party-analytics-to-bigquery.ts +1 -1
  12. package/corpus/templates/analytics/actions/navigate.ts +4 -5
  13. package/corpus/templates/analytics/actions/provider-api-register.ts +50 -0
  14. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +44 -11
  15. package/corpus/templates/analytics/actions/test-custom-api-connection.ts +106 -0
  16. package/corpus/templates/analytics/app/components/CustomApiCard.tsx +430 -0
  17. package/corpus/templates/analytics/app/i18n-data.ts +680 -0
  18. package/corpus/templates/analytics/app/lib/native-mcp-exclusions.ts +6 -0
  19. package/corpus/templates/analytics/app/lib/sql-query.ts +33 -6
  20. package/corpus/templates/analytics/app/pages/DataSources.tsx +4 -0
  21. package/corpus/templates/analytics/changelog/2026-08-06-analytics-dashboards-load-reliably-during-background-data-sw.md +6 -0
  22. package/corpus/templates/analytics/changelog/2026-08-06-analytics-dashboards-remain-responsive-while-historical-data.md +6 -0
  23. package/corpus/templates/analytics/changelog/2026-08-06-analytics-query-results-now-render-as-a-table-with-csv-downl.md +6 -0
  24. package/corpus/templates/analytics/changelog/2026-08-06-connect-public-https-custom-apis-and-hand-tested-endpoints-t.md +6 -0
  25. package/corpus/templates/analytics/changelog/2026-08-06-durable-agent-worker-memory.md +6 -0
  26. package/corpus/templates/analytics/changelog/2026-08-06-live-dashboard-panels-use-the-shared-query-timeout.md +6 -0
  27. package/corpus/templates/analytics/changelog/2026-08-06-on-demand-billing-is-available-as-a-native-dashboard-with-ta.md +6 -0
  28. package/corpus/templates/analytics/changelog/2026-08-06-visible-dashboard-names-are-unique.md +6 -0
  29. package/corpus/templates/analytics/netlify.toml +7 -0
  30. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +4 -0
  31. package/corpus/templates/analytics/server/db/index.ts +27 -0
  32. package/corpus/templates/analytics/server/db/schema.ts +10 -0
  33. package/corpus/templates/analytics/server/lib/dashboards-store.ts +227 -60
  34. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +156 -45
  35. package/corpus/templates/analytics/server/lib/native-v2-dashboards.ts +227 -1
  36. package/corpus/templates/analytics/server/plugins/agent-chat.ts +5 -0
  37. package/corpus/templates/analytics/server/plugins/analytics-rollup-backfill-jobs.ts +1 -0
  38. package/corpus/templates/analytics/server/plugins/db.ts +52 -18
  39. package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +28 -2
  40. package/corpus/templates/assets/.agents/skills/image-generation/SKILL.md +16 -1
  41. package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +296 -0
  42. package/corpus/templates/assets/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  43. package/corpus/templates/assets/.agents/skills/turn-into-skill/SKILL.md +112 -0
  44. package/corpus/templates/assets/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  45. package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +296 -0
  46. package/corpus/templates/brain/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  47. package/corpus/templates/brain/.agents/skills/turn-into-skill/SKILL.md +112 -0
  48. package/corpus/templates/brain/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  49. package/corpus/templates/brain/actions/list-connection-providers.ts +24 -3
  50. package/corpus/templates/brain/app/lib/dispatch-links.ts +44 -0
  51. package/corpus/templates/brain/app/routes/sources.tsx +15 -7
  52. package/corpus/templates/brain/changelog/2026-08-06-brain-provider-setup-links-open-dispatch-correctly-in-standa.md +6 -0
  53. package/corpus/templates/brain/server/plugins/agent-chat.ts +1 -0
  54. package/corpus/templates/calendar/.agents/skills/event-management/SKILL.md +26 -0
  55. package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +296 -0
  56. package/corpus/templates/calendar/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  57. package/corpus/templates/calendar/.agents/skills/turn-into-skill/SKILL.md +112 -0
  58. package/corpus/templates/calendar/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  59. package/corpus/templates/calendar/AGENTS.md +11 -32
  60. package/corpus/templates/calendar/actions/update-event.ts +107 -1
  61. package/corpus/templates/calendar/app/components/calendar/EventCalendarSelect.tsx +83 -0
  62. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +57 -0
  63. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +59 -73
  64. package/corpus/templates/calendar/app/hooks/use-events.ts +4 -1
  65. package/corpus/templates/calendar/app/i18n-data.ts +20 -0
  66. package/corpus/templates/calendar/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
  67. package/corpus/templates/calendar/changelog/2026-08-06-existing-events-can-move-between-connected-google-account-ca.md +6 -0
  68. package/corpus/templates/calendar/server/lib/google-calendar.ts +101 -0
  69. package/corpus/templates/calendar/server/plugins/agent-chat.ts +7 -1
  70. package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
  71. package/corpus/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  72. package/corpus/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
  73. package/corpus/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  74. package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +296 -0
  75. package/corpus/templates/clips/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  76. package/corpus/templates/clips/.agents/skills/turn-into-skill/SKILL.md +112 -0
  77. package/corpus/templates/clips/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  78. package/corpus/templates/clips/app/components/editor/editor-layout.tsx +9 -24
  79. package/corpus/templates/clips/app/components/editor/timeline-geometry.ts +15 -0
  80. package/corpus/templates/clips/app/components/editor/waveform.tsx +4 -17
  81. package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +14 -3
  82. package/corpus/templates/clips/app/components/player/player-controls.tsx +0 -3
  83. package/corpus/templates/clips/app/components/player/scrubber.tsx +2 -33
  84. package/corpus/templates/clips/app/components/player/video-player.tsx +58 -11
  85. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +28 -38
  86. package/corpus/templates/clips/app/routes/share.$shareId.tsx +21 -27
  87. package/corpus/templates/clips/changelog/2026-08-06-clips-recovers-from-stalled-recording-setup-without-requirin.md +6 -0
  88. package/corpus/templates/clips/changelog/2026-08-06-clips-starts-faster-after-a-deploy-or-idle-period-startup-no.md +6 -0
  89. package/corpus/templates/clips/changelog/2026-08-06-deleting-a-recording-returns-cleanly-to-the-library-and-fit-.md +6 -0
  90. package/corpus/templates/clips/changelog/2026-08-06-hide-clip-insights-from-viewers-without-analytics-access.md +6 -0
  91. package/corpus/templates/clips/changelog/2026-08-06-trimmed-clips-play-on-a-clean-timeline-without-cut-markers.md +6 -0
  92. package/corpus/templates/clips/desktop/src/app.tsx +48 -20
  93. package/corpus/templates/clips/desktop/src/lib/recorder.ts +275 -74
  94. package/corpus/templates/clips/desktop/src/lib/recording-start-guard.ts +84 -0
  95. package/corpus/templates/clips/desktop/src/overlays/toolbar.tsx +14 -4
  96. package/corpus/templates/clips/server/plugins/db.ts +214 -26
  97. package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +296 -0
  98. package/corpus/templates/content/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  99. package/corpus/templates/content/.agents/skills/turn-into-skill/SKILL.md +112 -0
  100. package/corpus/templates/content/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  101. package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +296 -0
  102. package/corpus/templates/crm/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  103. package/corpus/templates/crm/.agents/skills/turn-into-skill/SKILL.md +112 -0
  104. package/corpus/templates/crm/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  105. package/corpus/templates/crm/changelog/2026-08-06-crm-starts-faster-after-a-deploy-or-idle-period-one-time-dat.md +6 -0
  106. package/corpus/templates/crm/server/plugins/db.ts +11 -8
  107. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +36 -1
  108. package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +296 -0
  109. package/corpus/templates/design/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  110. package/corpus/templates/design/.agents/skills/turn-into-skill/SKILL.md +112 -0
  111. package/corpus/templates/design/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  112. package/corpus/templates/design/actions/import-from-url.ts +1 -1
  113. package/corpus/templates/design/app/components/design/LayersPanel.tsx +27 -18
  114. package/corpus/templates/design/app/pages/Index.tsx +6 -2
  115. package/corpus/templates/design/changelog/2026-08-05-deleting-a-design-from-the-home-page-no-longer-leaves-the-ap.md +6 -0
  116. package/corpus/templates/design/changelog/2026-08-05-renaming-a-layer-now-focuses-its-name-field-automatically.md +6 -0
  117. package/corpus/templates/design/server/plugins/agent-chat.ts +2 -0
  118. package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +296 -0
  119. package/corpus/templates/dispatch/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  120. package/corpus/templates/dispatch/.agents/skills/turn-into-skill/SKILL.md +112 -0
  121. package/corpus/templates/dispatch/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  122. package/corpus/templates/dispatch/AGENTS.md +8 -1
  123. package/corpus/templates/dispatch/app/dispatch-extensions.tsx +1 -0
  124. package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +30 -15
  125. package/corpus/templates/dispatch/app/i18n-data.ts +131 -0
  126. package/corpus/templates/dispatch/app/routes/admin._index.tsx +4 -0
  127. package/corpus/templates/dispatch/app/routes/admin.agents.tsx +1 -0
  128. package/corpus/templates/dispatch/app/routes/admin.approvals.tsx +1 -0
  129. package/corpus/templates/dispatch/app/routes/admin.apps.$appId.tsx +1 -0
  130. package/corpus/templates/dispatch/app/routes/admin.apps.tsx +1 -0
  131. package/corpus/templates/dispatch/app/routes/admin.audit.tsx +1 -0
  132. package/corpus/templates/dispatch/app/routes/admin.automations.tsx +1 -0
  133. package/corpus/templates/dispatch/app/routes/admin.destinations.tsx +4 -0
  134. package/corpus/templates/dispatch/app/routes/admin.dreams.tsx +1 -0
  135. package/corpus/templates/dispatch/app/routes/admin.identities.tsx +1 -0
  136. package/corpus/templates/dispatch/app/routes/admin.integrations.tsx +4 -0
  137. package/corpus/templates/dispatch/app/routes/admin.messaging.tsx +1 -0
  138. package/corpus/templates/dispatch/app/routes/admin.metrics.tsx +1 -0
  139. package/corpus/templates/dispatch/app/routes/admin.new-app.tsx +1 -0
  140. package/corpus/templates/dispatch/app/routes/admin.operations.tsx +1 -0
  141. package/corpus/templates/dispatch/app/routes/admin.thread-debug.tsx +4 -0
  142. package/corpus/templates/dispatch/app/routes/admin.transactional-email.$appId.$id.tsx +4 -0
  143. package/corpus/templates/dispatch/app/routes/admin.transactional-email.tsx +4 -0
  144. package/corpus/templates/dispatch/app/routes/admin.tsx +1 -0
  145. package/corpus/templates/dispatch/app/routes/admin.vault.tsx +1 -0
  146. package/corpus/templates/dispatch/app/routes/admin.workspace.tsx +1 -0
  147. package/corpus/templates/dispatch/changelog/2026-08-06-dispatch-keeps-everyday-navigation-focused-while-management-.md +6 -0
  148. package/corpus/templates/dispatch/changelog/2026-08-06-ready-workspace-apps-stay-one-click-away-in-a-compact-dispat.md +6 -0
  149. package/corpus/templates/dispatch/changelog/2026-08-06-shared-vault-values-and-management-are-now-restricted-to-wor.md +6 -0
  150. package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +296 -0
  151. package/corpus/templates/factory/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  152. package/corpus/templates/factory/.agents/skills/turn-into-skill/SKILL.md +112 -0
  153. package/corpus/templates/factory/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  154. package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +296 -0
  155. package/corpus/templates/forms/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  156. package/corpus/templates/forms/.agents/skills/turn-into-skill/SKILL.md +112 -0
  157. package/corpus/templates/forms/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  158. package/corpus/templates/forms/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
  159. package/corpus/templates/forms/server/plugins/agent-chat.ts +4 -0
  160. package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +296 -0
  161. package/corpus/templates/macros/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  162. package/corpus/templates/macros/.agents/skills/turn-into-skill/SKILL.md +112 -0
  163. package/corpus/templates/macros/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  164. package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +296 -0
  165. package/corpus/templates/mail/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  166. package/corpus/templates/mail/.agents/skills/turn-into-skill/SKILL.md +112 -0
  167. package/corpus/templates/mail/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  168. package/corpus/templates/mail/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
  169. package/corpus/templates/mail/server/plugins/agent-chat.ts +6 -0
  170. package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +296 -0
  171. package/corpus/templates/plan/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  172. package/corpus/templates/plan/.agents/skills/turn-into-skill/SKILL.md +112 -0
  173. package/corpus/templates/plan/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  174. package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +48 -5
  175. package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +37 -1
  176. package/corpus/templates/slides/.agents/skills/image-generation-via-a2a/SKILL.md +6 -0
  177. package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +15 -2
  178. package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +29 -24
  179. package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +296 -0
  180. package/corpus/templates/slides/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  181. package/corpus/templates/slides/.agents/skills/turn-into-skill/SKILL.md +112 -0
  182. package/corpus/templates/slides/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  183. package/corpus/templates/slides/AGENTS.md +17 -21
  184. package/corpus/templates/slides/_gitignore +1 -0
  185. package/corpus/templates/slides/actions/export-pptx.ts +470 -36
  186. package/corpus/templates/slides/actions/get-deck.ts +12 -0
  187. package/corpus/templates/slides/actions/import-file.ts +175 -139
  188. package/corpus/templates/slides/actions/import-google-slides-reference.ts +271 -12
  189. package/corpus/templates/slides/actions/import-pptx.ts +193 -68
  190. package/corpus/templates/slides/actions/patch-deck.ts +51 -0
  191. package/corpus/templates/slides/actions/update-slide.ts +29 -3
  192. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +10 -13
  193. package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +5 -1
  194. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +25 -12
  195. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +112 -57
  196. package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +202 -0
  197. package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +26 -14
  198. package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +173 -0
  199. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +182 -141
  200. package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +1 -0
  201. package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +18 -0
  202. package/corpus/templates/slides/app/components/editor/slide-text-targets.ts +85 -0
  203. package/corpus/templates/slides/app/components/layout/Layout.tsx +3 -0
  204. package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +15 -0
  205. package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +27 -1
  206. package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
  207. package/corpus/templates/slides/app/lib/create-deck-generation.ts +72 -11
  208. package/corpus/templates/slides/app/lib/deck-preview-frame.ts +15 -0
  209. package/corpus/templates/slides/app/lib/deck-share-links.ts +9 -0
  210. package/corpus/templates/slides/app/lib/export-pptx-client.ts +89 -0
  211. package/corpus/templates/slides/app/lib/import-uploaded-deck.ts +89 -0
  212. package/corpus/templates/slides/app/lib/slide-animation-elements.ts +3 -0
  213. package/corpus/templates/slides/app/pages/Index.tsx +172 -15
  214. package/corpus/templates/slides/changelog/2026-08-06-clicking-the-gray-canvas-around-a-slide-clears-its-selection.md +6 -0
  215. package/corpus/templates/slides/changelog/2026-08-06-deck-thumbnails-keep-a-consistent-listing-frame-across-aspec.md +6 -0
  216. package/corpus/templates/slides/changelog/2026-08-06-deep-linked-decks-open-directly-instead-of-being-interrupted.md +6 -0
  217. package/corpus/templates/slides/changelog/2026-08-06-google-slides-exports-now-show-clear-import-steps-when-direc.md +6 -0
  218. package/corpus/templates/slides/changelog/2026-08-06-import-pdf-google-slides-and-powerpoint-decks-directly-from-.md +6 -0
  219. package/corpus/templates/slides/changelog/2026-08-06-imported-powerpoint-exports-keep-text-and-images-editable-an.md +6 -0
  220. package/corpus/templates/slides/changelog/2026-08-06-presentation-prompts-continue-adding-rendered-slides-until-t.md +6 -0
  221. package/corpus/templates/slides/changelog/2026-08-06-public-decks-now-share-read-only-presentation-links-by-defau.md +6 -0
  222. package/corpus/templates/slides/changelog/2026-08-06-slides-offers-a-direct-connect-google-button-when-a-drive-co.md +6 -0
  223. package/corpus/templates/slides/changelog/2026-08-06-slides-preserve-uploaded-pdf-layouts-accept-larger-reference.md +6 -0
  224. package/corpus/templates/slides/changelog/2026-08-06-styled-words-stay-part-of-their-text-box-instead-of-becoming.md +6 -0
  225. package/corpus/templates/slides/changelog/2026-08-06-uploaded-decks-keep-their-slides-and-visuals-when-you-improv.md +6 -0
  226. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +7 -20
  227. package/corpus/templates/slides/server/handlers/import/html-converter.ts +247 -13
  228. package/corpus/templates/slides/server/handlers/import/pptx-assets.ts +67 -0
  229. package/corpus/templates/slides/server/handlers/import/pptx-parser.ts +2 -0
  230. package/corpus/templates/slides/server/handlers/uploads.ts +7 -3
  231. package/corpus/templates/slides/server/lib/chat-attachments.ts +7 -4
  232. package/corpus/templates/slides/server/lib/emails.ts +7 -2
  233. package/corpus/templates/slides/server/lib/google-docs-error.ts +50 -0
  234. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +1 -0
  235. package/corpus/templates/slides/server/lib/import-asset-storage.ts +127 -0
  236. package/corpus/templates/slides/server/lib/source-import.ts +167 -0
  237. package/corpus/templates/slides/server/plugins/agent-chat.ts +12 -3
  238. package/corpus/templates/slides/server/routes/api/import-assets/[token].get.ts +70 -0
  239. package/corpus/templates/slides/shared/upload-types.ts +3 -0
  240. package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +296 -0
  241. package/corpus/templates/tasks/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  242. package/corpus/templates/tasks/.agents/skills/turn-into-skill/SKILL.md +112 -0
  243. package/corpus/templates/tasks/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  244. package/dist/agent/production-agent.d.ts +17 -0
  245. package/dist/agent/production-agent.js +72 -1
  246. package/dist/cli/agent-plugin.d.ts +112 -0
  247. package/dist/cli/agent-plugin.js +1081 -0
  248. package/dist/cli/app-skill.js +39 -1
  249. package/dist/cli/code-agent-executor.d.ts +3 -0
  250. package/dist/cli/code-agent-executor.js +51 -13
  251. package/dist/cli/index.js +13 -0
  252. package/dist/cli/templates-meta.js +1 -1
  253. package/dist/client/AgentPanel.d.ts +3 -1
  254. package/dist/client/AgentPanel.js +9 -2
  255. package/dist/client/AssistantChat.d.ts +8 -0
  256. package/dist/client/AssistantChat.js +23 -8
  257. package/dist/client/NewWorkspaceAppFlow.js +1 -0
  258. package/dist/client/agent-chat-adapter.js +123 -4
  259. package/dist/client/assistant-ui-recovery.d.ts +2 -1
  260. package/dist/client/assistant-ui-recovery.js +7 -3
  261. package/dist/client/onboarding/FirstRunOnboarding.js +11 -4
  262. package/dist/client/org/TeamPage.js +1 -1
  263. package/dist/client/require-session.js +1 -1
  264. package/dist/client/resources/McpConnectionSuggestion.d.ts +1 -0
  265. package/dist/client/resources/McpConnectionSuggestion.js +27 -10
  266. package/dist/client/resources/McpIntegrationDialog.js +77 -45
  267. package/dist/client/resources/mcp-integration-catalog.d.ts +13 -1
  268. package/dist/client/resources/mcp-integration-catalog.js +255 -2
  269. package/dist/client/resources/mcp-integration-logos.js +18 -2
  270. package/dist/client/settings/AccountSettingsCard.js +2 -1
  271. package/dist/collab/struct-routes.d.ts +1 -1
  272. package/dist/db/client.d.ts +9 -0
  273. package/dist/db/client.js +51 -16
  274. package/dist/db/create-get-db.js +2 -2
  275. package/dist/db/ddl-guard.d.ts +11 -10
  276. package/dist/db/ddl-guard.js +40 -12
  277. package/dist/deploy/build.d.ts +2 -0
  278. package/dist/deploy/build.js +97 -4
  279. package/dist/deploy/workspace-deploy.js +0 -2
  280. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  281. package/dist/guards/no-env-credentials.js +9 -0
  282. package/dist/ingestion/index.d.ts +1 -1
  283. package/dist/ingestion/pptx.d.ts +68 -0
  284. package/dist/ingestion/pptx.js +660 -213
  285. package/dist/integrations/plugin.js +9 -6
  286. package/dist/jobs/scheduler.js +79 -23
  287. package/dist/localization/default-messages.d.ts +54 -0
  288. package/dist/localization/default-messages.js +57 -2
  289. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  290. package/dist/mcp-client/oauth-routes.d.ts +2 -0
  291. package/dist/mcp-client/oauth-routes.js +73 -6
  292. package/dist/observability/routes.d.ts +5 -5
  293. package/dist/onboarding/app-profile.js +11 -0
  294. package/dist/progress/routes.d.ts +1 -1
  295. package/dist/resources/handlers.d.ts +1 -1
  296. package/dist/resources/store.js +15 -1
  297. package/dist/scripts/call-agent.js +34 -4
  298. package/dist/secrets/routes.d.ts +3 -3
  299. package/dist/server/agent-chat/action-filters-a2a.d.ts +1 -1
  300. package/dist/server/agent-chat/action-filters-a2a.js +36 -1
  301. package/dist/server/agent-chat-plugin.js +29 -8
  302. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  303. package/dist/server/auth.js +47 -11
  304. package/dist/server/better-auth-instance.js +5 -3
  305. package/dist/server/core-routes-plugin.d.ts +8 -1
  306. package/dist/server/core-routes-plugin.js +28 -3
  307. package/dist/server/credential-provider.d.ts +3 -3
  308. package/dist/server/credential-provider.js +90 -4
  309. package/dist/server/onboarding-html.d.ts +2 -0
  310. package/dist/server/onboarding-html.js +115 -29
  311. package/dist/server/realtime-token.d.ts +1 -1
  312. package/dist/server/self-dispatch.d.ts +5 -4
  313. package/dist/server/self-dispatch.js +25 -14
  314. package/dist/server/ssr-handler.d.ts +1 -1
  315. package/dist/server/ssr-handler.js +1 -1
  316. package/dist/server/transcribe-voice.d.ts +1 -1
  317. package/dist/shared/cache-control.d.ts +26 -2
  318. package/dist/shared/cache-control.js +43 -2
  319. package/dist/shared/password-policy.d.ts +3 -0
  320. package/dist/shared/password-policy.js +3 -0
  321. package/dist/sharing/actions/set-resource-visibility.js +16 -4
  322. package/dist/sharing/registry.d.ts +14 -0
  323. package/dist/styles/agent-native.css +6 -0
  324. package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
  325. package/dist/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  326. package/dist/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
  327. package/dist/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  328. package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +296 -0
  329. package/dist/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  330. package/dist/templates/default/.agents/skills/turn-into-skill/SKILL.md +112 -0
  331. package/dist/templates/default/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  332. package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +296 -0
  333. package/dist/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  334. package/dist/templates/headless/.agents/skills/turn-into-skill/SKILL.md +112 -0
  335. package/dist/templates/headless/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  336. package/dist/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +6 -0
  337. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +51 -0
  338. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +296 -0
  339. package/dist/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  340. package/dist/templates/workspace-core/.agents/skills/turn-into-skill/SKILL.md +112 -0
  341. package/dist/templates/workspace-core/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  342. package/dist/templates/workspace-root/AGENTS.md +7 -0
  343. package/dist/user-profile/actions/change-password.js +8 -3
  344. package/dist/user-profile/actions/set-password.js +5 -1
  345. package/dist/vite/action-types-plugin.js +59 -0
  346. package/docs/content/creating-templates.mdx +1 -1
  347. package/docs/content/getting-started-actions.mdx +38 -189
  348. package/docs/content/getting-started-database.mdx +80 -164
  349. package/docs/content/getting-started-pages.mdx +44 -155
  350. package/docs/content/getting-started.mdx +26 -106
  351. package/docs/content/skills-guide.mdx +13 -0
  352. package/package.json +6 -2
  353. package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
  354. package/src/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  355. package/src/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
  356. package/src/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  357. package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +296 -0
  358. package/src/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  359. package/src/templates/default/.agents/skills/turn-into-skill/SKILL.md +112 -0
  360. package/src/templates/default/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  361. package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +296 -0
  362. package/src/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  363. package/src/templates/headless/.agents/skills/turn-into-skill/SKILL.md +112 -0
  364. package/src/templates/headless/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  365. package/src/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +6 -0
  366. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +51 -0
  367. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +296 -0
  368. package/src/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  369. package/src/templates/workspace-core/.agents/skills/turn-into-skill/SKILL.md +112 -0
  370. package/src/templates/workspace-core/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  371. package/src/templates/workspace-root/AGENTS.md +7 -0
@@ -26,6 +26,11 @@ import { z } from "zod";
26
26
  import { normalizeSlidePadding } from "../app/lib/normalize-slide-padding.js";
27
27
  import { getDb, schema } from "../server/db/index.js";
28
28
  import { notifyClients } from "../server/handlers/decks.js";
29
+ import {
30
+ assertSourceSlidePreserved,
31
+ sourceImportForDeck,
32
+ type SourceImportMetadata,
33
+ } from "../server/lib/source-import.js";
29
34
  import { ASPECT_RATIO_VALUES } from "../shared/aspect-ratios.js";
30
35
 
31
36
  // ---------------------------------------------------------------------------
@@ -79,6 +84,13 @@ const PatchSlideOp = z.object({
79
84
  op: z.literal("patch-slide"),
80
85
  slideId: z.string(),
81
86
  fields: SlideFieldsSchema,
87
+ preserveSource: z
88
+ .boolean()
89
+ .optional()
90
+ .default(true)
91
+ .describe(
92
+ "Keep source-imported images and factual copy (default true). Set false only for an explicit rewrite.",
93
+ ),
82
94
  });
83
95
 
84
96
  /** Delete a single slide by ID */
@@ -141,6 +153,24 @@ export const OperationSchema = z.discriminatedUnion("op", [
141
153
 
142
154
  export type Operation = z.infer<typeof OperationSchema>;
143
155
 
156
+ export function assertSourceImportOperationsPreserved(
157
+ metadata: SourceImportMetadata | null,
158
+ operations: Operation[],
159
+ ): void {
160
+ if (!metadata) return;
161
+ const structuralOperation = operations.find(
162
+ (operation) =>
163
+ operation.op === "delete-slide" ||
164
+ operation.op === "reorder-slides" ||
165
+ operation.op === "add-slide",
166
+ );
167
+ if (!structuralOperation) return;
168
+
169
+ throw new Error(
170
+ `Cannot ${structuralOperation.op} on a source-imported deck while source preservation is enabled. Preserve the imported slide structure, or use an explicit source rewrite workflow.`,
171
+ );
172
+ }
173
+
144
174
  // The browser uses the full operation union above. Agents additionally use
145
175
  // this action for one bounded, deck-wide layout repair: one patch-slide per
146
176
  // slide in a single SQL transaction, followed by a fresh read for verification.
@@ -404,6 +434,27 @@ export default defineAction({
404
434
  );
405
435
  }
406
436
 
437
+ const sourceImport = sourceImportForDeck(deck.sourceImport);
438
+ assertSourceImportOperationsPreserved(sourceImport, operations);
439
+ for (const op of operations) {
440
+ if (
441
+ op.op !== "patch-slide" ||
442
+ (op.fields.content === undefined && op.fields.notes === undefined)
443
+ ) {
444
+ continue;
445
+ }
446
+ assertSourceSlidePreserved({
447
+ metadata: sourceImport,
448
+ slideId: op.slideId,
449
+ nextContent:
450
+ op.fields.content === undefined
451
+ ? undefined
452
+ : normalizeSlidePadding(op.fields.content),
453
+ nextNotes: op.fields.notes,
454
+ preserveSource: op.preserveSource,
455
+ });
456
+ }
457
+
407
458
  for (const op of operations) {
408
459
  applyOperation(deck, op);
409
460
  }
@@ -16,6 +16,10 @@ import { normalizeSlidePadding } from "../app/lib/normalize-slide-padding.js";
16
16
  import { getDb, schema } from "../server/db/index.js"; // ensure registerShareableResource runs
17
17
  import { notifyClients } from "../server/handlers/decks.js";
18
18
  import { createDeckVersionSnapshot } from "../server/lib/deck-versions.js";
19
+ import {
20
+ assertSourceSlidePreserved,
21
+ sourceImportForDeck,
22
+ } from "../server/lib/source-import.js";
19
23
  import { hashSlideContent } from "../shared/slide-fit.js";
20
24
  import { slideLabelFor, touchAgentSlidePresence } from "./_agent-presence.js";
21
25
  import {
@@ -89,7 +93,7 @@ function storedCreativeContext(value: unknown): {
89
93
  export default defineAction({
90
94
  description:
91
95
  "Surgically edit a slide's content using search-replace or full replacement. " +
92
- "Syncs live to open editors. Prefer this over full deck rewrites.",
96
+ "Syncs live to open editors. Prefer this over full deck rewrites. Source-imported slides preserve their original images and factual copy by default.",
93
97
  schema: z.object({
94
98
  deckId: z.string().describe("Deck ID"),
95
99
  slideId: z.string().describe("Slide ID"),
@@ -105,6 +109,13 @@ export default defineAction({
105
109
  .string()
106
110
  .optional()
107
111
  .describe("Full HTML to replace entire slide content"),
112
+ preserveSource: z
113
+ .boolean()
114
+ .optional()
115
+ .default(true)
116
+ .describe(
117
+ "Keep source-imported images and factual copy (default true). Set false only when the user explicitly asks to rewrite the source slide.",
118
+ ),
108
119
  contextPackId: z
109
120
  .string()
110
121
  .optional()
@@ -131,6 +142,7 @@ export default defineAction({
131
142
  find,
132
143
  replace,
133
144
  fullContent,
145
+ preserveSource,
134
146
  contextPackId,
135
147
  contextModeOverride,
136
148
  reuseLabels,
@@ -205,17 +217,31 @@ export default defineAction({
205
217
  let notFound = false;
206
218
 
207
219
  if (fullContent) {
208
- slide.content = normalizeSlidePadding(fullContent);
220
+ const nextContent = normalizeSlidePadding(fullContent);
221
+ assertSourceSlidePreserved({
222
+ metadata: sourceImportForDeck(deck.sourceImport),
223
+ slideId,
224
+ nextContent,
225
+ preserveSource,
226
+ });
227
+ slide.content = nextContent;
209
228
  applied = true;
210
229
  } else if (find) {
211
230
  const idx = (slide.content as string).indexOf(find);
212
231
  if (idx === -1) {
213
232
  notFound = true;
214
233
  } else {
215
- slide.content =
234
+ const nextContent =
216
235
  slide.content.slice(0, idx) +
217
236
  (replace ?? "") +
218
237
  slide.content.slice(idx + find.length);
238
+ assertSourceSlidePreserved({
239
+ metadata: sourceImportForDeck(deck.sourceImport),
240
+ slideId,
241
+ nextContent,
242
+ preserveSource,
243
+ });
244
+ slide.content = nextContent;
219
245
  applied = true;
220
246
  }
221
247
  }
@@ -23,7 +23,7 @@ import {
23
23
  DropdownMenuSeparator,
24
24
  } from "@/components/ui/dropdown-menu";
25
25
  import type { Deck } from "@/context/DeckContext";
26
- import { getAspectRatioDims } from "@/lib/aspect-ratios";
26
+ import { getDeckListingPreviewFrameStyle } from "@/lib/deck-preview-frame";
27
27
 
28
28
  import SlideRenderer from "./SlideRenderer";
29
29
 
@@ -52,7 +52,7 @@ export default function DeckCard({
52
52
  }: DeckCardProps) {
53
53
  const t = useT();
54
54
  const firstSlide = deck.slides?.[0];
55
- const previewDims = getAspectRatioDims(deck.aspectRatio);
55
+ const previewFrameStyle = getDeckListingPreviewFrameStyle(deck.aspectRatio);
56
56
  const [isRenaming, setIsRenaming] = useState(false);
57
57
  const [menuOpen, setMenuOpen] = useState(false);
58
58
  const [renameValue, setRenameValue] = useState(deck.title);
@@ -106,18 +106,15 @@ export default function DeckCard({
106
106
  }}
107
107
  >
108
108
  {/* Slide Preview */}
109
- <div
110
- className="relative overflow-hidden bg-muted/30"
111
- style={{
112
- aspectRatio: `${previewDims.width} / ${previewDims.height}`,
113
- }}
114
- >
109
+ <div className="relative flex aspect-video items-center justify-center overflow-hidden bg-muted/30">
115
110
  {firstSlide && (
116
- <SlideRenderer
117
- slide={firstSlide}
118
- className="rounded-none"
119
- aspectRatio={deck.aspectRatio}
120
- />
111
+ <div className="relative overflow-hidden" style={previewFrameStyle}>
112
+ <SlideRenderer
113
+ slide={firstSlide}
114
+ className="rounded-none"
115
+ aspectRatio={deck.aspectRatio}
116
+ />
117
+ </div>
121
118
  )}
122
119
  <div className="pointer-events-none absolute inset-0 bg-gradient-to-t from-[hsl(240,5%,8%)] via-transparent to-transparent opacity-60" />
123
120
  </div>
@@ -13,6 +13,8 @@ import {
13
13
  } from "@/components/editor/PromptDialog";
14
14
  import { addSlideAgentMessage } from "@/lib/agent-visible-message";
15
15
 
16
+ import { MAX_REFERENCE_FILE_BYTES } from "../../../shared/upload-types";
17
+
16
18
  const MAX_SOURCE_CONTEXT_CHARS = 60_000;
17
19
 
18
20
  function truncateSourceForContext(prompt: string): {
@@ -46,7 +48,7 @@ function describeUploadedFilesForAgent(
46
48
  "",
47
49
  "File handling rules:",
48
50
  `- PPTX files: call \`import-pptx --filePath "<path>" --deckId ${deckId}\` when the user wants the deck/slides imported, or to extract slide source from a presentation.`,
49
- `- PDF and DOCX files: call \`import-file --filePath "<path>" --format auto --deckId ${deckId}\` and use the returned extracted text as source material. The returned text is capped for reliability; re-run with maxChars only if more context is needed.`,
51
+ `- PDF and DOCX files: call \`import-file --filePath "<path>" --format auto --deckId ${deckId}\` and use the returned extracted text as source material. For a visual PDF whose original layout should be preserved, pass \`--importIntoDeck true\` instead of rebuilding the pages from extracted text.`,
50
52
  "- Text-like files: use the uploaded-text-file blocks already included in the prompt; do not call import-file for them.",
51
53
  '- Image files with an embeddable URL can be inserted directly into slide HTML as `<img src="...">` or used as visual references.',
52
54
  "- Image files without a URL are visual/reference assets only; do not claim to have processed a PPTX/PDF/DOCX unless the relevant import action succeeds.",
@@ -241,6 +243,8 @@ export function AddSlidePopover({
241
243
  )}
242
244
  <PromptComposer
243
245
  autoFocus
246
+ maxDocumentAttachmentBytes={MAX_REFERENCE_FILE_BYTES}
247
+ documentAttachmentLimitLabel="Slides reference files"
244
248
  placeholder={t("editorSidebar.promptPlaceholder")}
245
249
  draftScope={`slides:add-slide:${deckId}`}
246
250
  onSubmit={handleSubmit}
@@ -67,6 +67,7 @@ import {
67
67
  type AspectRatio,
68
68
  DEFAULT_ASPECT_RATIO,
69
69
  } from "@/lib/aspect-ratios";
70
+ import { getDeckShareLinkOrder } from "@/lib/deck-share-links";
70
71
  import type { GoogleSlidesExportResult } from "@/lib/export-google-slides-client";
71
72
  import { parseUploadResponse } from "@/lib/upload-response";
72
73
  import { shortcutLabel } from "@/lib/utils";
@@ -288,10 +289,9 @@ export default function EditorToolbar({
288
289
  canEdit = true,
289
290
  }: EditorToolbarProps) {
290
291
  const t = useT();
291
- // Mirror Google Slides: the share dialog exposes both the editor URL
292
- // (primary) and the presentation URL (secondary). Access is enforced on
293
- // the deck, not the URL shape — anyone with at least viewer access can
294
- // open either link.
292
+ // Public decks default to the read-only presentation URL so recipients do
293
+ // not get sent through the editor's auth gate. Restricted decks keep the
294
+ // editor URL primary, where auth resolves viewer access.
295
295
  const editorUrl =
296
296
  typeof window === "undefined"
297
297
  ? `/deck/${deckId}`
@@ -300,6 +300,21 @@ export default function EditorToolbar({
300
300
  typeof window === "undefined"
301
301
  ? `/p/${deckId}`
302
302
  : `${window.location.origin}${appPath(`/p/${deckId}`)}`;
303
+ const shareLinks = {
304
+ editor: {
305
+ url: editorUrl,
306
+ label: t("editorToolbar.editorLink"),
307
+ description: t("editorToolbar.editorLinkDescription"),
308
+ },
309
+ presentation: {
310
+ url: presentationUrl,
311
+ label: t("editorToolbar.presentationLink"),
312
+ description: t("editorToolbar.presentationLinkDescription"),
313
+ },
314
+ };
315
+ const shareLinkOrder = getDeckShareLinkOrder(deck.visibility);
316
+ const primaryShareLink = shareLinks[shareLinkOrder.primary];
317
+ const secondaryShareLink = shareLinks[shareLinkOrder.secondary];
303
318
 
304
319
  // Live save state for the toolbar indicator, so users always see whether
305
320
  // their work has committed (a lost-deck report motivated surfacing this).
@@ -940,14 +955,12 @@ graph TD
940
955
  resourceType="deck"
941
956
  resourceId={deckId}
942
957
  resourceTitle={deckTitle}
943
- shareUrl={editorUrl}
944
- shareUrlLabel={t("editorToolbar.editorLink")}
945
- shareUrlDescription={t("editorToolbar.editorLinkDescription")}
946
- secondaryShareUrl={presentationUrl}
947
- secondaryShareUrlLabel={t("editorToolbar.presentationLink")}
948
- secondaryShareUrlDescription={t(
949
- "editorToolbar.presentationLinkDescription",
950
- )}
958
+ shareUrl={primaryShareLink.url}
959
+ shareUrlLabel={primaryShareLink.label}
960
+ shareUrlDescription={primaryShareLink.description}
961
+ secondaryShareUrl={secondaryShareLink.url}
962
+ secondaryShareUrlLabel={secondaryShareLink.label}
963
+ secondaryShareUrlDescription={secondaryShareLink.description}
951
964
  shareTabs={{
952
965
  tabs: [
953
966
  {
@@ -13,8 +13,18 @@ import {
13
13
  IconBrandGoogle,
14
14
  IconPlugConnected,
15
15
  } from "@tabler/icons-react";
16
+ import { useRef, useState } from "react";
16
17
  import { toast } from "sonner";
17
18
 
19
+ import { Button } from "@/components/ui/button";
20
+ import {
21
+ Dialog,
22
+ DialogContent,
23
+ DialogDescription,
24
+ DialogFooter,
25
+ DialogHeader,
26
+ DialogTitle,
27
+ } from "@/components/ui/dialog";
18
28
  import {
19
29
  DropdownMenu,
20
30
  DropdownMenuContent,
@@ -51,6 +61,8 @@ export function ExportMenu({
51
61
  onShareTeam,
52
62
  }: ExportMenuProps) {
53
63
  const t = useT();
64
+ const [googleSlidesImportOpen, setGoogleSlidesImportOpen] = useState(false);
65
+ const googleSlidesImportTarget = useRef<Window | null>(null);
54
66
  const triggerBlobDownload = (blob: Blob, filename: string) => {
55
67
  const url = URL.createObjectURL(blob);
56
68
  const a = document.createElement("a");
@@ -100,9 +112,11 @@ export function ExportMenu({
100
112
  // Opened up-front: browsers only honour window.open() inside the click
101
113
  // gesture, and building the PPTX is async.
102
114
  const target = window.open("", "_blank");
115
+ googleSlidesImportTarget.current = target;
103
116
  try {
104
117
  const result = await onExportGoogleSlides();
105
118
  if (result.url !== null) {
119
+ googleSlidesImportTarget.current = null;
106
120
  if (target) target.location.href = result.url;
107
121
  toast.success(t("editorExport.googleSlidesCreated"), {
108
122
  description: t("editorExport.googleSlidesCreatedHint"),
@@ -111,10 +125,12 @@ export function ExportMenu({
111
125
  }
112
126
  console.warn("Google Slides upload unavailable:", result.reason);
113
127
  if (target) target.location.href = GOOGLE_SLIDES_IMPORT_URL;
128
+ setGoogleSlidesImportOpen(true);
114
129
  toast.success(t("editorExport.googleSlidesDownloaded"), {
115
130
  description: t("editorExport.googleSlidesImportHint"),
116
131
  });
117
132
  } catch (err) {
133
+ googleSlidesImportTarget.current = null;
118
134
  target?.close();
119
135
  console.error("Export failed:", err);
120
136
  toast.error(t("editorExport.exportFailed"), {
@@ -207,66 +223,105 @@ export function ExportMenu({
207
223
  };
208
224
 
209
225
  return (
210
- <DropdownMenu>
211
- <DropdownMenuTrigger asChild>
212
- <button className="flex items-center gap-1.5 px-2.5 py-1.5 rounded-md text-muted-foreground hover:text-foreground hover:bg-accent text-xs cursor-pointer whitespace-nowrap">
213
- <IconUpload className="w-3.5 h-3.5" />
214
- <span className="hidden md:inline">{t("editorExport.export")}</span>
215
- </button>
216
- </DropdownMenuTrigger>
217
- <DropdownMenuContent align="end" className="w-52">
218
- <DropdownMenuLabel className="text-[11px] text-muted-foreground">
219
- {t("editorExport.exportAndDuplicate")}
220
- </DropdownMenuLabel>
221
- {onShareTeam && (
222
- <DropdownMenuItem onClick={onShareTeam} className="cursor-pointer">
223
- <IconShare2 className="w-4 h-4 mr-2" />
224
- {t("editorExport.shareWithTeam")}
226
+ <>
227
+ <DropdownMenu>
228
+ <DropdownMenuTrigger asChild>
229
+ <button className="flex items-center gap-1.5 px-2.5 py-1.5 rounded-md text-muted-foreground hover:text-foreground hover:bg-accent text-xs cursor-pointer whitespace-nowrap">
230
+ <IconUpload className="w-3.5 h-3.5" />
231
+ <span className="hidden md:inline">{t("editorExport.export")}</span>
232
+ </button>
233
+ </DropdownMenuTrigger>
234
+ <DropdownMenuContent align="end" className="w-52">
235
+ <DropdownMenuLabel className="text-[11px] text-muted-foreground">
236
+ {t("editorExport.exportAndDuplicate")}
237
+ </DropdownMenuLabel>
238
+ {onShareTeam && (
239
+ <DropdownMenuItem onClick={onShareTeam} className="cursor-pointer">
240
+ <IconShare2 className="w-4 h-4 mr-2" />
241
+ {t("editorExport.shareWithTeam")}
242
+ </DropdownMenuItem>
243
+ )}
244
+ {onShareLink && (
245
+ <DropdownMenuItem onClick={onShareLink} className="cursor-pointer">
246
+ <IconShare2 className="w-4 h-4 mr-2" />
247
+ {t("editorExport.publicShareLink")}
248
+ </DropdownMenuItem>
249
+ )}
250
+ <DropdownMenuSeparator />
251
+ <DropdownMenuItem
252
+ onClick={handleExportHtml}
253
+ className="cursor-pointer"
254
+ >
255
+ <IconCode className="w-4 h-4 mr-2" />
256
+ {t("editorExport.downloadHtml")}
225
257
  </DropdownMenuItem>
226
- )}
227
- {onShareLink && (
228
- <DropdownMenuItem onClick={onShareLink} className="cursor-pointer">
229
- <IconShare2 className="w-4 h-4 mr-2" />
230
- {t("editorExport.publicShareLink")}
258
+ <DropdownMenuItem onClick={onExportPdf} className="cursor-pointer">
259
+ <IconFileTypePdf className="w-4 h-4 mr-2" />
260
+ {t("editorExport.exportPdf")}
231
261
  </DropdownMenuItem>
232
- )}
233
- <DropdownMenuSeparator />
234
- <DropdownMenuItem onClick={handleExportHtml} className="cursor-pointer">
235
- <IconCode className="w-4 h-4 mr-2" />
236
- {t("editorExport.downloadHtml")}
237
- </DropdownMenuItem>
238
- <DropdownMenuItem onClick={onExportPdf} className="cursor-pointer">
239
- <IconFileTypePdf className="w-4 h-4 mr-2" />
240
- {t("editorExport.exportPdf")}
241
- </DropdownMenuItem>
242
- <DropdownMenuItem onClick={handleExportPptx} className="cursor-pointer">
243
- <IconDownload className="w-4 h-4 mr-2" />
244
- {t("editorExport.exportPptx")}
245
- </DropdownMenuItem>
246
- {onExportGoogleSlides && (
247
- <>
248
- <DropdownMenuItem
249
- onClick={handleConnectGoogle}
250
- className="cursor-pointer"
251
- >
252
- <IconPlugConnected className="w-4 h-4 mr-2" />
253
- {t("editorExport.connectGoogle")}
254
- </DropdownMenuItem>
255
- <DropdownMenuItem
256
- onClick={handleExportGoogleSlides}
257
- className="cursor-pointer"
262
+ <DropdownMenuItem
263
+ onClick={handleExportPptx}
264
+ className="cursor-pointer"
265
+ >
266
+ <IconDownload className="w-4 h-4 mr-2" />
267
+ {t("editorExport.exportPptx")}
268
+ </DropdownMenuItem>
269
+ {onExportGoogleSlides && (
270
+ <>
271
+ <DropdownMenuItem
272
+ onClick={handleConnectGoogle}
273
+ className="cursor-pointer"
274
+ >
275
+ <IconPlugConnected className="w-4 h-4 mr-2" />
276
+ {t("editorExport.connectGoogle")}
277
+ </DropdownMenuItem>
278
+ <DropdownMenuItem
279
+ onClick={handleExportGoogleSlides}
280
+ className="cursor-pointer"
281
+ >
282
+ <IconBrandGoogle className="w-4 h-4 mr-2" />
283
+ {t("editorExport.openInGoogleSlides")}
284
+ </DropdownMenuItem>
285
+ </>
286
+ )}
287
+ <DropdownMenuSeparator />
288
+ <DropdownMenuItem onClick={onDuplicate} className="cursor-pointer">
289
+ <IconCopy className="w-4 h-4 mr-2" />
290
+ {t("editorExport.duplicateDeck")}
291
+ </DropdownMenuItem>
292
+ </DropdownMenuContent>
293
+ </DropdownMenu>
294
+ <Dialog
295
+ open={googleSlidesImportOpen}
296
+ onOpenChange={setGoogleSlidesImportOpen}
297
+ >
298
+ <DialogContent>
299
+ <DialogHeader>
300
+ <DialogTitle>
301
+ {t("editorExport.googleSlidesDownloaded")}
302
+ </DialogTitle>
303
+ <DialogDescription>
304
+ {t("editorExport.googleSlidesImportHint")}
305
+ </DialogDescription>
306
+ </DialogHeader>
307
+ <DialogFooter>
308
+ <Button
309
+ type="button"
310
+ onClick={() => {
311
+ const target = googleSlidesImportTarget.current;
312
+ if (target && !target.closed) {
313
+ target.focus?.();
314
+ } else {
315
+ window.open(GOOGLE_SLIDES_IMPORT_URL, "_blank");
316
+ }
317
+ setGoogleSlidesImportOpen(false);
318
+ }}
258
319
  >
259
- <IconBrandGoogle className="w-4 h-4 mr-2" />
260
320
  {t("editorExport.openInGoogleSlides")}
261
- </DropdownMenuItem>
262
- </>
263
- )}
264
- <DropdownMenuSeparator />
265
- <DropdownMenuItem onClick={onDuplicate} className="cursor-pointer">
266
- <IconCopy className="w-4 h-4 mr-2" />
267
- {t("editorExport.duplicateDeck")}
268
- </DropdownMenuItem>
269
- </DropdownMenuContent>
270
- </DropdownMenu>
321
+ </Button>
322
+ </DialogFooter>
323
+ </DialogContent>
324
+ </Dialog>
325
+ </>
271
326
  );
272
327
  }