@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
@@ -8,6 +8,7 @@ import { resolveAccess } from "@agent-native/core/sharing";
8
8
  import { z } from "zod";
9
9
 
10
10
  import "../server/db/index.js"; // ensure registerShareableResource runs
11
+ import { readLocalImportedAsset } from "../server/lib/import-asset-storage.js";
11
12
  import {
12
13
  safeGeneratedFilename,
13
14
  tenantExportDir,
@@ -98,6 +99,20 @@ interface TextElement {
98
99
  align?: "left" | "center" | "right";
99
100
  letterSpacing?: number;
100
101
  lineSpacing?: number;
102
+ runs?: TextRunElement[];
103
+ order?: number;
104
+ }
105
+
106
+ interface TextRunElement {
107
+ text: string;
108
+ options: {
109
+ fontSize?: number;
110
+ fontFace?: string;
111
+ color?: string;
112
+ bold?: boolean;
113
+ italic?: boolean;
114
+ underline?: { style: "sng" };
115
+ };
101
116
  }
102
117
 
103
118
  interface ImageElement {
@@ -106,6 +121,28 @@ interface ImageElement {
106
121
  y: number;
107
122
  w: number;
108
123
  h: number;
124
+ order?: number;
125
+ }
126
+
127
+ interface ShapeElement {
128
+ x: number;
129
+ y: number;
130
+ w: number;
131
+ h: number;
132
+ fill?: string;
133
+ lineColor?: string;
134
+ lineWidth?: number;
135
+ rounded?: boolean;
136
+ order?: number;
137
+ }
138
+
139
+ interface GridElement {
140
+ color: string;
141
+ stepX: number;
142
+ stepY: number;
143
+ offsetX: number;
144
+ offsetY: number;
145
+ lineWidth: number;
109
146
  }
110
147
 
111
148
  export function assertServerPptxExportable(
@@ -118,6 +155,7 @@ export function assertServerPptxExportable(
118
155
  const hasPersistedFreeformObject =
119
156
  /\bdata-slide-object-id\s*=/i.test(html) ||
120
157
  /\bclass\s*=\s*["'][^"']*\bfmd-freeform-object\b/i.test(html);
158
+ if (html.includes('data-imported-pptx="true"')) return;
121
159
  if (!hasPersistedFreeformObject) return;
122
160
 
123
161
  const error = new Error(
@@ -138,14 +176,24 @@ export function parseSlideHtml(
138
176
  ): {
139
177
  texts: TextElement[];
140
178
  images: ImageElement[];
179
+ shapes: ShapeElement[];
180
+ grid?: GridElement;
141
181
  bgColor: string;
142
182
  } {
143
183
  assertServerPptxExportable(html, slideNumber);
184
+ const dims = getAspectRatioDims(aspectRatio);
185
+ if (html.includes('data-imported-pdf="true"')) {
186
+ return parseImportedPdfSlideHtml(html, dims);
187
+ }
188
+ if (html.includes('data-imported-pptx="true"')) {
189
+ return parseImportedSlideHtml(html, dims);
190
+ }
191
+
144
192
  const texts: TextElement[] = [];
145
193
  const images: ImageElement[] = [];
194
+ const shapes: ShapeElement[] = [];
146
195
  let bgColor = "000000";
147
196
 
148
- const dims = getAspectRatioDims(aspectRatio);
149
197
  const slideW = dims.pptxInches.w;
150
198
  const slideH = dims.pptxInches.h;
151
199
 
@@ -321,7 +369,306 @@ export function parseSlideHtml(
321
369
  }
322
370
  }
323
371
 
324
- return { texts, images, bgColor };
372
+ return { texts, images, shapes, bgColor };
373
+ }
374
+
375
+ type SlideDims = ReturnType<typeof getAspectRatioDims>;
376
+
377
+ function parseImportedPdfSlideHtml(
378
+ html: string,
379
+ dims: SlideDims,
380
+ ): {
381
+ texts: TextElement[];
382
+ images: ImageElement[];
383
+ shapes: ShapeElement[];
384
+ grid?: GridElement;
385
+ bgColor: string;
386
+ } {
387
+ const outerStyle = html.match(
388
+ /class=["'][^"']*\bfmd-slide\b[^"']*["'][^>]*style=["']([^"']*)["']/i,
389
+ )?.[1];
390
+ const bgColor = colorToHex(
391
+ outerStyle
392
+ ? (getStyle(outerStyle, "background(?:-color)?") ?? "#000000") // guard:allow-raw-color - imported PDF fallback
393
+ : "#000000", // guard:allow-raw-color - imported PDF fallback
394
+ );
395
+ const src = html.match(/<img\b[^>]*\bsrc=["']([^"']+)["'][^>]*>/i)?.[1];
396
+ const outerAttrs = html.match(/<div\b([^>]*)>/i)?.[1] ?? "";
397
+ const sourceWidth = Number.parseFloat(
398
+ getAttribute(outerAttrs, "data-source-width") ?? "",
399
+ );
400
+ const sourceHeight = Number.parseFloat(
401
+ getAttribute(outerAttrs, "data-source-height") ?? "",
402
+ );
403
+ let x = 0;
404
+ let y = 0;
405
+ let w = dims.pptxInches.w;
406
+ let h = dims.pptxInches.h;
407
+ if (
408
+ Number.isFinite(sourceWidth) &&
409
+ Number.isFinite(sourceHeight) &&
410
+ sourceWidth > 0 &&
411
+ sourceHeight > 0
412
+ ) {
413
+ const sourceAspect = sourceWidth / sourceHeight;
414
+ const deckAspect = dims.pptxInches.w / dims.pptxInches.h;
415
+ if (sourceAspect > deckAspect) {
416
+ h = w / sourceAspect;
417
+ y = (dims.pptxInches.h - h) / 2;
418
+ } else {
419
+ w = h * sourceAspect;
420
+ x = (dims.pptxInches.w - w) / 2;
421
+ }
422
+ }
423
+ return {
424
+ texts: [],
425
+ images: src
426
+ ? [
427
+ {
428
+ src: decodeHtmlText(src),
429
+ x,
430
+ y,
431
+ w,
432
+ h,
433
+ order: 0,
434
+ },
435
+ ]
436
+ : [],
437
+ shapes: [],
438
+ bgColor,
439
+ };
440
+ }
441
+
442
+ function parseImportedSlideHtml(
443
+ html: string,
444
+ dims: SlideDims,
445
+ ): {
446
+ texts: TextElement[];
447
+ images: ImageElement[];
448
+ shapes: ShapeElement[];
449
+ grid?: GridElement;
450
+ bgColor: string;
451
+ } {
452
+ const texts: TextElement[] = [];
453
+ const images: ImageElement[] = [];
454
+ const shapes: ShapeElement[] = [];
455
+ const outerStyle = html.match(
456
+ /class=["'][^"']*\bfmd-slide\b[^"']*["'][^>]*style=["']([^"']*)["']/i,
457
+ )?.[1];
458
+ const bgColor = colorToHex(
459
+ outerStyle
460
+ ? (getStyle(outerStyle, "background(?:-color)?") ?? "#000000") // guard:allow-raw-color - PPTX background fallback
461
+ : "#000000", // guard:allow-raw-color - PPTX background fallback
462
+ );
463
+ const grid = outerStyle ? parseImportedGrid(outerStyle) : undefined;
464
+ const elementRegex =
465
+ /<div\b([^>]*\bdata-pptx-element-kind=["'](text|image|shape)["'][^>]*)>([\s\S]*?)<\/div>/gi;
466
+ let match: RegExpExecArray | null;
467
+ while ((match = elementRegex.exec(html)) !== null) {
468
+ const attrs = match[1];
469
+ const kind = match[2].toLowerCase();
470
+ const innerHtml = match[3];
471
+ const style = getAttribute(attrs, "style") ?? "";
472
+ const geometry = importedGeometry(style, dims);
473
+ if (!geometry) continue;
474
+
475
+ if (kind === "image") {
476
+ const imageAttrs = innerHtml.match(/<img\b([^>]*)>/i)?.[1] ?? "";
477
+ const src = getAttribute(imageAttrs, "src");
478
+ if (src) {
479
+ images.push({ src, ...geometry, order: match.index });
480
+ }
481
+ continue;
482
+ }
483
+
484
+ if (kind === "shape") {
485
+ const fill = getStyle(style, "background(?:-color)?");
486
+ const border = getStyle(style, "border");
487
+ const borderMatch = border?.match(/([\d.]+)px\s+solid\s+(.+)/i);
488
+ shapes.push({
489
+ ...geometry,
490
+ ...(fill && !fill.includes("gradient")
491
+ ? { fill: colorToHex(fill) }
492
+ : {}),
493
+ ...(borderMatch
494
+ ? {
495
+ lineColor: colorToHex(borderMatch[2]),
496
+ lineWidth: Number(borderMatch[1]),
497
+ }
498
+ : {}),
499
+ rounded: style.includes("border-radius"),
500
+ order: match.index,
501
+ });
502
+ continue;
503
+ }
504
+
505
+ const runs = importedTextRuns(innerHtml);
506
+ const firstRun = runs.find((run) => run.text.trim()) ?? runs[0];
507
+ const firstParagraph = innerHtml.match(
508
+ /<p\b[^>]*style=["']([^"']*)["']/i,
509
+ )?.[1];
510
+ const lineHeight = firstParagraph
511
+ ? getStyle(firstParagraph, "line-height")
512
+ : null;
513
+ const fontSize = firstRun?.options.fontSize ?? 18;
514
+ const alignValue = getStyle(style, "text-align");
515
+ texts.push({
516
+ text: runs.map((run) => run.text).join(""),
517
+ fontSize,
518
+ fontFace: firstRun?.options.fontFace ?? "Poppins",
519
+ color: firstRun?.options.color ?? "FFFFFF",
520
+ bold: firstRun?.options.bold ?? false,
521
+ align:
522
+ alignValue === "center" || alignValue === "right" ? alignValue : "left",
523
+ lineSpacing: lineHeight ? Number(lineHeight) * fontSize : undefined,
524
+ x: geometry.x,
525
+ y: geometry.y,
526
+ w: geometry.w,
527
+ h: geometry.h,
528
+ runs,
529
+ order: match.index,
530
+ });
531
+ }
532
+
533
+ return { texts, images, shapes, grid, bgColor };
534
+ }
535
+
536
+ function parseImportedGrid(style: string): GridElement | undefined {
537
+ const backgroundImage = getStyle(style, "background-image");
538
+ const size = getStyle(style, "background-size")
539
+ ?.split(/\s+/)
540
+ .map((value) => Number.parseFloat(value));
541
+ const position = getStyle(style, "background-position")
542
+ ?.split(/\s+/)
543
+ .map((value) => Number.parseFloat(value));
544
+ const color = backgroundImage?.match(/#[0-9a-f]{6}|rgb\([^)]*\)/i)?.[0];
545
+ const lineWidth = backgroundImage?.match(/\s0\s+([\d.]+)px/i)?.[1];
546
+ if (
547
+ !color ||
548
+ !size ||
549
+ size.length < 2 ||
550
+ !Number.isFinite(size[0]) ||
551
+ !Number.isFinite(size[1]) ||
552
+ size[0] <= 0 ||
553
+ size[1] <= 0 ||
554
+ !position ||
555
+ position.length < 2 ||
556
+ !Number.isFinite(position[0]) ||
557
+ !Number.isFinite(position[1]) ||
558
+ !lineWidth
559
+ ) {
560
+ return undefined;
561
+ }
562
+ return {
563
+ color: colorToHex(color),
564
+ stepX: size[0],
565
+ stepY: size[1],
566
+ offsetX: position[0],
567
+ offsetY: position[1],
568
+ lineWidth: Number.parseFloat(lineWidth),
569
+ };
570
+ }
571
+
572
+ function importedGeometry(
573
+ style: string,
574
+ dims: SlideDims,
575
+ ): { x: number; y: number; w: number; h: number } | null {
576
+ const left = cssPx(style, "left");
577
+ const top = cssPx(style, "top");
578
+ const width = cssPx(style, "width");
579
+ const height = cssPx(style, "height");
580
+ if (left == null || top == null || width == null || height == null)
581
+ return null;
582
+ return {
583
+ x: pxToIn(left, dims),
584
+ y: pxToInY(top, dims),
585
+ w: pxToIn(width, dims),
586
+ h: pxToInY(height, dims),
587
+ };
588
+ }
589
+
590
+ function pxToInY(px: number, dims: SlideDims): number {
591
+ return (px / dims.height) * dims.pptxInches.h;
592
+ }
593
+
594
+ function importedTextRuns(html: string): TextRunElement[] {
595
+ const paragraphs = [...html.matchAll(/<p\b[^>]*>([\s\S]*?)<\/p>/gi)].map(
596
+ (match) => match[1],
597
+ );
598
+ const blocks = paragraphs.length > 0 ? paragraphs : [html];
599
+ const runs: TextRunElement[] = [];
600
+ blocks.forEach((block, paragraphIndex) => {
601
+ if (paragraphIndex > 0) runs.push({ text: "\n", options: {} });
602
+ const spans = [...block.matchAll(/<span\b([^>]*)>([\s\S]*?)<\/span>/gi)];
603
+ if (spans.length === 0) {
604
+ const text = decodeHtmlText(stripTags(block));
605
+ if (text) runs.push({ text, options: {} });
606
+ return;
607
+ }
608
+ for (const span of spans) {
609
+ const attrs = span[1];
610
+ const style = getAttribute(attrs, "style") ?? "";
611
+ const text = decodeHtmlText(stripTags(span[2]));
612
+ if (!text) continue;
613
+ runs.push({ text, options: importedRunOptions(style) });
614
+ }
615
+ });
616
+ return runs;
617
+ }
618
+
619
+ function importedRunOptions(style: string): TextRunElement["options"] {
620
+ const fontSizePx = cssPx(style, "font-size");
621
+ const fontFamily = getStyle(style, "font-family")
622
+ ?.replace(/["']/g, "")
623
+ .split(",")[0]
624
+ ?.trim();
625
+ const fontWeight = getStyle(style, "font-weight");
626
+ return {
627
+ ...(fontSizePx != null ? { fontSize: pxToPt(fontSizePx) } : {}),
628
+ ...(fontFamily ? { fontFace: fontFamily } : {}),
629
+ ...(getStyle(style, "color")
630
+ ? { color: colorToHex(getStyle(style, "color") ?? "#FFFFFF") } // guard:allow-raw-color - PPTX text fallback
631
+ : {}),
632
+ ...(fontWeight
633
+ ? {
634
+ bold: Number.parseInt(fontWeight, 10) >= 700 || fontWeight === "bold",
635
+ }
636
+ : {}),
637
+ ...(getStyle(style, "font-style") === "italic" ? { italic: true } : {}),
638
+ ...(getStyle(style, "text-decoration")?.includes("underline")
639
+ ? { underline: { style: "sng" as const } }
640
+ : {}),
641
+ };
642
+ }
643
+
644
+ function cssPx(style: string, property: string): number | null {
645
+ const value = getStyle(style, property);
646
+ if (!value) return null;
647
+ const parsed = Number.parseFloat(value);
648
+ return Number.isFinite(parsed) ? parsed : null;
649
+ }
650
+
651
+ function getAttribute(attrs: string, name: string): string | null {
652
+ const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
653
+ const match = attrs.match(
654
+ new RegExp(`\\b${escapedName}\\s*=\\s*(["'])(.*?)\\1`, "i"),
655
+ );
656
+ return match?.[2] ?? null;
657
+ }
658
+
659
+ function stripTags(value: string): string {
660
+ return value.replace(/<br\s*\/?\s*>/gi, "\n").replace(/<[^>]+>/g, "");
661
+ }
662
+
663
+ function decodeHtmlText(value: string): string {
664
+ return value
665
+ .replace(/&nbsp;/gi, " ")
666
+ .replace(/&amp;/gi, "&")
667
+ .replace(/&lt;/gi, "<")
668
+ .replace(/&gt;/gi, ">")
669
+ .replace(/&quot;/gi, '"')
670
+ .replace(/&#x27;|&#39;/gi, "'")
671
+ .replace(/&#x25cf;/gi, "●");
325
672
  }
326
673
 
327
674
  /**
@@ -334,8 +681,23 @@ export function parseSlideHtml(
334
681
  * image so a 200 OK from an internal HTML / JSON endpoint can't smuggle bytes
335
682
  * into the .pptx.
336
683
  */
337
- export async function fetchImageAsBase64(url: string): Promise<string | null> {
684
+ export async function fetchImageAsBase64(
685
+ url: string,
686
+ ownerEmail?: string,
687
+ ): Promise<string | null> {
338
688
  try {
689
+ const parsedUrl = new URL(url, "http://slides.local");
690
+ if (parsedUrl.pathname.startsWith("/api/import-assets/") && ownerEmail) {
691
+ const token = parsedUrl.pathname.slice("/api/import-assets/".length);
692
+ const localAsset = await readLocalImportedAsset({
693
+ token,
694
+ email: ownerEmail,
695
+ });
696
+ if (localAsset) {
697
+ return `data:${localAsset.mimeType};base64,${Buffer.from(localAsset.data).toString("base64")}`;
698
+ }
699
+ return null;
700
+ }
339
701
  const response = await ssrfSafeFetch(
340
702
  url,
341
703
  { signal: AbortSignal.timeout(10_000) },
@@ -356,7 +718,7 @@ export async function fetchImageAsBase64(url: string): Promise<string | null> {
356
718
 
357
719
  export default defineAction({
358
720
  description:
359
- "Export a normal-flow deck as a PowerPoint (.pptx) file. Decks with freeform positioned objects must use the Slides editor's Export > PowerPoint flow so browser-rendered geometry is preserved. Returns a download URL for the generated file.",
721
+ "Export a deck as a PowerPoint (.pptx) file, preserving imported PPTX geometry, text styles, shapes, and images. Freeform editor objects must use the Slides editor's Export > PowerPoint flow so browser-rendered geometry is preserved. Returns a download URL for the generated file.",
360
722
  schema: z.object({
361
723
  deckId: z.string().describe("Deck ID to export"),
362
724
  includeNotes: z
@@ -409,7 +771,7 @@ export default defineAction({
409
771
  slide && typeof slide === "object" && typeof slide.content === "string"
410
772
  ? slide.content
411
773
  : "";
412
- const { texts, images, bgColor } = parseSlideHtml(
774
+ const { texts, images, shapes, grid, bgColor } = parseSlideHtml(
413
775
  slideContent,
414
776
  aspectRatio,
415
777
  slideIndex + 1,
@@ -417,39 +779,111 @@ export default defineAction({
417
779
 
418
780
  pptxSlide.background = { color: bgColor };
419
781
 
420
- // Add text elements
421
- for (const t of texts) {
422
- pptxSlide.addText(t.text, {
423
- x: t.x,
424
- y: t.y,
425
- w: t.w,
426
- h: t.h,
427
- fontSize: t.fontSize,
428
- fontFace: t.fontFace,
429
- color: t.color,
430
- bold: t.bold,
431
- align: t.align || "left",
432
- valign: "top",
433
- wrap: true,
434
- ...(t.letterSpacing != null ? { charSpacing: t.letterSpacing } : {}),
435
- ...(t.lineSpacing != null
436
- ? { lineSpacingMultiple: t.lineSpacing / t.fontSize }
437
- : {}),
438
- });
782
+ if (grid) {
783
+ const gridWidth = pxToIn(grid.stepX, dims);
784
+ const gridHeight = pxToInY(grid.stepY, dims);
785
+ const gridX = pxToIn(grid.offsetX, dims);
786
+ const gridY = pxToInY(grid.offsetY, dims);
787
+ const lineWidth = Math.max(0.5, grid.lineWidth * 0.75);
788
+
789
+ for (let x = gridX; x < dims.pptxInches.w; x += gridWidth) {
790
+ pptxSlide.addShape(pptx.ShapeType.line, {
791
+ x,
792
+ y: 0,
793
+ w: 0,
794
+ h: dims.pptxInches.h,
795
+ line: { color: grid.color, width: lineWidth },
796
+ });
797
+ }
798
+ for (let y = gridY; y < dims.pptxInches.h; y += gridHeight) {
799
+ pptxSlide.addShape(pptx.ShapeType.line, {
800
+ x: 0,
801
+ y,
802
+ w: dims.pptxInches.w,
803
+ h: 0,
804
+ line: { color: grid.color, width: lineWidth },
805
+ });
806
+ }
439
807
  }
440
808
 
441
- // Add images
442
- for (const img of images) {
443
- // Try to fetch and embed as base64
444
- const dataUri = await fetchImageAsBase64(img.src);
445
- if (dataUri) {
446
- pptxSlide.addImage({
447
- data: dataUri,
448
- x: img.x,
449
- y: img.y,
450
- w: img.w,
451
- h: img.h,
452
- });
809
+ const orderedTexts = [...texts].sort(
810
+ (a, b) => (a.order ?? 0) - (b.order ?? 0),
811
+ );
812
+ const orderedImages = [...images].sort(
813
+ (a, b) => (a.order ?? 0) - (b.order ?? 0),
814
+ );
815
+ const orderedShapes = [...shapes].sort(
816
+ (a, b) => (a.order ?? 0) - (b.order ?? 0),
817
+ );
818
+
819
+ // Imported elements are parsed separately because PptxGenJS needs real
820
+ // slide objects. Keep their source order so overlapping objects retain
821
+ // the same paint order as the editor preview.
822
+ const orderedObjects = [
823
+ ...orderedTexts.map((value) => ({ kind: "text" as const, value })),
824
+ ...orderedImages.map((value) => ({ kind: "image" as const, value })),
825
+ ...orderedShapes.map((value) => ({ kind: "shape" as const, value })),
826
+ ].sort((a, b) => (a.value.order ?? 0) - (b.value.order ?? 0));
827
+
828
+ for (const object of orderedObjects) {
829
+ if (object.kind === "text") {
830
+ const t = object.value;
831
+ const options = {
832
+ x: t.x,
833
+ y: t.y,
834
+ w: t.w,
835
+ h: t.h,
836
+ fontSize: t.fontSize,
837
+ fontFace: t.fontFace,
838
+ color: t.color,
839
+ bold: t.bold,
840
+ align: t.align || "left",
841
+ valign: "top" as const,
842
+ wrap: true,
843
+ ...(t.letterSpacing != null
844
+ ? { charSpacing: t.letterSpacing }
845
+ : {}),
846
+ ...(t.lineSpacing != null
847
+ ? { lineSpacingMultiple: t.lineSpacing / t.fontSize }
848
+ : {}),
849
+ };
850
+ if (t.runs?.length) {
851
+ pptxSlide.addText(t.runs, options);
852
+ } else {
853
+ pptxSlide.addText(t.text, options);
854
+ }
855
+ } else if (object.kind === "image") {
856
+ const img = object.value;
857
+ const dataUri = await fetchImageAsBase64(img.src, userEmail);
858
+ if (dataUri) {
859
+ pptxSlide.addImage({
860
+ data: dataUri,
861
+ x: img.x,
862
+ y: img.y,
863
+ w: img.w,
864
+ h: img.h,
865
+ });
866
+ }
867
+ } else {
868
+ const shape = object.value;
869
+ pptxSlide.addShape(
870
+ shape.rounded ? pptx.ShapeType.roundRect : pptx.ShapeType.rect,
871
+ {
872
+ x: shape.x,
873
+ y: shape.y,
874
+ w: shape.w,
875
+ h: shape.h,
876
+ ...(shape.fill ? { fill: { color: shape.fill } } : {}),
877
+ ...(shape.lineColor
878
+ ? {
879
+ line: {
880
+ color: shape.lineColor,
881
+ width: shape.lineWidth ?? 1,
882
+ },
883
+ }
884
+ : {}),
885
+ },
886
+ );
453
887
  }
454
888
  }
455
889
 
@@ -68,6 +68,18 @@ export default defineAction({
68
68
  title: row.title || data?.title,
69
69
  visibility: row.visibility,
70
70
  designSystemId: row.designSystemId ?? null,
71
+ sourceImport: data?.sourceImport
72
+ ? {
73
+ mode: data.sourceImport.mode,
74
+ format: data.sourceImport.format,
75
+ fidelity: data.sourceImport.fidelity,
76
+ slideCount: data.sourceImport.slideCount,
77
+ slideIds: data.sourceImport.slideIds,
78
+ ...(typeof data.sourceImport.imagesSkipped === "number"
79
+ ? { imagesSkipped: data.sourceImport.imagesSkipped }
80
+ : {}),
81
+ }
82
+ : null,
71
83
  slideCount: slides.length,
72
84
  slideNumbering:
73
85
  'User-visible slide numbers are 1-based and match the UI. "Slide 1" means slideNumber 1 / zeroBasedIndex 0. Use slideId for edits.',