@agent-native/core 0.148.1 → 0.149.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 (165) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/changelog/2026-08-10-wide-tables-in-analytics-chat-now-scroll-horizontally-within.md +6 -0
  3. package/corpus/templates/calendar/app/components/calendar/DayView.tsx +13 -53
  4. package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +11 -70
  5. package/corpus/templates/calendar/app/lib/event-layout.ts +122 -0
  6. package/corpus/templates/calendar/app/routes/_app.availability.tsx +1 -1
  7. package/corpus/templates/calendar/changelog/2026-08-10-opening-availability-settings-from-the-agent-lands-on-the-av.md +6 -0
  8. package/corpus/templates/calendar/vitest.config.ts +6 -1
  9. package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +3 -1
  10. package/corpus/templates/clips/app/components/player/video-player.tsx +44 -4
  11. package/corpus/templates/clips/changelog/2026-08-10-fixed-transcription-failures-for-recordings-without-captured.md +6 -0
  12. package/corpus/templates/clips/changelog/2026-08-10-mobile-clips-can-now-enter-fullscreen-on-iphone-safari.md +6 -0
  13. package/corpus/templates/content/actions/_property-utils.ts +11 -1
  14. package/corpus/templates/content/actions/view-screen.ts +62 -12
  15. package/corpus/templates/content/server/plugins/agent-chat.ts +2 -0
  16. package/corpus/templates/design/.agents/skills/design-templates/SKILL.md +22 -0
  17. package/corpus/templates/design/AGENTS.md +3 -0
  18. package/corpus/templates/design/actions/create-design-from-template.ts +19 -0
  19. package/corpus/templates/design/actions/get-design-snapshot.ts +18 -0
  20. package/corpus/templates/design/actions/get-design-template.ts +178 -0
  21. package/corpus/templates/design/actions/list-designs.ts +3 -1
  22. package/corpus/templates/design/actions/view-screen.ts +31 -0
  23. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +225 -214
  24. package/corpus/templates/design/app/components/design/multi-screen/types.ts +3 -0
  25. package/corpus/templates/design/app/i18n-data.ts +78 -0
  26. package/corpus/templates/design/app/lib/design-authors.ts +64 -0
  27. package/corpus/templates/design/app/pages/Index.tsx +114 -4
  28. package/corpus/templates/design/app/pages/design-editor/generation-prompt-directives.ts +1 -0
  29. package/corpus/templates/design/changelog/2026-08-07-alt-dragging-an-element-to-copy-it-now-keeps-the-copy-visibl.md +6 -0
  30. package/corpus/templates/design/changelog/2026-08-07-design-cards-now-show-who-created-each-design-with-a-filter-.md +6 -0
  31. package/corpus/templates/design/changelog/2026-08-07-drawing-a-shape-on-the-overview-canvas-now-keeps-the-shape-s.md +6 -0
  32. package/corpus/templates/design/changelog/2026-08-07-hold-option-alt-while-dragging-a-frame-on-the-overview-canva.md +6 -0
  33. package/corpus/templates/design/server/lib/design-template-data.ts +143 -0
  34. package/corpus/templates/design/server/plugins/agent-chat.ts +1 -0
  35. package/corpus/templates/forms/AGENTS.md +2 -2
  36. package/corpus/templates/forms/actions/create-form.ts +1 -1
  37. package/corpus/templates/forms/actions/update-form.ts +5 -5
  38. package/corpus/templates/forms/changelog/2026-08-10-forms-now-keep-agent-applied-field-changes-visible-after-an-.md +6 -0
  39. package/corpus/templates/forms/changelog/2026-08-10-published-form-links-always-use-the-working-public-form-url.md +6 -0
  40. package/corpus/templates/forms/server/plugins/agent-chat.ts +2 -2
  41. package/corpus/templates/slides/AGENTS.md +4 -3
  42. package/corpus/templates/slides/actions/import-google-slides-reference.ts +56 -10
  43. package/corpus/templates/slides/actions/patch-deck.ts +18 -2
  44. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +46 -0
  45. package/corpus/templates/slides/app/components/editor/BlockBubbleMenu.tsx +194 -3
  46. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +22 -75
  47. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +5 -3
  48. package/corpus/templates/slides/app/components/editor/GeneratingSlidePreview.tsx +5 -1
  49. package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +15 -4
  50. package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +116 -55
  51. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +27 -4
  52. package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +45 -0
  53. package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +143 -18
  54. package/corpus/templates/slides/app/i18n/en-US.ts +6 -0
  55. package/corpus/templates/slides/app/lib/export-pdf-client.ts +84 -25
  56. package/corpus/templates/slides/app/lib/generation-state.ts +7 -1
  57. package/corpus/templates/slides/app/lib/import-uploaded-deck.ts +11 -0
  58. package/corpus/templates/slides/app/pages/DeckEditor.tsx +44 -14
  59. package/corpus/templates/slides/app/pages/Index.tsx +124 -135
  60. package/corpus/templates/slides/changelog/2026-08-08-google-slides-export-now-tells-you-why-a-deck-fell-back-to-a.md +6 -0
  61. package/corpus/templates/slides/changelog/2026-08-09-delete-key-now-removes-a-selected-image.md +6 -0
  62. package/corpus/templates/slides/changelog/2026-08-09-editing-a-slide-in-an-imported-deck-no-longer-fails-to-save.md +6 -0
  63. package/corpus/templates/slides/changelog/2026-08-09-fixed-pdf-and-custom-size-powerpoint-imports-rendering-with-.md +6 -0
  64. package/corpus/templates/slides/changelog/2026-08-09-images-from-sites-without-cors-no-longer-export-blank.md +6 -0
  65. package/corpus/templates/slides/changelog/2026-08-09-imported-pdf-headings-no-longer-lose-the-space-between-color.md +6 -0
  66. package/corpus/templates/slides/changelog/2026-08-09-imported-slide-text-no-longer-renders-too-large-for-its-box.md +6 -0
  67. package/corpus/templates/slides/changelog/2026-08-09-large-decks-no-longer-render-slowly-or-glitch-in-the-editor.md +6 -0
  68. package/corpus/templates/slides/changelog/2026-08-09-revise-highlighted-slide-text-with-ai.md +6 -0
  69. package/corpus/templates/slides/changelog/2026-08-09-the-deck-editor-no-longer-stays-dimmed-after-the-window-narro.md +6 -0
  70. package/corpus/templates/slides/changelog/2026-08-10-imported-reference-decks-now-show-clear-success-and-stay-sel.md +6 -0
  71. package/corpus/templates/slides/changelog/2026-08-10-pasted-google-slides-links-import-after-reconnecting-google-.md +6 -0
  72. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +4 -0
  73. package/corpus/templates/slides/server/handlers/import/html-converter.ts +115 -22
  74. package/corpus/templates/slides/server/handlers/import/pdf-fidelity-parser.ts +11 -2
  75. package/corpus/templates/slides/server/lib/fetch-remote-image.ts +192 -0
  76. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +13 -0
  77. package/corpus/templates/slides/server/lib/image-proxy-url.ts +192 -0
  78. package/corpus/templates/slides/server/plugins/agent-chat.ts +1 -1
  79. package/corpus/templates/slides/server/routes/api/image-proxy.get.ts +65 -0
  80. package/dist/agent/engine/registry.d.ts +8 -2
  81. package/dist/agent/engine/registry.js +63 -29
  82. package/dist/agent/production-agent.js +7 -0
  83. package/dist/agent/run-manager.d.ts +5 -4
  84. package/dist/agent/run-manager.js +6 -5
  85. package/dist/cli/claude-code-participant.d.ts +2 -1
  86. package/dist/cli/claude-code-participant.js +19 -0
  87. package/dist/cli/code-agent-executor.js +223 -0
  88. package/dist/cli/create-workspace.js +3 -3
  89. package/dist/cli/create.d.ts +3 -2
  90. package/dist/cli/create.js +20 -24
  91. package/dist/client/AgentPanel.js +8 -4
  92. package/dist/client/AssistantChat.js +34 -1
  93. package/dist/client/agent-chat-adapter.d.ts +1 -0
  94. package/dist/client/agent-chat-adapter.js +10 -2
  95. package/dist/client/chat/markdown-renderer.d.ts +1 -0
  96. package/dist/client/chat/markdown-renderer.js +4 -0
  97. package/dist/client/chat/message-components.d.ts +1 -0
  98. package/dist/client/chat/message-components.js +9 -1
  99. package/dist/client/chat/tool-call-display.d.ts +8 -0
  100. package/dist/client/chat/tool-call-display.js +30 -21
  101. package/dist/client/chat-first/app-pane.js +1 -1
  102. package/dist/client/chat-first/apps-rail.d.ts +1 -1
  103. package/dist/client/chat-first/apps-rail.js +11 -11
  104. package/dist/client/chat-first/chat-history.d.ts +1 -1
  105. package/dist/client/chat-first/chat-history.js +2 -0
  106. package/dist/client/chat-first/primary-nav.js +1 -1
  107. package/dist/client/progress/RunsTray.js +14 -1
  108. package/dist/client/resources/McpConnectionSuggestion.js +2 -2
  109. package/dist/client/settings/SettingsTabsPage.d.ts +3 -1
  110. package/dist/client/settings/SettingsTabsPage.js +2 -2
  111. package/dist/client/sse-event-processor.d.ts +8 -0
  112. package/dist/client/sse-event-processor.js +13 -6
  113. package/dist/collab/awareness.d.ts +2 -2
  114. package/dist/collab/routes.d.ts +1 -1
  115. package/dist/deploy/build.d.ts +5 -7
  116. package/dist/deploy/build.js +19 -12
  117. package/dist/localization/default-messages.js +1 -1
  118. package/dist/notifications/routes.d.ts +3 -3
  119. package/dist/observability/routes.d.ts +6 -6
  120. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  121. package/dist/scripts/call-agent.js +3 -3
  122. package/dist/scripts/describe-workspace-apps.js +1 -1
  123. package/dist/server/agent-capabilities.js +0 -0
  124. package/dist/server/agent-chat/context-tools.js +1 -1
  125. package/dist/server/agent-chat/prompt-resources.js +1 -1
  126. package/dist/server/agent-chat-plugin.js +1 -1
  127. package/dist/server/auth.js +190 -42
  128. package/dist/server/better-auth-migrations.js +53 -0
  129. package/dist/server/http-response-telemetry.js +7 -1
  130. package/dist/server/onboarding-html.js +119 -33
  131. package/dist/server/transcribe-voice.d.ts +1 -1
  132. package/dist/shared/password-policy.d.ts +2 -1
  133. package/dist/shared/password-policy.js +2 -1
  134. package/dist/styles/agent-conversation.css +20 -3
  135. package/dist/styles/agent-native.css +14 -2
  136. package/dist/templates/default/app/i18n/ar-SA.ts +1 -1
  137. package/dist/templates/default/app/i18n/de-DE.ts +1 -1
  138. package/dist/templates/default/app/i18n/en-US.ts +1 -1
  139. package/dist/templates/default/app/i18n/es-ES.ts +1 -1
  140. package/dist/templates/default/app/i18n/fr-FR.ts +1 -1
  141. package/dist/templates/default/app/i18n/hi-IN.ts +1 -1
  142. package/dist/templates/default/app/i18n/ja-JP.ts +1 -1
  143. package/dist/templates/default/app/i18n/ko-KR.ts +1 -1
  144. package/dist/templates/default/app/i18n/pt-BR.ts +1 -1
  145. package/dist/templates/default/app/i18n/zh-CN.ts +1 -1
  146. package/dist/templates/default/app/i18n/zh-TW.ts +1 -1
  147. package/dist/templates/default/pnpm-workspace.yaml +1 -0
  148. package/dist/templates/workspace-root/pnpm-workspace.yaml +2 -0
  149. package/docs/content/cloneable-saas.mdx +6 -6
  150. package/docs/content/deployment.mdx +10 -8
  151. package/docs/content/environment-variables.mdx +4 -3
  152. package/package.json +2 -2
  153. package/src/templates/default/app/i18n/ar-SA.ts +1 -1
  154. package/src/templates/default/app/i18n/de-DE.ts +1 -1
  155. package/src/templates/default/app/i18n/en-US.ts +1 -1
  156. package/src/templates/default/app/i18n/es-ES.ts +1 -1
  157. package/src/templates/default/app/i18n/fr-FR.ts +1 -1
  158. package/src/templates/default/app/i18n/hi-IN.ts +1 -1
  159. package/src/templates/default/app/i18n/ja-JP.ts +1 -1
  160. package/src/templates/default/app/i18n/ko-KR.ts +1 -1
  161. package/src/templates/default/app/i18n/pt-BR.ts +1 -1
  162. package/src/templates/default/app/i18n/zh-CN.ts +1 -1
  163. package/src/templates/default/app/i18n/zh-TW.ts +1 -1
  164. package/src/templates/default/pnpm-workspace.yaml +1 -0
  165. package/src/templates/workspace-root/pnpm-workspace.yaml +2 -0
@@ -27,12 +27,13 @@ import { toast } from "sonner";
27
27
  import DeckCard from "@/components/deck/DeckCard";
28
28
  import {
29
29
  NewDeckReferenceStep,
30
+ type ImportedReference,
30
31
  type NewDeckReferenceSelection,
32
+ type NewDeckReferenceSource,
31
33
  } from "@/components/editor/NewDeckReferenceStep";
32
34
  import PromptPopover, {
33
35
  uploadPromptFiles,
34
36
  type UploadedFile,
35
- type PromptImportSelection,
36
37
  } from "@/components/editor/PromptDialog";
37
38
  import {
38
39
  AlertDialog,
@@ -58,6 +59,7 @@ import { createDeckAgentMessage } from "@/lib/agent-visible-message";
58
59
  import { savePromptToComposerDraft } from "@/lib/composer-draft";
59
60
  import { sortDecksByRecency } from "@/lib/deck-sorting";
60
61
  import {
62
+ IMPORT_ACTION_TIMEOUT_MS,
61
63
  importUploadedDeckIntoDeck,
62
64
  type ImportedSourceDeck,
63
65
  } from "@/lib/import-uploaded-deck";
@@ -772,95 +774,6 @@ export default function Index() {
772
774
  [setNewDeckPromptOpen],
773
775
  );
774
776
 
775
- const handleDirectImport = useCallback(
776
- async (selection: PromptImportSelection): Promise<boolean> => {
777
- if (!session) {
778
- setSignInPromptHadFiles(selection.kind !== "google-slides");
779
- setShowSignInDialog(true);
780
- return false;
781
- }
782
-
783
- if (selection.kind === "google-slides") {
784
- const imported = (await callAction("import-google-slides-reference", {
785
- presentationUrl: selection.url,
786
- })) as { id?: unknown };
787
- if (typeof imported.id !== "string" || !imported.id) {
788
- throw new Error(
789
- "The Google Slides presentation did not create a deck.",
790
- );
791
- }
792
- await reloadDecks();
793
- navigate(`/deck/${imported.id}`, { flushSync: true });
794
- return true;
795
- }
796
-
797
- const uploaded = await uploadPromptFiles(selection.files);
798
- const file = uploaded[0];
799
- if (!file) throw new Error("The selected file could not be uploaded.");
800
-
801
- if (selection.kind === "pptx") {
802
- const imported = (await callAction("import-pptx", {
803
- filePath: file.path,
804
- designSystemId: initialDesignSystemId,
805
- })) as { id?: unknown };
806
- if (typeof imported.id !== "string" || !imported.id) {
807
- throw new Error("The PowerPoint presentation did not create a deck.");
808
- }
809
- await reloadDecks();
810
- navigate(`/deck/${imported.id}`, { flushSync: true });
811
- return true;
812
- }
813
-
814
- let deck: ReturnType<typeof createDeck> | undefined;
815
- flushSync(() => {
816
- deck = createDeck(undefined, {
817
- noDefaultSlides: true,
818
- designSystemId: initialDesignSystemId,
819
- });
820
- });
821
- if (!deck) throw new Error("The PDF deck could not be created.");
822
-
823
- const persisted = await ensureDeckPersisted(deck.id);
824
- if (!persisted.persisted) {
825
- deleteDeck(deck.id);
826
- throw new Error(
827
- describeDeckPersistenceFailure(
828
- persisted,
829
- "The PDF deck could not be saved.",
830
- ),
831
- );
832
- }
833
-
834
- try {
835
- const imported = (await callAction("import-file", {
836
- filePath: file.path,
837
- format: "pdf",
838
- deckId: deck.id,
839
- importIntoDeck: true,
840
- })) as { imported?: unknown; deckId?: unknown };
841
- if (imported.imported !== true || imported.deckId !== deck.id) {
842
- throw new Error("The PDF could not be imported into the new deck.");
843
- }
844
- await reloadDecks();
845
- navigate(`/deck/${deck.id}`, { flushSync: true });
846
- return true;
847
- } catch (error) {
848
- deleteDeck(deck.id);
849
- throw error;
850
- }
851
- },
852
- [
853
- callAction,
854
- createDeck,
855
- deleteDeck,
856
- ensureDeckPersisted,
857
- navigate,
858
- reloadDecks,
859
- session,
860
- initialDesignSystemId,
861
- ],
862
- );
863
-
864
777
  const handleReferenceSelect = useCallback(
865
778
  async (selection: NewDeckReferenceSelection) => {
866
779
  const pending = pendingDeck;
@@ -886,9 +799,9 @@ export default function Index() {
886
799
  );
887
800
 
888
801
  const handleReferenceImport = useCallback(
889
- async (files: File[]) => {
802
+ async (files: File[]): Promise<ImportedReference | null> => {
890
803
  const pending = pendingDeck;
891
- if (!pending) return;
804
+ if (!pending) return null;
892
805
  setReferenceImporting(true);
893
806
  try {
894
807
  const uploaded = await uploadPromptFiles(files);
@@ -898,26 +811,38 @@ export default function Index() {
898
811
  const pdfReference = uploaded.find((file) =>
899
812
  file.originalName.toLowerCase().endsWith(".pdf"),
900
813
  );
901
- let referenceSelection: NewDeckReferenceSelection = {
902
- designSystemId: null,
903
- referenceDeckId: null,
904
- };
814
+ let importedReference: ImportedReference | null = null;
815
+ let generationFiles = uploaded;
905
816
  if (pptxReference) {
906
- const imported = (await callAction("import-pptx", {
907
- filePath: pptxReference.path,
908
- })) as { id?: unknown };
909
- if (typeof imported.id !== "string" || !imported.id) {
817
+ const imported = (await callAction(
818
+ "import-pptx",
819
+ { filePath: pptxReference.path },
820
+ { timeoutMs: IMPORT_ACTION_TIMEOUT_MS },
821
+ )) as {
822
+ id?: unknown;
823
+ imported?: unknown;
824
+ slideCount?: unknown;
825
+ title?: unknown;
826
+ };
827
+ if (
828
+ typeof imported.id !== "string" ||
829
+ !imported.id ||
830
+ imported.imported !== true ||
831
+ typeof imported.slideCount !== "number" ||
832
+ imported.slideCount < 1
833
+ ) {
910
834
  throw new Error("The imported presentation did not create a deck.");
911
835
  }
912
- await reloadDecks();
913
- rememberReference({ id: imported.id, kind: "deck" });
914
- setSelectedReferenceDeckId(imported.id);
915
- referenceSelection = {
916
- designSystemId: null,
917
- referenceDeckId: imported.id,
836
+ importedReference = {
837
+ id: imported.id,
838
+ title:
839
+ typeof imported.title === "string" && imported.title
840
+ ? imported.title
841
+ : t("home.importedReferenceDeck"),
842
+ source: "pptx",
918
843
  };
919
- }
920
- if (!pptxReference && pdfReference) {
844
+ generationFiles = uploaded.filter((file) => file !== pptxReference);
845
+ } else if (pdfReference) {
921
846
  const referenceDeck = createDeck(undefined, {
922
847
  noDefaultSlides: true,
923
848
  });
@@ -932,41 +857,54 @@ export default function Index() {
932
857
  );
933
858
  }
934
859
  try {
935
- const imported = (await callAction("import-file", {
936
- filePath: pdfReference.path,
937
- format: "pdf",
938
- deckId: referenceDeck.id,
939
- importIntoDeck: true,
940
- })) as { imported?: unknown; deckId?: unknown };
860
+ const imported = (await callAction(
861
+ "import-file",
862
+ {
863
+ filePath: pdfReference.path,
864
+ format: "pdf",
865
+ deckId: referenceDeck.id,
866
+ importIntoDeck: true,
867
+ },
868
+ { timeoutMs: IMPORT_ACTION_TIMEOUT_MS },
869
+ )) as {
870
+ imported?: unknown;
871
+ deckId?: unknown;
872
+ pageCount?: unknown;
873
+ title?: unknown;
874
+ };
941
875
  if (
942
876
  imported.imported !== true ||
943
- imported.deckId !== referenceDeck.id
877
+ imported.deckId !== referenceDeck.id ||
878
+ typeof imported.pageCount !== "number" ||
879
+ imported.pageCount < 1
944
880
  ) {
945
881
  throw new Error("The PDF reference deck could not be imported.");
946
882
  }
947
- await reloadDecks();
948
- rememberReference({ id: referenceDeck.id, kind: "deck" });
949
- setSelectedReferenceDeckId(referenceDeck.id);
950
- referenceSelection = {
951
- designSystemId: null,
952
- referenceDeckId: referenceDeck.id,
883
+ importedReference = {
884
+ id: referenceDeck.id,
885
+ title:
886
+ typeof imported.title === "string" && imported.title
887
+ ? imported.title
888
+ : t("home.importedReferenceDeck"),
889
+ source: "pdf",
953
890
  };
891
+ generationFiles = uploaded.filter((file) => file !== pdfReference);
954
892
  } catch (error) {
955
893
  deleteDeck(referenceDeck.id);
956
894
  throw error;
957
895
  }
958
896
  }
959
- const importedReference = pptxReference ?? pdfReference;
960
- const generationFiles = uploaded.filter(
961
- (file) => file !== importedReference,
962
- );
963
- setShowNewDeckReferenceStep(false);
964
- setPendingDeck(null);
965
- await handleCreateDeckWithPrompt(
966
- pending.prompt,
967
- [...pending.files, ...generationFiles],
968
- referenceSelection,
897
+ setPendingDeck((current) =>
898
+ current
899
+ ? { ...current, files: [...current.files, ...generationFiles] }
900
+ : current,
969
901
  );
902
+ if (importedReference) {
903
+ await reloadDecks();
904
+ rememberReference({ id: importedReference.id, kind: "deck" });
905
+ setSelectedReferenceDeckId(importedReference.id);
906
+ }
907
+ return importedReference;
970
908
  } catch (error) {
971
909
  toast.error(t("editorToolbar.uploadFailed"), {
972
910
  description:
@@ -974,6 +912,7 @@ export default function Index() {
974
912
  ? error.message
975
913
  : t("editorToolbar.importFailedDescription"),
976
914
  });
915
+ return null;
977
916
  } finally {
978
917
  setReferenceImporting(false);
979
918
  }
@@ -983,7 +922,6 @@ export default function Index() {
983
922
  createDeck,
984
923
  deleteDeck,
985
924
  ensureDeckPersisted,
986
- handleCreateDeckWithPrompt,
987
925
  pendingDeck,
988
926
  reloadDecks,
989
927
  rememberReference,
@@ -991,6 +929,59 @@ export default function Index() {
991
929
  ],
992
930
  );
993
931
 
932
+ const handleReferenceSourceImport = useCallback(
933
+ async (
934
+ source: NewDeckReferenceSource,
935
+ ): Promise<ImportedReference | null> => {
936
+ if (source.kind !== "google-docs") return null;
937
+ setReferenceImporting(true);
938
+ try {
939
+ const imported = (await callAction("import-google-slides-reference", {
940
+ presentationUrl: source.value,
941
+ })) as {
942
+ id?: unknown;
943
+ imported?: unknown;
944
+ slideCount?: unknown;
945
+ title?: unknown;
946
+ };
947
+ if (
948
+ typeof imported.id !== "string" ||
949
+ !imported.id ||
950
+ imported.imported !== true ||
951
+ typeof imported.slideCount !== "number" ||
952
+ imported.slideCount < 1
953
+ ) {
954
+ throw new Error(
955
+ "The Google Slides presentation did not create a deck.",
956
+ );
957
+ }
958
+ const importedReference: ImportedReference = {
959
+ id: imported.id,
960
+ title:
961
+ typeof imported.title === "string" && imported.title
962
+ ? imported.title
963
+ : t("home.importedReferenceDeck"),
964
+ source: "google-slides",
965
+ };
966
+ await reloadDecks();
967
+ rememberReference({ id: importedReference.id, kind: "deck" });
968
+ setSelectedReferenceDeckId(importedReference.id);
969
+ return importedReference;
970
+ } catch (error) {
971
+ toast.error(t("editorToolbar.uploadFailed"), {
972
+ description:
973
+ error instanceof Error
974
+ ? error.message
975
+ : t("editorToolbar.importFailedDescription"),
976
+ });
977
+ return null;
978
+ } finally {
979
+ setReferenceImporting(false);
980
+ }
981
+ },
982
+ [callAction, reloadDecks, rememberReference, t],
983
+ );
984
+
994
985
  const handleReferenceSkip = useCallback(() => {
995
986
  const pending = pendingDeck;
996
987
  if (!pending) {
@@ -1329,8 +1320,6 @@ export default function Index() {
1329
1320
  onSkip={handleCreateDeckBlank}
1330
1321
  skipLabel={t("home.skipPrompt")}
1331
1322
  onSubmit={handlePromptSubmit}
1332
- onImport={handleDirectImport}
1333
- importFromLabel={t("home.importFrom")}
1334
1323
  importingLabel={t("editorToolbar.importing")}
1335
1324
  onBeforeUpload={(prompt, files) => {
1336
1325
  if (session) return true;
@@ -1364,6 +1353,7 @@ export default function Index() {
1364
1353
  recentReferences={recentReferences}
1365
1354
  onSelect={(selection) => void handleReferenceSelect(selection)}
1366
1355
  onImport={handleReferenceImport}
1356
+ onImportSource={handleReferenceSourceImport}
1367
1357
  onSkip={handleReferenceSkip}
1368
1358
  importing={referenceImporting}
1369
1359
  title={t("home.newDeckPromptTitle")}
@@ -1372,7 +1362,6 @@ export default function Index() {
1372
1362
  chooseDeckLabel={t("home.referenceDeckPlaceholder")}
1373
1363
  importingLabel={t("editorToolbar.importing")}
1374
1364
  skipLabel={t("home.referenceDeckNone")}
1375
- defaultSuffix={t("home.defaultSuffix")}
1376
1365
  starredLabel={t("home.referenceDeckStarredGroup")}
1377
1366
  otherDecksLabel={t("home.referenceDeckOtherGroup")}
1378
1367
  searchDecksLabel={t("root.searchDecks")}
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-08
4
+ ---
5
+
6
+ Google Slides export now tells you why a deck fell back to a .pptx download instead of reporting success.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-09
4
+ ---
5
+
6
+ Fixed the Delete key doing nothing after selecting an image that sits inside a slide's layout, such as a picture in a card grid. Only images that had been moved freely on the canvas could be deleted before.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-09
4
+ ---
5
+
6
+ Fixed direct edits to a PDF/PPTX-imported deck's slide text sometimes failing to save with a generic "Internal server error" — the source-preservation guard meant to stop an agent from silently dropping the original artwork or copy was also blocking ordinary human edits, which have no way to opt out of it.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-09
4
+ ---
5
+
6
+ Fixed PDF and custom-size PowerPoint imports rendering with distorted, mispositioned images and text on non-16:9 pages.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-09
4
+ ---
5
+
6
+ Fixed images vanishing from exported PDFs and PowerPoint files when they came from a site that blocks direct browser access, such as a blog or a stock photo host. Those images are now fetched through the app and appear in the export.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-09
4
+ ---
5
+
6
+ Fixed imported PDF text losing the space between words when a line changes color or weight mid-sentence, which ran headings like "7 Air purifying house plants" together into "7 Airpurifying".
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-09
4
+ ---
5
+
6
+ Fixed imported PDF/PowerPoint slide text rendering larger than its original box (often overlapping neighboring text) whenever the source page's physical size didn't match the deck canvas's assumed size — font sizes now scale by the same factor as element positions instead of a fixed point-to-pixel conversion.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-09
4
+ ---
5
+
6
+ Fixed decks with many slides loading slowly and rendering incorrectly in the editor. Every slide thumbnail measured its full layout on mount, so a long deck forced hundreds of page reflows at once; off-screen thumbnails now wait until they scroll into view, and the browser skips painting them entirely until then. The hover buttons on each thumbnail also no longer blur what is behind them, which was making the rail flicker and leaving dark patches over the editor.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: added
3
+ date: 2026-08-09
4
+ ---
5
+
6
+ Highlight text on a slide and the formatting bar now offers "Revise with AI". Describe the change you want — shorter, punchier, on-brand — and the agent rewrites just that text without disturbing the rest of the slide.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-09
4
+ ---
5
+
6
+ Fixed the deck editor staying covered by the mobile slide-rail dimming overlay after the window was narrowed, which washed the whole editor dark with no way to dismiss it.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-08-10
4
+ ---
5
+
6
+ Imported reference decks now show clear success and stay selected for new deck generation
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-10
4
+ ---
5
+
6
+ Pasted Google Slides links import after reconnecting Google Drive when needed.
@@ -23,6 +23,7 @@ import {
23
23
  getGoogleDocsAccessToken,
24
24
  getGoogleDocsAuthUrl,
25
25
  getGooglePickerConfig,
26
+ hasGoogleDriveExportScope,
26
27
  isGoogleDocsOAuthConfigured,
27
28
  listGoogleDocsAccounts,
28
29
  } from "../lib/google-docs-oauth.js";
@@ -163,6 +164,9 @@ export const getGoogleDocsStatus = defineEventHandler(
163
164
  return {
164
165
  configured: await isGoogleDocsOAuthConfigured(owner),
165
166
  connected: accounts.length > 0,
167
+ googleSlidesUrlImportReady: accounts.some((account) =>
168
+ hasGoogleDriveExportScope(account.scope),
169
+ ),
166
170
  accounts,
167
171
  pickerConfigured: !!(picker.apiKey && picker.appId),
168
172
  pickerApiKey: picker.apiKey,