@agent-native/core 0.141.6 → 0.144.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 (501) hide show
  1. package/agent-native.eject.json +9 -0
  2. package/corpus/README.md +1 -1
  3. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +3 -14
  4. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +11 -6
  5. package/corpus/templates/analytics/.agents/skills/prometheus/SKILL.md +5 -5
  6. package/corpus/templates/analytics/.agents/skills/provider-api/SKILL.md +19 -0
  7. package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +296 -0
  8. package/corpus/templates/analytics/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  9. package/corpus/templates/analytics/.agents/skills/turn-into-skill/SKILL.md +112 -0
  10. package/corpus/templates/analytics/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  11. package/corpus/templates/analytics/AGENTS.md +37 -40
  12. package/corpus/templates/analytics/actions/compose-dashboard.ts +1 -1
  13. package/corpus/templates/analytics/actions/ensure-native-v2-dashboards.ts +1 -1
  14. package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +17 -22
  15. package/corpus/templates/analytics/actions/migrate-first-party-analytics-to-bigquery.ts +135 -0
  16. package/corpus/templates/analytics/actions/navigate.ts +5 -6
  17. package/corpus/templates/analytics/actions/provider-api-register.ts +50 -0
  18. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +46 -13
  19. package/corpus/templates/analytics/actions/test-custom-api-connection.ts +106 -0
  20. package/corpus/templates/analytics/actions/update-dashboard.ts +0 -1
  21. package/corpus/templates/analytics/actions/view-screen.ts +0 -20
  22. package/corpus/templates/analytics/app/components/CustomApiCard.tsx +430 -0
  23. package/corpus/templates/analytics/app/components/layout/Header.tsx +0 -1
  24. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +5 -5
  25. package/corpus/templates/analytics/app/i18n-data.ts +682 -90
  26. package/corpus/templates/analytics/app/lib/native-mcp-exclusions.ts +6 -0
  27. package/corpus/templates/analytics/app/lib/sql-query.ts +33 -6
  28. package/corpus/templates/analytics/app/pages/Agents.tsx +0 -3
  29. package/corpus/templates/analytics/app/pages/DataSources.tsx +4 -0
  30. package/corpus/templates/analytics/app/pages/Settings.tsx +22 -43
  31. package/corpus/templates/analytics/app/pages/settings/settings-search.ts +23 -20
  32. package/corpus/templates/analytics/app/routes/extensions._index.tsx +1 -1
  33. package/corpus/templates/analytics/app/routes/settings.$.tsx +1 -0
  34. package/corpus/templates/analytics/app/routes/team.tsx +1 -1
  35. package/corpus/templates/analytics/changelog/2026-08-05-settings-no-longer-includes-an-unnecessary-about-section.md +6 -0
  36. package/corpus/templates/analytics/changelog/2026-08-06-analytics-dashboards-load-reliably-during-background-data-sw.md +6 -0
  37. package/corpus/templates/analytics/changelog/2026-08-06-analytics-dashboards-remain-responsive-while-historical-data.md +6 -0
  38. package/corpus/templates/analytics/changelog/2026-08-06-analytics-query-results-now-render-as-a-table-with-csv-downl.md +6 -0
  39. package/corpus/templates/analytics/changelog/2026-08-06-connect-public-https-custom-apis-and-hand-tested-endpoints-t.md +6 -0
  40. package/corpus/templates/analytics/changelog/2026-08-06-durable-agent-worker-memory.md +6 -0
  41. package/corpus/templates/analytics/changelog/2026-08-06-live-dashboard-panels-use-the-shared-query-timeout.md +6 -0
  42. package/corpus/templates/analytics/changelog/2026-08-06-on-demand-billing-is-available-as-a-native-dashboard-with-ta.md +6 -0
  43. package/corpus/templates/analytics/changelog/2026-08-06-visible-dashboard-names-are-unique.md +6 -0
  44. package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +1 -1
  45. package/corpus/templates/analytics/netlify.toml +7 -0
  46. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +4 -0
  47. package/corpus/templates/analytics/scripts/first-party-analytics-bigquery.sql +104 -0
  48. package/corpus/templates/analytics/server/db/index.ts +27 -0
  49. package/corpus/templates/analytics/server/db/schema.ts +10 -0
  50. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +0 -2
  51. package/corpus/templates/analytics/server/lib/dashboards-store.ts +227 -60
  52. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +1147 -0
  53. package/corpus/templates/analytics/server/lib/first-party-analytics-health.ts +34 -15
  54. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +57 -4
  55. package/corpus/templates/analytics/server/lib/native-v2-dashboards.ts +227 -1
  56. package/corpus/templates/analytics/server/lib/real-data-actions.ts +1 -3
  57. package/corpus/templates/analytics/server/plugins/agent-chat.ts +7 -4
  58. package/corpus/templates/analytics/server/plugins/analytics-rollup-backfill-jobs.ts +1 -0
  59. package/corpus/templates/analytics/server/plugins/db.ts +52 -18
  60. package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +36 -8
  61. package/corpus/templates/assets/.agents/skills/image-generation/SKILL.md +16 -1
  62. package/corpus/templates/assets/.agents/skills/library-management/SKILL.md +16 -1
  63. package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +296 -0
  64. package/corpus/templates/assets/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  65. package/corpus/templates/assets/.agents/skills/turn-into-skill/SKILL.md +112 -0
  66. package/corpus/templates/assets/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  67. package/corpus/templates/assets/AGENTS.md +1 -0
  68. package/corpus/templates/assets/actions/_helpers.ts +12 -0
  69. package/corpus/templates/assets/actions/generate-image.ts +9 -3
  70. package/corpus/templates/assets/actions/import-style-from-url.ts +115 -0
  71. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +3 -1
  72. package/corpus/templates/assets/app/routes/extensions._index.tsx +1 -1
  73. package/corpus/templates/assets/app/routes/settings.$.tsx +1 -0
  74. package/corpus/templates/assets/app/routes/settings.tsx +5 -0
  75. package/corpus/templates/assets/app/routes/team.tsx +1 -1
  76. package/corpus/templates/assets/changelog/2026-08-05-brand-kits-can-import-a-website-s-hydrated-visual-language-a.md +6 -0
  77. package/corpus/templates/assets/changelog/2026-08-05-generated-images-now-hand-off-embeddable-previews-to-other-w.md +6 -0
  78. package/corpus/templates/assets/server/lib/generation.ts +58 -0
  79. package/corpus/templates/assets/shared/api.ts +12 -0
  80. package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +296 -0
  81. package/corpus/templates/brain/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  82. package/corpus/templates/brain/.agents/skills/turn-into-skill/SKILL.md +112 -0
  83. package/corpus/templates/brain/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  84. package/corpus/templates/brain/actions/list-connection-providers.ts +24 -3
  85. package/corpus/templates/brain/app/lib/dispatch-links.ts +44 -0
  86. package/corpus/templates/brain/app/routes/extensions._index.tsx +1 -1
  87. package/corpus/templates/brain/app/routes/sources.tsx +15 -7
  88. package/corpus/templates/brain/app/routes/team.tsx +1 -1
  89. package/corpus/templates/brain/app/routes.ts +1 -1
  90. package/corpus/templates/brain/changelog/2026-08-06-brain-provider-setup-links-open-dispatch-correctly-in-standa.md +6 -0
  91. package/corpus/templates/brain/server/plugins/agent-chat.ts +1 -0
  92. package/corpus/templates/calendar/.agents/skills/event-management/SKILL.md +26 -0
  93. package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +296 -0
  94. package/corpus/templates/calendar/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  95. package/corpus/templates/calendar/.agents/skills/turn-into-skill/SKILL.md +112 -0
  96. package/corpus/templates/calendar/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  97. package/corpus/templates/calendar/AGENTS.md +11 -32
  98. package/corpus/templates/calendar/actions/update-event.ts +107 -1
  99. package/corpus/templates/calendar/app/components/calendar/EventCalendarSelect.tsx +83 -0
  100. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +57 -0
  101. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +59 -73
  102. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +3 -1
  103. package/corpus/templates/calendar/app/hooks/use-events.ts +4 -1
  104. package/corpus/templates/calendar/app/i18n-data.ts +20 -0
  105. package/corpus/templates/calendar/app/routes/_app.extensions._index.tsx +1 -1
  106. package/corpus/templates/calendar/app/routes/_app.settings.$.tsx +1 -0
  107. package/corpus/templates/calendar/app/routes/_app.team.tsx +1 -1
  108. package/corpus/templates/calendar/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
  109. package/corpus/templates/calendar/changelog/2026-08-06-existing-events-can-move-between-connected-google-account-ca.md +6 -0
  110. package/corpus/templates/calendar/server/lib/google-calendar.ts +101 -0
  111. package/corpus/templates/calendar/server/plugins/agent-chat.ts +7 -1
  112. package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
  113. package/corpus/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  114. package/corpus/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
  115. package/corpus/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  116. package/corpus/templates/chat/app/components/layout/Layout.tsx +1 -1
  117. package/corpus/templates/chat/app/hooks/use-navigation-state.ts +1 -1
  118. package/corpus/templates/chat/app/root.tsx +1 -1
  119. package/corpus/templates/chat/app/routes/agent.tsx +7 -7
  120. package/corpus/templates/chat/app/routes/extensions._index.tsx +1 -1
  121. package/corpus/templates/chat/app/routes/settings.$.tsx +1 -0
  122. package/corpus/templates/chat/app/routes/team.tsx +1 -1
  123. package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +296 -0
  124. package/corpus/templates/clips/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  125. package/corpus/templates/clips/.agents/skills/turn-into-skill/SKILL.md +112 -0
  126. package/corpus/templates/clips/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  127. package/corpus/templates/clips/app/components/editor/editor-layout.tsx +9 -24
  128. package/corpus/templates/clips/app/components/editor/timeline-geometry.ts +15 -0
  129. package/corpus/templates/clips/app/components/editor/waveform.tsx +4 -17
  130. package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -1
  131. package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +14 -3
  132. package/corpus/templates/clips/app/components/player/transcript-panel.tsx +1 -1
  133. package/corpus/templates/clips/app/components/recorder/storage-setup-card.tsx +1 -1
  134. package/corpus/templates/clips/app/routes/_app.extensions._index.tsx +1 -1
  135. package/corpus/templates/clips/app/routes/_app.settings.$.tsx +1 -0
  136. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +28 -38
  137. package/corpus/templates/clips/app/routes/share.$shareId.tsx +21 -27
  138. package/corpus/templates/clips/changelog/2026-08-06-clips-recovers-from-stalled-recording-setup-without-requirin.md +6 -0
  139. package/corpus/templates/clips/changelog/2026-08-06-clips-starts-faster-after-a-deploy-or-idle-period-startup-no.md +6 -0
  140. package/corpus/templates/clips/changelog/2026-08-06-deleting-a-recording-returns-cleanly-to-the-library-and-fit-.md +6 -0
  141. package/corpus/templates/clips/changelog/2026-08-06-hide-clip-insights-from-viewers-without-analytics-access.md +6 -0
  142. package/corpus/templates/clips/desktop/src/app.tsx +48 -20
  143. package/corpus/templates/clips/desktop/src/lib/recorder.ts +275 -74
  144. package/corpus/templates/clips/desktop/src/lib/recording-start-guard.ts +84 -0
  145. package/corpus/templates/clips/desktop/src/overlays/toolbar.tsx +14 -4
  146. package/corpus/templates/clips/server/plugins/db.ts +214 -26
  147. package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +296 -0
  148. package/corpus/templates/content/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  149. package/corpus/templates/content/.agents/skills/turn-into-skill/SKILL.md +112 -0
  150. package/corpus/templates/content/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  151. package/corpus/templates/content/app/routes/_app.extensions._index.tsx +1 -1
  152. package/corpus/templates/content/app/routes/_app.settings.$.tsx +1 -0
  153. package/corpus/templates/content/app/routes/_app.team.tsx +1 -1
  154. package/corpus/templates/content/e2e/global-setup.ts +1 -1
  155. package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +296 -0
  156. package/corpus/templates/crm/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  157. package/corpus/templates/crm/.agents/skills/turn-into-skill/SKILL.md +112 -0
  158. package/corpus/templates/crm/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  159. package/corpus/templates/crm/changelog/2026-08-06-crm-starts-faster-after-a-deploy-or-idle-period-one-time-dat.md +6 -0
  160. package/corpus/templates/crm/server/plugins/db.ts +11 -8
  161. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +36 -1
  162. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +6 -1
  163. package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +296 -0
  164. package/corpus/templates/design/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  165. package/corpus/templates/design/.agents/skills/turn-into-skill/SKILL.md +112 -0
  166. package/corpus/templates/design/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  167. package/corpus/templates/design/actions/analyze-brand-assets.ts +7 -7
  168. package/corpus/templates/design/actions/import-from-url.ts +6 -5
  169. package/corpus/templates/design/app/components/design/LayersPanel.tsx +27 -18
  170. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +2 -2
  171. package/corpus/templates/design/app/pages/Index.tsx +6 -2
  172. package/corpus/templates/design/app/routes/extensions._index.tsx +1 -1
  173. package/corpus/templates/design/app/routes/settings.$.tsx +1 -0
  174. package/corpus/templates/design/app/routes/team.tsx +1 -1
  175. package/corpus/templates/design/changelog/2026-08-05-deleting-a-design-from-the-home-page-no-longer-leaves-the-ap.md +6 -0
  176. package/corpus/templates/design/changelog/2026-08-05-renaming-a-layer-now-focuses-its-name-field-automatically.md +6 -0
  177. package/corpus/templates/design/changelog/2026-08-05-website-url-imports-now-capture-hydrated-browser-computed-de.md +6 -0
  178. package/corpus/templates/design/e2e/global-setup.ts +1 -1
  179. package/corpus/templates/design/server/plugins/agent-chat.ts +2 -0
  180. package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +296 -0
  181. package/corpus/templates/dispatch/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  182. package/corpus/templates/dispatch/.agents/skills/turn-into-skill/SKILL.md +112 -0
  183. package/corpus/templates/dispatch/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  184. package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +1 -1
  185. package/corpus/templates/dispatch/app/routes/settings.$.tsx +1 -0
  186. package/corpus/templates/dispatch/app/routes/team.tsx +1 -1
  187. package/corpus/templates/dispatch/changelog/2026-08-06-ready-workspace-apps-stay-one-click-away-in-a-compact-dispat.md +6 -0
  188. package/corpus/templates/dispatch/changelog/2026-08-06-shared-vault-values-and-management-are-now-restricted-to-wor.md +6 -0
  189. package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +296 -0
  190. package/corpus/templates/factory/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  191. package/corpus/templates/factory/.agents/skills/turn-into-skill/SKILL.md +112 -0
  192. package/corpus/templates/factory/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  193. package/corpus/templates/factory/app/hooks/use-navigation-state.ts +1 -1
  194. package/corpus/templates/factory/app/routes/extensions._index.tsx +1 -1
  195. package/corpus/templates/factory/app/routes/settings.$.tsx +1 -0
  196. package/corpus/templates/factory/app/routes/team.tsx +1 -1
  197. package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +296 -0
  198. package/corpus/templates/forms/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  199. package/corpus/templates/forms/.agents/skills/turn-into-skill/SKILL.md +112 -0
  200. package/corpus/templates/forms/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  201. package/corpus/templates/forms/app/routes/_app.extensions._index.tsx +1 -1
  202. package/corpus/templates/forms/app/routes/_app.settings.$.tsx +1 -0
  203. package/corpus/templates/forms/app/routes/_app.team.tsx +1 -1
  204. package/corpus/templates/forms/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
  205. package/corpus/templates/forms/server/plugins/agent-chat.ts +4 -0
  206. package/corpus/templates/forms/shared/navigation.ts +1 -1
  207. package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +296 -0
  208. package/corpus/templates/macros/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  209. package/corpus/templates/macros/.agents/skills/turn-into-skill/SKILL.md +112 -0
  210. package/corpus/templates/macros/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  211. package/corpus/templates/macros/app/routes/extensions._index.tsx +1 -1
  212. package/corpus/templates/macros/app/routes/settings.$.tsx +1 -0
  213. package/corpus/templates/macros/app/routes/team.tsx +1 -1
  214. package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +296 -0
  215. package/corpus/templates/mail/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  216. package/corpus/templates/mail/.agents/skills/turn-into-skill/SKILL.md +112 -0
  217. package/corpus/templates/mail/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  218. package/corpus/templates/mail/app/routes/extensions._index.tsx +1 -1
  219. package/corpus/templates/mail/app/routes/settings.$.tsx +1 -0
  220. package/corpus/templates/mail/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
  221. package/corpus/templates/mail/server/plugins/agent-chat.ts +6 -0
  222. package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +296 -0
  223. package/corpus/templates/plan/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  224. package/corpus/templates/plan/.agents/skills/turn-into-skill/SKILL.md +112 -0
  225. package/corpus/templates/plan/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  226. package/corpus/templates/plan/app/hooks/use-navigation-state.ts +1 -1
  227. package/corpus/templates/plan/app/routes/extensions._index.tsx +1 -1
  228. package/corpus/templates/plan/app/routes/settings.$.tsx +1 -0
  229. package/corpus/templates/plan/app/routes/team.tsx +1 -1
  230. package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +48 -5
  231. package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +40 -2
  232. package/corpus/templates/slides/.agents/skills/image-generation-via-a2a/SKILL.md +6 -0
  233. package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +15 -2
  234. package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +29 -24
  235. package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +296 -0
  236. package/corpus/templates/slides/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  237. package/corpus/templates/slides/.agents/skills/turn-into-skill/SKILL.md +112 -0
  238. package/corpus/templates/slides/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  239. package/corpus/templates/slides/AGENTS.md +7 -9
  240. package/corpus/templates/slides/_gitignore +1 -0
  241. package/corpus/templates/slides/actions/analyze-brand-assets.ts +7 -7
  242. package/corpus/templates/slides/actions/export-pptx.ts +402 -36
  243. package/corpus/templates/slides/actions/import-file.ts +46 -85
  244. package/corpus/templates/slides/actions/import-from-url.ts +6 -6
  245. package/corpus/templates/slides/actions/import-google-slides-reference.ts +271 -12
  246. package/corpus/templates/slides/actions/import-pptx.ts +85 -60
  247. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +10 -13
  248. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +1 -1
  249. package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +5 -1
  250. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +25 -12
  251. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +112 -57
  252. package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +202 -0
  253. package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +26 -14
  254. package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +176 -0
  255. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +182 -141
  256. package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +1 -0
  257. package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +18 -0
  258. package/corpus/templates/slides/app/components/editor/slide-text-targets.ts +85 -0
  259. package/corpus/templates/slides/app/components/layout/Layout.tsx +3 -0
  260. package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +13 -3
  261. package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +27 -1
  262. package/corpus/templates/slides/app/context/DeckContext.tsx +71 -20
  263. package/corpus/templates/slides/app/global.css +6 -0
  264. package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
  265. package/corpus/templates/slides/app/lib/create-deck-generation.ts +10 -6
  266. package/corpus/templates/slides/app/lib/deck-preview-frame.ts +15 -0
  267. package/corpus/templates/slides/app/lib/deck-share-links.ts +9 -0
  268. package/corpus/templates/slides/app/lib/export-pptx-client.ts +89 -0
  269. package/corpus/templates/slides/app/lib/slide-animation-elements.ts +3 -0
  270. package/corpus/templates/slides/app/pages/DeckEditor.tsx +17 -0
  271. package/corpus/templates/slides/app/pages/Index.tsx +107 -6
  272. package/corpus/templates/slides/app/routes/extensions._index.tsx +1 -1
  273. package/corpus/templates/slides/app/routes/settings.$.tsx +1 -0
  274. package/corpus/templates/slides/app/routes/team.tsx +1 -1
  275. package/corpus/templates/slides/changelog/2026-08-05-failed-deck-creation-and-reference-uploads-now-recover-clean.md +6 -0
  276. package/corpus/templates/slides/changelog/2026-08-05-slides-recover-completed-generation-results-after-a-sync-hic.md +6 -0
  277. package/corpus/templates/slides/changelog/2026-08-05-website-url-imports-now-capture-hydrated-browser-computed-st.md +6 -0
  278. package/corpus/templates/slides/changelog/2026-08-06-clicking-the-gray-canvas-around-a-slide-clears-its-selection.md +6 -0
  279. package/corpus/templates/slides/changelog/2026-08-06-deck-thumbnails-keep-a-consistent-listing-frame-across-aspec.md +6 -0
  280. package/corpus/templates/slides/changelog/2026-08-06-deep-linked-decks-open-directly-instead-of-being-interrupted.md +6 -0
  281. package/corpus/templates/slides/changelog/2026-08-06-google-slides-exports-now-show-clear-import-steps-when-direc.md +6 -0
  282. package/corpus/templates/slides/changelog/2026-08-06-import-pdf-google-slides-and-powerpoint-decks-directly-from-.md +6 -0
  283. package/corpus/templates/slides/changelog/2026-08-06-imported-powerpoint-exports-keep-text-and-images-editable-an.md +6 -0
  284. package/corpus/templates/slides/changelog/2026-08-06-presentation-prompts-continue-adding-rendered-slides-until-t.md +6 -0
  285. package/corpus/templates/slides/changelog/2026-08-06-public-decks-now-share-read-only-presentation-links-by-defau.md +6 -0
  286. package/corpus/templates/slides/changelog/2026-08-06-slides-offers-a-direct-connect-google-button-when-a-drive-co.md +6 -0
  287. package/corpus/templates/slides/changelog/2026-08-06-slides-preserve-uploaded-pdf-layouts-accept-larger-reference.md +6 -0
  288. package/corpus/templates/slides/changelog/2026-08-06-styled-words-stay-part-of-their-text-box-instead-of-becoming.md +6 -0
  289. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +7 -20
  290. package/corpus/templates/slides/server/handlers/import/html-converter.ts +236 -13
  291. package/corpus/templates/slides/server/handlers/import/pptx-assets.ts +67 -0
  292. package/corpus/templates/slides/server/handlers/import/pptx-parser.ts +2 -0
  293. package/corpus/templates/slides/server/handlers/uploads.ts +7 -3
  294. package/corpus/templates/slides/server/lib/chat-attachments.ts +6 -3
  295. package/corpus/templates/slides/server/lib/emails.ts +7 -2
  296. package/corpus/templates/slides/server/lib/google-docs-error.ts +50 -0
  297. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +1 -0
  298. package/corpus/templates/slides/server/lib/import-asset-storage.ts +127 -0
  299. package/corpus/templates/slides/server/plugins/agent-chat.ts +4 -3
  300. package/corpus/templates/slides/server/routes/api/import-assets/[token].get.ts +70 -0
  301. package/corpus/templates/slides/shared/upload-types.ts +3 -0
  302. package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +296 -0
  303. package/corpus/templates/tasks/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  304. package/corpus/templates/tasks/.agents/skills/turn-into-skill/SKILL.md +112 -0
  305. package/corpus/templates/tasks/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  306. package/corpus/templates/tasks/app/components/layout/Header.tsx +3 -1
  307. package/corpus/templates/tasks/app/routes/extensions._index.tsx +1 -1
  308. package/corpus/templates/tasks/app/routes/settings.$.tsx +1 -0
  309. package/dist/agent/engine/ai-sdk-engine.js +49 -3
  310. package/dist/agent/production-agent.d.ts +18 -0
  311. package/dist/agent/production-agent.js +80 -1
  312. package/dist/agent/types.d.ts +7 -0
  313. package/dist/cli/agent-plugin.d.ts +112 -0
  314. package/dist/cli/agent-plugin.js +1081 -0
  315. package/dist/cli/app-skill.js +39 -1
  316. package/dist/cli/code-agent-executor.d.ts +3 -0
  317. package/dist/cli/code-agent-executor.js +51 -13
  318. package/dist/cli/index.js +13 -0
  319. package/dist/cli/templates-meta.js +1 -1
  320. package/dist/client/AgentPanel.d.ts +3 -1
  321. package/dist/client/AgentPanel.js +9 -2
  322. package/dist/client/AssistantChat.d.ts +8 -0
  323. package/dist/client/AssistantChat.js +23 -8
  324. package/dist/client/NewWorkspaceAppFlow.js +1 -0
  325. package/dist/client/agent-chat-adapter.d.ts +1 -1
  326. package/dist/client/agent-chat-adapter.js +153 -7
  327. package/dist/client/agent-page/AgentWorkspaceContent.d.ts +1 -1
  328. package/dist/client/agent-page/AgentWorkspaceContent.js +13 -13
  329. package/dist/client/assistant-ui-recovery.d.ts +2 -1
  330. package/dist/client/assistant-ui-recovery.js +7 -3
  331. package/dist/client/chat/run-recovery.js +5 -1
  332. package/dist/client/embed-auth.js +6 -2
  333. package/dist/client/error-format.js +12 -0
  334. package/dist/client/integrations/IntegrationsPanel.js +40 -6
  335. package/dist/client/onboarding/FirstRunOnboarding.js +11 -4
  336. package/dist/client/org/OrgSwitcher.js +2 -2
  337. package/dist/client/org/TeamPage.js +92 -72
  338. package/dist/client/require-session.d.ts +1 -1
  339. package/dist/client/require-session.js +4 -4
  340. package/dist/client/resources/McpConnectionSuggestion.d.ts +1 -0
  341. package/dist/client/resources/McpConnectionSuggestion.js +27 -10
  342. package/dist/client/resources/McpIntegrationDialog.js +77 -45
  343. package/dist/client/resources/mcp-integration-catalog.d.ts +13 -1
  344. package/dist/client/resources/mcp-integration-catalog.js +255 -2
  345. package/dist/client/resources/mcp-integration-logos.js +18 -2
  346. package/dist/client/resources/use-mcp-servers.d.ts +5 -0
  347. package/dist/client/resources/use-mcp-servers.js +36 -0
  348. package/dist/client/settings/AccountSettingsCard.js +42 -36
  349. package/dist/client/settings/AutomationsSection.js +1 -1
  350. package/dist/client/settings/DemoModeSection.d.ts +3 -1
  351. package/dist/client/settings/DemoModeSection.js +4 -1
  352. package/dist/client/settings/ExtensionsSettingsContent.js +1 -1
  353. package/dist/client/settings/SchedulingTimezoneField.d.ts +3 -1
  354. package/dist/client/settings/SchedulingTimezoneField.js +9 -5
  355. package/dist/client/settings/SettingsPanel.d.ts +4 -1
  356. package/dist/client/settings/SettingsPanel.js +21 -21
  357. package/dist/client/settings/SettingsTabsPage.d.ts +2 -2
  358. package/dist/client/settings/SettingsTabsPage.js +98 -45
  359. package/dist/client/settings/VoiceTranscriptionSection.js +6 -1
  360. package/dist/client/settings/useSettingsPanelController.js +47 -8
  361. package/dist/collab/routes.d.ts +1 -1
  362. package/dist/db/client.d.ts +9 -0
  363. package/dist/db/client.js +51 -16
  364. package/dist/db/create-get-db.js +2 -2
  365. package/dist/db/ddl-guard.d.ts +11 -10
  366. package/dist/db/ddl-guard.js +40 -12
  367. package/dist/deploy/build.d.ts +2 -0
  368. package/dist/deploy/build.js +97 -4
  369. package/dist/deploy/workspace-deploy.js +0 -2
  370. package/dist/guards/no-env-credentials.js +9 -0
  371. package/dist/ingestion/index.d.ts +1 -1
  372. package/dist/ingestion/pptx.d.ts +68 -0
  373. package/dist/ingestion/pptx.js +660 -213
  374. package/dist/ingestion/website.d.ts +30 -0
  375. package/dist/integrations/plugin.js +9 -6
  376. package/dist/localization/default-messages.d.ts +59 -0
  377. package/dist/localization/default-messages.js +62 -2
  378. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  379. package/dist/mcp-client/oauth-routes.d.ts +2 -0
  380. package/dist/mcp-client/oauth-routes.js +74 -7
  381. package/dist/mcp-client/routes.d.ts +1 -0
  382. package/dist/mcp-client/routes.js +49 -0
  383. package/dist/navigation/index.js +16 -5
  384. package/dist/notifications/routes.d.ts +1 -1
  385. package/dist/observability/routes.d.ts +3 -3
  386. package/dist/onboarding/app-profile.js +11 -0
  387. package/dist/progress/routes.d.ts +1 -1
  388. package/dist/provider-api/actions/custom-provider-registration.d.ts +13 -13
  389. package/dist/provider-api/actions/provider-api.d.ts +11 -11
  390. package/dist/resources/store.js +15 -1
  391. package/dist/scripts/call-agent.js +45 -4
  392. package/dist/secrets/routes.d.ts +6 -6
  393. package/dist/server/agent-chat/action-filters-a2a.d.ts +1 -1
  394. package/dist/server/agent-chat/action-filters-a2a.js +36 -1
  395. package/dist/server/agent-chat-plugin.js +29 -8
  396. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  397. package/dist/server/auth.js +55 -17
  398. package/dist/server/better-auth-instance.js +5 -3
  399. package/dist/server/core-routes-plugin.d.ts +8 -1
  400. package/dist/server/core-routes-plugin.js +28 -3
  401. package/dist/server/credential-provider.d.ts +3 -3
  402. package/dist/server/credential-provider.js +90 -4
  403. package/dist/server/identity-sso.js +2 -1
  404. package/dist/server/onboarding-html.d.ts +2 -0
  405. package/dist/server/onboarding-html.js +171 -62
  406. package/dist/server/realtime-token.d.ts +1 -1
  407. package/dist/server/self-dispatch.d.ts +5 -4
  408. package/dist/server/self-dispatch.js +25 -14
  409. package/dist/server/ssr-handler.d.ts +1 -1
  410. package/dist/server/ssr-handler.js +1 -1
  411. package/dist/server/workspace-provider-oauth.js +1 -1
  412. package/dist/setup-connections/onboarding.js +1 -1
  413. package/dist/shared/cache-control.d.ts +26 -2
  414. package/dist/shared/cache-control.js +43 -2
  415. package/dist/shared/index.d.ts +1 -1
  416. package/dist/shared/index.js +1 -1
  417. package/dist/shared/password-policy.d.ts +3 -0
  418. package/dist/shared/password-policy.js +3 -0
  419. package/dist/shared/sign-in-journey.d.ts +5 -2
  420. package/dist/shared/sign-in-journey.js +10 -4
  421. package/dist/sharing/actions/set-resource-visibility.js +16 -4
  422. package/dist/sharing/registry.d.ts +14 -0
  423. package/dist/styles/agent-native.css +6 -0
  424. package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
  425. package/dist/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  426. package/dist/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
  427. package/dist/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  428. package/dist/templates/chat/app/components/layout/Layout.tsx +1 -1
  429. package/dist/templates/chat/app/hooks/use-navigation-state.ts +1 -1
  430. package/dist/templates/chat/app/root.tsx +1 -1
  431. package/dist/templates/chat/app/routes/agent.tsx +7 -7
  432. package/dist/templates/chat/app/routes/extensions._index.tsx +1 -1
  433. package/dist/templates/chat/app/routes/settings.$.tsx +1 -0
  434. package/dist/templates/chat/app/routes/team.tsx +1 -1
  435. package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +296 -0
  436. package/dist/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  437. package/dist/templates/default/.agents/skills/turn-into-skill/SKILL.md +112 -0
  438. package/dist/templates/default/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  439. package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +296 -0
  440. package/dist/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  441. package/dist/templates/headless/.agents/skills/turn-into-skill/SKILL.md +112 -0
  442. package/dist/templates/headless/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  443. package/dist/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +6 -0
  444. package/dist/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +37 -6
  445. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +4 -2
  446. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +51 -0
  447. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +296 -0
  448. package/dist/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  449. package/dist/templates/workspace-core/.agents/skills/turn-into-skill/SKILL.md +112 -0
  450. package/dist/templates/workspace-core/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  451. package/dist/templates/workspace-root/AGENTS.md +7 -0
  452. package/dist/user-profile/actions/change-password.js +8 -3
  453. package/dist/user-profile/actions/set-password.js +5 -1
  454. package/dist/vite/action-types-plugin.js +59 -0
  455. package/docs/content/authentication.mdx +4 -5
  456. package/docs/content/skills-guide.mdx +13 -0
  457. package/docs/content/template-analytics-developers.mdx +1 -1
  458. package/docs/content/template-calendar-developers.mdx +1 -1
  459. package/docs/content/template-chat-developers.mdx +2 -2
  460. package/docs/content/template-content-developers.mdx +1 -1
  461. package/docs/content/template-mail-developers.mdx +1 -1
  462. package/docs/content/template-plan-developers.mdx +1 -1
  463. package/docs/content/toolkit-command-navigation.mdx +6 -6
  464. package/docs/content/toolkit-org-team.mdx +1 -1
  465. package/docs/content/toolkit-settings.mdx +8 -8
  466. package/docs/content/toolkit-setup-connections.mdx +1 -1
  467. package/package.json +6 -2
  468. package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
  469. package/src/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  470. package/src/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
  471. package/src/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  472. package/src/templates/chat/app/components/layout/Layout.tsx +1 -1
  473. package/src/templates/chat/app/hooks/use-navigation-state.ts +1 -1
  474. package/src/templates/chat/app/root.tsx +1 -1
  475. package/src/templates/chat/app/routes/agent.tsx +7 -7
  476. package/src/templates/chat/app/routes/extensions._index.tsx +1 -1
  477. package/src/templates/chat/app/routes/settings.$.tsx +1 -0
  478. package/src/templates/chat/app/routes/team.tsx +1 -1
  479. package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +296 -0
  480. package/src/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  481. package/src/templates/default/.agents/skills/turn-into-skill/SKILL.md +112 -0
  482. package/src/templates/default/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  483. package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +296 -0
  484. package/src/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  485. package/src/templates/headless/.agents/skills/turn-into-skill/SKILL.md +112 -0
  486. package/src/templates/headless/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  487. package/src/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +6 -0
  488. package/src/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +37 -6
  489. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +4 -2
  490. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +51 -0
  491. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +296 -0
  492. package/src/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  493. package/src/templates/workspace-core/.agents/skills/turn-into-skill/SKILL.md +112 -0
  494. package/src/templates/workspace-core/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  495. package/src/templates/workspace-root/AGENTS.md +7 -0
  496. package/corpus/templates/analytics/.agents/skills/dashboard-management/references/template-catalog-and-demo.md +0 -62
  497. package/corpus/templates/analytics/actions/install-dashboard-template.ts +0 -369
  498. package/corpus/templates/analytics/actions/list-dashboard-templates.ts +0 -47
  499. package/corpus/templates/analytics/actions/list-native-v2-dashboard-templates.ts +0 -34
  500. package/corpus/templates/analytics/app/routes/catalog.tsx +0 -240
  501. package/src/templates/default/actions/navigate.spec.ts +0 -53
@@ -1,6 +1,5 @@
1
1
  import { defineAction } from "@agent-native/core";
2
2
  import { writeAppState } from "@agent-native/core/application-state";
3
- import { uploadFile } from "@agent-native/core/file-upload";
4
3
  import {
5
4
  getRequestUserEmail,
6
5
  getRequestOrgId,
@@ -13,51 +12,70 @@ import { z } from "zod";
13
12
  import { getDb, schema } from "../server/db/index.js";
14
13
  import { notifyClients } from "../server/handlers/decks.js";
15
14
  import { convertToSlideHtml } from "../server/handlers/import/html-converter.js";
15
+ import { uploadPptxSlideImages } from "../server/handlers/import/pptx-assets.js";
16
16
  import {
17
17
  parsePptx,
18
- type ParsedSlide,
18
+ type ParsedElement,
19
+ type ParsedImage,
20
+ type ParsedPresentation,
19
21
  } from "../server/handlers/import/pptx-parser.js";
20
22
  import { getDeckUrl } from "./_app-url.js";
21
23
  import { readUserUploadedFile } from "./_uploaded-files.js";
22
24
 
23
- // EMF/WMF (Windows metafiles) and TIFF are valid PPTX embed formats but
24
- // browsers can't render them in an <img> tag — uploading and linking one
25
- // would just produce a broken image icon.
26
- const BROWSER_RENDERABLE_IMAGE_MIME_TYPES = new Set([
27
- "image/png",
28
- "image/jpeg",
29
- "image/gif",
30
- "image/webp",
31
- "image/svg+xml",
32
- "image/bmp",
33
- ]);
34
-
35
- async function uploadFirstSlideImage(
36
- slide: ParsedSlide,
37
- slideIndex: number,
38
- ownerEmail: string,
39
- ): Promise<string | undefined> {
40
- const image = slide.images[0];
41
- if (!image || !BROWSER_RENDERABLE_IMAGE_MIME_TYPES.has(image.mimeType)) {
42
- return undefined;
43
- }
44
- const filename =
45
- "pptx-import-" + Date.now() + "-s" + slideIndex + "-" + image.name;
46
- try {
47
- const result = await uploadFile({
48
- data: Buffer.from(image.data),
49
- filename,
50
- mimeType: image.mimeType,
51
- ownerEmail,
52
- recordAsset: false,
53
- });
54
- return result?.url;
55
- } catch {
56
- // A single slide's upload failing (network/API/rate-limit) shouldn't
57
- // abort the whole deck import — that slide's text still imports fine,
58
- // it just falls back to a placeholder like an unsupported format would.
59
- return undefined;
25
+ export interface ImportedImageFallback {
26
+ slideIndex: number;
27
+ x: number;
28
+ y: number;
29
+ width: number;
30
+ height: number;
31
+ data: Uint8Array;
32
+ mimeType: string;
33
+ name: string;
34
+ crop?: ParsedImage["crop"];
35
+ }
36
+
37
+ /** Add source-native image objects that a Google Slides PPTX export omitted. */
38
+ export function applyImageFallbacks(
39
+ presentation: Awaited<ReturnType<typeof parsePptx>>,
40
+ fallbacks: ImportedImageFallback[] = [],
41
+ ): number {
42
+ let added = 0;
43
+ for (const [fallbackIndex, fallback] of fallbacks.entries()) {
44
+ const slide = presentation.slides[fallback.slideIndex];
45
+ if (!slide || fallback.width <= 0 || fallback.height <= 0) continue;
46
+
47
+ const duplicate = slide.elements.some(
48
+ (element) =>
49
+ element.kind === "image" &&
50
+ Math.abs(element.x - fallback.x) < 1000 &&
51
+ Math.abs(element.y - fallback.y) < 1000 &&
52
+ Math.abs(element.width - fallback.width) < 1000 &&
53
+ Math.abs(element.height - fallback.height) < 1000,
54
+ );
55
+ if (duplicate) continue;
56
+
57
+ const image: ParsedImage = {
58
+ data: fallback.data,
59
+ mimeType: fallback.mimeType,
60
+ name: fallback.name,
61
+ aspectRatio: fallback.width / fallback.height,
62
+ ...(fallback.crop ? { crop: fallback.crop } : {}),
63
+ };
64
+ const element: ParsedElement = {
65
+ id: `image-fallback-${fallback.slideIndex}-${fallbackIndex}`,
66
+ name: fallback.name,
67
+ kind: "image",
68
+ x: fallback.x,
69
+ y: fallback.y,
70
+ width: fallback.width,
71
+ height: fallback.height,
72
+ image,
73
+ };
74
+ slide.images.push(image);
75
+ slide.elements.push(element);
76
+ added++;
60
77
  }
78
+ return added;
61
79
  }
62
80
 
63
81
  export async function importPptxBufferToDeck(args: {
@@ -65,6 +83,8 @@ export async function importPptxBufferToDeck(args: {
65
83
  title?: string;
66
84
  deckId?: string;
67
85
  source?: string;
86
+ imageFallbacks?: ImportedImageFallback[];
87
+ parsedPresentation?: ParsedPresentation;
68
88
  }): Promise<{
69
89
  id: string;
70
90
  title: string;
@@ -74,8 +94,16 @@ export async function importPptxBufferToDeck(args: {
74
94
  url: string;
75
95
  imagesSkipped?: number;
76
96
  }> {
77
- const { fileBuffer, title, deckId, source = "import-pptx" } = args;
78
- const presentation = await parsePptx(fileBuffer);
97
+ const {
98
+ fileBuffer,
99
+ title,
100
+ deckId,
101
+ source = "import-pptx",
102
+ imageFallbacks,
103
+ parsedPresentation,
104
+ } = args;
105
+ const presentation = parsedPresentation ?? (await parsePptx(fileBuffer));
106
+ applyImageFallbacks(presentation, imageFallbacks);
79
107
  const deckTitle = title || presentation.title || "Imported Presentation";
80
108
  const ownerEmail = getRequestUserEmail();
81
109
  if (!ownerEmail) throw new Error("no authenticated user");
@@ -88,38 +116,35 @@ export async function importPptxBufferToDeck(args: {
88
116
  await assertAccess("deck", deckId, "editor");
89
117
  }
90
118
 
91
- // Convert each parsed slide to our HTML format, uploading the first
92
- // embedded image (if any) so it renders as a real image instead of a
93
- // text placeholder. Concurrency is capped so a large deck doesn't fire
94
- // one outbound upload per slide at once. An image can end up unused
95
- // (unsupported format, or upload storage not configured) without
96
- // failing the whole import — the slide's text still imports fine — but
97
- // that shouldn't be a silent, invisible degradation, so it's counted
98
- // and returned to the caller.
119
+ // Convert each parsed slide to its positioned scene graph, uploading every
120
+ // browser-renderable image so the imported deck keeps the source layering
121
+ // and media instead of collapsing to a one-image approximation.
99
122
  const uploadLimit = pLimit(4);
100
123
  const results = await Promise.all(
101
124
  presentation.slides.map((parsedSlide, i) =>
102
125
  uploadLimit(async () => {
103
- const imageUrl = await uploadFirstSlideImage(
104
- parsedSlide,
105
- i,
126
+ const uploadedImages = await uploadPptxSlideImages({
127
+ slide: parsedSlide,
128
+ slideIndex: i,
106
129
  ownerEmail,
130
+ });
131
+ const html = convertToSlideHtml(
132
+ parsedSlide,
133
+ uploadedImages.urls,
134
+ themeFont,
107
135
  );
108
- const html = convertToSlideHtml(parsedSlide, imageUrl, themeFont);
109
136
  return {
110
137
  slide: {
111
138
  id: `slide-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
112
139
  content: html,
113
140
  layout: parsedSlide.layoutHint ?? "content",
114
141
  notes: parsedSlide.notes,
142
+ ...(parsedSlide.transition
143
+ ? { transition: parsedSlide.transition }
144
+ : {}),
145
+ ...(parsedSlide.splitByParagraph ? { splitByParagraph: true } : {}),
115
146
  },
116
- // Only the first image on a slide is ever uploaded, so every
117
- // other image on that slide is unconditionally dropped too —
118
- // not just the first one when it's unsupported.
119
- imageSkippedCount: Math.max(
120
- 0,
121
- parsedSlide.images.length - (imageUrl ? 1 : 0),
122
- ),
147
+ imageSkippedCount: uploadedImages.imageSkippedCount,
123
148
  };
124
149
  }),
125
150
  ),
@@ -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>
@@ -479,7 +479,7 @@ export function DesignSystemSetup({
479
479
 
480
480
  if (websiteUrls.length > 0) {
481
481
  parts.push(
482
- `\n## Website URLs\nAnalyze these websites for design tokens. Call \`import-from-url\` for each:\n${websiteUrls.map((u) => `- ${u}`).join("\n")}`,
482
+ `\n## Website URLs\nAnalyze these websites for design tokens. Call \`import-from-url\` for each:\n${websiteUrls.map((u) => `- ${u}`).join("\n")}\n\nThe shared action uses the layered real-browser renderer so hydrated React, CSS-in-JS, Tailwind, SPA content, loaded fonts, computed colors, component styles, CSS variables, and desktop/mobile screenshot evidence are captured consistently. It falls back explicitly to SSRF-safe static extraction only when a browser is unavailable. Use its design.md-style result as the source of truth for the deck style.`,
483
483
  );
484
484
  }
485
485
 
@@ -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
  }