@comergehq/studio 0.1.15 → 0.1.17

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.
package/dist/index.mjs CHANGED
@@ -6,8 +6,8 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
6
6
  });
7
7
 
8
8
  // src/studio/ComergeStudio.tsx
9
- import * as React43 from "react";
10
- import { Platform as RNPlatform, View as View45 } from "react-native";
9
+ import * as React46 from "react";
10
+ import { Platform as RNPlatform, View as View46 } from "react-native";
11
11
  import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
12
12
 
13
13
  // src/studio/bootstrap/StudioBootstrap.tsx
@@ -816,6 +816,35 @@ function extractMeta(payload) {
816
816
  threadId: typeof obj.threadId === "string" ? obj.threadId : void 0
817
817
  };
818
818
  }
819
+ function getPayloadMeta(payload) {
820
+ const meta = payload == null ? void 0 : payload.meta;
821
+ if (!meta || typeof meta !== "object") return null;
822
+ return meta;
823
+ }
824
+ function isQueuedHiddenMessage(m) {
825
+ if (m.authorType !== "human") return false;
826
+ const meta = getPayloadMeta(m.payload);
827
+ return (meta == null ? void 0 : meta.visibility) === "queued";
828
+ }
829
+ function toEpochMs(value) {
830
+ if (value == null) return 0;
831
+ if (typeof value === "number") return value;
832
+ if (value instanceof Date) return value.getTime();
833
+ const parsed = Date.parse(String(value));
834
+ return Number.isFinite(parsed) ? parsed : 0;
835
+ }
836
+ function getEffectiveSortMs(m) {
837
+ const meta = getPayloadMeta(m.payload);
838
+ const runStartedAt = meta == null ? void 0 : meta.runStartedAt;
839
+ const runMs = toEpochMs(runStartedAt);
840
+ return runMs > 0 ? runMs : toEpochMs(m.createdAt);
841
+ }
842
+ function compareMessages(a, b) {
843
+ const aMs = getEffectiveSortMs(a);
844
+ const bMs = getEffectiveSortMs(b);
845
+ if (aMs !== bMs) return aMs - bMs;
846
+ return String(a.createdAt).localeCompare(String(b.createdAt));
847
+ }
819
848
  function mapMessageToChatMessage(m) {
820
849
  var _a, _b;
821
850
  const kind = typeof ((_a = m.payload) == null ? void 0 : _a.type) === "string" ? String(m.payload.type) : null;
@@ -835,8 +864,9 @@ function useThreadMessages(threadId) {
835
864
  const activeRequestIdRef = React4.useRef(0);
836
865
  const foregroundSignal = useForegroundSignal(Boolean(threadId));
837
866
  const upsertSorted = React4.useCallback((prev, m) => {
838
- const next = prev.some((x) => x.id === m.id) ? prev.map((x) => x.id === m.id ? m : x) : [...prev, m];
839
- next.sort((a, b) => String(a.createdAt).localeCompare(String(b.createdAt)));
867
+ const next = prev.filter((x) => x.id !== m.id);
868
+ next.push(m);
869
+ next.sort(compareMessages);
840
870
  return next;
841
871
  }, []);
842
872
  const refetch = React4.useCallback(async () => {
@@ -850,7 +880,7 @@ function useThreadMessages(threadId) {
850
880
  try {
851
881
  const list = await messagesRepository.list(threadId);
852
882
  if (activeRequestIdRef.current !== requestId) return;
853
- setRaw([...list].sort((a, b) => String(a.createdAt).localeCompare(String(b.createdAt))));
883
+ setRaw([...list].sort(compareMessages));
854
884
  } catch (e) {
855
885
  if (activeRequestIdRef.current !== requestId) return;
856
886
  setError(e instanceof Error ? e : new Error(String(e)));
@@ -876,7 +906,11 @@ function useThreadMessages(threadId) {
876
906
  if (foregroundSignal <= 0) return;
877
907
  void refetch();
878
908
  }, [foregroundSignal, refetch, threadId]);
879
- const messages = React4.useMemo(() => raw.map(mapMessageToChatMessage), [raw]);
909
+ const messages = React4.useMemo(() => {
910
+ const visible = raw.filter((m) => !isQueuedHiddenMessage(m));
911
+ const resolved = visible.length > 0 ? visible : raw;
912
+ return resolved.map(mapMessageToChatMessage);
913
+ }, [raw]);
880
914
  return { raw, messages, loading, error, refetch };
881
915
  }
882
916
 
@@ -1902,6 +1936,9 @@ function useStudioActions({
1902
1936
  userId,
1903
1937
  app,
1904
1938
  onForkedApp,
1939
+ onEditStart,
1940
+ onEditQueued,
1941
+ onEditFinished,
1905
1942
  uploadAttachments
1906
1943
  }) {
1907
1944
  const [forking, setForking] = React8.useState(false);
@@ -1928,16 +1965,21 @@ function useStudioActions({
1928
1965
  setForking(false);
1929
1966
  const threadId = targetApp.threadId;
1930
1967
  if (!threadId) throw new Error("No thread available for this app.");
1968
+ onEditStart == null ? void 0 : onEditStart();
1931
1969
  let attachmentMetas;
1932
1970
  if (attachments && attachments.length > 0 && uploadAttachments) {
1933
1971
  attachmentMetas = await uploadAttachments({ threadId, appId: targetApp.id, dataUrls: attachments });
1934
1972
  }
1935
- await agentRepository.editApp({
1973
+ const editResult = await agentRepository.editApp({
1936
1974
  prompt,
1937
1975
  thread_id: threadId,
1938
1976
  app_id: targetApp.id,
1939
1977
  attachments: attachmentMetas && attachmentMetas.length > 0 ? attachmentMetas : void 0
1940
1978
  });
1979
+ onEditQueued == null ? void 0 : onEditQueued({
1980
+ queueItemId: editResult.queueItemId ?? null,
1981
+ queuePosition: editResult.queuePosition ?? null
1982
+ });
1941
1983
  } catch (e) {
1942
1984
  const err = e instanceof Error ? e : new Error(String(e));
1943
1985
  setError(err);
@@ -1945,32 +1987,14 @@ function useStudioActions({
1945
1987
  } finally {
1946
1988
  setForking(false);
1947
1989
  setSending(false);
1990
+ onEditFinished == null ? void 0 : onEditFinished();
1948
1991
  }
1949
1992
  },
1950
- [app, onForkedApp, sending, shouldForkOnEdit, uploadAttachments, userId]
1993
+ [app, onEditFinished, onEditQueued, onEditStart, onForkedApp, sending, shouldForkOnEdit, uploadAttachments, userId]
1951
1994
  );
1952
1995
  return { isOwner, shouldForkOnEdit, forking, sending, error, sendEdit };
1953
1996
  }
1954
1997
 
1955
- // src/studio/lib/chat.ts
1956
- function hasNoOutcomeAfterLastHuman(messages) {
1957
- if (!messages || messages.length === 0) return false;
1958
- let lastHumanIndex = -1;
1959
- for (let i = messages.length - 1; i >= 0; i -= 1) {
1960
- if (messages[i].authorType === "human") {
1961
- lastHumanIndex = i;
1962
- break;
1963
- }
1964
- }
1965
- if (lastHumanIndex === -1) return false;
1966
- for (let i = lastHumanIndex + 1; i < messages.length; i += 1) {
1967
- const m = messages[i];
1968
- const payload = m.payload;
1969
- if (m.authorType === "ai" && (payload == null ? void 0 : payload.type) === "outcome") return false;
1970
- }
1971
- return true;
1972
- }
1973
-
1974
1998
  // src/studio/ui/RuntimeRenderer.tsx
1975
1999
  import * as React9 from "react";
1976
2000
  import { View as View2 } from "react-native";
@@ -2008,8 +2032,8 @@ function RuntimeRenderer({
2008
2032
  }
2009
2033
 
2010
2034
  // src/studio/ui/StudioOverlay.tsx
2011
- import * as React42 from "react";
2012
- import { Keyboard as Keyboard5, Platform as Platform10, View as View44, useWindowDimensions as useWindowDimensions4 } from "react-native";
2035
+ import * as React43 from "react";
2036
+ import { Keyboard as Keyboard5, Platform as Platform10, View as View45, useWindowDimensions as useWindowDimensions4 } from "react-native";
2013
2037
 
2014
2038
  // src/components/studio-sheet/StudioBottomSheet.tsx
2015
2039
  import * as React12 from "react";
@@ -5869,8 +5893,8 @@ function PreviewPanel({
5869
5893
  }
5870
5894
 
5871
5895
  // src/studio/ui/ChatPanel.tsx
5872
- import * as React39 from "react";
5873
- import { ActivityIndicator as ActivityIndicator8, View as View41 } from "react-native";
5896
+ import * as React40 from "react";
5897
+ import { ActivityIndicator as ActivityIndicator9, View as View42 } from "react-native";
5874
5898
 
5875
5899
  // src/components/chat/ChatPage.tsx
5876
5900
  import * as React37 from "react";
@@ -6067,6 +6091,7 @@ function ChatPage({
6067
6091
  showTypingIndicator,
6068
6092
  renderMessageContent,
6069
6093
  topBanner,
6094
+ composerTop,
6070
6095
  composer,
6071
6096
  overlay,
6072
6097
  style,
@@ -6077,6 +6102,7 @@ function ChatPage({
6077
6102
  const theme = useTheme();
6078
6103
  const insets = useSafeAreaInsets4();
6079
6104
  const [composerHeight, setComposerHeight] = React37.useState(0);
6105
+ const [composerTopHeight, setComposerTopHeight] = React37.useState(0);
6080
6106
  const [keyboardVisible, setKeyboardVisible] = React37.useState(false);
6081
6107
  React37.useEffect(() => {
6082
6108
  if (Platform9.OS !== "ios") return;
@@ -6088,8 +6114,9 @@ function ChatPage({
6088
6114
  };
6089
6115
  }, []);
6090
6116
  const footerBottomPadding = Platform9.OS === "ios" ? keyboardVisible ? 0 : insets.bottom : insets.bottom + 10;
6091
- const overlayBottom = composerHeight + footerBottomPadding + theme.spacing.lg;
6092
- const bottomInset = composerHeight + footerBottomPadding + theme.spacing.xl;
6117
+ const totalComposerHeight = composerHeight + composerTopHeight;
6118
+ const overlayBottom = totalComposerHeight + footerBottomPadding + theme.spacing.lg;
6119
+ const bottomInset = totalComposerHeight + footerBottomPadding + theme.spacing.xl;
6093
6120
  const resolvedOverlay = React37.useMemo(() => {
6094
6121
  var _a;
6095
6122
  if (!overlay) return null;
@@ -6099,6 +6126,10 @@ function ChatPage({
6099
6126
  style: [prevStyle, { bottom: overlayBottom }]
6100
6127
  });
6101
6128
  }, [overlay, overlayBottom]);
6129
+ React37.useEffect(() => {
6130
+ if (composerTop) return;
6131
+ setComposerTopHeight(0);
6132
+ }, [composerTop]);
6102
6133
  return /* @__PURE__ */ jsxs29(View37, { style: [{ flex: 1 }, style], children: [
6103
6134
  header ? /* @__PURE__ */ jsx49(View37, { children: header }) : null,
6104
6135
  topBanner ? /* @__PURE__ */ jsx49(View37, { style: { paddingHorizontal: theme.spacing.lg, paddingTop: theme.spacing.sm }, children: topBanner }) : null,
@@ -6123,7 +6154,7 @@ function ChatPage({
6123
6154
  ]
6124
6155
  }
6125
6156
  ),
6126
- /* @__PURE__ */ jsx49(
6157
+ /* @__PURE__ */ jsxs29(
6127
6158
  View37,
6128
6159
  {
6129
6160
  style: {
@@ -6135,14 +6166,24 @@ function ChatPage({
6135
6166
  paddingTop: theme.spacing.sm,
6136
6167
  paddingBottom: footerBottomPadding
6137
6168
  },
6138
- children: /* @__PURE__ */ jsx49(
6139
- ChatComposer,
6140
- {
6141
- ...composer,
6142
- attachments: composer.attachments ?? [],
6143
- onLayout: ({ height }) => setComposerHeight(height)
6144
- }
6145
- )
6169
+ children: [
6170
+ composerTop ? /* @__PURE__ */ jsx49(
6171
+ View37,
6172
+ {
6173
+ style: { marginBottom: theme.spacing.sm },
6174
+ onLayout: (e) => setComposerTopHeight(e.nativeEvent.layout.height),
6175
+ children: composerTop
6176
+ }
6177
+ ) : null,
6178
+ /* @__PURE__ */ jsx49(
6179
+ ChatComposer,
6180
+ {
6181
+ ...composer,
6182
+ attachments: composer.attachments ?? [],
6183
+ onLayout: ({ height }) => setComposerHeight(height)
6184
+ }
6185
+ )
6186
+ ]
6146
6187
  }
6147
6188
  )
6148
6189
  ] })
@@ -6292,8 +6333,154 @@ function ForkNoticeBanner({ isOwner = true, title, description, style }) {
6292
6333
  );
6293
6334
  }
6294
6335
 
6295
- // src/studio/ui/ChatPanel.tsx
6336
+ // src/components/chat/ChatQueue.tsx
6337
+ import * as React39 from "react";
6338
+ import { ActivityIndicator as ActivityIndicator8, Pressable as Pressable13, View as View41 } from "react-native";
6296
6339
  import { jsx as jsx53, jsxs as jsxs31 } from "react/jsx-runtime";
6340
+ function ChatQueue({ items, onRemove }) {
6341
+ const theme = useTheme();
6342
+ const [expanded, setExpanded] = React39.useState({});
6343
+ const [canExpand, setCanExpand] = React39.useState({});
6344
+ const [collapsedText, setCollapsedText] = React39.useState({});
6345
+ const [removing, setRemoving] = React39.useState({});
6346
+ const buildCollapsedText = React39.useCallback((lines) => {
6347
+ var _a, _b;
6348
+ const line1 = ((_a = lines[0]) == null ? void 0 : _a.text) ?? "";
6349
+ const line2 = ((_b = lines[1]) == null ? void 0 : _b.text) ?? "";
6350
+ const moreLabel = "more";
6351
+ const reserve = `\u2026 ${moreLabel}`.length;
6352
+ let trimmedLine2 = line2;
6353
+ if (trimmedLine2.length > reserve) {
6354
+ trimmedLine2 = trimmedLine2.slice(0, Math.max(0, trimmedLine2.length - reserve));
6355
+ } else {
6356
+ trimmedLine2 = "";
6357
+ }
6358
+ trimmedLine2 = trimmedLine2.replace(/\s+$/, "");
6359
+ return `${line1}
6360
+ ${trimmedLine2}\u2026 `;
6361
+ }, []);
6362
+ React39.useEffect(() => {
6363
+ if (items.length === 0) return;
6364
+ const ids = new Set(items.map((item) => item.id));
6365
+ setExpanded((prev) => Object.fromEntries(Object.entries(prev).filter(([id]) => ids.has(id))));
6366
+ setCanExpand((prev) => Object.fromEntries(Object.entries(prev).filter(([id]) => ids.has(id))));
6367
+ setCollapsedText((prev) => Object.fromEntries(Object.entries(prev).filter(([id]) => ids.has(id))));
6368
+ setRemoving((prev) => Object.fromEntries(Object.entries(prev).filter(([id]) => ids.has(id))));
6369
+ }, [items]);
6370
+ if (items.length === 0) return null;
6371
+ return /* @__PURE__ */ jsxs31(
6372
+ View41,
6373
+ {
6374
+ style: {
6375
+ borderWidth: 1,
6376
+ borderColor: theme.colors.border,
6377
+ borderRadius: theme.radii.lg,
6378
+ marginHorizontal: theme.spacing.md,
6379
+ padding: theme.spacing.md,
6380
+ backgroundColor: "transparent"
6381
+ },
6382
+ children: [
6383
+ /* @__PURE__ */ jsx53(Text, { variant: "caption", style: { marginBottom: theme.spacing.sm }, children: "Queue" }),
6384
+ /* @__PURE__ */ jsx53(View41, { style: { gap: theme.spacing.sm }, children: items.map((item) => {
6385
+ const isExpanded = Boolean(expanded[item.id]);
6386
+ const showToggle = Boolean(canExpand[item.id]);
6387
+ const prompt = item.prompt ?? "";
6388
+ const moreLabel = "more";
6389
+ const displayPrompt = !isExpanded && showToggle && collapsedText[item.id] ? collapsedText[item.id] : prompt;
6390
+ const isRemoving = Boolean(removing[item.id]);
6391
+ return /* @__PURE__ */ jsxs31(
6392
+ View41,
6393
+ {
6394
+ style: {
6395
+ flexDirection: "row",
6396
+ alignItems: "flex-start",
6397
+ gap: theme.spacing.sm,
6398
+ paddingHorizontal: theme.spacing.md,
6399
+ paddingVertical: theme.spacing.sm,
6400
+ borderRadius: theme.radii.md,
6401
+ backgroundColor: withAlpha(theme.colors.surface, theme.scheme === "dark" ? 0.8 : 0.9)
6402
+ },
6403
+ children: [
6404
+ /* @__PURE__ */ jsxs31(View41, { style: { flex: 1 }, children: [
6405
+ !canExpand[item.id] ? /* @__PURE__ */ jsx53(
6406
+ Text,
6407
+ {
6408
+ style: { position: "absolute", opacity: 0, zIndex: -1, width: "100%" },
6409
+ onTextLayout: (e) => {
6410
+ var _a;
6411
+ const lines = (_a = e.nativeEvent) == null ? void 0 : _a.lines;
6412
+ if (!lines) return;
6413
+ if (lines.length > 2) {
6414
+ setCanExpand((prev) => ({ ...prev, [item.id]: true }));
6415
+ setCollapsedText((prev) => ({
6416
+ ...prev,
6417
+ [item.id]: buildCollapsedText(lines)
6418
+ }));
6419
+ }
6420
+ },
6421
+ children: prompt
6422
+ }
6423
+ ) : null,
6424
+ /* @__PURE__ */ jsxs31(
6425
+ Text,
6426
+ {
6427
+ variant: "bodyMuted",
6428
+ numberOfLines: isExpanded ? void 0 : 2,
6429
+ children: [
6430
+ displayPrompt,
6431
+ !isExpanded && showToggle ? /* @__PURE__ */ jsx53(
6432
+ Text,
6433
+ {
6434
+ color: theme.colors.text,
6435
+ onPress: () => setExpanded((prev) => ({ ...prev, [item.id]: true })),
6436
+ suppressHighlighting: true,
6437
+ children: moreLabel
6438
+ }
6439
+ ) : null
6440
+ ]
6441
+ }
6442
+ ),
6443
+ showToggle && isExpanded ? /* @__PURE__ */ jsx53(
6444
+ Pressable13,
6445
+ {
6446
+ onPress: () => setExpanded((prev) => ({ ...prev, [item.id]: false })),
6447
+ hitSlop: 6,
6448
+ style: { alignSelf: "flex-start", marginTop: 4 },
6449
+ children: /* @__PURE__ */ jsx53(Text, { variant: "captionMuted", color: theme.colors.text, children: "less" })
6450
+ }
6451
+ ) : null
6452
+ ] }),
6453
+ /* @__PURE__ */ jsx53(
6454
+ Pressable13,
6455
+ {
6456
+ onPress: () => {
6457
+ if (!onRemove || isRemoving) return;
6458
+ setRemoving((prev) => ({ ...prev, [item.id]: true }));
6459
+ Promise.resolve(onRemove(item.id)).finally(() => {
6460
+ setRemoving((prev) => {
6461
+ if (!prev[item.id]) return prev;
6462
+ const { [item.id]: _removed, ...rest } = prev;
6463
+ return rest;
6464
+ });
6465
+ });
6466
+ },
6467
+ hitSlop: 8,
6468
+ style: { alignSelf: "center" },
6469
+ children: isRemoving ? /* @__PURE__ */ jsx53(ActivityIndicator8, { size: "small", color: theme.colors.text }) : /* @__PURE__ */ jsx53(IconClose, { size: 14, colorToken: "text" })
6470
+ }
6471
+ )
6472
+ ]
6473
+ },
6474
+ item.id
6475
+ );
6476
+ }) })
6477
+ ]
6478
+ }
6479
+ );
6480
+ }
6481
+
6482
+ // src/studio/ui/ChatPanel.tsx
6483
+ import { jsx as jsx54, jsxs as jsxs32 } from "react/jsx-runtime";
6297
6484
  function ChatPanel({
6298
6485
  title = "Chat",
6299
6486
  autoFocusComposer = false,
@@ -6311,11 +6498,13 @@ function ChatPanel({
6311
6498
  onClose,
6312
6499
  onNavigateHome,
6313
6500
  onStartDraw,
6314
- onSend
6501
+ onSend,
6502
+ queueItems = [],
6503
+ onRemoveQueueItem
6315
6504
  }) {
6316
- const listRef = React39.useRef(null);
6317
- const [nearBottom, setNearBottom] = React39.useState(true);
6318
- const handleSend = React39.useCallback(
6505
+ const listRef = React40.useRef(null);
6506
+ const [nearBottom, setNearBottom] = React40.useState(true);
6507
+ const handleSend = React40.useCallback(
6319
6508
  async (text, composerAttachments) => {
6320
6509
  const all = composerAttachments ?? attachments;
6321
6510
  await onSend(text, all.length > 0 ? all : void 0);
@@ -6329,25 +6518,25 @@ function ChatPanel({
6329
6518
  },
6330
6519
  [attachments, nearBottom, onClearAttachments, onSend]
6331
6520
  );
6332
- const handleScrollToBottom = React39.useCallback(() => {
6521
+ const handleScrollToBottom = React40.useCallback(() => {
6333
6522
  var _a;
6334
6523
  (_a = listRef.current) == null ? void 0 : _a.scrollToBottom({ animated: true });
6335
6524
  }, []);
6336
- const header = /* @__PURE__ */ jsx53(
6525
+ const header = /* @__PURE__ */ jsx54(
6337
6526
  ChatHeader,
6338
6527
  {
6339
- left: /* @__PURE__ */ jsxs31(View41, { style: { flexDirection: "row", alignItems: "center" }, children: [
6340
- /* @__PURE__ */ jsx53(StudioSheetHeaderIconButton, { onPress: onBack, accessibilityLabel: "Back", style: { marginRight: 8 }, children: /* @__PURE__ */ jsx53(IconBack, { size: 20, colorToken: "floatingContent" }) }),
6341
- onNavigateHome ? /* @__PURE__ */ jsx53(StudioSheetHeaderIconButton, { onPress: onNavigateHome, accessibilityLabel: "Home", children: /* @__PURE__ */ jsx53(IconHome, { size: 20, colorToken: "floatingContent" }) }) : null
6528
+ left: /* @__PURE__ */ jsxs32(View42, { style: { flexDirection: "row", alignItems: "center" }, children: [
6529
+ /* @__PURE__ */ jsx54(StudioSheetHeaderIconButton, { onPress: onBack, accessibilityLabel: "Back", style: { marginRight: 8 }, children: /* @__PURE__ */ jsx54(IconBack, { size: 20, colorToken: "floatingContent" }) }),
6530
+ onNavigateHome ? /* @__PURE__ */ jsx54(StudioSheetHeaderIconButton, { onPress: onNavigateHome, accessibilityLabel: "Home", children: /* @__PURE__ */ jsx54(IconHome, { size: 20, colorToken: "floatingContent" }) }) : null
6342
6531
  ] }),
6343
- right: /* @__PURE__ */ jsxs31(View41, { style: { flexDirection: "row", alignItems: "center" }, children: [
6344
- onStartDraw ? /* @__PURE__ */ jsx53(StudioSheetHeaderIconButton, { onPress: onStartDraw, accessibilityLabel: "Draw", intent: "danger", style: { marginRight: 8 }, children: /* @__PURE__ */ jsx53(IconDraw, { size: 20, colorToken: "onDanger" }) }) : null,
6345
- /* @__PURE__ */ jsx53(StudioSheetHeaderIconButton, { onPress: onClose, accessibilityLabel: "Close", children: /* @__PURE__ */ jsx53(IconClose, { size: 20, colorToken: "floatingContent" }) })
6532
+ right: /* @__PURE__ */ jsxs32(View42, { style: { flexDirection: "row", alignItems: "center" }, children: [
6533
+ onStartDraw ? /* @__PURE__ */ jsx54(StudioSheetHeaderIconButton, { onPress: onStartDraw, accessibilityLabel: "Draw", intent: "danger", style: { marginRight: 8 }, children: /* @__PURE__ */ jsx54(IconDraw, { size: 20, colorToken: "onDanger" }) }) : null,
6534
+ /* @__PURE__ */ jsx54(StudioSheetHeaderIconButton, { onPress: onClose, accessibilityLabel: "Close", children: /* @__PURE__ */ jsx54(IconClose, { size: 20, colorToken: "floatingContent" }) })
6346
6535
  ] }),
6347
6536
  center: null
6348
6537
  }
6349
6538
  );
6350
- const topBanner = shouldForkOnEdit ? /* @__PURE__ */ jsx53(
6539
+ const topBanner = shouldForkOnEdit ? /* @__PURE__ */ jsx54(
6351
6540
  ForkNoticeBanner,
6352
6541
  {
6353
6542
  isOwner: !shouldForkOnEdit,
@@ -6356,33 +6545,35 @@ function ChatPanel({
6356
6545
  ) : null;
6357
6546
  const showMessagesLoading = Boolean(loading) && messages.length === 0 || forking;
6358
6547
  if (showMessagesLoading) {
6359
- return /* @__PURE__ */ jsxs31(View41, { style: { flex: 1 }, children: [
6360
- /* @__PURE__ */ jsx53(View41, { children: header }),
6361
- topBanner ? /* @__PURE__ */ jsx53(View41, { style: { paddingHorizontal: 16, paddingTop: 8 }, children: topBanner }) : null,
6362
- /* @__PURE__ */ jsxs31(View41, { style: { flex: 1, alignItems: "center", justifyContent: "center", paddingHorizontal: 24, paddingVertical: 12 }, children: [
6363
- /* @__PURE__ */ jsx53(ActivityIndicator8, {}),
6364
- /* @__PURE__ */ jsx53(View41, { style: { height: 12 } }),
6365
- /* @__PURE__ */ jsx53(Text, { variant: "bodyMuted", children: forking ? "Creating your copy\u2026" : "Loading messages\u2026" })
6548
+ return /* @__PURE__ */ jsxs32(View42, { style: { flex: 1 }, children: [
6549
+ /* @__PURE__ */ jsx54(View42, { children: header }),
6550
+ topBanner ? /* @__PURE__ */ jsx54(View42, { style: { paddingHorizontal: 16, paddingTop: 8 }, children: topBanner }) : null,
6551
+ /* @__PURE__ */ jsxs32(View42, { style: { flex: 1, alignItems: "center", justifyContent: "center", paddingHorizontal: 24, paddingVertical: 12 }, children: [
6552
+ /* @__PURE__ */ jsx54(ActivityIndicator9, {}),
6553
+ /* @__PURE__ */ jsx54(View42, { style: { height: 12 } }),
6554
+ /* @__PURE__ */ jsx54(Text, { variant: "bodyMuted", children: forking ? "Creating your copy\u2026" : "Loading messages\u2026" })
6366
6555
  ] })
6367
6556
  ] });
6368
6557
  }
6369
- return /* @__PURE__ */ jsx53(
6558
+ const queueTop = queueItems.length > 0 ? /* @__PURE__ */ jsx54(ChatQueue, { items: queueItems, onRemove: onRemoveQueueItem }) : null;
6559
+ return /* @__PURE__ */ jsx54(
6370
6560
  ChatPage,
6371
6561
  {
6372
6562
  header,
6373
6563
  messages,
6374
6564
  showTypingIndicator,
6375
6565
  topBanner,
6566
+ composerTop: queueTop,
6376
6567
  composerHorizontalPadding: 0,
6377
6568
  listRef,
6378
6569
  onNearBottomChange: setNearBottom,
6379
- overlay: /* @__PURE__ */ jsx53(
6570
+ overlay: /* @__PURE__ */ jsx54(
6380
6571
  ScrollToBottomButton,
6381
6572
  {
6382
6573
  visible: !nearBottom,
6383
6574
  onPress: handleScrollToBottom,
6384
6575
  style: { bottom: 80 },
6385
- children: /* @__PURE__ */ jsx53(IconArrowDown, { size: 20, colorToken: "floatingContent" })
6576
+ children: /* @__PURE__ */ jsx54(IconArrowDown, { size: 20, colorToken: "floatingContent" })
6386
6577
  }
6387
6578
  ),
6388
6579
  composer: {
@@ -6403,16 +6594,16 @@ function ChatPanel({
6403
6594
  }
6404
6595
 
6405
6596
  // src/components/dialogs/ConfirmMergeRequestDialog.tsx
6406
- import * as React40 from "react";
6407
- import { Pressable as Pressable14, View as View43 } from "react-native";
6597
+ import * as React41 from "react";
6598
+ import { Pressable as Pressable15, View as View44 } from "react-native";
6408
6599
 
6409
6600
  // src/components/primitives/Modal.tsx
6410
6601
  import {
6411
6602
  Modal as RNModal,
6412
- Pressable as Pressable13,
6413
- View as View42
6603
+ Pressable as Pressable14,
6604
+ View as View43
6414
6605
  } from "react-native";
6415
- import { jsx as jsx54, jsxs as jsxs32 } from "react/jsx-runtime";
6606
+ import { jsx as jsx55, jsxs as jsxs33 } from "react/jsx-runtime";
6416
6607
  function Modal({
6417
6608
  visible,
6418
6609
  onRequestClose,
@@ -6421,30 +6612,30 @@ function Modal({
6421
6612
  contentStyle
6422
6613
  }) {
6423
6614
  const theme = useTheme();
6424
- return /* @__PURE__ */ jsx54(
6615
+ return /* @__PURE__ */ jsx55(
6425
6616
  RNModal,
6426
6617
  {
6427
6618
  visible,
6428
6619
  transparent: true,
6429
6620
  animationType: "fade",
6430
6621
  onRequestClose,
6431
- children: /* @__PURE__ */ jsxs32(View42, { style: { flex: 1, backgroundColor: theme.colors.backdrop, justifyContent: "center", padding: theme.spacing.lg }, children: [
6432
- /* @__PURE__ */ jsx54(
6433
- Pressable13,
6622
+ children: /* @__PURE__ */ jsxs33(View43, { style: { flex: 1, backgroundColor: theme.colors.backdrop, justifyContent: "center", padding: theme.spacing.lg }, children: [
6623
+ /* @__PURE__ */ jsx55(
6624
+ Pressable14,
6434
6625
  {
6435
6626
  accessibilityRole: "button",
6436
6627
  onPress: dismissOnBackdropPress ? onRequestClose : void 0,
6437
6628
  style: { position: "absolute", inset: 0 }
6438
6629
  }
6439
6630
  ),
6440
- /* @__PURE__ */ jsx54(Card, { variant: "surfaceRaised", padded: true, style: [{ borderRadius: theme.radii.xl }, contentStyle], children })
6631
+ /* @__PURE__ */ jsx55(Card, { variant: "surfaceRaised", padded: true, style: [{ borderRadius: theme.radii.xl }, contentStyle], children })
6441
6632
  ] })
6442
6633
  }
6443
6634
  );
6444
6635
  }
6445
6636
 
6446
6637
  // src/components/dialogs/ConfirmMergeRequestDialog.tsx
6447
- import { jsx as jsx55, jsxs as jsxs33 } from "react/jsx-runtime";
6638
+ import { jsx as jsx56, jsxs as jsxs34 } from "react/jsx-runtime";
6448
6639
  function ConfirmMergeRequestDialog({
6449
6640
  visible,
6450
6641
  onOpenChange,
@@ -6455,14 +6646,14 @@ function ConfirmMergeRequestDialog({
6455
6646
  onTestFirst
6456
6647
  }) {
6457
6648
  const theme = useTheme();
6458
- const close = React40.useCallback(() => onOpenChange(false), [onOpenChange]);
6649
+ const close = React41.useCallback(() => onOpenChange(false), [onOpenChange]);
6459
6650
  const canConfirm = Boolean(mergeRequest) && !approveDisabled;
6460
- const handleConfirm = React40.useCallback(() => {
6651
+ const handleConfirm = React41.useCallback(() => {
6461
6652
  if (!mergeRequest) return;
6462
6653
  onOpenChange(false);
6463
6654
  void onConfirm();
6464
6655
  }, [mergeRequest, onConfirm, onOpenChange]);
6465
- const handleTestFirst = React40.useCallback(() => {
6656
+ const handleTestFirst = React41.useCallback(() => {
6466
6657
  if (!mergeRequest) return;
6467
6658
  onOpenChange(false);
6468
6659
  void onTestFirst(mergeRequest);
@@ -6474,7 +6665,7 @@ function ConfirmMergeRequestDialog({
6474
6665
  justifyContent: "center",
6475
6666
  alignSelf: "stretch"
6476
6667
  };
6477
- return /* @__PURE__ */ jsxs33(
6668
+ return /* @__PURE__ */ jsxs34(
6478
6669
  Modal,
6479
6670
  {
6480
6671
  visible,
@@ -6485,7 +6676,7 @@ function ConfirmMergeRequestDialog({
6485
6676
  backgroundColor: theme.colors.background
6486
6677
  },
6487
6678
  children: [
6488
- /* @__PURE__ */ jsx55(View43, { children: /* @__PURE__ */ jsx55(
6679
+ /* @__PURE__ */ jsx56(View44, { children: /* @__PURE__ */ jsx56(
6489
6680
  Text,
6490
6681
  {
6491
6682
  style: {
@@ -6497,9 +6688,9 @@ function ConfirmMergeRequestDialog({
6497
6688
  children: "Are you sure you want to approve this merge request?"
6498
6689
  }
6499
6690
  ) }),
6500
- /* @__PURE__ */ jsxs33(View43, { style: { marginTop: 16 }, children: [
6501
- /* @__PURE__ */ jsx55(
6502
- View43,
6691
+ /* @__PURE__ */ jsxs34(View44, { style: { marginTop: 16 }, children: [
6692
+ /* @__PURE__ */ jsx56(
6693
+ View44,
6503
6694
  {
6504
6695
  style: [
6505
6696
  fullWidthButtonBase,
@@ -6508,22 +6699,22 @@ function ConfirmMergeRequestDialog({
6508
6699
  opacity: canConfirm ? 1 : 0.5
6509
6700
  }
6510
6701
  ],
6511
- children: /* @__PURE__ */ jsx55(
6512
- Pressable14,
6702
+ children: /* @__PURE__ */ jsx56(
6703
+ Pressable15,
6513
6704
  {
6514
6705
  accessibilityRole: "button",
6515
6706
  accessibilityLabel: "Approve Merge",
6516
6707
  disabled: !canConfirm,
6517
6708
  onPress: handleConfirm,
6518
6709
  style: [fullWidthButtonBase, { flex: 1 }],
6519
- children: /* @__PURE__ */ jsx55(Text, { style: { textAlign: "center", color: theme.colors.onPrimary }, children: "Approve Merge" })
6710
+ children: /* @__PURE__ */ jsx56(Text, { style: { textAlign: "center", color: theme.colors.onPrimary }, children: "Approve Merge" })
6520
6711
  }
6521
6712
  )
6522
6713
  }
6523
6714
  ),
6524
- /* @__PURE__ */ jsx55(View43, { style: { height: 8 } }),
6525
- /* @__PURE__ */ jsx55(
6526
- View43,
6715
+ /* @__PURE__ */ jsx56(View44, { style: { height: 8 } }),
6716
+ /* @__PURE__ */ jsx56(
6717
+ View44,
6527
6718
  {
6528
6719
  style: [
6529
6720
  fullWidthButtonBase,
@@ -6534,22 +6725,22 @@ function ConfirmMergeRequestDialog({
6534
6725
  opacity: isBuilding || !mergeRequest ? 0.5 : 1
6535
6726
  }
6536
6727
  ],
6537
- children: /* @__PURE__ */ jsx55(
6538
- Pressable14,
6728
+ children: /* @__PURE__ */ jsx56(
6729
+ Pressable15,
6539
6730
  {
6540
6731
  accessibilityRole: "button",
6541
6732
  accessibilityLabel: isBuilding ? "Preparing\u2026" : "Test edits first",
6542
6733
  disabled: isBuilding || !mergeRequest,
6543
6734
  onPress: handleTestFirst,
6544
6735
  style: [fullWidthButtonBase, { flex: 1 }],
6545
- children: /* @__PURE__ */ jsx55(Text, { style: { textAlign: "center", color: theme.colors.text }, children: isBuilding ? "Preparing\u2026" : "Test edits first" })
6736
+ children: /* @__PURE__ */ jsx56(Text, { style: { textAlign: "center", color: theme.colors.text }, children: isBuilding ? "Preparing\u2026" : "Test edits first" })
6546
6737
  }
6547
6738
  )
6548
6739
  }
6549
6740
  ),
6550
- /* @__PURE__ */ jsx55(View43, { style: { height: 8 } }),
6551
- /* @__PURE__ */ jsx55(
6552
- View43,
6741
+ /* @__PURE__ */ jsx56(View44, { style: { height: 8 } }),
6742
+ /* @__PURE__ */ jsx56(
6743
+ View44,
6553
6744
  {
6554
6745
  style: [
6555
6746
  fullWidthButtonBase,
@@ -6559,14 +6750,14 @@ function ConfirmMergeRequestDialog({
6559
6750
  borderColor: theme.colors.border
6560
6751
  }
6561
6752
  ],
6562
- children: /* @__PURE__ */ jsx55(
6563
- Pressable14,
6753
+ children: /* @__PURE__ */ jsx56(
6754
+ Pressable15,
6564
6755
  {
6565
6756
  accessibilityRole: "button",
6566
6757
  accessibilityLabel: "Cancel",
6567
6758
  onPress: close,
6568
6759
  style: [fullWidthButtonBase, { flex: 1 }],
6569
- children: /* @__PURE__ */ jsx55(Text, { style: { textAlign: "center", color: theme.colors.text }, children: "Cancel" })
6760
+ children: /* @__PURE__ */ jsx56(Text, { style: { textAlign: "center", color: theme.colors.text }, children: "Cancel" })
6570
6761
  }
6571
6762
  )
6572
6763
  }
@@ -6578,7 +6769,7 @@ function ConfirmMergeRequestDialog({
6578
6769
  }
6579
6770
 
6580
6771
  // src/studio/ui/ConfirmMergeFlow.tsx
6581
- import { jsx as jsx56 } from "react/jsx-runtime";
6772
+ import { jsx as jsx57 } from "react/jsx-runtime";
6582
6773
  function ConfirmMergeFlow({
6583
6774
  visible,
6584
6775
  onOpenChange,
@@ -6589,7 +6780,7 @@ function ConfirmMergeFlow({
6589
6780
  onConfirm,
6590
6781
  onTestFirst
6591
6782
  }) {
6592
- return /* @__PURE__ */ jsx56(
6783
+ return /* @__PURE__ */ jsx57(
6593
6784
  ConfirmMergeRequestDialog,
6594
6785
  {
6595
6786
  visible,
@@ -6611,11 +6802,11 @@ function ConfirmMergeFlow({
6611
6802
  }
6612
6803
 
6613
6804
  // src/studio/hooks/useOptimisticChatMessages.ts
6614
- import * as React41 from "react";
6805
+ import * as React42 from "react";
6615
6806
  function makeOptimisticId() {
6616
6807
  return `optimistic:${Date.now().toString(36)}:${Math.random().toString(36).slice(2, 10)}`;
6617
6808
  }
6618
- function toEpochMs(createdAt) {
6809
+ function toEpochMs2(createdAt) {
6619
6810
  if (createdAt == null) return 0;
6620
6811
  if (typeof createdAt === "number") return createdAt;
6621
6812
  if (createdAt instanceof Date) return createdAt.getTime();
@@ -6634,7 +6825,7 @@ function isOptimisticResolvedByServer(chatMessages, o) {
6634
6825
  for (const m of candidates) {
6635
6826
  if (m.author !== "human") continue;
6636
6827
  if (normalize(m.content) !== target) continue;
6637
- const serverMs = toEpochMs(m.createdAt);
6828
+ const serverMs = toEpochMs2(m.createdAt);
6638
6829
  const optimisticMs = Date.parse(o.createdAtIso);
6639
6830
  if (Number.isFinite(optimisticMs) && optimisticMs > 0 && serverMs > 0) {
6640
6831
  if (serverMs + 12e4 < optimisticMs) continue;
@@ -6646,14 +6837,15 @@ function isOptimisticResolvedByServer(chatMessages, o) {
6646
6837
  function useOptimisticChatMessages({
6647
6838
  threadId,
6648
6839
  shouldForkOnEdit,
6840
+ disableOptimistic = false,
6649
6841
  chatMessages,
6650
6842
  onSendChat
6651
6843
  }) {
6652
- const [optimisticChat, setOptimisticChat] = React41.useState([]);
6653
- React41.useEffect(() => {
6844
+ const [optimisticChat, setOptimisticChat] = React42.useState([]);
6845
+ React42.useEffect(() => {
6654
6846
  setOptimisticChat([]);
6655
6847
  }, [threadId]);
6656
- const messages = React41.useMemo(() => {
6848
+ const messages = React42.useMemo(() => {
6657
6849
  if (!optimisticChat || optimisticChat.length === 0) return chatMessages;
6658
6850
  const unresolved = optimisticChat.filter((o) => !isOptimisticResolvedByServer(chatMessages, o));
6659
6851
  if (unresolved.length === 0) return chatMessages;
@@ -6669,7 +6861,7 @@ function useOptimisticChatMessages({
6669
6861
  merged.sort((a, b) => String(a.createdAt).localeCompare(String(b.createdAt)));
6670
6862
  return merged;
6671
6863
  }, [chatMessages, optimisticChat]);
6672
- React41.useEffect(() => {
6864
+ React42.useEffect(() => {
6673
6865
  if (optimisticChat.length === 0) return;
6674
6866
  setOptimisticChat((prev) => {
6675
6867
  if (prev.length === 0) return prev;
@@ -6677,9 +6869,9 @@ function useOptimisticChatMessages({
6677
6869
  return next.length === prev.length ? prev : next;
6678
6870
  });
6679
6871
  }, [chatMessages, optimisticChat.length]);
6680
- const onSend = React41.useCallback(
6872
+ const onSend = React42.useCallback(
6681
6873
  async (text, attachments) => {
6682
- if (shouldForkOnEdit) {
6874
+ if (shouldForkOnEdit || disableOptimistic) {
6683
6875
  await onSendChat(text, attachments);
6684
6876
  return;
6685
6877
  }
@@ -6691,7 +6883,7 @@ function useOptimisticChatMessages({
6691
6883
  setOptimisticChat((prev) => prev.map((m) => m.id === id ? { ...m, failed: true } : m));
6692
6884
  });
6693
6885
  },
6694
- [chatMessages, onSendChat, shouldForkOnEdit]
6886
+ [chatMessages, disableOptimistic, onSendChat, shouldForkOnEdit]
6695
6887
  );
6696
6888
  return { messages, onSend };
6697
6889
  }
@@ -6701,7 +6893,7 @@ import {
6701
6893
  publishComergeStudioUIState,
6702
6894
  startStudioControlPolling
6703
6895
  } from "@comergehq/studio-control";
6704
- import { Fragment as Fragment6, jsx as jsx57, jsxs as jsxs34 } from "react/jsx-runtime";
6896
+ import { Fragment as Fragment6, jsx as jsx58, jsxs as jsxs35 } from "react/jsx-runtime";
6705
6897
  function StudioOverlay({
6706
6898
  captureTargetRef,
6707
6899
  app,
@@ -6728,44 +6920,50 @@ function StudioOverlay({
6728
6920
  chatSending,
6729
6921
  chatShowTypingIndicator,
6730
6922
  onSendChat,
6923
+ chatQueueItems,
6924
+ onRemoveQueueItem,
6731
6925
  onNavigateHome,
6732
6926
  showBubble,
6733
6927
  studioControlOptions
6734
6928
  }) {
6735
6929
  const theme = useTheme();
6736
6930
  const { width } = useWindowDimensions4();
6737
- const [sheetOpen, setSheetOpen] = React42.useState(false);
6738
- const sheetOpenRef = React42.useRef(sheetOpen);
6739
- const [activePage, setActivePage] = React42.useState("preview");
6740
- const [drawing, setDrawing] = React42.useState(false);
6741
- const [chatAttachments, setChatAttachments] = React42.useState([]);
6742
- const [commentsAppId, setCommentsAppId] = React42.useState(null);
6743
- const [commentsCount, setCommentsCount] = React42.useState(null);
6931
+ const [sheetOpen, setSheetOpen] = React43.useState(false);
6932
+ const sheetOpenRef = React43.useRef(sheetOpen);
6933
+ const [activePage, setActivePage] = React43.useState("preview");
6934
+ const [drawing, setDrawing] = React43.useState(false);
6935
+ const [chatAttachments, setChatAttachments] = React43.useState([]);
6936
+ const [commentsAppId, setCommentsAppId] = React43.useState(null);
6937
+ const [commentsCount, setCommentsCount] = React43.useState(null);
6744
6938
  const threadId = (app == null ? void 0 : app.threadId) ?? null;
6939
+ const isForking = chatForking || (app == null ? void 0 : app.status) === "forking";
6940
+ const queueItemsForChat = isForking ? [] : chatQueueItems;
6941
+ const disableOptimistic = Boolean(queueItemsForChat && queueItemsForChat.length > 0) || (app == null ? void 0 : app.status) === "editing";
6745
6942
  const optimistic = useOptimisticChatMessages({
6746
6943
  threadId,
6747
6944
  shouldForkOnEdit,
6945
+ disableOptimistic,
6748
6946
  chatMessages,
6749
6947
  onSendChat
6750
6948
  });
6751
- const [confirmMrId, setConfirmMrId] = React42.useState(null);
6752
- const confirmMr = React42.useMemo(
6949
+ const [confirmMrId, setConfirmMrId] = React43.useState(null);
6950
+ const confirmMr = React43.useMemo(
6753
6951
  () => confirmMrId ? incomingMergeRequests.find((m) => m.id === confirmMrId) ?? null : null,
6754
6952
  [confirmMrId, incomingMergeRequests]
6755
6953
  );
6756
- const handleSheetOpenChange = React42.useCallback((open) => {
6954
+ const handleSheetOpenChange = React43.useCallback((open) => {
6757
6955
  setSheetOpen(open);
6758
6956
  if (!open) Keyboard5.dismiss();
6759
6957
  }, []);
6760
- const closeSheet = React42.useCallback(() => {
6958
+ const closeSheet = React43.useCallback(() => {
6761
6959
  handleSheetOpenChange(false);
6762
6960
  }, [handleSheetOpenChange]);
6763
- const openSheet = React42.useCallback(() => setSheetOpen(true), []);
6764
- const goToChat = React42.useCallback(() => {
6961
+ const openSheet = React43.useCallback(() => setSheetOpen(true), []);
6962
+ const goToChat = React43.useCallback(() => {
6765
6963
  setActivePage("chat");
6766
6964
  openSheet();
6767
6965
  }, [openSheet]);
6768
- const backToPreview = React42.useCallback(() => {
6966
+ const backToPreview = React43.useCallback(() => {
6769
6967
  if (Platform10.OS !== "ios") {
6770
6968
  Keyboard5.dismiss();
6771
6969
  setActivePage("preview");
@@ -6783,11 +6981,11 @@ function StudioOverlay({
6783
6981
  const t = setTimeout(finalize, 350);
6784
6982
  Keyboard5.dismiss();
6785
6983
  }, []);
6786
- const startDraw = React42.useCallback(() => {
6984
+ const startDraw = React43.useCallback(() => {
6787
6985
  setDrawing(true);
6788
6986
  closeSheet();
6789
6987
  }, [closeSheet]);
6790
- const handleDrawCapture = React42.useCallback(
6988
+ const handleDrawCapture = React43.useCallback(
6791
6989
  (dataUrl) => {
6792
6990
  setChatAttachments((prev) => [...prev, dataUrl]);
6793
6991
  setDrawing(false);
@@ -6796,7 +6994,7 @@ function StudioOverlay({
6796
6994
  },
6797
6995
  [openSheet]
6798
6996
  );
6799
- const toggleSheet = React42.useCallback(async () => {
6997
+ const toggleSheet = React43.useCallback(async () => {
6800
6998
  if (!sheetOpen) {
6801
6999
  const shouldExitTest = Boolean(testingMrId) || isTesting;
6802
7000
  if (shouldExitTest) {
@@ -6808,7 +7006,7 @@ function StudioOverlay({
6808
7006
  closeSheet();
6809
7007
  }
6810
7008
  }, [closeSheet, isTesting, onRestoreBase, sheetOpen, testingMrId]);
6811
- const handleTestMr = React42.useCallback(
7009
+ const handleTestMr = React43.useCallback(
6812
7010
  async (mr) => {
6813
7011
  if (!onTestMr) return;
6814
7012
  await onTestMr(mr);
@@ -6816,10 +7014,10 @@ function StudioOverlay({
6816
7014
  },
6817
7015
  [closeSheet, onTestMr]
6818
7016
  );
6819
- React42.useEffect(() => {
7017
+ React43.useEffect(() => {
6820
7018
  sheetOpenRef.current = sheetOpen;
6821
7019
  }, [sheetOpen]);
6822
- React42.useEffect(() => {
7020
+ React43.useEffect(() => {
6823
7021
  const poller = startStudioControlPolling((action) => {
6824
7022
  if (action === "show" && !sheetOpenRef.current) openSheet();
6825
7023
  if (action === "hide" && sheetOpenRef.current) closeSheet();
@@ -6827,17 +7025,17 @@ function StudioOverlay({
6827
7025
  }, studioControlOptions);
6828
7026
  return () => poller.stop();
6829
7027
  }, [closeSheet, openSheet, studioControlOptions, toggleSheet]);
6830
- React42.useEffect(() => {
7028
+ React43.useEffect(() => {
6831
7029
  void publishComergeStudioUIState(sheetOpen, studioControlOptions);
6832
7030
  }, [sheetOpen, studioControlOptions]);
6833
- return /* @__PURE__ */ jsxs34(Fragment6, { children: [
6834
- /* @__PURE__ */ jsx57(EdgeGlowFrame, { visible: isTesting, role: "accent", thickness: 40, intensity: 1 }),
6835
- /* @__PURE__ */ jsx57(StudioBottomSheet, { open: sheetOpen, onOpenChange: handleSheetOpenChange, children: /* @__PURE__ */ jsx57(
7031
+ return /* @__PURE__ */ jsxs35(Fragment6, { children: [
7032
+ /* @__PURE__ */ jsx58(EdgeGlowFrame, { visible: isTesting, role: "accent", thickness: 40, intensity: 1 }),
7033
+ /* @__PURE__ */ jsx58(StudioBottomSheet, { open: sheetOpen, onOpenChange: handleSheetOpenChange, children: /* @__PURE__ */ jsx58(
6836
7034
  StudioSheetPager,
6837
7035
  {
6838
7036
  activePage,
6839
7037
  width,
6840
- preview: /* @__PURE__ */ jsx57(
7038
+ preview: /* @__PURE__ */ jsx58(
6841
7039
  PreviewPanel,
6842
7040
  {
6843
7041
  app,
@@ -6863,7 +7061,7 @@ function StudioOverlay({
6863
7061
  commentCountOverride: commentsCount ?? void 0
6864
7062
  }
6865
7063
  ),
6866
- chat: /* @__PURE__ */ jsx57(
7064
+ chat: /* @__PURE__ */ jsx58(
6867
7065
  ChatPanel,
6868
7066
  {
6869
7067
  messages: optimistic.messages,
@@ -6881,12 +7079,14 @@ function StudioOverlay({
6881
7079
  onClose: closeSheet,
6882
7080
  onNavigateHome,
6883
7081
  onStartDraw: startDraw,
6884
- onSend: optimistic.onSend
7082
+ onSend: optimistic.onSend,
7083
+ queueItems: queueItemsForChat,
7084
+ onRemoveQueueItem
6885
7085
  }
6886
7086
  )
6887
7087
  }
6888
7088
  ) }),
6889
- showBubble && /* @__PURE__ */ jsx57(
7089
+ showBubble && /* @__PURE__ */ jsx58(
6890
7090
  Bubble,
6891
7091
  {
6892
7092
  visible: !sheetOpen && !drawing,
@@ -6894,10 +7094,10 @@ function StudioOverlay({
6894
7094
  badgeCount: incomingMergeRequests.length,
6895
7095
  onPress: toggleSheet,
6896
7096
  isLoading: (app == null ? void 0 : app.status) === "editing",
6897
- children: /* @__PURE__ */ jsx57(View44, { style: { width: 28, height: 28, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx57(MergeIcon, { width: 24, height: 24, color: theme.colors.floatingContent }) })
7097
+ children: /* @__PURE__ */ jsx58(View45, { style: { width: 28, height: 28, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx58(MergeIcon, { width: 24, height: 24, color: theme.colors.floatingContent }) })
6898
7098
  }
6899
7099
  ),
6900
- /* @__PURE__ */ jsx57(
7100
+ /* @__PURE__ */ jsx58(
6901
7101
  DrawModeOverlay,
6902
7102
  {
6903
7103
  visible: drawing,
@@ -6906,7 +7106,7 @@ function StudioOverlay({
6906
7106
  onCapture: handleDrawCapture
6907
7107
  }
6908
7108
  ),
6909
- /* @__PURE__ */ jsx57(
7109
+ /* @__PURE__ */ jsx58(
6910
7110
  ConfirmMergeFlow,
6911
7111
  {
6912
7112
  visible: Boolean(confirmMr),
@@ -6919,7 +7119,7 @@ function StudioOverlay({
6919
7119
  onTestFirst: handleTestMr
6920
7120
  }
6921
7121
  ),
6922
- /* @__PURE__ */ jsx57(
7122
+ /* @__PURE__ */ jsx58(
6923
7123
  AppCommentsSheet,
6924
7124
  {
6925
7125
  appId: commentsAppId,
@@ -6931,8 +7131,190 @@ function StudioOverlay({
6931
7131
  ] });
6932
7132
  }
6933
7133
 
7134
+ // src/studio/hooks/useEditQueue.ts
7135
+ import * as React44 from "react";
7136
+
7137
+ // src/data/apps/edit-queue/remote.ts
7138
+ var EditQueueRemoteDataSourceImpl = class extends BaseRemote {
7139
+ async list(appId) {
7140
+ const { data } = await api.get(
7141
+ `/v1/apps/${encodeURIComponent(appId)}/edit-queue`
7142
+ );
7143
+ return data;
7144
+ }
7145
+ async update(appId, queueItemId, payload) {
7146
+ const { data } = await api.patch(
7147
+ `/v1/apps/${encodeURIComponent(appId)}/edit-queue/${encodeURIComponent(queueItemId)}`,
7148
+ payload
7149
+ );
7150
+ return data;
7151
+ }
7152
+ async cancel(appId, queueItemId) {
7153
+ const { data } = await api.delete(
7154
+ `/v1/apps/${encodeURIComponent(appId)}/edit-queue/${encodeURIComponent(queueItemId)}`
7155
+ );
7156
+ return data;
7157
+ }
7158
+ };
7159
+ var editQueueRemoteDataSource = new EditQueueRemoteDataSourceImpl();
7160
+
7161
+ // src/data/apps/edit-queue/repository.ts
7162
+ var ACTIVE_STATUSES = ["pending"];
7163
+ function toString(value) {
7164
+ return typeof value === "string" && value.trim().length > 0 ? value : null;
7165
+ }
7166
+ function toAttachments(value) {
7167
+ return Array.isArray(value) ? value : [];
7168
+ }
7169
+ function mapQueueItem(row) {
7170
+ const payload = row.payload ?? {};
7171
+ return {
7172
+ id: row.id,
7173
+ status: row.status,
7174
+ prompt: toString(payload.trimmedPrompt),
7175
+ messageId: toString(payload.messageId),
7176
+ attachments: toAttachments(payload.attachments),
7177
+ createdAt: row.created_at,
7178
+ updatedAt: row.updated_at,
7179
+ runAfter: row.run_after,
7180
+ priority: row.priority
7181
+ };
7182
+ }
7183
+ var EditQueueRepositoryImpl = class extends BaseRepository {
7184
+ constructor(remote) {
7185
+ super();
7186
+ this.remote = remote;
7187
+ }
7188
+ async list(appId) {
7189
+ const res = await this.remote.list(appId);
7190
+ const data = this.unwrapOrThrow(res);
7191
+ return data.items ?? [];
7192
+ }
7193
+ async update(appId, queueItemId, payload) {
7194
+ const res = await this.remote.update(appId, queueItemId, payload);
7195
+ return this.unwrapOrThrow(res);
7196
+ }
7197
+ async cancel(appId, queueItemId) {
7198
+ const res = await this.remote.cancel(appId, queueItemId);
7199
+ return this.unwrapOrThrow(res);
7200
+ }
7201
+ subscribeEditQueue(appId, handlers) {
7202
+ const supabase = getSupabaseClient();
7203
+ const channel = supabase.channel(`edit-queue:app:${appId}`).on(
7204
+ "postgres_changes",
7205
+ { event: "INSERT", schema: "public", table: "app_job_queue", filter: `app_id=eq.${appId}` },
7206
+ (payload) => {
7207
+ var _a;
7208
+ const row = payload.new;
7209
+ if (row.kind !== "edit") return;
7210
+ const item = mapQueueItem(row);
7211
+ if (!ACTIVE_STATUSES.includes(item.status)) return;
7212
+ (_a = handlers.onInsert) == null ? void 0 : _a.call(handlers, item);
7213
+ }
7214
+ ).on(
7215
+ "postgres_changes",
7216
+ { event: "UPDATE", schema: "public", table: "app_job_queue", filter: `app_id=eq.${appId}` },
7217
+ (payload) => {
7218
+ var _a, _b;
7219
+ const row = payload.new;
7220
+ if (row.kind !== "edit") return;
7221
+ const item = mapQueueItem(row);
7222
+ if (ACTIVE_STATUSES.includes(item.status)) (_a = handlers.onUpdate) == null ? void 0 : _a.call(handlers, item);
7223
+ else (_b = handlers.onDelete) == null ? void 0 : _b.call(handlers, item);
7224
+ }
7225
+ ).on(
7226
+ "postgres_changes",
7227
+ { event: "DELETE", schema: "public", table: "app_job_queue", filter: `app_id=eq.${appId}` },
7228
+ (payload) => {
7229
+ var _a;
7230
+ const row = payload.old;
7231
+ if (row.kind !== "edit") return;
7232
+ (_a = handlers.onDelete) == null ? void 0 : _a.call(handlers, mapQueueItem(row));
7233
+ }
7234
+ ).subscribe();
7235
+ return () => {
7236
+ supabase.removeChannel(channel);
7237
+ };
7238
+ }
7239
+ };
7240
+ var editQueueRepository = new EditQueueRepositoryImpl(
7241
+ editQueueRemoteDataSource
7242
+ );
7243
+
7244
+ // src/studio/hooks/useEditQueue.ts
7245
+ function useEditQueue(appId) {
7246
+ const [items, setItems] = React44.useState([]);
7247
+ const [loading, setLoading] = React44.useState(false);
7248
+ const [error, setError] = React44.useState(null);
7249
+ const activeRequestIdRef = React44.useRef(0);
7250
+ const foregroundSignal = useForegroundSignal(Boolean(appId));
7251
+ const upsertSorted = React44.useCallback((prev, nextItem) => {
7252
+ const next = prev.some((x) => x.id === nextItem.id) ? prev.map((x) => x.id === nextItem.id ? nextItem : x) : [...prev, nextItem];
7253
+ next.sort((a, b) => String(a.createdAt).localeCompare(String(b.createdAt)));
7254
+ return next;
7255
+ }, []);
7256
+ const refetch = React44.useCallback(async () => {
7257
+ if (!appId) {
7258
+ setItems([]);
7259
+ return;
7260
+ }
7261
+ const requestId = ++activeRequestIdRef.current;
7262
+ setLoading(true);
7263
+ setError(null);
7264
+ try {
7265
+ const list = await editQueueRepository.list(appId);
7266
+ if (activeRequestIdRef.current !== requestId) return;
7267
+ setItems([...list].sort((a, b) => String(a.createdAt).localeCompare(String(b.createdAt))));
7268
+ } catch (e) {
7269
+ if (activeRequestIdRef.current !== requestId) return;
7270
+ setError(e instanceof Error ? e : new Error(String(e)));
7271
+ setItems([]);
7272
+ } finally {
7273
+ if (activeRequestIdRef.current === requestId) setLoading(false);
7274
+ }
7275
+ }, [appId]);
7276
+ React44.useEffect(() => {
7277
+ void refetch();
7278
+ }, [refetch]);
7279
+ React44.useEffect(() => {
7280
+ if (!appId) return;
7281
+ const unsubscribe = editQueueRepository.subscribeEditQueue(appId, {
7282
+ onInsert: (item) => setItems((prev) => upsertSorted(prev, item)),
7283
+ onUpdate: (item) => setItems((prev) => upsertSorted(prev, item)),
7284
+ onDelete: (item) => setItems((prev) => prev.filter((x) => x.id !== item.id))
7285
+ });
7286
+ return unsubscribe;
7287
+ }, [appId, upsertSorted, foregroundSignal]);
7288
+ React44.useEffect(() => {
7289
+ if (!appId) return;
7290
+ if (foregroundSignal <= 0) return;
7291
+ void refetch();
7292
+ }, [appId, foregroundSignal, refetch]);
7293
+ return { items, loading, error, refetch };
7294
+ }
7295
+
7296
+ // src/studio/hooks/useEditQueueActions.ts
7297
+ import * as React45 from "react";
7298
+ function useEditQueueActions(appId) {
7299
+ const update = React45.useCallback(
7300
+ async (queueItemId, payload) => {
7301
+ if (!appId) return;
7302
+ await editQueueRepository.update(appId, queueItemId, payload);
7303
+ },
7304
+ [appId]
7305
+ );
7306
+ const cancel = React45.useCallback(
7307
+ async (queueItemId) => {
7308
+ if (!appId) return;
7309
+ await editQueueRepository.cancel(appId, queueItemId);
7310
+ },
7311
+ [appId]
7312
+ );
7313
+ return { update, cancel };
7314
+ }
7315
+
6934
7316
  // src/studio/ComergeStudio.tsx
6935
- import { jsx as jsx58, jsxs as jsxs35 } from "react/jsx-runtime";
7317
+ import { jsx as jsx59, jsxs as jsxs36 } from "react/jsx-runtime";
6936
7318
  function ComergeStudio({
6937
7319
  appId,
6938
7320
  clientKey: clientKey2,
@@ -6943,17 +7325,17 @@ function ComergeStudio({
6943
7325
  studioControlOptions,
6944
7326
  embeddedBaseBundles
6945
7327
  }) {
6946
- const [activeAppId, setActiveAppId] = React43.useState(appId);
6947
- const [runtimeAppId, setRuntimeAppId] = React43.useState(appId);
6948
- const [pendingRuntimeTargetAppId, setPendingRuntimeTargetAppId] = React43.useState(null);
6949
- const platform = React43.useMemo(() => RNPlatform.OS === "ios" ? "ios" : "android", []);
6950
- React43.useEffect(() => {
7328
+ const [activeAppId, setActiveAppId] = React46.useState(appId);
7329
+ const [runtimeAppId, setRuntimeAppId] = React46.useState(appId);
7330
+ const [pendingRuntimeTargetAppId, setPendingRuntimeTargetAppId] = React46.useState(null);
7331
+ const platform = React46.useMemo(() => RNPlatform.OS === "ios" ? "ios" : "android", []);
7332
+ React46.useEffect(() => {
6951
7333
  setActiveAppId(appId);
6952
7334
  setRuntimeAppId(appId);
6953
7335
  setPendingRuntimeTargetAppId(null);
6954
7336
  }, [appId]);
6955
- const captureTargetRef = React43.useRef(null);
6956
- return /* @__PURE__ */ jsx58(StudioBootstrap, { clientKey: clientKey2, fallback: /* @__PURE__ */ jsx58(View45, { style: { flex: 1 } }), children: ({ userId }) => /* @__PURE__ */ jsx58(BottomSheetModalProvider, { children: /* @__PURE__ */ jsx58(LiquidGlassResetProvider, { resetTriggers: [appId, activeAppId, runtimeAppId], children: /* @__PURE__ */ jsx58(
7337
+ const captureTargetRef = React46.useRef(null);
7338
+ return /* @__PURE__ */ jsx59(StudioBootstrap, { clientKey: clientKey2, fallback: /* @__PURE__ */ jsx59(View46, { style: { flex: 1 } }), children: ({ userId }) => /* @__PURE__ */ jsx59(BottomSheetModalProvider, { children: /* @__PURE__ */ jsx59(LiquidGlassResetProvider, { resetTriggers: [appId, activeAppId, runtimeAppId], children: /* @__PURE__ */ jsx59(
6957
7339
  ComergeStudioInner,
6958
7340
  {
6959
7341
  userId,
@@ -6994,11 +7376,11 @@ function ComergeStudioInner({
6994
7376
  const { app, loading: appLoading } = useApp(activeAppId);
6995
7377
  const { app: runtimeAppFromHook } = useApp(runtimeAppId, { enabled: runtimeAppId !== activeAppId });
6996
7378
  const runtimeApp = runtimeAppId === activeAppId ? app : runtimeAppFromHook;
6997
- const sawEditingOnPendingTargetRef = React43.useRef(false);
6998
- React43.useEffect(() => {
7379
+ const sawEditingOnPendingTargetRef = React46.useRef(false);
7380
+ React46.useEffect(() => {
6999
7381
  sawEditingOnPendingTargetRef.current = false;
7000
7382
  }, [pendingRuntimeTargetAppId]);
7001
- React43.useEffect(() => {
7383
+ React46.useEffect(() => {
7002
7384
  if (!pendingRuntimeTargetAppId) return;
7003
7385
  if (activeAppId !== pendingRuntimeTargetAppId) return;
7004
7386
  if ((app == null ? void 0 : app.status) === "editing") {
@@ -7016,13 +7398,13 @@ function ComergeStudioInner({
7016
7398
  canRequestLatest: (runtimeApp == null ? void 0 : runtimeApp.status) === "ready",
7017
7399
  embeddedBaseBundles
7018
7400
  });
7019
- const sawEditingOnActiveAppRef = React43.useRef(false);
7020
- const [showPostEditPreparing, setShowPostEditPreparing] = React43.useState(false);
7021
- React43.useEffect(() => {
7401
+ const sawEditingOnActiveAppRef = React46.useRef(false);
7402
+ const [showPostEditPreparing, setShowPostEditPreparing] = React46.useState(false);
7403
+ React46.useEffect(() => {
7022
7404
  sawEditingOnActiveAppRef.current = false;
7023
7405
  setShowPostEditPreparing(false);
7024
7406
  }, [activeAppId]);
7025
- React43.useEffect(() => {
7407
+ React46.useEffect(() => {
7026
7408
  if (!(app == null ? void 0 : app.id)) return;
7027
7409
  if (app.status === "editing") {
7028
7410
  sawEditingOnActiveAppRef.current = true;
@@ -7034,7 +7416,7 @@ function ComergeStudioInner({
7034
7416
  sawEditingOnActiveAppRef.current = false;
7035
7417
  }
7036
7418
  }, [app == null ? void 0 : app.id, app == null ? void 0 : app.status]);
7037
- React43.useEffect(() => {
7419
+ React46.useEffect(() => {
7038
7420
  if (!showPostEditPreparing) return;
7039
7421
  const stillProcessingBaseBundle = bundle.loading && bundle.loadingMode === "base" && !bundle.isTesting;
7040
7422
  if (!stillProcessingBaseBundle) {
@@ -7043,15 +7425,27 @@ function ComergeStudioInner({
7043
7425
  }, [showPostEditPreparing, bundle.loading, bundle.loadingMode, bundle.isTesting]);
7044
7426
  const threadId = (app == null ? void 0 : app.threadId) ?? "";
7045
7427
  const thread = useThreadMessages(threadId);
7428
+ const editQueue = useEditQueue(activeAppId);
7429
+ const editQueueActions = useEditQueueActions(activeAppId);
7430
+ const [lastEditQueueInfo, setLastEditQueueInfo] = React46.useState(null);
7431
+ const lastEditQueueInfoRef = React46.useRef(null);
7432
+ const [suppressQueueUntilResponse, setSuppressQueueUntilResponse] = React46.useState(false);
7046
7433
  const mergeRequests = useMergeRequests({ appId: activeAppId });
7047
- const hasOpenOutgoingMr = React43.useMemo(() => {
7434
+ const hasOpenOutgoingMr = React46.useMemo(() => {
7048
7435
  return mergeRequests.lists.outgoing.some((mr) => mr.status === "open");
7049
7436
  }, [mergeRequests.lists.outgoing]);
7050
- const incomingReviewMrs = React43.useMemo(() => {
7437
+ const incomingReviewMrs = React46.useMemo(() => {
7051
7438
  if (!userId) return mergeRequests.lists.incoming;
7052
7439
  return mergeRequests.lists.incoming.filter((mr) => mr.createdBy !== userId);
7053
7440
  }, [mergeRequests.lists.incoming, userId]);
7054
7441
  const uploader = useAttachmentUpload();
7442
+ const updateLastEditQueueInfo = React46.useCallback(
7443
+ (info) => {
7444
+ lastEditQueueInfoRef.current = info;
7445
+ setLastEditQueueInfo(info);
7446
+ },
7447
+ []
7448
+ );
7055
7449
  const actions = useStudioActions({
7056
7450
  userId,
7057
7451
  app,
@@ -7066,20 +7460,62 @@ function ComergeStudioInner({
7066
7460
  setPendingRuntimeTargetAppId(null);
7067
7461
  }
7068
7462
  },
7069
- uploadAttachments: uploader.uploadBase64Images
7463
+ uploadAttachments: uploader.uploadBase64Images,
7464
+ onEditStart: () => {
7465
+ if (editQueue.items.length === 0) {
7466
+ setSuppressQueueUntilResponse(true);
7467
+ }
7468
+ },
7469
+ onEditQueued: (info) => {
7470
+ updateLastEditQueueInfo(info);
7471
+ if (info.queuePosition !== 1) {
7472
+ setSuppressQueueUntilResponse(false);
7473
+ }
7474
+ },
7475
+ onEditFinished: () => {
7476
+ var _a;
7477
+ if (((_a = lastEditQueueInfoRef.current) == null ? void 0 : _a.queuePosition) !== 1) {
7478
+ setSuppressQueueUntilResponse(false);
7479
+ }
7480
+ }
7070
7481
  });
7071
- const chatSendDisabled = hasNoOutcomeAfterLastHuman(thread.raw);
7072
- const [processingMrId, setProcessingMrId] = React43.useState(null);
7073
- const [testingMrId, setTestingMrId] = React43.useState(null);
7074
- const chatShowTypingIndicator = React43.useMemo(() => {
7482
+ const chatSendDisabled = false;
7483
+ const [processingMrId, setProcessingMrId] = React46.useState(null);
7484
+ const [testingMrId, setTestingMrId] = React46.useState(null);
7485
+ const chatShowTypingIndicator = React46.useMemo(() => {
7075
7486
  var _a;
7076
7487
  if (!thread.raw || thread.raw.length === 0) return false;
7077
7488
  const last = thread.raw[thread.raw.length - 1];
7078
7489
  const payloadType = typeof ((_a = last.payload) == null ? void 0 : _a.type) === "string" ? String(last.payload.type) : void 0;
7079
7490
  return payloadType !== "outcome";
7080
7491
  }, [thread.raw]);
7081
- return /* @__PURE__ */ jsx58(View45, { style: [{ flex: 1 }, style], children: /* @__PURE__ */ jsxs35(View45, { ref: captureTargetRef, style: { flex: 1 }, collapsable: false, children: [
7082
- /* @__PURE__ */ jsx58(
7492
+ React46.useEffect(() => {
7493
+ updateLastEditQueueInfo(null);
7494
+ setSuppressQueueUntilResponse(false);
7495
+ }, [activeAppId, updateLastEditQueueInfo]);
7496
+ React46.useEffect(() => {
7497
+ if (!(lastEditQueueInfo == null ? void 0 : lastEditQueueInfo.queueItemId)) return;
7498
+ const stillPresent = editQueue.items.some((item) => item.id === lastEditQueueInfo.queueItemId);
7499
+ if (!stillPresent) {
7500
+ updateLastEditQueueInfo(null);
7501
+ setSuppressQueueUntilResponse(false);
7502
+ }
7503
+ }, [editQueue.items, lastEditQueueInfo == null ? void 0 : lastEditQueueInfo.queueItemId]);
7504
+ const chatQueueItems = React46.useMemo(() => {
7505
+ var _a;
7506
+ if (suppressQueueUntilResponse && editQueue.items.length <= 1) {
7507
+ return [];
7508
+ }
7509
+ if (!lastEditQueueInfo || lastEditQueueInfo.queuePosition !== 1 || !lastEditQueueInfo.queueItemId) {
7510
+ return editQueue.items;
7511
+ }
7512
+ if (editQueue.items.length === 1 && ((_a = editQueue.items[0]) == null ? void 0 : _a.id) === lastEditQueueInfo.queueItemId) {
7513
+ return [];
7514
+ }
7515
+ return editQueue.items;
7516
+ }, [editQueue.items, lastEditQueueInfo, suppressQueueUntilResponse]);
7517
+ return /* @__PURE__ */ jsx59(View46, { style: [{ flex: 1 }, style], children: /* @__PURE__ */ jsxs36(View46, { ref: captureTargetRef, style: { flex: 1 }, collapsable: false, children: [
7518
+ /* @__PURE__ */ jsx59(
7083
7519
  RuntimeRenderer,
7084
7520
  {
7085
7521
  appKey,
@@ -7089,7 +7525,7 @@ function ComergeStudioInner({
7089
7525
  allowInitialPreparing: !embeddedBaseBundles
7090
7526
  }
7091
7527
  ),
7092
- /* @__PURE__ */ jsx58(
7528
+ /* @__PURE__ */ jsx59(
7093
7529
  StudioOverlay,
7094
7530
  {
7095
7531
  captureTargetRef,
@@ -7141,6 +7577,8 @@ function ComergeStudioInner({
7141
7577
  chatSending: actions.sending,
7142
7578
  chatShowTypingIndicator,
7143
7579
  onSendChat: (text, attachments) => actions.sendEdit({ prompt: text, attachments }),
7580
+ chatQueueItems,
7581
+ onRemoveQueueItem: (id) => editQueueActions.cancel(id),
7144
7582
  onNavigateHome,
7145
7583
  showBubble,
7146
7584
  studioControlOptions