@alpaca-editor/core 1.0.4101 → 1.0.4103

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.
@@ -1,2 +1,2 @@
1
- export declare const version = "1.0.4101";
2
- export declare const buildDate = "2025-09-22 15:29:23";
1
+ export declare const version = "1.0.4103";
2
+ export declare const buildDate = "2025-09-23 01:47:30";
package/dist/revision.js CHANGED
@@ -1,3 +1,3 @@
1
- export const version = "1.0.4101";
2
- export const buildDate = "2025-09-22 15:29:23";
1
+ export const version = "1.0.4103";
2
+ export const buildDate = "2025-09-23 01:47:30";
3
3
  //# sourceMappingURL=revision.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alpaca-editor/core",
3
- "version": "1.0.4101",
3
+ "version": "1.0.4103",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -110,7 +110,7 @@ import { ReviewCommands } from "../editor/menubar/toolbar-sections/ReviewCommand
110
110
  import { TranslateStep } from "../page-wizard/steps/TranslateStep";
111
111
  import {
112
112
  BookA,
113
- ClockIcon,
113
+ History,
114
114
  FolderTreeIcon,
115
115
  Ghost,
116
116
  InboxIcon,
@@ -118,7 +118,6 @@ import {
118
118
  Layers,
119
119
  MessageCircleMore,
120
120
  Settings,
121
- SparklesIcon,
122
121
  Users,
123
122
  Bug,
124
123
  Timer,
@@ -515,7 +514,7 @@ export const getConfiguration = (): EditorConfiguration => {
515
514
  {
516
515
  name: "history",
517
516
  title: "History",
518
- icon: <ClockIcon strokeWidth={1} />,
517
+ icon: <History strokeWidth={1} />,
519
518
  leftSidebar: {
520
519
  panels: [
521
520
  {
@@ -273,6 +273,7 @@ const FieldActionsOverlay = React.forwardRef<
273
273
  className="w-auto p-1"
274
274
  align="start"
275
275
  side="bottom"
276
+ data-testid="field-actions-overlay"
276
277
  container={portalContainer}
277
278
  onOpenAutoFocus={(e) => {
278
279
  e.preventDefault();
@@ -18,7 +18,7 @@ type Message = {
18
18
  };
19
19
 
20
20
  export const Terminal = forwardRef<
21
- { submit: () => void },
21
+ { submit: () => void; focusPrompt: () => void },
22
22
  {
23
23
  commandHandler: (
24
24
  text: string,
@@ -26,6 +26,7 @@ export const Terminal = forwardRef<
26
26
  ) => void;
27
27
  prompt: string;
28
28
  setPrompt: (text: string) => void;
29
+ placeholder?: string;
29
30
  onReset: () => void;
30
31
  toolbar?: React.ReactNode;
31
32
  statusbar?: React.ReactNode;
@@ -41,6 +42,7 @@ export const Terminal = forwardRef<
41
42
  commandHandler,
42
43
  prompt,
43
44
  setPrompt,
45
+ placeholder,
44
46
  onReset,
45
47
  toolbar,
46
48
  statusbar,
@@ -196,6 +198,16 @@ export const Terminal = forwardRef<
196
198
 
197
199
  useImperativeHandle(ref, () => ({
198
200
  submit,
201
+ focusPrompt: () => {
202
+ if (inputRef.current) {
203
+ inputRef.current.focus();
204
+ const value = inputRef.current.value || "";
205
+ try {
206
+ inputRef.current.selectionStart = value.length;
207
+ inputRef.current.selectionEnd = value.length;
208
+ } catch {}
209
+ }
210
+ },
199
211
  }));
200
212
 
201
213
  return (
@@ -249,6 +261,10 @@ export const Terminal = forwardRef<
249
261
  rows={4}
250
262
  cols={30}
251
263
  disabled={disabled}
264
+ placeholder={
265
+ placeholder ??
266
+ "Type your message... (Enter to send, Shift+Enter for new line)"
267
+ }
252
268
  />
253
269
  <div className="flex items-center justify-between py-1">
254
270
  {statusbar}
@@ -199,6 +199,9 @@ export function AgentTerminal({
199
199
  const [agent, setAgent] = useState<AgentDetails | undefined>(undefined);
200
200
  const [messages, setMessages] = useState<AgentChatMessage[]>([]);
201
201
  const [prompt, setPrompt] = useState("");
202
+ const [inputPlaceholder, setInputPlaceholder] = useState<string>(
203
+ "Type your message... (Enter to send, Ctrl+Enter for new line)",
204
+ );
202
205
  const [isLoading, setIsLoading] = useState(false);
203
206
  const [isConnecting, setIsConnecting] = useState(false);
204
207
  const [isSubmitting, setIsSubmitting] = useState(false);
@@ -2120,6 +2123,22 @@ export function AgentTerminal({
2120
2123
  ""
2121
2124
  ).trim();
2122
2125
  if (!text) return;
2126
+ if (action.behavior === "compose") {
2127
+ setPrompt(text);
2128
+ setInputPlaceholder(
2129
+ action.placeholder ||
2130
+ "Review and edit, then press Enter to send",
2131
+ );
2132
+ if (textareaRef.current) {
2133
+ try {
2134
+ textareaRef.current.focus();
2135
+ const v = textareaRef.current.value || "";
2136
+ textareaRef.current.selectionStart = v.length;
2137
+ textareaRef.current.selectionEnd = v.length;
2138
+ } catch {}
2139
+ }
2140
+ return;
2141
+ }
2123
2142
  // Stop any current execution before sending the next message
2124
2143
  if (isExecuting) {
2125
2144
  try {
@@ -2155,7 +2174,7 @@ export function AgentTerminal({
2155
2174
  }
2156
2175
  }}
2157
2176
  onKeyDown={handleKeyPress}
2158
- placeholder="Type your message... (Enter to send, Ctrl+Enter for new line)"
2177
+ placeholder={inputPlaceholder}
2159
2178
  className="h-[80px] flex-1 resize-none overflow-y-auto text-xs"
2160
2179
  data-testid="agent-terminal-prompt"
2161
2180
  disabled={isSubmitting}
@@ -15,6 +15,8 @@ type QuickAction = {
15
15
  prompt?: string;
16
16
  value?: string;
17
17
  style?: "primary" | "secondary" | "destructive" | "outline";
18
+ behavior?: "compose" | "submit";
19
+ placeholder?: string;
18
20
  };
19
21
 
20
22
  type ContentSegment =
@@ -173,6 +175,17 @@ function parseContentSegments(
173
175
  prompt: a.prompt,
174
176
  value: a.value,
175
177
  style: a.style,
178
+ behavior:
179
+ a.behavior &&
180
+ (a.behavior === "compose" || a.behavior === "submit")
181
+ ? a.behavior
182
+ : (a as any).submit === false ||
183
+ (a as any).compose === true ||
184
+ (a as any).draft === true ||
185
+ (a as any).mode === "compose"
186
+ ? "compose"
187
+ : undefined,
188
+ placeholder: (a as any).placeholder,
176
189
  };
177
190
  if (action.label) actions.push(action);
178
191
  });
@@ -271,6 +284,17 @@ function parseContentSegments(
271
284
  prompt: a.prompt,
272
285
  value: a.value,
273
286
  style: a.style,
287
+ behavior:
288
+ a.behavior &&
289
+ (a.behavior === "compose" || a.behavior === "submit")
290
+ ? a.behavior
291
+ : (a as any).submit === false ||
292
+ (a as any).compose === true ||
293
+ (a as any).draft === true ||
294
+ (a as any).mode === "compose"
295
+ ? "compose"
296
+ : undefined,
297
+ placeholder: (a as any).placeholder,
274
298
  };
275
299
  if (action.label) actions.push(action);
276
300
  });
@@ -334,7 +358,13 @@ export function AiResponseMessage({
334
358
  editOperations: EditOperation[];
335
359
  error?: string;
336
360
  onQuickAction?: (
337
- action: { label: string; prompt?: string; value?: string },
361
+ action: {
362
+ label: string;
363
+ prompt?: string;
364
+ value?: string;
365
+ behavior?: "compose" | "submit";
366
+ placeholder?: string;
367
+ },
338
368
  message: Message,
339
369
  ) => void;
340
370
  }) {
@@ -555,6 +585,8 @@ export function AiResponseMessage({
555
585
  label: a.label,
556
586
  prompt: a.prompt,
557
587
  value: a.value,
588
+ behavior: a.behavior,
589
+ placeholder: a.placeholder,
558
590
  },
559
591
  message,
560
592
  )
@@ -91,12 +91,17 @@ export function AiTerminal({
91
91
  const [initialPromptExecuted, setInitialPromptExecuted] = useState(false);
92
92
  const [agentId] = useState<string>(() => crypto.randomUUID());
93
93
  const selection = editContext.selection;
94
- const terminalRef = useRef<{ submit: () => void }>(null);
94
+ const terminalRef = useRef<{ submit: () => void; focusPrompt: () => void }>(
95
+ null,
96
+ );
95
97
  const [responseMessages, setResponseMessages] = useState<Message[]>(
96
98
  options?.initialMessages || [],
97
99
  );
98
100
  const [showSettings, setShowSettings] = useState(false);
99
101
  const settingsRef = useRef<HTMLDivElement>(null);
102
+ const [inputPlaceholder, setInputPlaceholder] = useState<string | undefined>(
103
+ undefined,
104
+ );
100
105
 
101
106
  useEffect(() => {
102
107
  if (options?.initialPrompt && !initialPromptExecuted && model) {
@@ -287,6 +292,12 @@ export function AiTerminal({
287
292
  ""
288
293
  ).trim();
289
294
  if (!text) return;
295
+ if (action.behavior === "compose") {
296
+ setPrompt(text);
297
+ setInputPlaceholder(action.placeholder);
298
+ setTimeout(() => terminalRef.current?.focusPrompt(), 0);
299
+ return;
300
+ }
290
301
  // Submit this as a new command
291
302
  commandHandler(text, (node, done) => {
292
303
  TerminalService.emit("response", node);
@@ -311,6 +322,12 @@ export function AiTerminal({
311
322
  ""
312
323
  ).trim();
313
324
  if (!text) return;
325
+ if (action.behavior === "compose") {
326
+ setPrompt(text);
327
+ setInputPlaceholder(action.placeholder);
328
+ setTimeout(() => terminalRef.current?.focusPrompt(), 0);
329
+ return;
330
+ }
314
331
  commandHandler(text, (node, done) => {
315
332
  TerminalService.emit("response", node);
316
333
  if (done) TerminalService.emit("response", undefined);
@@ -452,6 +469,7 @@ export function AiTerminal({
452
469
  }
453
470
  prompt={prompt}
454
471
  setPrompt={setPrompt}
472
+ placeholder={inputPlaceholder}
455
473
  statusbar=<div className="flex flex-1 items-center justify-between gap-1">
456
474
  <a
457
475
  className="ml-1 flex cursor-pointer items-center gap-1 text-xs"
@@ -1332,7 +1332,9 @@ export function EditorShell({
1332
1332
  setEditHistory((prev) => {
1333
1333
  const existingOpIndex = prev.findIndex((x) => x.id === op.id);
1334
1334
  if (existingOpIndex >= 0) {
1335
- prev[existingOpIndex] = op;
1335
+ const next = [...prev];
1336
+ next[existingOpIndex] = op;
1337
+ return next;
1336
1338
  }
1337
1339
  return prev;
1338
1340
  });
@@ -1694,7 +1696,6 @@ export function EditorShell({
1694
1696
  ) => {
1695
1697
  if ((!dragObject && !insertOption) || !page) return;
1696
1698
  setDragObject(undefined);
1697
-
1698
1699
 
1699
1700
  if (spotPositionElement && spotPositionAnchor) {
1700
1701
  setInserting({
@@ -1782,7 +1783,6 @@ export function EditorShell({
1782
1783
  id: uuid(),
1783
1784
  description: "Move component",
1784
1785
  } as MoveComponentOperation;
1785
-
1786
1786
  }
1787
1787
  }
1788
1788
 
@@ -244,14 +244,6 @@ export function useSocketMessageHandler(deps: {
244
244
  if (message.type === "edit-operation") {
245
245
  const op = message.payload as EditOperation;
246
246
  if (op.type === "edit-field") {
247
- // Ignore our own edit-field operations to avoid redundant updates
248
- if (
249
- op.sessionId &&
250
- op.sessionId === sessionId &&
251
- (op as any).user?.ai !== true
252
- )
253
- return;
254
-
255
247
  const editFieldOperation = op as any;
256
248
  const field = await itemsRepository.getField({
257
249
  item: {
@@ -293,20 +285,29 @@ export function useSocketMessageHandler(deps: {
293
285
  requestRefresh("immediate");
294
286
  }
295
287
  } else {
296
- itemsRepository.updateFieldValue(
297
- {
298
- fieldId: editFieldOperation.fieldId,
299
- item: {
300
- ...editFieldOperation.mainItem,
301
- id: editFieldOperation.itemId,
288
+ // For our own edit-field ops, skip duplicating local field updates but still continue
289
+ // so the edit history gets refreshed below.
290
+ const isOwnNonAiOperation =
291
+ !!op.sessionId &&
292
+ op.sessionId === sessionId &&
293
+ (op as any).user?.ai !== true;
294
+
295
+ if (!isOwnNonAiOperation) {
296
+ itemsRepository.updateFieldValue(
297
+ {
298
+ fieldId: editFieldOperation.fieldId,
299
+ item: {
300
+ ...editFieldOperation.mainItem,
301
+ id: editFieldOperation.itemId,
302
+ },
302
303
  },
303
- },
304
- editFieldOperation.user ?? { name: "unknown", ai: false },
305
- false,
306
- editFieldOperation.undone
307
- ? editFieldOperation.oldValue
308
- : editFieldOperation.value,
309
- );
304
+ editFieldOperation.user ?? { name: "unknown", ai: false },
305
+ false,
306
+ editFieldOperation.undone
307
+ ? editFieldOperation.oldValue
308
+ : editFieldOperation.value,
309
+ );
310
+ }
310
311
  }
311
312
  } else {
312
313
  // For non-field operations, refresh only if the current page matches the operation's main item
package/src/revision.ts CHANGED
@@ -1,2 +1,2 @@
1
- export const version = "1.0.4101";
2
- export const buildDate = "2025-09-22 15:29:23";
1
+ export const version = "1.0.4103";
2
+ export const buildDate = "2025-09-23 01:47:30";