@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.js +615 -177
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +609 -171
- 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 +43 -6
- package/src/studio/ui/ChatPanel.tsx +11 -0
- package/src/studio/ui/StudioOverlay.tsx +10 -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,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.
|
|
839
|
-
next.
|
|
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(
|
|
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(() =>
|
|
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
|
|
2012
|
-
import { Keyboard as Keyboard5, Platform as Platform10, View as
|
|
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
|
|
5873
|
-
import { ActivityIndicator as
|
|
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
|
|
6092
|
-
const
|
|
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__ */
|
|
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:
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
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/
|
|
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 =
|
|
6317
|
-
const [nearBottom, setNearBottom] =
|
|
6318
|
-
const handleSend =
|
|
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 =
|
|
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__ */
|
|
6525
|
+
const header = /* @__PURE__ */ jsx54(
|
|
6337
6526
|
ChatHeader,
|
|
6338
6527
|
{
|
|
6339
|
-
left: /* @__PURE__ */
|
|
6340
|
-
/* @__PURE__ */
|
|
6341
|
-
onNavigateHome ? /* @__PURE__ */
|
|
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__ */
|
|
6344
|
-
onStartDraw ? /* @__PURE__ */
|
|
6345
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
6360
|
-
/* @__PURE__ */
|
|
6361
|
-
topBanner ? /* @__PURE__ */
|
|
6362
|
-
/* @__PURE__ */
|
|
6363
|
-
/* @__PURE__ */
|
|
6364
|
-
/* @__PURE__ */
|
|
6365
|
-
/* @__PURE__ */
|
|
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
|
-
|
|
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__ */
|
|
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__ */
|
|
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
|
|
6407
|
-
import { Pressable as
|
|
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
|
|
6413
|
-
View as
|
|
6603
|
+
Pressable as Pressable14,
|
|
6604
|
+
View as View43
|
|
6414
6605
|
} from "react-native";
|
|
6415
|
-
import { jsx as
|
|
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__ */
|
|
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__ */
|
|
6432
|
-
/* @__PURE__ */
|
|
6433
|
-
|
|
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__ */
|
|
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
|
|
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 =
|
|
6649
|
+
const close = React41.useCallback(() => onOpenChange(false), [onOpenChange]);
|
|
6459
6650
|
const canConfirm = Boolean(mergeRequest) && !approveDisabled;
|
|
6460
|
-
const handleConfirm =
|
|
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 =
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
6501
|
-
/* @__PURE__ */
|
|
6502
|
-
|
|
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__ */
|
|
6512
|
-
|
|
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__ */
|
|
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__ */
|
|
6525
|
-
/* @__PURE__ */
|
|
6526
|
-
|
|
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__ */
|
|
6538
|
-
|
|
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__ */
|
|
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__ */
|
|
6551
|
-
/* @__PURE__ */
|
|
6552
|
-
|
|
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__ */
|
|
6563
|
-
|
|
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__ */
|
|
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
|
|
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__ */
|
|
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
|
|
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
|
|
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 =
|
|
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] =
|
|
6653
|
-
|
|
6844
|
+
const [optimisticChat, setOptimisticChat] = React42.useState([]);
|
|
6845
|
+
React42.useEffect(() => {
|
|
6654
6846
|
setOptimisticChat([]);
|
|
6655
6847
|
}, [threadId]);
|
|
6656
|
-
const messages =
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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] =
|
|
6738
|
-
const sheetOpenRef =
|
|
6739
|
-
const [activePage, setActivePage] =
|
|
6740
|
-
const [drawing, setDrawing] =
|
|
6741
|
-
const [chatAttachments, setChatAttachments] =
|
|
6742
|
-
const [commentsAppId, setCommentsAppId] =
|
|
6743
|
-
const [commentsCount, setCommentsCount] =
|
|
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] =
|
|
6752
|
-
const confirmMr =
|
|
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 =
|
|
6954
|
+
const handleSheetOpenChange = React43.useCallback((open) => {
|
|
6757
6955
|
setSheetOpen(open);
|
|
6758
6956
|
if (!open) Keyboard5.dismiss();
|
|
6759
6957
|
}, []);
|
|
6760
|
-
const closeSheet =
|
|
6958
|
+
const closeSheet = React43.useCallback(() => {
|
|
6761
6959
|
handleSheetOpenChange(false);
|
|
6762
6960
|
}, [handleSheetOpenChange]);
|
|
6763
|
-
const openSheet =
|
|
6764
|
-
const goToChat =
|
|
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 =
|
|
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 =
|
|
6984
|
+
const startDraw = React43.useCallback(() => {
|
|
6787
6985
|
setDrawing(true);
|
|
6788
6986
|
closeSheet();
|
|
6789
6987
|
}, [closeSheet]);
|
|
6790
|
-
const handleDrawCapture =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
7017
|
+
React43.useEffect(() => {
|
|
6820
7018
|
sheetOpenRef.current = sheetOpen;
|
|
6821
7019
|
}, [sheetOpen]);
|
|
6822
|
-
|
|
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
|
-
|
|
7028
|
+
React43.useEffect(() => {
|
|
6831
7029
|
void publishComergeStudioUIState(sheetOpen, studioControlOptions);
|
|
6832
7030
|
}, [sheetOpen, studioControlOptions]);
|
|
6833
|
-
return /* @__PURE__ */
|
|
6834
|
-
/* @__PURE__ */
|
|
6835
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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] =
|
|
6947
|
-
const [runtimeAppId, setRuntimeAppId] =
|
|
6948
|
-
const [pendingRuntimeTargetAppId, setPendingRuntimeTargetAppId] =
|
|
6949
|
-
const platform =
|
|
6950
|
-
|
|
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 =
|
|
6956
|
-
return /* @__PURE__ */
|
|
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 =
|
|
6998
|
-
|
|
7379
|
+
const sawEditingOnPendingTargetRef = React46.useRef(false);
|
|
7380
|
+
React46.useEffect(() => {
|
|
6999
7381
|
sawEditingOnPendingTargetRef.current = false;
|
|
7000
7382
|
}, [pendingRuntimeTargetAppId]);
|
|
7001
|
-
|
|
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 =
|
|
7020
|
-
const [showPostEditPreparing, setShowPostEditPreparing] =
|
|
7021
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
7434
|
+
const hasOpenOutgoingMr = React46.useMemo(() => {
|
|
7048
7435
|
return mergeRequests.lists.outgoing.some((mr) => mr.status === "open");
|
|
7049
7436
|
}, [mergeRequests.lists.outgoing]);
|
|
7050
|
-
const incomingReviewMrs =
|
|
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 =
|
|
7072
|
-
const [processingMrId, setProcessingMrId] =
|
|
7073
|
-
const [testingMrId, setTestingMrId] =
|
|
7074
|
-
const chatShowTypingIndicator =
|
|
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
|
-
|
|
7082
|
-
|
|
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__ */
|
|
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
|