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