@alpaca-editor/core 1.0.4032 → 1.0.4037

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 (195) hide show
  1. package/dist/components/index.d.ts +1 -0
  2. package/dist/components/index.js +1 -0
  3. package/dist/components/index.js.map +1 -1
  4. package/dist/{editor/menubar → components/ui}/LanguageSelector.d.ts +1 -1
  5. package/dist/{editor/menubar → components/ui}/LanguageSelector.js +8 -8
  6. package/dist/components/ui/LanguageSelector.js.map +1 -0
  7. package/dist/components/ui/button.d.ts +1 -1
  8. package/dist/components/ui/dropdown-menu.d.ts +1 -1
  9. package/dist/components/ui/dropdown-menu.js +2 -2
  10. package/dist/components/ui/dropdown-menu.js.map +1 -1
  11. package/dist/components/ui/sonner.js +3 -1
  12. package/dist/components/ui/sonner.js.map +1 -1
  13. package/dist/config/config.js +5 -5
  14. package/dist/config/config.js.map +1 -1
  15. package/dist/editor/ContentTree.d.ts +2 -1
  16. package/dist/editor/ContentTree.js +33 -9
  17. package/dist/editor/ContentTree.js.map +1 -1
  18. package/dist/editor/PictureEditor.js +2 -2
  19. package/dist/editor/PictureEditor.js.map +1 -1
  20. package/dist/editor/ScrollingContentTree.d.ts +2 -1
  21. package/dist/editor/ScrollingContentTree.js +2 -2
  22. package/dist/editor/ScrollingContentTree.js.map +1 -1
  23. package/dist/editor/Terminal.d.ts +2 -0
  24. package/dist/editor/Terminal.js +2 -2
  25. package/dist/editor/Terminal.js.map +1 -1
  26. package/dist/editor/ai/AgentHistory.d.ts +11 -0
  27. package/dist/editor/ai/AgentHistory.js +12 -0
  28. package/dist/editor/ai/AgentHistory.js.map +1 -0
  29. package/dist/editor/ai/Agents.js +187 -24
  30. package/dist/editor/ai/Agents.js.map +1 -1
  31. package/dist/editor/ai/AiResponseMessage.d.ts +2 -1
  32. package/dist/editor/ai/AiResponseMessage.js +6 -6
  33. package/dist/editor/ai/AiResponseMessage.js.map +1 -1
  34. package/dist/editor/ai/AiTerminal.d.ts +1 -0
  35. package/dist/editor/ai/AiTerminal.js +330 -43
  36. package/dist/editor/ai/AiTerminal.js.map +1 -1
  37. package/dist/editor/ai/aiPageModel.d.ts +2 -1
  38. package/dist/editor/ai/aiPageModel.js +56 -9
  39. package/dist/editor/ai/aiPageModel.js.map +1 -1
  40. package/dist/editor/client/itemsRepository.js +19 -7
  41. package/dist/editor/client/itemsRepository.js.map +1 -1
  42. package/dist/editor/field-types/InternalLinkFieldEditor.js +48 -1
  43. package/dist/editor/field-types/InternalLinkFieldEditor.js.map +1 -1
  44. package/dist/editor/field-types/richtext/contextMenuFactory.js +1 -1
  45. package/dist/editor/field-types/richtext/contextMenuFactory.js.map +1 -1
  46. package/dist/editor/menubar/ItemLanguageVersion.js +1 -1
  47. package/dist/editor/menubar/ItemLanguageVersion.js.map +1 -1
  48. package/dist/editor/menubar/PageSelector.js +1 -1
  49. package/dist/editor/menubar/PageSelector.js.map +1 -1
  50. package/dist/editor/page-editor-chrome/FieldActionIndicator.js +1 -1
  51. package/dist/editor/page-editor-chrome/FieldActionIndicator.js.map +1 -1
  52. package/dist/editor/page-editor-chrome/FieldEditedIndicator.js +2 -2
  53. package/dist/editor/page-editor-chrome/FieldEditedIndicator.js.map +1 -1
  54. package/dist/editor/page-editor-chrome/FrameMenu.js +2 -2
  55. package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
  56. package/dist/editor/page-editor-chrome/InlineEditor.js +9 -9
  57. package/dist/editor/page-editor-chrome/InlineEditor.js.map +1 -1
  58. package/dist/editor/page-editor-chrome/LockedFieldIndicator.js +2 -2
  59. package/dist/editor/page-editor-chrome/LockedFieldIndicator.js.map +1 -1
  60. package/dist/editor/page-editor-chrome/PageEditorChrome.js +1 -1
  61. package/dist/editor/page-editor-chrome/PageEditorChrome.js.map +1 -1
  62. package/dist/editor/page-editor-chrome/PictureEditorOverlay.js +1 -1
  63. package/dist/editor/page-editor-chrome/PictureEditorOverlay.js.map +1 -1
  64. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +1 -1
  65. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js +2 -2
  66. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js.map +1 -1
  67. package/dist/editor/page-editor-chrome/useInlineAICompletion.js +12 -12
  68. package/dist/editor/page-editor-chrome/useInlineAICompletion.js.map +1 -1
  69. package/dist/editor/page-viewer/EditorForm.js +1 -1
  70. package/dist/editor/page-viewer/EditorForm.js.map +1 -1
  71. package/dist/editor/page-viewer/MiniMap.js +10 -11
  72. package/dist/editor/page-viewer/MiniMap.js.map +1 -1
  73. package/dist/editor/page-viewer/PageViewer.js +2 -2
  74. package/dist/editor/page-viewer/PageViewer.js.map +1 -1
  75. package/dist/editor/page-viewer/PageViewerFrame.js +4 -4
  76. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  77. package/dist/editor/page-viewer/pageViewContext.d.ts +2 -2
  78. package/dist/editor/page-viewer/pageViewContext.js +11 -14
  79. package/dist/editor/page-viewer/pageViewContext.js.map +1 -1
  80. package/dist/editor/services/agentService.d.ts +21 -1
  81. package/dist/editor/services/agentService.js +101 -0
  82. package/dist/editor/services/agentService.js.map +1 -1
  83. package/dist/editor/services/aiService.d.ts +2 -1
  84. package/dist/editor/services/aiService.js +2 -4
  85. package/dist/editor/services/aiService.js.map +1 -1
  86. package/dist/editor/sidebar/GraphQL.js +5 -6
  87. package/dist/editor/sidebar/GraphQL.js.map +1 -1
  88. package/dist/editor/sidebar/MainContentTree.d.ts +2 -1
  89. package/dist/editor/sidebar/MainContentTree.js +9 -5
  90. package/dist/editor/sidebar/MainContentTree.js.map +1 -1
  91. package/dist/editor/ui/Icons.d.ts +5 -0
  92. package/dist/editor/ui/Icons.js +3 -0
  93. package/dist/editor/ui/Icons.js.map +1 -1
  94. package/dist/editor/ui/ItemNameDialogNew.js +26 -14
  95. package/dist/editor/ui/ItemNameDialogNew.js.map +1 -1
  96. package/dist/editor/ui/PerfectTree.js +54 -2
  97. package/dist/editor/ui/PerfectTree.js.map +1 -1
  98. package/dist/editor/views/CompareView.js +3 -3
  99. package/dist/editor/views/CompareView.js.map +1 -1
  100. package/dist/editor/views/EditView.js +1 -1
  101. package/dist/editor/views/EditView.js.map +1 -1
  102. package/dist/editor/views/ItemEditor.js +1 -1
  103. package/dist/editor/views/ItemEditor.js.map +1 -1
  104. package/dist/index.d.ts +3 -4
  105. package/dist/index.js +3 -4
  106. package/dist/index.js.map +1 -1
  107. package/dist/page-wizard/PageWizard.js +0 -5
  108. package/dist/page-wizard/PageWizard.js.map +1 -1
  109. package/dist/page-wizard/steps/ContentStep.js +39 -27
  110. package/dist/page-wizard/steps/ContentStep.js.map +1 -1
  111. package/dist/page-wizard/steps/FindItemsStep.js +2 -1
  112. package/dist/page-wizard/steps/FindItemsStep.js.map +1 -1
  113. package/dist/page-wizard/steps/ImagesStep.js +1 -1
  114. package/dist/page-wizard/steps/ImagesStep.js.map +1 -1
  115. package/dist/page-wizard/steps/LayoutStep.js +1 -1
  116. package/dist/page-wizard/steps/LayoutStep.js.map +1 -1
  117. package/dist/page-wizard/steps/MetaDataStep.js +1 -1
  118. package/dist/page-wizard/steps/MetaDataStep.js.map +1 -1
  119. package/dist/page-wizard/steps/SelectStep.js +1 -1
  120. package/dist/page-wizard/steps/StructureStep.js +32 -11
  121. package/dist/page-wizard/steps/StructureStep.js.map +1 -1
  122. package/dist/page-wizard/steps/TranslateStep.d.ts +1 -0
  123. package/dist/page-wizard/steps/TranslateStep.js +67 -73
  124. package/dist/page-wizard/steps/TranslateStep.js.map +1 -1
  125. package/dist/revision.d.ts +2 -2
  126. package/dist/revision.js +2 -2
  127. package/dist/splash-screen/NewPage.js +1 -1
  128. package/dist/splash-screen/NewPage.js.map +1 -1
  129. package/dist/splash-screen/OpenPage.js +1 -1
  130. package/dist/splash-screen/OpenPage.js.map +1 -1
  131. package/dist/styles.css +71 -8
  132. package/package.json +1 -1
  133. package/src/components/index.ts +1 -0
  134. package/src/{editor/menubar → components/ui}/LanguageSelector.tsx +12 -12
  135. package/src/components/ui/dropdown-menu.tsx +3 -1
  136. package/src/components/ui/sonner.tsx +5 -1
  137. package/src/config/config.tsx +4 -3
  138. package/src/editor/ContentTree.tsx +41 -12
  139. package/src/editor/PictureEditor.tsx +2 -2
  140. package/src/editor/ScrollingContentTree.tsx +3 -0
  141. package/src/editor/Terminal.tsx +16 -7
  142. package/src/editor/ai/AgentHistory.tsx +85 -0
  143. package/src/editor/ai/Agents.tsx +256 -88
  144. package/src/editor/ai/AiResponseMessage.tsx +25 -11
  145. package/src/editor/ai/AiTerminal.tsx +571 -73
  146. package/src/editor/ai/aiPageModel.ts +115 -6
  147. package/src/editor/client/itemsRepository.ts +29 -12
  148. package/src/editor/field-types/InternalLinkFieldEditor.tsx +53 -2
  149. package/src/editor/field-types/richtext/components/SimpleRichTextEditor.css +64 -0
  150. package/src/editor/field-types/richtext/contextMenuFactory.tsx +7 -8
  151. package/src/editor/menubar/ItemLanguageVersion.tsx +1 -1
  152. package/src/editor/menubar/PageSelector.tsx +1 -0
  153. package/src/editor/page-editor-chrome/FieldActionIndicator.tsx +1 -1
  154. package/src/editor/page-editor-chrome/FieldEditedIndicator.tsx +3 -3
  155. package/src/editor/page-editor-chrome/FrameMenu.tsx +2 -2
  156. package/src/editor/page-editor-chrome/InlineEditor.tsx +9 -12
  157. package/src/editor/page-editor-chrome/LockedFieldIndicator.tsx +3 -3
  158. package/src/editor/page-editor-chrome/PageEditorChrome.tsx +3 -3
  159. package/src/editor/page-editor-chrome/PictureEditorOverlay.tsx +1 -1
  160. package/src/editor/page-editor-chrome/PlaceholderDropZone.tsx +1 -1
  161. package/src/editor/page-editor-chrome/PlaceholderDropZones.tsx +2 -2
  162. package/src/editor/page-editor-chrome/useInlineAICompletion.tsx +12 -18
  163. package/src/editor/page-viewer/EditorForm.tsx +1 -1
  164. package/src/editor/page-viewer/MiniMap.tsx +10 -11
  165. package/src/editor/page-viewer/PageViewer.tsx +8 -3
  166. package/src/editor/page-viewer/PageViewerFrame.tsx +4 -4
  167. package/src/editor/page-viewer/pageViewContext.ts +71 -66
  168. package/src/editor/services/agentService.ts +129 -1
  169. package/src/editor/services/aiService.ts +5 -7
  170. package/src/editor/sidebar/GraphQL.tsx +16 -15
  171. package/src/editor/sidebar/MainContentTree.tsx +12 -4
  172. package/src/editor/ui/Icons.tsx +35 -0
  173. package/src/editor/ui/ItemNameDialogNew.tsx +29 -13
  174. package/src/editor/ui/PerfectTree.tsx +70 -4
  175. package/src/editor/views/CompareView.tsx +3 -3
  176. package/src/editor/views/EditView.tsx +1 -1
  177. package/src/editor/views/ItemEditor.tsx +1 -1
  178. package/src/index.ts +10 -4
  179. package/src/page-wizard/PageWizard.tsx +0 -12
  180. package/src/page-wizard/steps/ContentStep.tsx +46 -31
  181. package/src/page-wizard/steps/FindItemsStep.tsx +2 -1
  182. package/src/page-wizard/steps/ImagesStep.tsx +1 -1
  183. package/src/page-wizard/steps/LayoutStep.tsx +1 -1
  184. package/src/page-wizard/steps/MetaDataStep.tsx +1 -1
  185. package/src/page-wizard/steps/SelectStep.tsx +1 -1
  186. package/src/page-wizard/steps/StructureStep.tsx +45 -17
  187. package/src/page-wizard/steps/TranslateStep.tsx +326 -222
  188. package/src/revision.ts +2 -2
  189. package/src/splash-screen/NewPage.tsx +1 -0
  190. package/src/splash-screen/OpenPage.tsx +1 -0
  191. package/dist/components/SimpleLanguageSelector.d.ts +0 -10
  192. package/dist/components/SimpleLanguageSelector.js +0 -59
  193. package/dist/components/SimpleLanguageSelector.js.map +0 -1
  194. package/dist/editor/menubar/LanguageSelector.js.map +0 -1
  195. package/src/components/SimpleLanguageSelector.tsx +0 -113
@@ -59,8 +59,7 @@ export function useInlineAiCompletion({
59
59
  isUpdatingRef.current = true;
60
60
 
61
61
  try {
62
- const iframeWindow =
63
- pageViewContext.editorIframeRef.current?.contentWindow;
62
+ const iframeWindow = pageViewContext.editorIframe?.contentWindow;
64
63
  const iframeDocument = iframeWindow?.document;
65
64
  const editableElement = editContext?.inlineEditingFieldElement;
66
65
 
@@ -174,7 +173,7 @@ export function useInlineAiCompletion({
174
173
  if (e.key === "ArrowRight" || e.key === "Delete") {
175
174
  // Make sure the cursor span doesn't block the movement/deletion
176
175
  const cursorSpan =
177
- pageViewContext.editorIframeRef.current?.contentWindow?.document.getElementById(
176
+ pageViewContext.editorIframe?.contentWindow?.document.getElementById(
178
177
  cursorSpanId,
179
178
  );
180
179
  if (cursorSpan) {
@@ -193,12 +192,12 @@ export function useInlineAiCompletion({
193
192
  }
194
193
  };
195
194
 
196
- pageViewContext.editorIframeRef.current?.contentWindow?.document.addEventListener(
195
+ pageViewContext.editorIframe?.contentWindow?.document.addEventListener(
197
196
  "keydown",
198
197
  keyHandler,
199
198
  );
200
199
  return () => {
201
- pageViewContext.editorIframeRef.current?.contentWindow?.document.removeEventListener(
200
+ pageViewContext.editorIframe?.contentWindow?.document.removeEventListener(
202
201
  "keydown",
203
202
  keyHandler,
204
203
  );
@@ -207,7 +206,7 @@ export function useInlineAiCompletion({
207
206
 
208
207
  // Extracts the text up to the cursor position in the editable element
209
208
  const getContentUpToCursor = (element: HTMLElement) => {
210
- const iframeWindow = pageViewContext.editorIframeRef.current?.contentWindow;
209
+ const iframeWindow = pageViewContext.editorIframe?.contentWindow;
211
210
  const selection = iframeWindow?.getSelection();
212
211
  if (!element || !selection || selection.rangeCount === 0) return null;
213
212
  const range = selection.getRangeAt(0);
@@ -235,8 +234,7 @@ export function useInlineAiCompletion({
235
234
 
236
235
  // Loading animation with three dots changing color
237
236
  const startLoadingAnimation = () => {
238
- const doc =
239
- pageViewContext.editorIframeRef.current?.contentWindow?.document;
237
+ const doc = pageViewContext.editorIframe?.contentWindow?.document;
240
238
  const span = doc?.getElementById(cursorSpanId);
241
239
  if (!doc || !span) return;
242
240
 
@@ -456,8 +454,7 @@ ONLY provide the completion text (what comes after the user's text), never repea
456
454
 
457
455
  // Inserts or clears the ghost text inside the cursor span
458
456
  const updateCursorSpan = (text: string) => {
459
- const doc =
460
- pageViewContext.editorIframeRef.current?.contentWindow?.document;
457
+ const doc = pageViewContext.editorIframe?.contentWindow?.document;
461
458
  const span = doc?.getElementById(cursorSpanId);
462
459
  if (!doc || !span) return;
463
460
 
@@ -510,8 +507,7 @@ ONLY provide the completion text (what comes after the user's text), never repea
510
507
  });
511
508
 
512
509
  // Position the hint element relative to the iframe and cursor span
513
- const iframeRect =
514
- pageViewContext.editorIframeRef.current?.getBoundingClientRect();
510
+ const iframeRect = pageViewContext.editorIframe?.getBoundingClientRect();
515
511
  const spanRect = span.getBoundingClientRect();
516
512
 
517
513
  if (iframeRect) {
@@ -550,8 +546,7 @@ ONLY provide the completion text (what comes after the user's text), never repea
550
546
  };
551
547
 
552
548
  const clearCursorSpan = () => {
553
- const doc =
554
- pageViewContext.editorIframeRef.current?.contentWindow?.document;
549
+ const doc = pageViewContext.editorIframe?.contentWindow?.document;
555
550
  if (!doc) return;
556
551
 
557
552
  // Clear the completion text
@@ -587,7 +582,7 @@ ONLY provide the completion text (what comes after the user's text), never repea
587
582
  if (e.key === "Tab") {
588
583
  // Check if there's an actual completion in the cursor span
589
584
  const cursorSpan =
590
- pageViewContext.editorIframeRef.current?.contentWindow?.document.getElementById(
585
+ pageViewContext.editorIframe?.contentWindow?.document.getElementById(
591
586
  cursorSpanId,
592
587
  );
593
588
  if (
@@ -632,8 +627,7 @@ ONLY provide the completion text (what comes after the user's text), never repea
632
627
  const el = editContext?.inlineEditingFieldElement;
633
628
  if (!el) return false;
634
629
 
635
- const iframeWindow =
636
- pageViewContext.editorIframeRef.current?.contentWindow;
630
+ const iframeWindow = pageViewContext.editorIframe?.contentWindow;
637
631
  const selection = iframeWindow?.getSelection();
638
632
  if (!selection || selection.rangeCount === 0) return false;
639
633
 
@@ -729,7 +723,7 @@ ONLY provide the completion text (what comes after the user's text), never repea
729
723
  // Function to apply the completion
730
724
  const applyCompletion = () => {
731
725
  // Get the cursor span to read the most up-to-date completion
732
- const iframeWindow = pageViewContext.editorIframeRef.current?.contentWindow;
726
+ const iframeWindow = pageViewContext.editorIframe?.contentWindow;
733
727
  const iframeDocument = iframeWindow?.document;
734
728
  if (
735
729
  !iframeWindow ||
@@ -392,7 +392,7 @@ export function EditorForm({
392
392
  <SimpleTabs
393
393
  key="editor-tabs"
394
394
  tabs={tabPanels}
395
- className="flex flex-1 items-center justify-center border-b border-gray-200 pt-4 text-xs"
395
+ className="flex items-center justify-center border-b border-gray-200 pt-4 text-xs"
396
396
  activeTab={tabPanels.findIndex((x) => x.id === activeTabKey) || 0}
397
397
  setActiveTab={(index) => setActiveTabKey(tabPanels[index]?.id!)}
398
398
  ></SimpleTabs>
@@ -31,14 +31,13 @@ export function MiniMap({
31
31
 
32
32
  const observerRef = useRef<MutationObserver | null>(null);
33
33
 
34
- const editorIframeRef = mainViewIframeRef;
35
34
  const minimapContainerRef = useRef<HTMLDivElement>(null);
36
35
 
37
36
  if (!mainViewIframeRef.current) return;
38
37
 
39
38
  const scrollContainer =
40
- editorIframeRef.current?.contentWindow?.document.scrollingElement ||
41
- editorIframeRef.current?.contentWindow?.document.body;
39
+ mainViewIframeRef.current?.contentWindow?.document.scrollingElement ||
40
+ mainViewIframeRef.current?.contentWindow?.document.body;
42
41
 
43
42
  const calcAndUpdateScale = () => {
44
43
  const viewport = pageViewContext.viewport;
@@ -139,7 +138,7 @@ export function MiniMap({
139
138
  const handleLoad = () => {
140
139
  if (!mainViewIframeRef?.current?.contentWindow?.document) return;
141
140
 
142
- mirrorIframeContent(editorIframeRef.current!, iframeRef.current!);
141
+ mirrorIframeContent(mainViewIframeRef.current!, iframeRef.current!);
143
142
 
144
143
  const observer = new MutationObserver((mutationsList) => {
145
144
  const minimapDoc = iframeRef.current?.contentDocument;
@@ -197,15 +196,15 @@ export function MiniMap({
197
196
  };
198
197
 
199
198
  useEffect(() => {
200
- if (editorIframeRef?.current) {
201
- editorIframeRef?.current.addEventListener("load", handleLoad);
199
+ if (mainViewIframeRef?.current) {
200
+ mainViewIframeRef?.current.addEventListener("load", handleLoad);
202
201
  }
203
202
 
204
203
  handleLoad();
205
204
 
206
205
  // Cleanup function
207
206
  return () => {
208
- editorIframeRef?.current?.removeEventListener("load", handleLoad);
207
+ mainViewIframeRef?.current?.removeEventListener("load", handleLoad);
209
208
  };
210
209
  }, [mainViewIframeRef.current, iframeRef.current]);
211
210
 
@@ -213,7 +212,7 @@ export function MiniMap({
213
212
  calcAndUpdateScale();
214
213
  }, [
215
214
  refreshScale,
216
- editorIframeRef,
215
+ mainViewIframeRef,
217
216
  //pageViewContext?.windowSize,
218
217
  pageViewContext?.zoom,
219
218
  pageViewContext.viewport,
@@ -226,7 +225,7 @@ export function MiniMap({
226
225
  }
227
226
 
228
227
  const scrollDocumentTo = (y: number) => {
229
- if (!editorIframeRef?.current) return;
228
+ if (!mainViewIframeRef?.current) return;
230
229
 
231
230
  if (!scrollContainer) return;
232
231
 
@@ -289,7 +288,7 @@ export function MiniMap({
289
288
  left: 0,
290
289
  top: e.deltaY,
291
290
  });
292
- editorIframeRef.current?.contentWindow?.document.documentElement?.scrollBy(
291
+ mainViewIframeRef.current?.contentWindow?.document.documentElement?.scrollBy(
293
292
  {
294
293
  behavior: "instant",
295
294
  left: 0,
@@ -298,7 +297,7 @@ export function MiniMap({
298
297
  );
299
298
  e.stopPropagation();
300
299
  },
301
- [editorIframeRef],
300
+ [mainViewIframeRef],
302
301
  );
303
302
 
304
303
  return (
@@ -3,7 +3,10 @@ import { EditorForm } from "./EditorForm";
3
3
  import { PageViewerFrame } from "./PageViewerFrame";
4
4
  import { useEffect, useState } from "react";
5
5
  import { SimpleIconButton } from "../ui/SimpleIconButton";
6
- import { useEditContext, useModifiedFieldsContext } from "../client/editContext";
6
+ import {
7
+ useEditContext,
8
+ useModifiedFieldsContext,
9
+ } from "../client/editContext";
7
10
  import { PanelLeftClose, PanelLeftOpen } from "lucide-react";
8
11
  import { cn } from "../../lib/utils";
9
12
  import { Splitter, SplitterPanel } from "../ui/Splitter";
@@ -50,7 +53,9 @@ export function PageViewer({
50
53
  if (editContext?.inlineEditingFieldElement) return;
51
54
 
52
55
  const lastEdit =
53
- modifiedFieldsContext.recentEdits[modifiedFieldsContext.recentEdits.length - 1];
56
+ modifiedFieldsContext.recentEdits[
57
+ modifiedFieldsContext.recentEdits.length - 1
58
+ ];
54
59
 
55
60
  if (!lastEdit) return;
56
61
 
@@ -62,7 +67,7 @@ export function PageViewer({
62
67
  }
63
68
 
64
69
  const element =
65
- pageViewContext?.editorIframeRef.current?.contentWindow?.document.querySelector(
70
+ pageViewContext?.editorIframe?.contentWindow?.document.querySelector(
66
71
  `[data-fieldid="${lastEdit.fieldId}"][data-itemid="${lastEdit.item.id}"][data-language="${lastEdit.item.language}"][data-version="${lastEdit.item.version}"]`,
67
72
  );
68
73
 
@@ -62,7 +62,7 @@ export function PageViewerFrame({
62
62
 
63
63
  const editContextRef = useEditContextRef();
64
64
 
65
- const iframeRef = pageViewContext.editorIframeRef;
65
+ const iframeRef = useRef<HTMLIFrameElement | null>(null);
66
66
 
67
67
  const [showSpinner, setShowSpinner] = useState(false);
68
68
  const [scroll, setScroll] = useState(0);
@@ -118,10 +118,10 @@ export function PageViewerFrame({
118
118
 
119
119
  const pageItemDescriptor = pageViewContext.pageItemDescriptor;
120
120
 
121
+ // Update the context whenever the iframe ref changes
121
122
  useEffect(() => {
122
- //Workaround for iframeref updates not propagating to usePageViewContext
123
- pageViewContext.setWorkaround((x) => !x);
124
- }, [iframeRef.current]);
123
+ pageViewContext.setEditorIframe(iframeRef.current);
124
+ }, [iframeRef.current, pageViewContext.setEditorIframe]);
125
125
 
126
126
  const updateMiniMapVisibility = useDebouncedCallback(() => {
127
127
  if (!iframeRef.current) return;
@@ -17,7 +17,10 @@ export type PageViewContext = {
17
17
  setScroll: React.Dispatch<React.SetStateAction<number>>;
18
18
  fullscreen: boolean;
19
19
  setFullscreen: React.Dispatch<React.SetStateAction<boolean>>;
20
- editorIframeRef: React.RefObject<HTMLIFrameElement | null>;
20
+ editorIframe: HTMLIFrameElement | null;
21
+ setEditorIframe: React.Dispatch<
22
+ React.SetStateAction<HTMLIFrameElement | null>
23
+ >;
21
24
  deviceWidth?: number;
22
25
  deviceHeight?: number;
23
26
  setDeviceWidth: React.Dispatch<React.SetStateAction<number | undefined>>;
@@ -32,7 +35,6 @@ export type PageViewContext = {
32
35
  React.SetStateAction<PageSkeleton | undefined>
33
36
  >;
34
37
  viewport: { width: number; height: number };
35
- setWorkaround: React.Dispatch<React.SetStateAction<boolean>>;
36
38
  isHeadless: boolean;
37
39
  site?: Site;
38
40
  editUrl?: string;
@@ -52,13 +54,14 @@ export function usePageViewContext({
52
54
  const [zoom, setZoom] = useState<number>(1);
53
55
  const [scroll, setScroll] = useState<number>(0);
54
56
  const [fullscreen, setFullscreen] = useState<boolean>(false);
55
- const editorIframeRef = useRef<HTMLIFrameElement | null>(null);
57
+ const [editorIframe, setEditorIframe] = useState<HTMLIFrameElement | null>(
58
+ null,
59
+ );
56
60
  const [deviceWidth, setDeviceWidth] = useState<number>();
57
61
  const [deviceHeight, setDeviceHeight] = useState<number>();
58
62
  const [lockHeight, setLockHeight] = useState(true);
59
63
  const [rotate, setRotate] = useState(false);
60
64
  const [viewportRect, setViewportRect] = useState({ width: 0, height: 0 });
61
- const [workaround, setWorkaround] = useState(false);
62
65
  const [site, setSite] = useState<Site>();
63
66
  const [resolvedPageItemDescriptor, setResolvedPageItemDescriptor] =
64
67
  useState<ItemDescriptor>();
@@ -100,17 +103,15 @@ export function usePageViewContext({
100
103
  updateViewportRectDebounced();
101
104
  });
102
105
 
103
- if (editorIframeRef.current) {
104
- resizeObserver.observe(editorIframeRef.current);
106
+ if (editorIframe) {
107
+ resizeObserver.observe(editorIframe);
105
108
  }
106
109
 
107
110
  // Cleanup function
108
111
  return () => {
109
- if (editorIframeRef.current) {
110
- resizeObserver.disconnect();
111
- }
112
+ resizeObserver.disconnect();
112
113
  };
113
- }, [editorIframeRef.current, updateViewportRectDebounced]);
114
+ }, [editorIframe, updateViewportRectDebounced]);
114
115
 
115
116
  useEffect(() => {
116
117
  if (!pageItemDescriptor) return;
@@ -161,7 +162,8 @@ export function usePageViewContext({
161
162
  }, [pageItemDescriptor]);
162
163
 
163
164
  function updateViewportRect() {
164
- const rect = editorIframeRef.current?.getBoundingClientRect();
165
+ const rect = editorIframe?.getBoundingClientRect();
166
+
165
167
  if (rect) {
166
168
  setViewportRect((prev) => {
167
169
  // Only update if dimensions actually changed
@@ -173,61 +175,64 @@ export function usePageViewContext({
173
175
  }
174
176
  }
175
177
 
176
- const pageViewContext: PageViewContext = useMemo(() => ({
177
- device,
178
- setDevice,
179
- deviceWidth,
180
- setDeviceWidth,
181
- deviceHeight,
182
- setDeviceHeight,
183
- lockHeight,
184
- setLockHeight,
185
- scroll,
186
- setScroll,
187
- zoom,
188
- setZoom,
189
- fullscreen,
190
- setFullscreen,
191
- editorIframeRef,
192
- rotate,
193
- setRotate,
194
- page,
195
- setPageSkeleton,
196
- viewport: viewportRect,
197
- pageItemDescriptor: resolvedPageItemDescriptor,
198
- setWorkaround,
199
- isHeadless,
200
- site,
201
- editUrl,
202
- previewUrl,
203
- }), [
204
- device,
205
- deviceWidth,
206
- deviceHeight,
207
- lockHeight,
208
- scroll,
209
- zoom,
210
- fullscreen,
211
- rotate,
212
- page,
213
- viewportRect,
214
- resolvedPageItemDescriptor,
215
- isHeadless,
216
- site,
217
- editUrl,
218
- previewUrl,
219
- setDevice,
220
- setDeviceWidth,
221
- setDeviceHeight,
222
- setLockHeight,
223
- setScroll,
224
- setZoom,
225
- setFullscreen,
226
- setRotate,
227
- setPageSkeleton,
228
- setWorkaround,
229
- editorIframeRef
230
- ]);
178
+ const pageViewContext: PageViewContext = useMemo(
179
+ () => ({
180
+ device,
181
+ setDevice,
182
+ deviceWidth,
183
+ setDeviceWidth,
184
+ deviceHeight,
185
+ setDeviceHeight,
186
+ lockHeight,
187
+ setLockHeight,
188
+ scroll,
189
+ setScroll,
190
+ zoom,
191
+ setZoom,
192
+ fullscreen,
193
+ setFullscreen,
194
+ editorIframe,
195
+ setEditorIframe,
196
+ rotate,
197
+ setRotate,
198
+ page,
199
+ setPageSkeleton,
200
+ viewport: viewportRect,
201
+ pageItemDescriptor: resolvedPageItemDescriptor,
202
+ isHeadless,
203
+ site,
204
+ editUrl,
205
+ previewUrl,
206
+ }),
207
+ [
208
+ device,
209
+ deviceWidth,
210
+ deviceHeight,
211
+ lockHeight,
212
+ scroll,
213
+ zoom,
214
+ fullscreen,
215
+ rotate,
216
+ page,
217
+ viewportRect,
218
+ resolvedPageItemDescriptor,
219
+ isHeadless,
220
+ site,
221
+ editUrl,
222
+ previewUrl,
223
+ setDevice,
224
+ setDeviceWidth,
225
+ setDeviceHeight,
226
+ setLockHeight,
227
+ setScroll,
228
+ setZoom,
229
+ setFullscreen,
230
+ setRotate,
231
+ setPageSkeleton,
232
+ editorIframe,
233
+ setEditorIframe,
234
+ ],
235
+ );
231
236
 
232
237
  return pageViewContext;
233
238
  }
@@ -1,4 +1,4 @@
1
- import { AiContext } from "../ai/AiTerminal";
1
+ import { AiContext, Message } from "../ai/AiTerminal";
2
2
 
3
3
  export const AGENT_BASE_URL = "/alpaca/editor/agent";
4
4
 
@@ -297,6 +297,13 @@ async function processEventStream(
297
297
  }
298
298
  } catch (error) {
299
299
  console.error("Failed to parse SSE message:", error, line);
300
+ // Send error message to the client to notify user
301
+ onMessage({
302
+ type: AgentStreamMessageType.Error,
303
+ error: `Failed to parse stream message: ${error instanceof Error ? error.message : "Unknown parsing error"}`,
304
+ data: null,
305
+ timestamp: new Date().toISOString(),
306
+ });
300
307
  }
301
308
  }
302
309
  }
@@ -466,3 +473,124 @@ export async function cancelAgent(
466
473
 
467
474
  return await response.json();
468
475
  }
476
+
477
+ /**
478
+ * Permanently deletes an agent and all its messages
479
+ */
480
+ export async function deleteAgent(
481
+ agentId: string,
482
+ context: AiContext,
483
+ ): Promise<any> {
484
+ const response = await fetch(AGENT_BASE_URL + "/deleteAgent", {
485
+ method: "POST",
486
+ headers: {
487
+ "Content-Type": "application/json",
488
+ },
489
+ body: JSON.stringify({ agentId }),
490
+ });
491
+
492
+ if (!response.ok) {
493
+ throw new Error(
494
+ `Failed to delete agent: ${response.status} ${response.statusText}`,
495
+ );
496
+ }
497
+
498
+ return await response.json();
499
+ }
500
+
501
+ /**
502
+ * Closes an agent by canceling execution and setting status to closed
503
+ */
504
+ export async function closeAgent(
505
+ agentId: string,
506
+ context: AiContext,
507
+ ): Promise<any> {
508
+ const response = await fetch(AGENT_BASE_URL + "/closeAgent", {
509
+ method: "POST",
510
+ headers: {
511
+ "Content-Type": "application/json",
512
+ },
513
+ body: JSON.stringify({ agentId }),
514
+ });
515
+
516
+ if (!response.ok) {
517
+ throw new Error(
518
+ `Failed to close agent: ${response.status} ${response.statusText}`,
519
+ );
520
+ }
521
+
522
+ return await response.json();
523
+ }
524
+
525
+ /**
526
+ * Checks if an agent exists and returns its current state with messages
527
+ */
528
+ export async function checkAgentState(
529
+ agentId: string,
530
+ context: AiContext,
531
+ ): Promise<{ exists: boolean; agent?: AgentChat; isRunning: boolean }> {
532
+ try {
533
+ const agent = await getAgent(agentId, context);
534
+ return {
535
+ exists: true,
536
+ agent,
537
+ isRunning: agent.status === "Active",
538
+ };
539
+ } catch (error) {
540
+ // If agent doesn't exist, return false
541
+ return {
542
+ exists: false,
543
+ isRunning: false,
544
+ };
545
+ }
546
+ }
547
+
548
+ /**
549
+ * Converts persisted agent messages to the format expected by AiTerminal
550
+ */
551
+ export function convertAgentMessagesToTerminalFormat(
552
+ agentMessages: AgentChatMessage[],
553
+ ): Message[] {
554
+ const terminalMessages: Message[] = [];
555
+
556
+ for (const agentMessage of agentMessages) {
557
+ // Convert assistant and user messages
558
+ if (agentMessage.role === "assistant" || agentMessage.role === "user") {
559
+ const terminalMessage: Message = {
560
+ id: agentMessage.id,
561
+ content: agentMessage.content,
562
+ name: agentMessage.name,
563
+ role: agentMessage.role,
564
+ tool_calls: [],
565
+ };
566
+
567
+ // Add tool calls if they exist
568
+ if (agentMessage.toolCalls && agentMessage.toolCalls.length > 0) {
569
+ terminalMessage.tool_calls = agentMessage.toolCalls.map((tc) => ({
570
+ id: tc.toolCallId,
571
+ displayName: tc.functionName,
572
+ function: {
573
+ name: tc.functionName,
574
+ arguments: tc.functionArguments,
575
+ },
576
+ }));
577
+ }
578
+
579
+ terminalMessages.push(terminalMessage);
580
+ }
581
+ // Convert tool result messages
582
+ else if (agentMessage.role === "tool") {
583
+ const terminalMessage: Message = {
584
+ id: agentMessage.id,
585
+ content: agentMessage.content,
586
+ name: agentMessage.name,
587
+ role: agentMessage.role,
588
+ tool_call_id: agentMessage.toolCallId,
589
+ };
590
+
591
+ terminalMessages.push(terminalMessage);
592
+ }
593
+ }
594
+
595
+ return terminalMessages;
596
+ }
@@ -14,7 +14,7 @@ export type AiProfile = {
14
14
  id: string;
15
15
  name: string;
16
16
  instructions: string;
17
- defaultModel: string | null; // Guid as string, nullable
17
+ defaultModelId: string | null; // Guid as string, nullable
18
18
  models: AiModel[]; // Array of model objects with id and name
19
19
  prompts: { prompt: string; title: string }[];
20
20
  errorMessage?: string;
@@ -87,6 +87,7 @@ export interface ExecutePromptOptions {
87
87
  addContextContent?: boolean;
88
88
  addAllContent?: boolean;
89
89
  profile?: string;
90
+ endpoint?: string;
90
91
  }
91
92
 
92
93
  // Unified function signature
@@ -103,7 +104,6 @@ export async function executePrompt(
103
104
  callback?: (response: any) => void,
104
105
  stream?: boolean,
105
106
  ): Promise<ExecutePromptResponse | null> {
106
- let endpoint: string;
107
107
  let requestBody: any;
108
108
  let finalRequestOptions: RequestInit;
109
109
 
@@ -121,9 +121,6 @@ export async function executePrompt(
121
121
  }
122
122
  }
123
123
 
124
- // Use hardcoded endpoint for old prompt system
125
- endpoint = "/alpaca/editor/ai/Prompt";
126
-
127
124
  // Build unified request body
128
125
  requestBody = {
129
126
  messages,
@@ -135,8 +132,6 @@ export async function executePrompt(
135
132
  ...options,
136
133
  };
137
134
 
138
- console.log("ExecutePrompt: requestBody", requestBody);
139
-
140
135
  finalRequestOptions = {
141
136
  method: "POST",
142
137
  body: JSON.stringify(requestBody),
@@ -147,6 +142,9 @@ export async function executePrompt(
147
142
  ...requestOptions,
148
143
  };
149
144
 
145
+ // Use hardcoded endpoint for old prompt system
146
+ const endpoint = options.endpoint || "/alpaca/editor/ai/prompt";
147
+
150
148
  const response = await fetch(endpoint, finalRequestOptions);
151
149
 
152
150
  if (!response.ok) {
@@ -258,21 +258,22 @@ export function GraphQL() {
258
258
  <Splitter layout="horizontal" style={{ height: "100%" }}>
259
259
  <SplitterPanel size={50} className="relative">
260
260
  <div className="absolute inset-0 flex items-stretch">
261
- <div className="min-w-0 flex-1">
262
- <CodeEditor
263
- value={query}
264
- language="graphql"
265
- placeholder="Enter your GraphQL query here..."
266
- onChange={(evn: any) => setQuery(evn.target.value)}
267
- padding={15}
268
- style={{
269
- fontSize: 12,
270
- backgroundColor: "#f8f9fa",
271
- fontFamily:
272
- "ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace",
273
- height: "100%",
274
- }}
275
- />
261
+ <div className="relative min-w-0 flex-1">
262
+ <div className="absolute inset-0 overflow-auto">
263
+ <CodeEditor
264
+ value={query}
265
+ language="graphql"
266
+ placeholder="Enter your GraphQL query here..."
267
+ onChange={(evn: any) => setQuery(evn.target.value)}
268
+ padding={15}
269
+ style={{
270
+ fontSize: 12,
271
+ backgroundColor: "#f8f9fa",
272
+ fontFamily:
273
+ "ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace",
274
+ }}
275
+ />
276
+ </div>
276
277
  </div>
277
278
  <ActionButton
278
279
  onClick={refresh}