@comergehq/studio 0.1.22 → 0.1.24
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.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +697 -312
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +724 -336
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/bubble/Bubble.tsx +11 -5
- package/src/components/bubble/types.ts +2 -0
- package/src/components/chat/ChatComposer.tsx +4 -21
- package/src/components/chat/ChatMessageBubble.tsx +33 -2
- package/src/components/chat/ChatMessageList.tsx +12 -1
- package/src/components/chat/ChatPage.tsx +8 -14
- package/src/components/merge-requests/ReviewMergeRequestCard.tsx +1 -1
- package/src/components/primitives/MarkdownText.tsx +134 -35
- package/src/components/studio-sheet/StudioBottomSheet.tsx +26 -29
- package/src/core/services/http/index.ts +64 -1
- package/src/core/services/supabase/realtimeManager.ts +55 -1
- package/src/data/agent/types.ts +1 -0
- package/src/data/apps/bundles/remote.ts +4 -3
- package/src/data/users/types.ts +1 -1
- package/src/index.ts +1 -0
- package/src/studio/ComergeStudio.tsx +6 -2
- package/src/studio/hooks/useApp.ts +24 -6
- package/src/studio/hooks/useBundleManager.ts +12 -1
- package/src/studio/hooks/useForegroundSignal.ts +2 -4
- package/src/studio/hooks/useMergeRequests.ts +6 -1
- package/src/studio/hooks/useOptimisticChatMessages.ts +55 -3
- package/src/studio/hooks/useStudioActions.ts +60 -6
- package/src/studio/hooks/useThreadMessages.ts +26 -5
- package/src/studio/ui/ChatPanel.tsx +6 -3
- package/src/studio/ui/StudioOverlay.tsx +7 -2
package/dist/index.js
CHANGED
|
@@ -31,13 +31,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
ComergeStudio: () => ComergeStudio,
|
|
34
|
+
resetRealtimeState: () => resetRealtimeState,
|
|
34
35
|
setSupabaseClient: () => setSupabaseClient
|
|
35
36
|
});
|
|
36
37
|
module.exports = __toCommonJS(index_exports);
|
|
37
38
|
|
|
38
39
|
// src/studio/ComergeStudio.tsx
|
|
39
40
|
var React47 = __toESM(require("react"));
|
|
40
|
-
var
|
|
41
|
+
var import_react_native57 = require("react-native");
|
|
41
42
|
var import_bottom_sheet6 = require("@gorhom/bottom-sheet");
|
|
42
43
|
|
|
43
44
|
// src/studio/bootstrap/StudioBootstrap.tsx
|
|
@@ -393,6 +394,41 @@ var log = import_react_native_logs.logger.createLogger(
|
|
|
393
394
|
);
|
|
394
395
|
|
|
395
396
|
// src/core/services/http/index.ts
|
|
397
|
+
var RETRYABLE_MAX_ATTEMPTS = 3;
|
|
398
|
+
var RETRYABLE_BASE_DELAY_MS = 500;
|
|
399
|
+
var RETRYABLE_MAX_DELAY_MS = 4e3;
|
|
400
|
+
var RETRYABLE_JITTER_MS = 250;
|
|
401
|
+
function sleep(ms) {
|
|
402
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
403
|
+
}
|
|
404
|
+
function isRetryableNetworkError(e) {
|
|
405
|
+
var _a;
|
|
406
|
+
const err = e;
|
|
407
|
+
const code = typeof (err == null ? void 0 : err.code) === "string" ? err.code : "";
|
|
408
|
+
const message = typeof (err == null ? void 0 : err.message) === "string" ? err.message : "";
|
|
409
|
+
if (code === "ERR_NETWORK" || code === "ECONNABORTED") return true;
|
|
410
|
+
if (message.toLowerCase().includes("network error")) return true;
|
|
411
|
+
if (message.toLowerCase().includes("timeout")) return true;
|
|
412
|
+
const status = typeof ((_a = err == null ? void 0 : err.response) == null ? void 0 : _a.status) === "number" ? err.response.status : void 0;
|
|
413
|
+
if (status && (status === 429 || status >= 500)) return true;
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
function computeBackoffDelay(attempt) {
|
|
417
|
+
const exp = Math.min(RETRYABLE_MAX_DELAY_MS, RETRYABLE_BASE_DELAY_MS * Math.pow(2, attempt - 1));
|
|
418
|
+
const jitter = Math.floor(Math.random() * RETRYABLE_JITTER_MS);
|
|
419
|
+
return exp + jitter;
|
|
420
|
+
}
|
|
421
|
+
function parseRetryAfterMs(value) {
|
|
422
|
+
if (typeof value !== "string") return null;
|
|
423
|
+
const trimmed = value.trim();
|
|
424
|
+
if (!trimmed) return null;
|
|
425
|
+
const seconds = Number(trimmed);
|
|
426
|
+
if (!Number.isNaN(seconds) && seconds >= 0) return seconds * 1e3;
|
|
427
|
+
const parsed = Date.parse(trimmed);
|
|
428
|
+
if (Number.isNaN(parsed)) return null;
|
|
429
|
+
const delta = parsed - Date.now();
|
|
430
|
+
return delta > 0 ? delta : 0;
|
|
431
|
+
}
|
|
396
432
|
var createApiClient = (baseURL) => {
|
|
397
433
|
const apiClient = import_axios2.default.create({
|
|
398
434
|
baseURL,
|
|
@@ -450,7 +486,7 @@ var createApiClient = (baseURL) => {
|
|
|
450
486
|
return response;
|
|
451
487
|
},
|
|
452
488
|
async (error) => {
|
|
453
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
489
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
454
490
|
const originalRequest = error.config;
|
|
455
491
|
log.error("Response Error:", {
|
|
456
492
|
message: error.message,
|
|
@@ -486,6 +522,23 @@ var createApiClient = (baseURL) => {
|
|
|
486
522
|
return Promise.reject(refreshErr);
|
|
487
523
|
}
|
|
488
524
|
}
|
|
525
|
+
const method = ((_h = originalRequest.method) == null ? void 0 : _h.toLowerCase()) ?? "";
|
|
526
|
+
const isGet = method === "get";
|
|
527
|
+
const retryable = isRetryableNetworkError(error);
|
|
528
|
+
const retryCount = originalRequest._retryCount ?? 0;
|
|
529
|
+
const skipRetry = originalRequest.skipRetry === true;
|
|
530
|
+
if (isGet && retryable && !skipRetry && retryCount < RETRYABLE_MAX_ATTEMPTS) {
|
|
531
|
+
const retryAfterMs = parseRetryAfterMs((_j = (_i = error.response) == null ? void 0 : _i.headers) == null ? void 0 : _j["retry-after"]);
|
|
532
|
+
originalRequest._retryCount = retryCount + 1;
|
|
533
|
+
const delayMs = retryAfterMs ?? computeBackoffDelay(retryCount + 1);
|
|
534
|
+
log.warn("Retrying GET request after transient error", {
|
|
535
|
+
url: originalRequest.url,
|
|
536
|
+
attempt: originalRequest._retryCount,
|
|
537
|
+
delayMs
|
|
538
|
+
});
|
|
539
|
+
await sleep(delayMs);
|
|
540
|
+
return apiClient(originalRequest);
|
|
541
|
+
}
|
|
489
542
|
return Promise.reject(error);
|
|
490
543
|
}
|
|
491
544
|
);
|
|
@@ -620,6 +673,25 @@ function subscribeChannel(entry) {
|
|
|
620
673
|
scheduleResubscribe(entry, "SUBSCRIBE_FAILED");
|
|
621
674
|
}
|
|
622
675
|
}
|
|
676
|
+
function unsubscribeChannel(entry) {
|
|
677
|
+
var _a, _b;
|
|
678
|
+
if (!entry.channel) return;
|
|
679
|
+
try {
|
|
680
|
+
(_b = (_a = entry.channel).unsubscribe) == null ? void 0 : _b.call(_a);
|
|
681
|
+
} catch (error) {
|
|
682
|
+
realtimeLog.warn("[realtime] unsubscribe failed", error);
|
|
683
|
+
}
|
|
684
|
+
entry.channel = null;
|
|
685
|
+
}
|
|
686
|
+
function resetRealtimeState(reason) {
|
|
687
|
+
realtimeLog.warn(`[realtime] reset state ${reason}`);
|
|
688
|
+
entries.forEach((entry) => {
|
|
689
|
+
clearTimer(entry);
|
|
690
|
+
entry.backoffMs = INITIAL_BACKOFF_MS;
|
|
691
|
+
unsubscribeChannel(entry);
|
|
692
|
+
});
|
|
693
|
+
entries.clear();
|
|
694
|
+
}
|
|
623
695
|
function subscribeManagedChannel(key, configure) {
|
|
624
696
|
let entry = entries.get(key);
|
|
625
697
|
if (!entry) {
|
|
@@ -777,14 +849,12 @@ function useForegroundSignal(enabled = true) {
|
|
|
777
849
|
React2.useEffect(() => {
|
|
778
850
|
if (!enabled) return;
|
|
779
851
|
const sub = import_react_native4.AppState.addEventListener("change", (nextState) => {
|
|
780
|
-
var _a, _b;
|
|
781
852
|
const prevState = lastStateRef.current;
|
|
782
853
|
lastStateRef.current = nextState;
|
|
783
854
|
const didResume = (prevState === "background" || prevState === "inactive") && nextState === "active";
|
|
784
855
|
if (!didResume) return;
|
|
785
856
|
try {
|
|
786
|
-
|
|
787
|
-
(_b = (_a = supabase == null ? void 0 : supabase.realtime) == null ? void 0 : _a.connect) == null ? void 0 : _b.call(_a);
|
|
857
|
+
resetRealtimeState("APP_RESUME");
|
|
788
858
|
} catch {
|
|
789
859
|
}
|
|
790
860
|
setSignal((s) => s + 1);
|
|
@@ -799,8 +869,13 @@ function useApp(appId, options) {
|
|
|
799
869
|
const enabled = (options == null ? void 0 : options.enabled) ?? true;
|
|
800
870
|
const [app, setApp] = React3.useState(null);
|
|
801
871
|
const [loading, setLoading] = React3.useState(false);
|
|
872
|
+
const [refreshing, setRefreshing] = React3.useState(false);
|
|
802
873
|
const [error, setError] = React3.useState(null);
|
|
803
874
|
const foregroundSignal = useForegroundSignal(enabled && Boolean(appId));
|
|
875
|
+
const hasLoadedOnceRef = React3.useRef(false);
|
|
876
|
+
React3.useEffect(() => {
|
|
877
|
+
hasLoadedOnceRef.current = false;
|
|
878
|
+
}, [appId]);
|
|
804
879
|
const mergeApp = React3.useCallback((prev, next) => {
|
|
805
880
|
const merged = {
|
|
806
881
|
...prev ?? {},
|
|
@@ -810,21 +885,32 @@ function useApp(appId, options) {
|
|
|
810
885
|
};
|
|
811
886
|
return merged;
|
|
812
887
|
}, []);
|
|
813
|
-
const fetchOnce = React3.useCallback(async () => {
|
|
888
|
+
const fetchOnce = React3.useCallback(async (opts) => {
|
|
814
889
|
if (!enabled) return;
|
|
815
890
|
if (!appId) return;
|
|
816
|
-
|
|
891
|
+
const isBackground = Boolean(opts == null ? void 0 : opts.background);
|
|
892
|
+
const useBackgroundRefresh = isBackground && hasLoadedOnceRef.current;
|
|
893
|
+
if (useBackgroundRefresh) {
|
|
894
|
+
setRefreshing(true);
|
|
895
|
+
} else {
|
|
896
|
+
setLoading(true);
|
|
897
|
+
}
|
|
817
898
|
setError(null);
|
|
818
899
|
try {
|
|
819
900
|
const next = await appsRepository.getById(appId);
|
|
901
|
+
hasLoadedOnceRef.current = true;
|
|
820
902
|
setApp((prev) => mergeApp(prev, next));
|
|
821
903
|
} catch (e) {
|
|
822
904
|
setError(e instanceof Error ? e : new Error(String(e)));
|
|
823
905
|
setApp(null);
|
|
824
906
|
} finally {
|
|
825
|
-
|
|
907
|
+
if (useBackgroundRefresh) {
|
|
908
|
+
setRefreshing(false);
|
|
909
|
+
} else {
|
|
910
|
+
setLoading(false);
|
|
911
|
+
}
|
|
826
912
|
}
|
|
827
|
-
}, [appId, enabled]);
|
|
913
|
+
}, [appId, enabled, mergeApp]);
|
|
828
914
|
React3.useEffect(() => {
|
|
829
915
|
if (!enabled) return;
|
|
830
916
|
void fetchOnce();
|
|
@@ -849,9 +935,9 @@ function useApp(appId, options) {
|
|
|
849
935
|
if (!enabled) return;
|
|
850
936
|
if (!appId) return;
|
|
851
937
|
if (foregroundSignal <= 0) return;
|
|
852
|
-
void fetchOnce();
|
|
938
|
+
void fetchOnce({ background: true });
|
|
853
939
|
}, [appId, enabled, fetchOnce, foregroundSignal]);
|
|
854
|
-
return { app, loading, error, refetch: fetchOnce };
|
|
940
|
+
return { app, loading, refreshing, error, refetch: fetchOnce };
|
|
855
941
|
}
|
|
856
942
|
|
|
857
943
|
// src/studio/hooks/useThreadMessages.ts
|
|
@@ -985,33 +1071,52 @@ function mapMessageToChatMessage(m) {
|
|
|
985
1071
|
function useThreadMessages(threadId) {
|
|
986
1072
|
const [raw, setRaw] = React4.useState([]);
|
|
987
1073
|
const [loading, setLoading] = React4.useState(false);
|
|
1074
|
+
const [refreshing, setRefreshing] = React4.useState(false);
|
|
988
1075
|
const [error, setError] = React4.useState(null);
|
|
989
1076
|
const activeRequestIdRef = React4.useRef(0);
|
|
990
1077
|
const foregroundSignal = useForegroundSignal(Boolean(threadId));
|
|
1078
|
+
const hasLoadedOnceRef = React4.useRef(false);
|
|
1079
|
+
React4.useEffect(() => {
|
|
1080
|
+
hasLoadedOnceRef.current = false;
|
|
1081
|
+
}, [threadId]);
|
|
991
1082
|
const upsertSorted = React4.useCallback((prev, m) => {
|
|
992
1083
|
const next = prev.filter((x) => x.id !== m.id);
|
|
993
1084
|
next.push(m);
|
|
994
1085
|
next.sort(compareMessages);
|
|
995
1086
|
return next;
|
|
996
1087
|
}, []);
|
|
997
|
-
const refetch = React4.useCallback(async () => {
|
|
1088
|
+
const refetch = React4.useCallback(async (opts) => {
|
|
998
1089
|
if (!threadId) {
|
|
999
1090
|
setRaw([]);
|
|
1091
|
+
setLoading(false);
|
|
1092
|
+
setRefreshing(false);
|
|
1000
1093
|
return;
|
|
1001
1094
|
}
|
|
1002
1095
|
const requestId = ++activeRequestIdRef.current;
|
|
1003
|
-
|
|
1096
|
+
const isBackground = Boolean(opts == null ? void 0 : opts.background);
|
|
1097
|
+
const useBackgroundRefresh = isBackground && hasLoadedOnceRef.current;
|
|
1098
|
+
if (useBackgroundRefresh) {
|
|
1099
|
+
setRefreshing(true);
|
|
1100
|
+
} else {
|
|
1101
|
+
setLoading(true);
|
|
1102
|
+
}
|
|
1004
1103
|
setError(null);
|
|
1005
1104
|
try {
|
|
1006
1105
|
const list = await messagesRepository.list(threadId);
|
|
1007
1106
|
if (activeRequestIdRef.current !== requestId) return;
|
|
1107
|
+
hasLoadedOnceRef.current = true;
|
|
1008
1108
|
setRaw([...list].sort(compareMessages));
|
|
1009
1109
|
} catch (e) {
|
|
1010
1110
|
if (activeRequestIdRef.current !== requestId) return;
|
|
1011
1111
|
setError(e instanceof Error ? e : new Error(String(e)));
|
|
1012
1112
|
setRaw([]);
|
|
1013
1113
|
} finally {
|
|
1014
|
-
if (activeRequestIdRef.current
|
|
1114
|
+
if (activeRequestIdRef.current !== requestId) return;
|
|
1115
|
+
if (useBackgroundRefresh) {
|
|
1116
|
+
setRefreshing(false);
|
|
1117
|
+
} else {
|
|
1118
|
+
setLoading(false);
|
|
1119
|
+
}
|
|
1015
1120
|
}
|
|
1016
1121
|
}, [threadId]);
|
|
1017
1122
|
React4.useEffect(() => {
|
|
@@ -1029,14 +1134,14 @@ function useThreadMessages(threadId) {
|
|
|
1029
1134
|
React4.useEffect(() => {
|
|
1030
1135
|
if (!threadId) return;
|
|
1031
1136
|
if (foregroundSignal <= 0) return;
|
|
1032
|
-
void refetch();
|
|
1137
|
+
void refetch({ background: true });
|
|
1033
1138
|
}, [foregroundSignal, refetch, threadId]);
|
|
1034
1139
|
const messages = React4.useMemo(() => {
|
|
1035
1140
|
const visible = raw.filter((m) => !isQueuedHiddenMessage(m));
|
|
1036
1141
|
const resolved = visible.length > 0 ? visible : raw;
|
|
1037
1142
|
return resolved.map(mapMessageToChatMessage);
|
|
1038
1143
|
}, [raw]);
|
|
1039
|
-
return { raw, messages, loading, error, refetch };
|
|
1144
|
+
return { raw, messages, loading, refreshing, error, refetch };
|
|
1040
1145
|
}
|
|
1041
1146
|
|
|
1042
1147
|
// src/studio/hooks/useBundleManager.ts
|
|
@@ -1056,21 +1161,22 @@ var BundlesRemoteDataSourceImpl = class extends BaseRemote {
|
|
|
1056
1161
|
}
|
|
1057
1162
|
async getById(appId, bundleId) {
|
|
1058
1163
|
const { data } = await api.get(
|
|
1059
|
-
`/v1/apps/${encodeURIComponent(appId)}/bundles/${encodeURIComponent(bundleId)}
|
|
1164
|
+
`/v1/apps/${encodeURIComponent(appId)}/bundles/${encodeURIComponent(bundleId)}`,
|
|
1165
|
+
{ skipRetry: true }
|
|
1060
1166
|
);
|
|
1061
1167
|
return data;
|
|
1062
1168
|
}
|
|
1063
1169
|
async getSignedDownloadUrl(appId, bundleId, options) {
|
|
1064
1170
|
const { data } = await api.get(
|
|
1065
1171
|
`/v1/apps/${encodeURIComponent(appId)}/bundles/${encodeURIComponent(bundleId)}/download`,
|
|
1066
|
-
{ params: { redirect: (options == null ? void 0 : options.redirect) ?? false } }
|
|
1172
|
+
{ params: { redirect: (options == null ? void 0 : options.redirect) ?? false }, skipRetry: true }
|
|
1067
1173
|
);
|
|
1068
1174
|
return data;
|
|
1069
1175
|
}
|
|
1070
1176
|
async getSignedAssetsDownloadUrl(appId, bundleId, options) {
|
|
1071
1177
|
const { data } = await api.get(
|
|
1072
1178
|
`/v1/apps/${encodeURIComponent(appId)}/bundles/${encodeURIComponent(bundleId)}/assets/download`,
|
|
1073
|
-
{ params: { redirect: (options == null ? void 0 : options.redirect) ?? false, kind: options == null ? void 0 : options.kind } }
|
|
1179
|
+
{ params: { redirect: (options == null ? void 0 : options.redirect) ?? false, kind: options == null ? void 0 : options.kind }, skipRetry: true }
|
|
1074
1180
|
);
|
|
1075
1181
|
return data;
|
|
1076
1182
|
}
|
|
@@ -1103,10 +1209,10 @@ var BundlesRepositoryImpl = class extends BaseRepository {
|
|
|
1103
1209
|
var bundlesRepository = new BundlesRepositoryImpl(bundlesRemoteDataSource);
|
|
1104
1210
|
|
|
1105
1211
|
// src/studio/hooks/useBundleManager.ts
|
|
1106
|
-
function
|
|
1212
|
+
function sleep2(ms) {
|
|
1107
1213
|
return new Promise((r) => setTimeout(r, ms));
|
|
1108
1214
|
}
|
|
1109
|
-
function
|
|
1215
|
+
function isRetryableNetworkError2(e) {
|
|
1110
1216
|
var _a;
|
|
1111
1217
|
const err = e;
|
|
1112
1218
|
const code = typeof (err == null ? void 0 : err.code) === "string" ? err.code : "";
|
|
@@ -1125,13 +1231,13 @@ async function withRetry(fn, opts) {
|
|
|
1125
1231
|
return await fn();
|
|
1126
1232
|
} catch (e) {
|
|
1127
1233
|
lastErr = e;
|
|
1128
|
-
const retryable =
|
|
1234
|
+
const retryable = isRetryableNetworkError2(e);
|
|
1129
1235
|
if (!retryable || attempt >= opts.attempts) {
|
|
1130
1236
|
throw e;
|
|
1131
1237
|
}
|
|
1132
1238
|
const exp = Math.min(opts.maxDelayMs, opts.baseDelayMs * Math.pow(2, attempt - 1));
|
|
1133
1239
|
const jitter = Math.floor(Math.random() * 250);
|
|
1134
|
-
await
|
|
1240
|
+
await sleep2(exp + jitter);
|
|
1135
1241
|
}
|
|
1136
1242
|
}
|
|
1137
1243
|
throw lastErr;
|
|
@@ -1408,14 +1514,14 @@ async function pollBundle(appId, bundleId, opts) {
|
|
|
1408
1514
|
const bundle = await bundlesRepository.getById(appId, bundleId);
|
|
1409
1515
|
if (bundle.status === "succeeded" || bundle.status === "failed") return bundle;
|
|
1410
1516
|
} catch (e) {
|
|
1411
|
-
if (!
|
|
1517
|
+
if (!isRetryableNetworkError2(e)) {
|
|
1412
1518
|
throw e;
|
|
1413
1519
|
}
|
|
1414
1520
|
}
|
|
1415
1521
|
if (Date.now() - start > opts.timeoutMs) {
|
|
1416
1522
|
throw new Error("Bundle build timed out.");
|
|
1417
1523
|
}
|
|
1418
|
-
await
|
|
1524
|
+
await sleep2(opts.intervalMs);
|
|
1419
1525
|
}
|
|
1420
1526
|
}
|
|
1421
1527
|
async function resolveBundlePath(src, platform, mode) {
|
|
@@ -1484,6 +1590,7 @@ function useBundleManager({
|
|
|
1484
1590
|
const baseOpIdRef = React5.useRef(0);
|
|
1485
1591
|
const testOpIdRef = React5.useRef(0);
|
|
1486
1592
|
const activeLoadModeRef = React5.useRef(null);
|
|
1593
|
+
const desiredModeRef = React5.useRef("base");
|
|
1487
1594
|
const canRequestLatestRef = React5.useRef(canRequestLatest);
|
|
1488
1595
|
React5.useEffect(() => {
|
|
1489
1596
|
canRequestLatestRef.current = canRequestLatest;
|
|
@@ -1571,6 +1678,10 @@ function useBundleManager({
|
|
|
1571
1678
|
);
|
|
1572
1679
|
const load = React5.useCallback(async (src, mode) => {
|
|
1573
1680
|
if (!src.appId) return;
|
|
1681
|
+
if (mode === "test") {
|
|
1682
|
+
desiredModeRef.current = "test";
|
|
1683
|
+
baseOpIdRef.current += 1;
|
|
1684
|
+
}
|
|
1574
1685
|
const canRequestLatest2 = canRequestLatestRef.current;
|
|
1575
1686
|
if (mode === "base" && !canRequestLatest2) {
|
|
1576
1687
|
await activateCachedBase(src.appId);
|
|
@@ -1582,13 +1693,14 @@ function useBundleManager({
|
|
|
1582
1693
|
setLoadingMode(mode);
|
|
1583
1694
|
setError(null);
|
|
1584
1695
|
setStatusLabel(mode === "test" ? "Loading test bundle\u2026" : "Loading latest build\u2026");
|
|
1585
|
-
if (mode === "base") {
|
|
1696
|
+
if (mode === "base" && desiredModeRef.current === "base") {
|
|
1586
1697
|
void activateCachedBase(src.appId);
|
|
1587
1698
|
}
|
|
1588
1699
|
try {
|
|
1589
1700
|
const { bundlePath: path, bundle } = await resolveBundlePath(src, platform, mode);
|
|
1590
1701
|
if (mode === "base" && opId !== baseOpIdRef.current) return;
|
|
1591
1702
|
if (mode === "test" && opId !== testOpIdRef.current) return;
|
|
1703
|
+
if (desiredModeRef.current !== mode) return;
|
|
1592
1704
|
setBundlePath(path);
|
|
1593
1705
|
const fingerprint = bundle.checksumSha256 ?? `id:${bundle.id}`;
|
|
1594
1706
|
const shouldSkipInitialBaseRemount = mode === "base" && initialHydratedBaseFromDiskRef.current && !hasCompletedFirstNetworkBaseLoadRef.current && Boolean(lastBaseFingerprintRef.current) && lastBaseFingerprintRef.current === fingerprint;
|
|
@@ -1644,6 +1756,8 @@ function useBundleManager({
|
|
|
1644
1756
|
const restoreBase = React5.useCallback(async () => {
|
|
1645
1757
|
const src = baseRef.current;
|
|
1646
1758
|
if (!src.appId) return;
|
|
1759
|
+
desiredModeRef.current = "base";
|
|
1760
|
+
testOpIdRef.current += 1;
|
|
1647
1761
|
await activateCachedBase(src.appId);
|
|
1648
1762
|
if (canRequestLatestRef.current) {
|
|
1649
1763
|
await load(src, "base");
|
|
@@ -1805,9 +1919,12 @@ function useMergeRequests(params) {
|
|
|
1805
1919
|
const { appId } = params;
|
|
1806
1920
|
const [incoming, setIncoming] = React6.useState([]);
|
|
1807
1921
|
const [outgoing, setOutgoing] = React6.useState([]);
|
|
1808
|
-
const [loading, setLoading] = React6.useState(
|
|
1922
|
+
const [loading, setLoading] = React6.useState(() => Boolean(appId));
|
|
1809
1923
|
const [error, setError] = React6.useState(null);
|
|
1810
1924
|
const [creatorStatsById, setCreatorStatsById] = React6.useState({});
|
|
1925
|
+
React6.useEffect(() => {
|
|
1926
|
+
setLoading(Boolean(appId));
|
|
1927
|
+
}, [appId]);
|
|
1811
1928
|
const pollUntilMerged = React6.useCallback(async (mrId) => {
|
|
1812
1929
|
const startedAt = Date.now();
|
|
1813
1930
|
const timeoutMs = 2 * 60 * 1e3;
|
|
@@ -1823,6 +1940,7 @@ function useMergeRequests(params) {
|
|
|
1823
1940
|
setIncoming([]);
|
|
1824
1941
|
setOutgoing([]);
|
|
1825
1942
|
setCreatorStatsById({});
|
|
1943
|
+
setLoading(false);
|
|
1826
1944
|
return;
|
|
1827
1945
|
}
|
|
1828
1946
|
setLoading(true);
|
|
@@ -2057,6 +2175,45 @@ var AgentRepositoryImpl = class extends BaseRepository {
|
|
|
2057
2175
|
var agentRepository = new AgentRepositoryImpl(agentRemoteDataSource);
|
|
2058
2176
|
|
|
2059
2177
|
// src/studio/hooks/useStudioActions.ts
|
|
2178
|
+
function sleep3(ms) {
|
|
2179
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2180
|
+
}
|
|
2181
|
+
function isRetryableNetworkError3(e) {
|
|
2182
|
+
var _a;
|
|
2183
|
+
const err = e;
|
|
2184
|
+
const code = typeof (err == null ? void 0 : err.code) === "string" ? err.code : "";
|
|
2185
|
+
const message = typeof (err == null ? void 0 : err.message) === "string" ? err.message : "";
|
|
2186
|
+
if (code === "ERR_NETWORK" || code === "ECONNABORTED") return true;
|
|
2187
|
+
if (message.toLowerCase().includes("network error")) return true;
|
|
2188
|
+
if (message.toLowerCase().includes("timeout")) return true;
|
|
2189
|
+
const status = typeof ((_a = err == null ? void 0 : err.response) == null ? void 0 : _a.status) === "number" ? err.response.status : void 0;
|
|
2190
|
+
if (status && (status === 429 || status >= 500)) return true;
|
|
2191
|
+
return false;
|
|
2192
|
+
}
|
|
2193
|
+
async function withRetry2(fn, opts) {
|
|
2194
|
+
let lastErr = null;
|
|
2195
|
+
for (let attempt = 1; attempt <= opts.attempts; attempt += 1) {
|
|
2196
|
+
try {
|
|
2197
|
+
return await fn();
|
|
2198
|
+
} catch (e) {
|
|
2199
|
+
lastErr = e;
|
|
2200
|
+
const retryable = isRetryableNetworkError3(e);
|
|
2201
|
+
if (!retryable || attempt >= opts.attempts) {
|
|
2202
|
+
throw e;
|
|
2203
|
+
}
|
|
2204
|
+
const exp = Math.min(opts.maxDelayMs, opts.baseDelayMs * Math.pow(2, attempt - 1));
|
|
2205
|
+
const jitter = Math.floor(Math.random() * 250);
|
|
2206
|
+
await sleep3(exp + jitter);
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
throw lastErr;
|
|
2210
|
+
}
|
|
2211
|
+
function generateIdempotencyKey() {
|
|
2212
|
+
var _a, _b;
|
|
2213
|
+
const rnd = (_b = (_a = globalThis.crypto) == null ? void 0 : _a.randomUUID) == null ? void 0 : _b.call(_a);
|
|
2214
|
+
if (rnd) return `edit:${rnd}`;
|
|
2215
|
+
return `edit:${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
2216
|
+
}
|
|
2060
2217
|
function useStudioActions({
|
|
2061
2218
|
userId,
|
|
2062
2219
|
app,
|
|
@@ -2095,12 +2252,19 @@ function useStudioActions({
|
|
|
2095
2252
|
if (attachments && attachments.length > 0 && uploadAttachments) {
|
|
2096
2253
|
attachmentMetas = await uploadAttachments({ threadId, appId: targetApp.id, dataUrls: attachments });
|
|
2097
2254
|
}
|
|
2098
|
-
const
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2255
|
+
const idempotencyKey = generateIdempotencyKey();
|
|
2256
|
+
const editResult = await withRetry2(
|
|
2257
|
+
async () => {
|
|
2258
|
+
return await agentRepository.editApp({
|
|
2259
|
+
prompt,
|
|
2260
|
+
thread_id: threadId,
|
|
2261
|
+
app_id: targetApp.id,
|
|
2262
|
+
attachments: attachmentMetas && attachmentMetas.length > 0 ? attachmentMetas : void 0,
|
|
2263
|
+
idempotencyKey
|
|
2264
|
+
});
|
|
2265
|
+
},
|
|
2266
|
+
{ attempts: 3, baseDelayMs: 500, maxDelayMs: 4e3 }
|
|
2267
|
+
);
|
|
2104
2268
|
onEditQueued == null ? void 0 : onEditQueued({
|
|
2105
2269
|
queueItemId: editResult.queueItemId ?? null,
|
|
2106
2270
|
queuePosition: editResult.queuePosition ?? null
|
|
@@ -2158,12 +2322,12 @@ function RuntimeRenderer({
|
|
|
2158
2322
|
|
|
2159
2323
|
// src/studio/ui/StudioOverlay.tsx
|
|
2160
2324
|
var React44 = __toESM(require("react"));
|
|
2161
|
-
var
|
|
2325
|
+
var import_react_native56 = require("react-native");
|
|
2162
2326
|
|
|
2163
2327
|
// src/components/studio-sheet/StudioBottomSheet.tsx
|
|
2164
2328
|
var React12 = __toESM(require("react"));
|
|
2165
2329
|
var import_react_native9 = require("react-native");
|
|
2166
|
-
var import_bottom_sheet =
|
|
2330
|
+
var import_bottom_sheet = require("@gorhom/bottom-sheet");
|
|
2167
2331
|
var import_react_native_safe_area_context = require("react-native-safe-area-context");
|
|
2168
2332
|
|
|
2169
2333
|
// src/components/studio-sheet/StudioSheetBackground.tsx
|
|
@@ -2282,25 +2446,16 @@ function StudioBottomSheet({
|
|
|
2282
2446
|
const insets = (0, import_react_native_safe_area_context.useSafeAreaInsets)();
|
|
2283
2447
|
const internalSheetRef = React12.useRef(null);
|
|
2284
2448
|
const resolvedSheetRef = sheetRef ?? internalSheetRef;
|
|
2285
|
-
const
|
|
2449
|
+
const resolvedSnapPoints = React12.useMemo(() => [...snapPoints], [snapPoints]);
|
|
2450
|
+
const currentIndexRef = React12.useRef(open ? resolvedSnapPoints.length - 1 : -1);
|
|
2286
2451
|
const lastAppStateRef = React12.useRef(import_react_native9.AppState.currentState);
|
|
2287
2452
|
React12.useEffect(() => {
|
|
2288
2453
|
const sub = import_react_native9.AppState.addEventListener("change", (state) => {
|
|
2289
|
-
const prev = lastAppStateRef.current;
|
|
2290
2454
|
lastAppStateRef.current = state;
|
|
2291
2455
|
if (state === "background" || state === "inactive") {
|
|
2292
2456
|
import_react_native9.Keyboard.dismiss();
|
|
2293
2457
|
return;
|
|
2294
2458
|
}
|
|
2295
|
-
if (state !== "active") return;
|
|
2296
|
-
const sheet = resolvedSheetRef.current;
|
|
2297
|
-
if (!sheet) return;
|
|
2298
|
-
const idx = currentIndexRef.current;
|
|
2299
|
-
if (open && idx >= 0) {
|
|
2300
|
-
import_react_native9.Keyboard.dismiss();
|
|
2301
|
-
requestAnimationFrame(() => sheet.snapToIndex(idx));
|
|
2302
|
-
setTimeout(() => sheet.snapToIndex(idx), 120);
|
|
2303
|
-
}
|
|
2304
2459
|
});
|
|
2305
2460
|
return () => sub.remove();
|
|
2306
2461
|
}, [open, resolvedSheetRef]);
|
|
@@ -2308,11 +2463,11 @@ function StudioBottomSheet({
|
|
|
2308
2463
|
const sheet = resolvedSheetRef.current;
|
|
2309
2464
|
if (!sheet) return;
|
|
2310
2465
|
if (open) {
|
|
2311
|
-
sheet.
|
|
2466
|
+
sheet.present();
|
|
2312
2467
|
} else {
|
|
2313
|
-
sheet.
|
|
2468
|
+
sheet.dismiss();
|
|
2314
2469
|
}
|
|
2315
|
-
}, [open, resolvedSheetRef,
|
|
2470
|
+
}, [open, resolvedSheetRef, resolvedSnapPoints.length]);
|
|
2316
2471
|
const handleChange = React12.useCallback(
|
|
2317
2472
|
(index) => {
|
|
2318
2473
|
currentIndexRef.current = index;
|
|
@@ -2321,21 +2476,24 @@ function StudioBottomSheet({
|
|
|
2321
2476
|
[onOpenChange]
|
|
2322
2477
|
);
|
|
2323
2478
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2324
|
-
import_bottom_sheet.
|
|
2479
|
+
import_bottom_sheet.BottomSheetModal,
|
|
2325
2480
|
{
|
|
2326
2481
|
ref: resolvedSheetRef,
|
|
2327
|
-
index:
|
|
2328
|
-
snapPoints,
|
|
2482
|
+
index: resolvedSnapPoints.length - 1,
|
|
2483
|
+
snapPoints: resolvedSnapPoints,
|
|
2329
2484
|
enableDynamicSizing: false,
|
|
2330
2485
|
enablePanDownToClose: true,
|
|
2331
2486
|
enableContentPanningGesture: false,
|
|
2487
|
+
keyboardBehavior: "interactive",
|
|
2488
|
+
keyboardBlurBehavior: "restore",
|
|
2332
2489
|
android_keyboardInputMode: "adjustResize",
|
|
2333
2490
|
backgroundComponent: (props) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(StudioSheetBackground, { ...props, renderBackground: background == null ? void 0 : background.renderBackground }),
|
|
2334
2491
|
topInset: insets.top,
|
|
2335
2492
|
bottomInset: 0,
|
|
2336
2493
|
handleIndicatorStyle: { backgroundColor: theme.colors.handleIndicator },
|
|
2337
|
-
onChange: handleChange,
|
|
2338
2494
|
...bottomSheetProps,
|
|
2495
|
+
onChange: handleChange,
|
|
2496
|
+
onDismiss: () => onOpenChange == null ? void 0 : onOpenChange(false),
|
|
2339
2497
|
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native9.View, { style: { flex: 1, overflow: "hidden" }, children })
|
|
2340
2498
|
}
|
|
2341
2499
|
);
|
|
@@ -2413,6 +2571,21 @@ var ENTER_SCALE_FROM = 0.3;
|
|
|
2413
2571
|
var ENTER_ROTATION_FROM_DEG = -180;
|
|
2414
2572
|
var PULSE_DURATION_MS = 900;
|
|
2415
2573
|
|
|
2574
|
+
// src/components/utils/color.ts
|
|
2575
|
+
function withAlpha(color, alpha) {
|
|
2576
|
+
const a = Math.max(0, Math.min(1, alpha));
|
|
2577
|
+
const hex = color.trim();
|
|
2578
|
+
if (!hex.startsWith("#")) return color;
|
|
2579
|
+
const raw = hex.slice(1);
|
|
2580
|
+
const expanded = raw.length === 3 ? raw.split("").map((c) => c + c).join("") : raw;
|
|
2581
|
+
if (expanded.length !== 6) return color;
|
|
2582
|
+
const r = Number.parseInt(expanded.slice(0, 2), 16);
|
|
2583
|
+
const g = Number.parseInt(expanded.slice(2, 4), 16);
|
|
2584
|
+
const b = Number.parseInt(expanded.slice(4, 6), 16);
|
|
2585
|
+
if ([r, g, b].some((n) => Number.isNaN(n))) return color;
|
|
2586
|
+
return `rgba(${r}, ${g}, ${b}, ${a})`;
|
|
2587
|
+
}
|
|
2588
|
+
|
|
2416
2589
|
// src/components/bubble/Bubble.tsx
|
|
2417
2590
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
2418
2591
|
var HIDDEN_OFFSET_X = 20;
|
|
@@ -2441,6 +2614,7 @@ function Bubble({
|
|
|
2441
2614
|
disabled = false,
|
|
2442
2615
|
ariaLabel,
|
|
2443
2616
|
isLoading = false,
|
|
2617
|
+
loadingBorderTone = "default",
|
|
2444
2618
|
visible = true,
|
|
2445
2619
|
badgeCount = 0,
|
|
2446
2620
|
offset = DEFAULT_OFFSET,
|
|
@@ -2464,6 +2638,10 @@ function Bubble({
|
|
|
2464
2638
|
if (isDanger) return "rgba(239, 68, 68, 0.9)";
|
|
2465
2639
|
return theme.scheme === "dark" ? "rgba(0, 0, 0, 0.6)" : "rgba(255, 255, 255, 0.6)";
|
|
2466
2640
|
}, [backgroundColor, isDanger, theme.scheme]);
|
|
2641
|
+
const warningRingColors = (0, import_react.useMemo)(
|
|
2642
|
+
() => [withAlpha(theme.colors.warning, 0.35), withAlpha(theme.colors.warning, 1)],
|
|
2643
|
+
[theme.colors.warning]
|
|
2644
|
+
);
|
|
2467
2645
|
const translateX = (0, import_react_native_reanimated.useSharedValue)(getHiddenTranslateX(size));
|
|
2468
2646
|
const translateY = (0, import_react_native_reanimated.useSharedValue)(getHiddenTranslateY(height));
|
|
2469
2647
|
const scale = (0, import_react_native_reanimated.useSharedValue)(ENTER_SCALE_FROM);
|
|
@@ -2484,18 +2662,15 @@ function Bubble({
|
|
|
2484
2662
|
[height, rotation, scale, size, translateX, translateY]
|
|
2485
2663
|
);
|
|
2486
2664
|
const animateOut = (0, import_react.useCallback)(() => {
|
|
2665
|
+
var _a;
|
|
2487
2666
|
if (isAnimatingOut.current) return;
|
|
2488
2667
|
isAnimatingOut.current = true;
|
|
2489
2668
|
try {
|
|
2490
2669
|
void Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
|
|
2491
2670
|
} catch {
|
|
2492
2671
|
}
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
var _a;
|
|
2496
|
-
(_a = onPressRef.current) == null ? void 0 : _a.call(onPressRef);
|
|
2497
|
-
}
|
|
2498
|
-
});
|
|
2672
|
+
(_a = onPressRef.current) == null ? void 0 : _a.call(onPressRef);
|
|
2673
|
+
animateToHidden();
|
|
2499
2674
|
}, [animateToHidden]);
|
|
2500
2675
|
(0, import_react.useEffect)(() => {
|
|
2501
2676
|
if (isLoading) {
|
|
@@ -2580,10 +2755,11 @@ function Bubble({
|
|
|
2580
2755
|
]
|
|
2581
2756
|
}));
|
|
2582
2757
|
const borderAnimatedStyle = (0, import_react_native_reanimated.useAnimatedStyle)(() => {
|
|
2758
|
+
const isWarning = loadingBorderTone === "warning";
|
|
2583
2759
|
const borderColor = (0, import_react_native_reanimated.interpolateColor)(
|
|
2584
2760
|
borderPulse.value,
|
|
2585
2761
|
[0, 1],
|
|
2586
|
-
isDanger ? ["rgba(239,68,68,0.4)", "rgba(239,68,68,1)"] : theme.scheme === "dark" ? ["rgba(255,255,255,0.2)", "rgba(255,255,255,0.9)"] : ["rgba(55,0,179,0.2)", "rgba(55,0,179,0.9)"]
|
|
2762
|
+
isDanger ? ["rgba(239,68,68,0.4)", "rgba(239,68,68,1)"] : isWarning ? warningRingColors : theme.scheme === "dark" ? ["rgba(255,255,255,0.2)", "rgba(255,255,255,0.9)"] : ["rgba(55,0,179,0.2)", "rgba(55,0,179,0.9)"]
|
|
2587
2763
|
);
|
|
2588
2764
|
return {
|
|
2589
2765
|
borderWidth: isLoading ? 2 : 0,
|
|
@@ -2663,23 +2839,6 @@ var styles = import_react_native11.StyleSheet.create({
|
|
|
2663
2839
|
var React14 = __toESM(require("react"));
|
|
2664
2840
|
var import_react_native12 = require("react-native");
|
|
2665
2841
|
var import_expo_linear_gradient = require("expo-linear-gradient");
|
|
2666
|
-
|
|
2667
|
-
// src/components/utils/color.ts
|
|
2668
|
-
function withAlpha(color, alpha) {
|
|
2669
|
-
const a = Math.max(0, Math.min(1, alpha));
|
|
2670
|
-
const hex = color.trim();
|
|
2671
|
-
if (!hex.startsWith("#")) return color;
|
|
2672
|
-
const raw = hex.slice(1);
|
|
2673
|
-
const expanded = raw.length === 3 ? raw.split("").map((c) => c + c).join("") : raw;
|
|
2674
|
-
if (expanded.length !== 6) return color;
|
|
2675
|
-
const r = Number.parseInt(expanded.slice(0, 2), 16);
|
|
2676
|
-
const g = Number.parseInt(expanded.slice(2, 4), 16);
|
|
2677
|
-
const b = Number.parseInt(expanded.slice(4, 6), 16);
|
|
2678
|
-
if ([r, g, b].some((n) => Number.isNaN(n))) return color;
|
|
2679
|
-
return `rgba(${r}, ${g}, ${b}, ${a})`;
|
|
2680
|
-
}
|
|
2681
|
-
|
|
2682
|
-
// src/components/overlays/EdgeGlowFrame.tsx
|
|
2683
2842
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
2684
2843
|
function baseColor(role, theme) {
|
|
2685
2844
|
switch (role) {
|
|
@@ -3401,7 +3560,6 @@ function ChatComposer({
|
|
|
3401
3560
|
disabled = false,
|
|
3402
3561
|
sendDisabled = false,
|
|
3403
3562
|
sending = false,
|
|
3404
|
-
autoFocus = false,
|
|
3405
3563
|
onSend,
|
|
3406
3564
|
attachments = [],
|
|
3407
3565
|
onRemoveAttachment,
|
|
@@ -3424,18 +3582,6 @@ function ChatComposer({
|
|
|
3424
3582
|
const maxInputHeight = React19.useMemo(() => import_react_native18.Dimensions.get("window").height * 0.5, []);
|
|
3425
3583
|
const shakeAnim = React19.useRef(new import_react_native18.Animated.Value(0)).current;
|
|
3426
3584
|
const [sendPressed, setSendPressed] = React19.useState(false);
|
|
3427
|
-
const inputRef = React19.useRef(null);
|
|
3428
|
-
const prevAutoFocusRef = React19.useRef(false);
|
|
3429
|
-
React19.useEffect(() => {
|
|
3430
|
-
const shouldFocus = autoFocus && !prevAutoFocusRef.current && !disabled && !sending;
|
|
3431
|
-
prevAutoFocusRef.current = autoFocus;
|
|
3432
|
-
if (!shouldFocus) return;
|
|
3433
|
-
const t = setTimeout(() => {
|
|
3434
|
-
var _a;
|
|
3435
|
-
(_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
3436
|
-
}, 75);
|
|
3437
|
-
return () => clearTimeout(t);
|
|
3438
|
-
}, [autoFocus, disabled, sending]);
|
|
3439
3585
|
const triggerShake = React19.useCallback(() => {
|
|
3440
3586
|
shakeAnim.setValue(0);
|
|
3441
3587
|
import_react_native18.Animated.sequence([
|
|
@@ -3466,7 +3612,7 @@ function ChatComposer({
|
|
|
3466
3612
|
onLayout: (e) => onLayout == null ? void 0 : onLayout({ height: e.nativeEvent.layout.height }),
|
|
3467
3613
|
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react_native18.View, { style: { flexDirection: "row", alignItems: "flex-end", gap: 8 }, children: [
|
|
3468
3614
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native18.Animated.View, { style: { flex: 1, transform: [{ translateX: shakeAnim }] }, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
3469
|
-
|
|
3615
|
+
import_liquid_glass4.LiquidGlassView,
|
|
3470
3616
|
{
|
|
3471
3617
|
style: [
|
|
3472
3618
|
// LiquidGlassView doesn't reliably auto-size to children; ensure enough height for the
|
|
@@ -3518,13 +3664,12 @@ function ChatComposer({
|
|
|
3518
3664
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3519
3665
|
MultilineTextInput,
|
|
3520
3666
|
{
|
|
3521
|
-
ref: inputRef,
|
|
3522
3667
|
value: text,
|
|
3523
3668
|
onChangeText: setText,
|
|
3524
3669
|
placeholder,
|
|
3525
3670
|
editable: !disabled && !sending,
|
|
3526
3671
|
useBottomSheetTextInput,
|
|
3527
|
-
autoFocus,
|
|
3672
|
+
autoFocus: false,
|
|
3528
3673
|
placeholderTextColor,
|
|
3529
3674
|
scrollEnabled: true,
|
|
3530
3675
|
style: {
|
|
@@ -4950,10 +5095,42 @@ var import_lucide_react_native7 = require("lucide-react-native");
|
|
|
4950
5095
|
// src/components/primitives/MarkdownText.tsx
|
|
4951
5096
|
var import_react_native37 = require("react-native");
|
|
4952
5097
|
var import_react_native_markdown_display = __toESM(require("react-native-markdown-display"));
|
|
5098
|
+
var import_react2 = require("react");
|
|
4953
5099
|
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
5100
|
+
function copyMarkdownToClipboard(markdown) {
|
|
5101
|
+
var _a;
|
|
5102
|
+
if (!markdown) {
|
|
5103
|
+
return;
|
|
5104
|
+
}
|
|
5105
|
+
const navigatorClipboard = (_a = globalThis == null ? void 0 : globalThis.navigator) == null ? void 0 : _a.clipboard;
|
|
5106
|
+
if (navigatorClipboard == null ? void 0 : navigatorClipboard.writeText) {
|
|
5107
|
+
void navigatorClipboard.writeText(markdown);
|
|
5108
|
+
return;
|
|
5109
|
+
}
|
|
5110
|
+
try {
|
|
5111
|
+
const expoClipboard = require("expo-clipboard");
|
|
5112
|
+
if (expoClipboard == null ? void 0 : expoClipboard.setStringAsync) {
|
|
5113
|
+
void expoClipboard.setStringAsync(markdown);
|
|
5114
|
+
return;
|
|
5115
|
+
}
|
|
5116
|
+
} catch {
|
|
5117
|
+
}
|
|
5118
|
+
try {
|
|
5119
|
+
const rnClipboard = require("@react-native-clipboard/clipboard");
|
|
5120
|
+
if (rnClipboard == null ? void 0 : rnClipboard.setString) {
|
|
5121
|
+
rnClipboard.setString(markdown);
|
|
5122
|
+
}
|
|
5123
|
+
} catch {
|
|
5124
|
+
}
|
|
5125
|
+
}
|
|
4954
5126
|
function MarkdownText({ markdown, variant = "chat", bodyColor, style }) {
|
|
4955
5127
|
const theme = useTheme();
|
|
4956
5128
|
const isDark = theme.scheme === "dark";
|
|
5129
|
+
const [showCopied, setShowCopied] = (0, import_react2.useState)(false);
|
|
5130
|
+
const [tooltipPosition, setTooltipPosition] = (0, import_react2.useState)(null);
|
|
5131
|
+
const [tooltipWidth, setTooltipWidth] = (0, import_react2.useState)(0);
|
|
5132
|
+
const hideTimerRef = (0, import_react2.useRef)(null);
|
|
5133
|
+
const containerRef = (0, import_react2.useRef)(null);
|
|
4957
5134
|
const baseBodyColor = variant === "mergeRequest" ? theme.colors.textMuted : theme.colors.text;
|
|
4958
5135
|
const linkColor = variant === "mergeRequest" ? isDark ? theme.colors.primary : "#3700B3" : theme.colors.link;
|
|
4959
5136
|
const linkWeight = variant === "mergeRequest" ? theme.typography.fontWeight.semibold : void 0;
|
|
@@ -4961,40 +5138,96 @@ function MarkdownText({ markdown, variant = "chat", bodyColor, style }) {
|
|
|
4961
5138
|
const codeTextColor = isDark ? "#FFFFFF" : theme.colors.text;
|
|
4962
5139
|
const paragraphBottom = variant === "mergeRequest" ? 8 : 6;
|
|
4963
5140
|
const baseLineHeight = variant === "mergeRequest" ? 22 : 20;
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
5141
|
+
(0, import_react2.useEffect)(() => {
|
|
5142
|
+
return () => {
|
|
5143
|
+
if (hideTimerRef.current) {
|
|
5144
|
+
clearTimeout(hideTimerRef.current);
|
|
5145
|
+
}
|
|
5146
|
+
};
|
|
5147
|
+
}, []);
|
|
5148
|
+
const handleLongPress = (event) => {
|
|
5149
|
+
var _a;
|
|
5150
|
+
const { locationX, locationY, pageX, pageY } = event.nativeEvent;
|
|
5151
|
+
if ((_a = containerRef.current) == null ? void 0 : _a.measureInWindow) {
|
|
5152
|
+
containerRef.current.measureInWindow((x, y) => {
|
|
5153
|
+
setTooltipPosition({ x: pageX - x, y: pageY - y });
|
|
5154
|
+
});
|
|
5155
|
+
} else {
|
|
5156
|
+
setTooltipPosition({ x: locationX, y: locationY });
|
|
5157
|
+
}
|
|
5158
|
+
copyMarkdownToClipboard(markdown);
|
|
5159
|
+
setShowCopied(true);
|
|
5160
|
+
if (hideTimerRef.current) {
|
|
5161
|
+
clearTimeout(hideTimerRef.current);
|
|
5162
|
+
}
|
|
5163
|
+
hideTimerRef.current = setTimeout(() => {
|
|
5164
|
+
setShowCopied(false);
|
|
5165
|
+
}, 1200);
|
|
5166
|
+
};
|
|
5167
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_react_native37.Pressable, { style, onLongPress: handleLongPress, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_react_native37.View, { ref: containerRef, style: { position: "relative" }, children: [
|
|
5168
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
5169
|
+
import_react_native_markdown_display.default,
|
|
5170
|
+
{
|
|
5171
|
+
style: {
|
|
5172
|
+
body: { color: bodyColor ?? baseBodyColor, fontSize: 14, lineHeight: baseLineHeight },
|
|
5173
|
+
paragraph: { marginTop: 0, marginBottom: paragraphBottom },
|
|
5174
|
+
link: { color: linkColor, fontWeight: linkWeight },
|
|
5175
|
+
code_inline: {
|
|
5176
|
+
backgroundColor: codeBgColor,
|
|
5177
|
+
color: codeTextColor,
|
|
5178
|
+
paddingHorizontal: variant === "mergeRequest" ? 6 : 4,
|
|
5179
|
+
paddingVertical: variant === "mergeRequest" ? 2 : 0,
|
|
5180
|
+
borderRadius: variant === "mergeRequest" ? 6 : 4,
|
|
5181
|
+
fontFamily: import_react_native37.Platform.OS === "ios" ? "Menlo" : "monospace",
|
|
5182
|
+
fontSize: 13
|
|
5183
|
+
},
|
|
5184
|
+
code_block: {
|
|
5185
|
+
backgroundColor: codeBgColor,
|
|
5186
|
+
color: codeTextColor,
|
|
5187
|
+
padding: variant === "mergeRequest" ? 12 : 8,
|
|
5188
|
+
borderRadius: variant === "mergeRequest" ? 8 : 6,
|
|
5189
|
+
marginVertical: variant === "mergeRequest" ? 8 : 0
|
|
5190
|
+
},
|
|
5191
|
+
fence: {
|
|
5192
|
+
backgroundColor: codeBgColor,
|
|
5193
|
+
color: codeTextColor,
|
|
5194
|
+
padding: variant === "mergeRequest" ? 12 : 8,
|
|
5195
|
+
borderRadius: variant === "mergeRequest" ? 8 : 6,
|
|
5196
|
+
marginVertical: variant === "mergeRequest" ? 8 : 0
|
|
5197
|
+
}
|
|
4979
5198
|
},
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
5199
|
+
children: markdown
|
|
5200
|
+
}
|
|
5201
|
+
),
|
|
5202
|
+
showCopied && tooltipPosition ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
5203
|
+
import_react_native37.View,
|
|
5204
|
+
{
|
|
5205
|
+
pointerEvents: "none",
|
|
5206
|
+
style: {
|
|
5207
|
+
position: "absolute",
|
|
5208
|
+
left: tooltipPosition.x,
|
|
5209
|
+
top: tooltipPosition.y - theme.spacing.lg - 32,
|
|
5210
|
+
backgroundColor: theme.colors.success,
|
|
5211
|
+
borderRadius: theme.radii.pill,
|
|
5212
|
+
paddingHorizontal: theme.spacing.sm,
|
|
5213
|
+
paddingVertical: theme.spacing.xs,
|
|
5214
|
+
transform: [{ translateX: tooltipWidth ? -tooltipWidth / 2 : 0 }]
|
|
4986
5215
|
},
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
5216
|
+
onLayout: (event) => setTooltipWidth(event.nativeEvent.layout.width),
|
|
5217
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
5218
|
+
import_react_native37.Text,
|
|
5219
|
+
{
|
|
5220
|
+
style: {
|
|
5221
|
+
color: theme.colors.onSuccess,
|
|
5222
|
+
fontSize: theme.typography.fontSize.xs,
|
|
5223
|
+
fontWeight: theme.typography.fontWeight.medium
|
|
5224
|
+
},
|
|
5225
|
+
children: "Copied"
|
|
5226
|
+
}
|
|
5227
|
+
)
|
|
5228
|
+
}
|
|
5229
|
+
) : null
|
|
5230
|
+
] }) });
|
|
4998
5231
|
}
|
|
4999
5232
|
|
|
5000
5233
|
// src/components/merge-requests/mergeRequestStatusDisplay.ts
|
|
@@ -5322,7 +5555,7 @@ function ReviewMergeRequestCard({
|
|
|
5322
5555
|
children: status.text
|
|
5323
5556
|
}
|
|
5324
5557
|
),
|
|
5325
|
-
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Text, { style: { color: theme.colors.textMuted, fontSize: 12, lineHeight: 16, marginBottom: 12 }, children: creator ? `${creator.
|
|
5558
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Text, { style: { color: theme.colors.textMuted, fontSize: 12, lineHeight: 16, marginBottom: 12 }, children: creator ? `${creator.approvedOrMergedMergeRequests} approved merge${creator.approvedOrMergedMergeRequests !== 1 ? "s" : ""}` : "Loading stats..." }),
|
|
5326
5559
|
mr.description ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(MarkdownText, { markdown: mr.description, variant: "mergeRequest" }) : null
|
|
5327
5560
|
] }) : null,
|
|
5328
5561
|
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_react_native40.View, { style: { height: 1, backgroundColor: withAlpha(theme.colors.borderStrong, 0.5), marginTop: 12, marginBottom: 12 } }),
|
|
@@ -6102,23 +6335,88 @@ ${shareUrl}`;
|
|
|
6102
6335
|
|
|
6103
6336
|
// src/studio/ui/ChatPanel.tsx
|
|
6104
6337
|
var React41 = __toESM(require("react"));
|
|
6105
|
-
var
|
|
6338
|
+
var import_react_native53 = require("react-native");
|
|
6106
6339
|
|
|
6107
6340
|
// src/components/chat/ChatPage.tsx
|
|
6108
6341
|
var React38 = __toESM(require("react"));
|
|
6109
|
-
var
|
|
6342
|
+
var import_react_native48 = require("react-native");
|
|
6110
6343
|
var import_react_native_safe_area_context4 = require("react-native-safe-area-context");
|
|
6111
6344
|
|
|
6112
6345
|
// src/components/chat/ChatMessageList.tsx
|
|
6113
6346
|
var React37 = __toESM(require("react"));
|
|
6114
|
-
var
|
|
6347
|
+
var import_react_native47 = require("react-native");
|
|
6115
6348
|
var import_bottom_sheet5 = require("@gorhom/bottom-sheet");
|
|
6116
6349
|
|
|
6117
6350
|
// src/components/chat/ChatMessageBubble.tsx
|
|
6118
|
-
var
|
|
6351
|
+
var import_react_native45 = require("react-native");
|
|
6119
6352
|
var import_lucide_react_native10 = require("lucide-react-native");
|
|
6353
|
+
|
|
6354
|
+
// src/components/primitives/Button.tsx
|
|
6355
|
+
var import_react_native44 = require("react-native");
|
|
6120
6356
|
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
6121
|
-
function
|
|
6357
|
+
function backgroundFor2(variant, theme, pressed, disabled) {
|
|
6358
|
+
const { colors } = theme;
|
|
6359
|
+
if (variant === "ghost") return "transparent";
|
|
6360
|
+
if (disabled) {
|
|
6361
|
+
return colors.neutral;
|
|
6362
|
+
}
|
|
6363
|
+
const base = variant === "primary" ? colors.primary : variant === "danger" ? colors.danger : colors.neutral;
|
|
6364
|
+
if (!pressed) return base;
|
|
6365
|
+
return base;
|
|
6366
|
+
}
|
|
6367
|
+
function borderFor(variant, theme) {
|
|
6368
|
+
if (variant !== "ghost") return {};
|
|
6369
|
+
return { borderWidth: 1, borderColor: theme.colors.border };
|
|
6370
|
+
}
|
|
6371
|
+
function paddingFor(size, theme) {
|
|
6372
|
+
switch (size) {
|
|
6373
|
+
case "sm":
|
|
6374
|
+
return { paddingHorizontal: theme.spacing.md, paddingVertical: theme.spacing.sm, minHeight: 36 };
|
|
6375
|
+
case "icon":
|
|
6376
|
+
return { paddingHorizontal: 0, paddingVertical: 0, minHeight: 44, minWidth: 44 };
|
|
6377
|
+
case "md":
|
|
6378
|
+
default:
|
|
6379
|
+
return { paddingHorizontal: theme.spacing.lg, paddingVertical: theme.spacing.md, minHeight: 44 };
|
|
6380
|
+
}
|
|
6381
|
+
}
|
|
6382
|
+
function Button({
|
|
6383
|
+
variant = "neutral",
|
|
6384
|
+
size = "md",
|
|
6385
|
+
disabled,
|
|
6386
|
+
style,
|
|
6387
|
+
children,
|
|
6388
|
+
...props
|
|
6389
|
+
}) {
|
|
6390
|
+
const theme = useTheme();
|
|
6391
|
+
const isDisabled = disabled ?? void 0;
|
|
6392
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
6393
|
+
import_react_native44.Pressable,
|
|
6394
|
+
{
|
|
6395
|
+
...props,
|
|
6396
|
+
disabled: isDisabled,
|
|
6397
|
+
style: (state) => {
|
|
6398
|
+
const pressed = state.pressed;
|
|
6399
|
+
const base = {
|
|
6400
|
+
alignItems: "center",
|
|
6401
|
+
justifyContent: "center",
|
|
6402
|
+
flexDirection: "row",
|
|
6403
|
+
borderRadius: size === "icon" ? theme.radii.pill : theme.radii.pill,
|
|
6404
|
+
backgroundColor: backgroundFor2(variant, theme, pressed, isDisabled),
|
|
6405
|
+
opacity: pressed && !isDisabled ? 0.92 : 1,
|
|
6406
|
+
...paddingFor(size, theme),
|
|
6407
|
+
...borderFor(variant, theme)
|
|
6408
|
+
};
|
|
6409
|
+
const resolved = typeof style === "function" ? style({ pressed, disabled: isDisabled }) : style;
|
|
6410
|
+
return [base, resolved];
|
|
6411
|
+
},
|
|
6412
|
+
children
|
|
6413
|
+
}
|
|
6414
|
+
);
|
|
6415
|
+
}
|
|
6416
|
+
|
|
6417
|
+
// src/components/chat/ChatMessageBubble.tsx
|
|
6418
|
+
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
6419
|
+
function ChatMessageBubble({ message, renderContent, isLast, retrying, onRetry, style }) {
|
|
6122
6420
|
var _a, _b;
|
|
6123
6421
|
const theme = useTheme();
|
|
6124
6422
|
const metaEvent = ((_a = message.meta) == null ? void 0 : _a.event) ?? null;
|
|
@@ -6133,49 +6431,77 @@ function ChatMessageBubble({ message, renderContent, style }) {
|
|
|
6133
6431
|
const bubbleVariant = isHuman ? "surface" : "surfaceRaised";
|
|
6134
6432
|
const cornerStyle = isHuman ? { borderTopRightRadius: 0 } : { borderTopLeftRadius: 0 };
|
|
6135
6433
|
const bodyColor = metaStatus === "success" ? theme.colors.success : metaStatus === "error" ? theme.colors.danger : void 0;
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
/* @__PURE__ */ (0,
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6434
|
+
const showRetry = Boolean(onRetry) && isLast && metaStatus === "error";
|
|
6435
|
+
const retryLabel = retrying ? "Retrying..." : "Retry";
|
|
6436
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_react_native45.View, { style: [align, style], children: [
|
|
6437
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
6438
|
+
Surface,
|
|
6439
|
+
{
|
|
6440
|
+
variant: bubbleVariant,
|
|
6441
|
+
style: [
|
|
6442
|
+
{
|
|
6443
|
+
maxWidth: "85%",
|
|
6444
|
+
borderRadius: theme.radii.lg,
|
|
6445
|
+
paddingHorizontal: theme.spacing.lg,
|
|
6446
|
+
paddingVertical: theme.spacing.md,
|
|
6447
|
+
borderWidth: 1,
|
|
6448
|
+
borderColor: theme.colors.border
|
|
6449
|
+
},
|
|
6450
|
+
cornerStyle
|
|
6451
|
+
],
|
|
6452
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_react_native45.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
|
|
6453
|
+
isMergeCompleted || isSyncCompleted ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react_native10.CheckCheck, { size: 16, color: theme.colors.success, style: { marginRight: theme.spacing.sm } }) : null,
|
|
6454
|
+
isMergeApproved || isSyncStarted ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react_native10.GitMerge, { size: 16, color: theme.colors.text, style: { marginRight: theme.spacing.sm } }) : null,
|
|
6455
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_react_native45.View, { style: { flexShrink: 1, minWidth: 0 }, children: renderContent ? renderContent(message) : /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(MarkdownText, { markdown: message.content, variant: "chat", bodyColor }) })
|
|
6456
|
+
] })
|
|
6457
|
+
}
|
|
6458
|
+
),
|
|
6459
|
+
showRetry ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_react_native45.View, { style: { marginTop: theme.spacing.xs, alignSelf: align.alignSelf }, children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
6460
|
+
Button,
|
|
6461
|
+
{
|
|
6462
|
+
variant: "ghost",
|
|
6463
|
+
size: "sm",
|
|
6464
|
+
onPress: onRetry,
|
|
6465
|
+
disabled: retrying,
|
|
6466
|
+
style: { borderColor: theme.colors.danger },
|
|
6467
|
+
accessibilityLabel: "Retry send",
|
|
6468
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_react_native45.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
|
|
6469
|
+
!retrying ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react_native10.RotateCcw, { size: 14, color: theme.colors.danger }) : null,
|
|
6470
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
6471
|
+
Text,
|
|
6472
|
+
{
|
|
6473
|
+
variant: "caption",
|
|
6474
|
+
color: theme.colors.danger,
|
|
6475
|
+
style: { marginLeft: retrying ? 0 : theme.spacing.xs },
|
|
6476
|
+
numberOfLines: 1,
|
|
6477
|
+
children: retryLabel
|
|
6478
|
+
}
|
|
6479
|
+
)
|
|
6480
|
+
] })
|
|
6481
|
+
}
|
|
6482
|
+
) }) : null
|
|
6483
|
+
] });
|
|
6158
6484
|
}
|
|
6159
6485
|
|
|
6160
6486
|
// src/components/chat/TypingIndicator.tsx
|
|
6161
6487
|
var React36 = __toESM(require("react"));
|
|
6162
|
-
var
|
|
6163
|
-
var
|
|
6488
|
+
var import_react_native46 = require("react-native");
|
|
6489
|
+
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
6164
6490
|
function TypingIndicator({ style }) {
|
|
6165
6491
|
const theme = useTheme();
|
|
6166
6492
|
const dotColor = theme.colors.textSubtle;
|
|
6167
6493
|
const anims = React36.useMemo(
|
|
6168
|
-
() => [new
|
|
6494
|
+
() => [new import_react_native46.Animated.Value(0.3), new import_react_native46.Animated.Value(0.3), new import_react_native46.Animated.Value(0.3)],
|
|
6169
6495
|
[]
|
|
6170
6496
|
);
|
|
6171
6497
|
React36.useEffect(() => {
|
|
6172
6498
|
const loops = [];
|
|
6173
6499
|
anims.forEach((a, idx) => {
|
|
6174
|
-
const seq =
|
|
6175
|
-
|
|
6176
|
-
|
|
6500
|
+
const seq = import_react_native46.Animated.sequence([
|
|
6501
|
+
import_react_native46.Animated.timing(a, { toValue: 1, duration: 420, useNativeDriver: true, delay: idx * 140 }),
|
|
6502
|
+
import_react_native46.Animated.timing(a, { toValue: 0.3, duration: 420, useNativeDriver: true })
|
|
6177
6503
|
]);
|
|
6178
|
-
const loop =
|
|
6504
|
+
const loop = import_react_native46.Animated.loop(seq);
|
|
6179
6505
|
loops.push(loop);
|
|
6180
6506
|
loop.start();
|
|
6181
6507
|
});
|
|
@@ -6183,8 +6509,8 @@ function TypingIndicator({ style }) {
|
|
|
6183
6509
|
loops.forEach((l) => l.stop());
|
|
6184
6510
|
};
|
|
6185
6511
|
}, [anims]);
|
|
6186
|
-
return /* @__PURE__ */ (0,
|
|
6187
|
-
|
|
6512
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_react_native46.View, { style: [{ flexDirection: "row", alignItems: "center" }, style], children: anims.map((a, i) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
6513
|
+
import_react_native46.Animated.View,
|
|
6188
6514
|
{
|
|
6189
6515
|
style: {
|
|
6190
6516
|
width: 8,
|
|
@@ -6193,7 +6519,7 @@ function TypingIndicator({ style }) {
|
|
|
6193
6519
|
marginHorizontal: 3,
|
|
6194
6520
|
backgroundColor: dotColor,
|
|
6195
6521
|
opacity: a,
|
|
6196
|
-
transform: [{ translateY:
|
|
6522
|
+
transform: [{ translateY: import_react_native46.Animated.multiply(import_react_native46.Animated.subtract(a, 0.3), 2) }]
|
|
6197
6523
|
}
|
|
6198
6524
|
},
|
|
6199
6525
|
i
|
|
@@ -6201,12 +6527,14 @@ function TypingIndicator({ style }) {
|
|
|
6201
6527
|
}
|
|
6202
6528
|
|
|
6203
6529
|
// src/components/chat/ChatMessageList.tsx
|
|
6204
|
-
var
|
|
6530
|
+
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
6205
6531
|
var ChatMessageList = React37.forwardRef(
|
|
6206
6532
|
({
|
|
6207
6533
|
messages,
|
|
6208
6534
|
showTypingIndicator = false,
|
|
6209
6535
|
renderMessageContent,
|
|
6536
|
+
onRetryMessage,
|
|
6537
|
+
isRetryingMessage,
|
|
6210
6538
|
contentStyle,
|
|
6211
6539
|
bottomInset = 0,
|
|
6212
6540
|
onNearBottomChange,
|
|
@@ -6220,6 +6548,7 @@ var ChatMessageList = React37.forwardRef(
|
|
|
6220
6548
|
const data = React37.useMemo(() => {
|
|
6221
6549
|
return [...messages].reverse();
|
|
6222
6550
|
}, [messages]);
|
|
6551
|
+
const lastMessageId = messages.length > 0 ? messages[messages.length - 1].id : null;
|
|
6223
6552
|
const scrollToBottom = React37.useCallback((options) => {
|
|
6224
6553
|
var _a;
|
|
6225
6554
|
const animated = (options == null ? void 0 : options.animated) ?? true;
|
|
@@ -6255,7 +6584,7 @@ var ChatMessageList = React37.forwardRef(
|
|
|
6255
6584
|
}
|
|
6256
6585
|
return void 0;
|
|
6257
6586
|
}, [showTypingIndicator, scrollToBottom]);
|
|
6258
|
-
return /* @__PURE__ */ (0,
|
|
6587
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
6259
6588
|
import_bottom_sheet5.BottomSheetFlatList,
|
|
6260
6589
|
{
|
|
6261
6590
|
ref: listRef,
|
|
@@ -6281,11 +6610,20 @@ var ChatMessageList = React37.forwardRef(
|
|
|
6281
6610
|
},
|
|
6282
6611
|
contentStyle
|
|
6283
6612
|
],
|
|
6284
|
-
ItemSeparatorComponent: () => /* @__PURE__ */ (0,
|
|
6285
|
-
renderItem: ({ item }) => /* @__PURE__ */ (0,
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6613
|
+
ItemSeparatorComponent: () => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_react_native47.View, { style: { height: theme.spacing.sm } }),
|
|
6614
|
+
renderItem: ({ item }) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
6615
|
+
ChatMessageBubble,
|
|
6616
|
+
{
|
|
6617
|
+
message: item,
|
|
6618
|
+
renderContent: renderMessageContent,
|
|
6619
|
+
isLast: Boolean(lastMessageId && item.id === lastMessageId),
|
|
6620
|
+
retrying: (isRetryingMessage == null ? void 0 : isRetryingMessage(item.id)) ?? false,
|
|
6621
|
+
onRetry: onRetryMessage ? () => onRetryMessage(item.id) : void 0
|
|
6622
|
+
}
|
|
6623
|
+
),
|
|
6624
|
+
ListHeaderComponent: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(import_react_native47.View, { children: [
|
|
6625
|
+
showTypingIndicator ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_react_native47.View, { style: { marginTop: theme.spacing.sm, alignSelf: "flex-start", paddingHorizontal: theme.spacing.lg }, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(TypingIndicator, {}) }) : null,
|
|
6626
|
+
bottomInset > 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_react_native47.View, { style: { height: bottomInset } }) : null
|
|
6289
6627
|
] })
|
|
6290
6628
|
}
|
|
6291
6629
|
);
|
|
@@ -6294,12 +6632,14 @@ var ChatMessageList = React37.forwardRef(
|
|
|
6294
6632
|
ChatMessageList.displayName = "ChatMessageList";
|
|
6295
6633
|
|
|
6296
6634
|
// src/components/chat/ChatPage.tsx
|
|
6297
|
-
var
|
|
6635
|
+
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
6298
6636
|
function ChatPage({
|
|
6299
6637
|
header,
|
|
6300
6638
|
messages,
|
|
6301
6639
|
showTypingIndicator,
|
|
6302
6640
|
renderMessageContent,
|
|
6641
|
+
onRetryMessage,
|
|
6642
|
+
isRetryingMessage,
|
|
6303
6643
|
topBanner,
|
|
6304
6644
|
composerTop,
|
|
6305
6645
|
composer,
|
|
@@ -6313,17 +6653,7 @@ function ChatPage({
|
|
|
6313
6653
|
const insets = (0, import_react_native_safe_area_context4.useSafeAreaInsets)();
|
|
6314
6654
|
const [composerHeight, setComposerHeight] = React38.useState(0);
|
|
6315
6655
|
const [composerTopHeight, setComposerTopHeight] = React38.useState(0);
|
|
6316
|
-
const
|
|
6317
|
-
React38.useEffect(() => {
|
|
6318
|
-
if (import_react_native47.Platform.OS !== "ios") return;
|
|
6319
|
-
const show = import_react_native47.Keyboard.addListener("keyboardWillShow", () => setKeyboardVisible(true));
|
|
6320
|
-
const hide = import_react_native47.Keyboard.addListener("keyboardWillHide", () => setKeyboardVisible(false));
|
|
6321
|
-
return () => {
|
|
6322
|
-
show.remove();
|
|
6323
|
-
hide.remove();
|
|
6324
|
-
};
|
|
6325
|
-
}, []);
|
|
6326
|
-
const footerBottomPadding = import_react_native47.Platform.OS === "ios" ? keyboardVisible ? 0 : insets.bottom : insets.bottom + 10;
|
|
6656
|
+
const footerBottomPadding = import_react_native48.Platform.OS === "ios" ? insets.bottom : insets.bottom + 10;
|
|
6327
6657
|
const totalComposerHeight = composerHeight + composerTopHeight;
|
|
6328
6658
|
const overlayBottom = totalComposerHeight + footerBottomPadding + theme.spacing.lg;
|
|
6329
6659
|
const bottomInset = totalComposerHeight + footerBottomPadding + theme.spacing.xl;
|
|
@@ -6340,22 +6670,24 @@ function ChatPage({
|
|
|
6340
6670
|
if (composerTop) return;
|
|
6341
6671
|
setComposerTopHeight(0);
|
|
6342
6672
|
}, [composerTop]);
|
|
6343
|
-
return /* @__PURE__ */ (0,
|
|
6344
|
-
header ? /* @__PURE__ */ (0,
|
|
6345
|
-
topBanner ? /* @__PURE__ */ (0,
|
|
6346
|
-
/* @__PURE__ */ (0,
|
|
6347
|
-
/* @__PURE__ */ (0,
|
|
6348
|
-
|
|
6673
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_react_native48.View, { style: [{ flex: 1 }, style], children: [
|
|
6674
|
+
header ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_react_native48.View, { children: header }) : null,
|
|
6675
|
+
topBanner ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_react_native48.View, { style: { paddingHorizontal: theme.spacing.lg, paddingTop: theme.spacing.sm }, children: topBanner }) : null,
|
|
6676
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_react_native48.View, { style: { flex: 1 }, children: [
|
|
6677
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
|
|
6678
|
+
import_react_native48.View,
|
|
6349
6679
|
{
|
|
6350
6680
|
style: { flex: 1 },
|
|
6351
6681
|
children: [
|
|
6352
|
-
/* @__PURE__ */ (0,
|
|
6682
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
6353
6683
|
ChatMessageList,
|
|
6354
6684
|
{
|
|
6355
6685
|
ref: listRef,
|
|
6356
6686
|
messages,
|
|
6357
6687
|
showTypingIndicator,
|
|
6358
6688
|
renderMessageContent,
|
|
6689
|
+
onRetryMessage,
|
|
6690
|
+
isRetryingMessage,
|
|
6359
6691
|
onNearBottomChange,
|
|
6360
6692
|
bottomInset
|
|
6361
6693
|
}
|
|
@@ -6364,8 +6696,8 @@ function ChatPage({
|
|
|
6364
6696
|
]
|
|
6365
6697
|
}
|
|
6366
6698
|
),
|
|
6367
|
-
/* @__PURE__ */ (0,
|
|
6368
|
-
|
|
6699
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
|
|
6700
|
+
import_react_native48.View,
|
|
6369
6701
|
{
|
|
6370
6702
|
style: {
|
|
6371
6703
|
position: "absolute",
|
|
@@ -6377,15 +6709,15 @@ function ChatPage({
|
|
|
6377
6709
|
paddingBottom: footerBottomPadding
|
|
6378
6710
|
},
|
|
6379
6711
|
children: [
|
|
6380
|
-
composerTop ? /* @__PURE__ */ (0,
|
|
6381
|
-
|
|
6712
|
+
composerTop ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
6713
|
+
import_react_native48.View,
|
|
6382
6714
|
{
|
|
6383
6715
|
style: { marginBottom: theme.spacing.sm },
|
|
6384
6716
|
onLayout: (e) => setComposerTopHeight(e.nativeEvent.layout.height),
|
|
6385
6717
|
children: composerTop
|
|
6386
6718
|
}
|
|
6387
6719
|
) : null,
|
|
6388
|
-
/* @__PURE__ */ (0,
|
|
6720
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
6389
6721
|
ChatComposer,
|
|
6390
6722
|
{
|
|
6391
6723
|
...composer,
|
|
@@ -6402,9 +6734,9 @@ function ChatPage({
|
|
|
6402
6734
|
|
|
6403
6735
|
// src/components/chat/ScrollToBottomButton.tsx
|
|
6404
6736
|
var React39 = __toESM(require("react"));
|
|
6405
|
-
var
|
|
6737
|
+
var import_react_native49 = require("react-native");
|
|
6406
6738
|
var import_react_native_reanimated2 = __toESM(require("react-native-reanimated"));
|
|
6407
|
-
var
|
|
6739
|
+
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
6408
6740
|
function ScrollToBottomButton({ visible, onPress, children, style }) {
|
|
6409
6741
|
const theme = useTheme();
|
|
6410
6742
|
const progress = (0, import_react_native_reanimated2.useSharedValue)(visible ? 1 : 0);
|
|
@@ -6418,7 +6750,7 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
|
|
|
6418
6750
|
}));
|
|
6419
6751
|
const bg = theme.scheme === "dark" ? "rgba(39,39,42,0.9)" : "rgba(244,244,245,0.95)";
|
|
6420
6752
|
const border = theme.scheme === "dark" ? withAlpha("#FFFFFF", 0.12) : withAlpha("#000000", 0.08);
|
|
6421
|
-
return /* @__PURE__ */ (0,
|
|
6753
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
6422
6754
|
import_react_native_reanimated2.default.View,
|
|
6423
6755
|
{
|
|
6424
6756
|
pointerEvents: visible ? "auto" : "none",
|
|
@@ -6432,8 +6764,8 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
|
|
|
6432
6764
|
style,
|
|
6433
6765
|
animStyle
|
|
6434
6766
|
],
|
|
6435
|
-
children: /* @__PURE__ */ (0,
|
|
6436
|
-
|
|
6767
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
6768
|
+
import_react_native49.View,
|
|
6437
6769
|
{
|
|
6438
6770
|
style: {
|
|
6439
6771
|
width: 44,
|
|
@@ -6451,8 +6783,8 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
|
|
|
6451
6783
|
elevation: 5,
|
|
6452
6784
|
opacity: pressed ? 0.85 : 1
|
|
6453
6785
|
},
|
|
6454
|
-
children: /* @__PURE__ */ (0,
|
|
6455
|
-
|
|
6786
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
6787
|
+
import_react_native49.Pressable,
|
|
6456
6788
|
{
|
|
6457
6789
|
onPress,
|
|
6458
6790
|
onPressIn: () => setPressed(true),
|
|
@@ -6469,16 +6801,16 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
|
|
|
6469
6801
|
}
|
|
6470
6802
|
|
|
6471
6803
|
// src/components/chat/ChatHeader.tsx
|
|
6472
|
-
var
|
|
6473
|
-
var
|
|
6804
|
+
var import_react_native50 = require("react-native");
|
|
6805
|
+
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
6474
6806
|
function ChatHeader({ left, right, center, style }) {
|
|
6475
|
-
const flattenedStyle =
|
|
6807
|
+
const flattenedStyle = import_react_native50.StyleSheet.flatten([
|
|
6476
6808
|
{
|
|
6477
6809
|
paddingTop: 0
|
|
6478
6810
|
},
|
|
6479
6811
|
style
|
|
6480
6812
|
]);
|
|
6481
|
-
return /* @__PURE__ */ (0,
|
|
6813
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
6482
6814
|
StudioSheetHeader,
|
|
6483
6815
|
{
|
|
6484
6816
|
left,
|
|
@@ -6490,13 +6822,13 @@ function ChatHeader({ left, right, center, style }) {
|
|
|
6490
6822
|
}
|
|
6491
6823
|
|
|
6492
6824
|
// src/components/chat/ForkNoticeBanner.tsx
|
|
6493
|
-
var
|
|
6494
|
-
var
|
|
6825
|
+
var import_react_native51 = require("react-native");
|
|
6826
|
+
var import_jsx_runtime53 = require("react/jsx-runtime");
|
|
6495
6827
|
function ForkNoticeBanner({ isOwner = true, title, description, style }) {
|
|
6496
6828
|
const theme = useTheme();
|
|
6497
6829
|
const resolvedTitle = title ?? (isOwner ? "Remixed app" : "Remix app");
|
|
6498
6830
|
const resolvedDescription = description ?? (isOwner ? "Any changes you make will be a remix of the original app. You can view the edited version in the Remix tab in your apps page." : "Once you make edits, this remixed version will appear on your Remixed apps page.");
|
|
6499
|
-
return /* @__PURE__ */ (0,
|
|
6831
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
6500
6832
|
Card,
|
|
6501
6833
|
{
|
|
6502
6834
|
variant: "surfaceRaised",
|
|
@@ -6511,8 +6843,8 @@ function ForkNoticeBanner({ isOwner = true, title, description, style }) {
|
|
|
6511
6843
|
},
|
|
6512
6844
|
style
|
|
6513
6845
|
],
|
|
6514
|
-
children: /* @__PURE__ */ (0,
|
|
6515
|
-
/* @__PURE__ */ (0,
|
|
6846
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_react_native51.View, { style: { minWidth: 0 }, children: [
|
|
6847
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
6516
6848
|
Text,
|
|
6517
6849
|
{
|
|
6518
6850
|
style: {
|
|
@@ -6526,7 +6858,7 @@ function ForkNoticeBanner({ isOwner = true, title, description, style }) {
|
|
|
6526
6858
|
children: resolvedTitle
|
|
6527
6859
|
}
|
|
6528
6860
|
),
|
|
6529
|
-
/* @__PURE__ */ (0,
|
|
6861
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
6530
6862
|
Text,
|
|
6531
6863
|
{
|
|
6532
6864
|
style: {
|
|
@@ -6545,8 +6877,8 @@ function ForkNoticeBanner({ isOwner = true, title, description, style }) {
|
|
|
6545
6877
|
|
|
6546
6878
|
// src/components/chat/ChatQueue.tsx
|
|
6547
6879
|
var React40 = __toESM(require("react"));
|
|
6548
|
-
var
|
|
6549
|
-
var
|
|
6880
|
+
var import_react_native52 = require("react-native");
|
|
6881
|
+
var import_jsx_runtime54 = require("react/jsx-runtime");
|
|
6550
6882
|
function ChatQueue({ items, onRemove }) {
|
|
6551
6883
|
const theme = useTheme();
|
|
6552
6884
|
const [expanded, setExpanded] = React40.useState({});
|
|
@@ -6578,8 +6910,8 @@ ${trimmedLine2}\u2026 `;
|
|
|
6578
6910
|
setRemoving((prev) => Object.fromEntries(Object.entries(prev).filter(([id]) => ids.has(id))));
|
|
6579
6911
|
}, [items]);
|
|
6580
6912
|
if (items.length === 0) return null;
|
|
6581
|
-
return /* @__PURE__ */ (0,
|
|
6582
|
-
|
|
6913
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
|
|
6914
|
+
import_react_native52.View,
|
|
6583
6915
|
{
|
|
6584
6916
|
style: {
|
|
6585
6917
|
borderWidth: 1,
|
|
@@ -6590,16 +6922,16 @@ ${trimmedLine2}\u2026 `;
|
|
|
6590
6922
|
backgroundColor: "transparent"
|
|
6591
6923
|
},
|
|
6592
6924
|
children: [
|
|
6593
|
-
/* @__PURE__ */ (0,
|
|
6594
|
-
/* @__PURE__ */ (0,
|
|
6925
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(Text, { variant: "caption", style: { marginBottom: theme.spacing.sm }, children: "Queue" }),
|
|
6926
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_react_native52.View, { style: { gap: theme.spacing.sm }, children: items.map((item) => {
|
|
6595
6927
|
const isExpanded = Boolean(expanded[item.id]);
|
|
6596
6928
|
const showToggle = Boolean(canExpand[item.id]);
|
|
6597
6929
|
const prompt = item.prompt ?? "";
|
|
6598
6930
|
const moreLabel = "more";
|
|
6599
6931
|
const displayPrompt = !isExpanded && showToggle && collapsedText[item.id] ? collapsedText[item.id] : prompt;
|
|
6600
6932
|
const isRemoving = Boolean(removing[item.id]);
|
|
6601
|
-
return /* @__PURE__ */ (0,
|
|
6602
|
-
|
|
6933
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
|
|
6934
|
+
import_react_native52.View,
|
|
6603
6935
|
{
|
|
6604
6936
|
style: {
|
|
6605
6937
|
flexDirection: "row",
|
|
@@ -6611,8 +6943,8 @@ ${trimmedLine2}\u2026 `;
|
|
|
6611
6943
|
backgroundColor: withAlpha(theme.colors.surface, theme.scheme === "dark" ? 0.8 : 0.9)
|
|
6612
6944
|
},
|
|
6613
6945
|
children: [
|
|
6614
|
-
/* @__PURE__ */ (0,
|
|
6615
|
-
!canExpand[item.id] ? /* @__PURE__ */ (0,
|
|
6946
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(import_react_native52.View, { style: { flex: 1 }, children: [
|
|
6947
|
+
!canExpand[item.id] ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
6616
6948
|
Text,
|
|
6617
6949
|
{
|
|
6618
6950
|
style: { position: "absolute", opacity: 0, zIndex: -1, width: "100%" },
|
|
@@ -6631,14 +6963,14 @@ ${trimmedLine2}\u2026 `;
|
|
|
6631
6963
|
children: prompt
|
|
6632
6964
|
}
|
|
6633
6965
|
) : null,
|
|
6634
|
-
/* @__PURE__ */ (0,
|
|
6966
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
|
|
6635
6967
|
Text,
|
|
6636
6968
|
{
|
|
6637
6969
|
variant: "bodyMuted",
|
|
6638
6970
|
numberOfLines: isExpanded ? void 0 : 2,
|
|
6639
6971
|
children: [
|
|
6640
6972
|
displayPrompt,
|
|
6641
|
-
!isExpanded && showToggle ? /* @__PURE__ */ (0,
|
|
6973
|
+
!isExpanded && showToggle ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
6642
6974
|
Text,
|
|
6643
6975
|
{
|
|
6644
6976
|
color: theme.colors.text,
|
|
@@ -6650,18 +6982,18 @@ ${trimmedLine2}\u2026 `;
|
|
|
6650
6982
|
]
|
|
6651
6983
|
}
|
|
6652
6984
|
),
|
|
6653
|
-
showToggle && isExpanded ? /* @__PURE__ */ (0,
|
|
6654
|
-
|
|
6985
|
+
showToggle && isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
6986
|
+
import_react_native52.Pressable,
|
|
6655
6987
|
{
|
|
6656
6988
|
onPress: () => setExpanded((prev) => ({ ...prev, [item.id]: false })),
|
|
6657
6989
|
hitSlop: 6,
|
|
6658
6990
|
style: { alignSelf: "flex-start", marginTop: 4 },
|
|
6659
|
-
children: /* @__PURE__ */ (0,
|
|
6991
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(Text, { variant: "captionMuted", color: theme.colors.text, children: "less" })
|
|
6660
6992
|
}
|
|
6661
6993
|
) : null
|
|
6662
6994
|
] }),
|
|
6663
|
-
/* @__PURE__ */ (0,
|
|
6664
|
-
|
|
6995
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
6996
|
+
import_react_native52.Pressable,
|
|
6665
6997
|
{
|
|
6666
6998
|
onPress: () => {
|
|
6667
6999
|
if (!onRemove || isRemoving) return;
|
|
@@ -6676,7 +7008,7 @@ ${trimmedLine2}\u2026 `;
|
|
|
6676
7008
|
},
|
|
6677
7009
|
hitSlop: 8,
|
|
6678
7010
|
style: { alignSelf: "center" },
|
|
6679
|
-
children: isRemoving ? /* @__PURE__ */ (0,
|
|
7011
|
+
children: isRemoving ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_react_native52.ActivityIndicator, { size: "small", color: theme.colors.text }) : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(IconClose, { size: 14, colorToken: "text" })
|
|
6680
7012
|
}
|
|
6681
7013
|
)
|
|
6682
7014
|
]
|
|
@@ -6690,10 +7022,9 @@ ${trimmedLine2}\u2026 `;
|
|
|
6690
7022
|
}
|
|
6691
7023
|
|
|
6692
7024
|
// src/studio/ui/ChatPanel.tsx
|
|
6693
|
-
var
|
|
7025
|
+
var import_jsx_runtime55 = require("react/jsx-runtime");
|
|
6694
7026
|
function ChatPanel({
|
|
6695
7027
|
title = "Chat",
|
|
6696
|
-
autoFocusComposer = false,
|
|
6697
7028
|
messages,
|
|
6698
7029
|
showTypingIndicator,
|
|
6699
7030
|
loading,
|
|
@@ -6709,6 +7040,8 @@ function ChatPanel({
|
|
|
6709
7040
|
onNavigateHome,
|
|
6710
7041
|
onStartDraw,
|
|
6711
7042
|
onSend,
|
|
7043
|
+
onRetryMessage,
|
|
7044
|
+
isRetryingMessage,
|
|
6712
7045
|
queueItems = [],
|
|
6713
7046
|
onRemoveQueueItem
|
|
6714
7047
|
}) {
|
|
@@ -6732,21 +7065,21 @@ function ChatPanel({
|
|
|
6732
7065
|
var _a;
|
|
6733
7066
|
(_a = listRef.current) == null ? void 0 : _a.scrollToBottom({ animated: true });
|
|
6734
7067
|
}, []);
|
|
6735
|
-
const header = /* @__PURE__ */ (0,
|
|
7068
|
+
const header = /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
6736
7069
|
ChatHeader,
|
|
6737
7070
|
{
|
|
6738
|
-
left: /* @__PURE__ */ (0,
|
|
6739
|
-
/* @__PURE__ */ (0,
|
|
6740
|
-
onNavigateHome ? /* @__PURE__ */ (0,
|
|
7071
|
+
left: /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(import_react_native53.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
|
|
7072
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(StudioSheetHeaderIconButton, { onPress: onBack, accessibilityLabel: "Back", style: { marginRight: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(IconBack, { size: 20, colorToken: "floatingContent" }) }),
|
|
7073
|
+
onNavigateHome ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(StudioSheetHeaderIconButton, { onPress: onNavigateHome, accessibilityLabel: "Home", children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(IconHome, { size: 20, colorToken: "floatingContent" }) }) : null
|
|
6741
7074
|
] }),
|
|
6742
|
-
right: /* @__PURE__ */ (0,
|
|
6743
|
-
onStartDraw ? /* @__PURE__ */ (0,
|
|
6744
|
-
/* @__PURE__ */ (0,
|
|
7075
|
+
right: /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(import_react_native53.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
|
|
7076
|
+
onStartDraw ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(StudioSheetHeaderIconButton, { onPress: onStartDraw, accessibilityLabel: "Draw", intent: "danger", style: { marginRight: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(IconDraw, { size: 20, colorToken: "onDanger" }) }) : null,
|
|
7077
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(StudioSheetHeaderIconButton, { onPress: onClose, accessibilityLabel: "Close", children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(IconClose, { size: 20, colorToken: "floatingContent" }) })
|
|
6745
7078
|
] }),
|
|
6746
7079
|
center: null
|
|
6747
7080
|
}
|
|
6748
7081
|
);
|
|
6749
|
-
const topBanner = shouldForkOnEdit ? /* @__PURE__ */ (0,
|
|
7082
|
+
const topBanner = shouldForkOnEdit ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
6750
7083
|
ForkNoticeBanner,
|
|
6751
7084
|
{
|
|
6752
7085
|
isOwner: !shouldForkOnEdit,
|
|
@@ -6755,35 +7088,37 @@ function ChatPanel({
|
|
|
6755
7088
|
) : null;
|
|
6756
7089
|
const showMessagesLoading = Boolean(loading) && messages.length === 0 || forking;
|
|
6757
7090
|
if (showMessagesLoading) {
|
|
6758
|
-
return /* @__PURE__ */ (0,
|
|
6759
|
-
/* @__PURE__ */ (0,
|
|
6760
|
-
topBanner ? /* @__PURE__ */ (0,
|
|
6761
|
-
/* @__PURE__ */ (0,
|
|
6762
|
-
/* @__PURE__ */ (0,
|
|
6763
|
-
/* @__PURE__ */ (0,
|
|
6764
|
-
/* @__PURE__ */ (0,
|
|
7091
|
+
return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(import_react_native53.View, { style: { flex: 1 }, children: [
|
|
7092
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_react_native53.View, { children: header }),
|
|
7093
|
+
topBanner ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_react_native53.View, { style: { paddingHorizontal: 16, paddingTop: 8 }, children: topBanner }) : null,
|
|
7094
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(import_react_native53.View, { style: { flex: 1, alignItems: "center", justifyContent: "center", paddingHorizontal: 24, paddingVertical: 12 }, children: [
|
|
7095
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_react_native53.ActivityIndicator, {}),
|
|
7096
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_react_native53.View, { style: { height: 12 } }),
|
|
7097
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Text, { variant: "bodyMuted", children: forking ? "Creating your copy\u2026" : "Loading messages\u2026" })
|
|
6765
7098
|
] })
|
|
6766
7099
|
] });
|
|
6767
7100
|
}
|
|
6768
|
-
const queueTop = queueItems.length > 0 ? /* @__PURE__ */ (0,
|
|
6769
|
-
return /* @__PURE__ */ (0,
|
|
7101
|
+
const queueTop = queueItems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(ChatQueue, { items: queueItems, onRemove: onRemoveQueueItem }) : null;
|
|
7102
|
+
return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
6770
7103
|
ChatPage,
|
|
6771
7104
|
{
|
|
6772
7105
|
header,
|
|
6773
7106
|
messages,
|
|
6774
7107
|
showTypingIndicator,
|
|
7108
|
+
onRetryMessage,
|
|
7109
|
+
isRetryingMessage,
|
|
6775
7110
|
topBanner,
|
|
6776
7111
|
composerTop: queueTop,
|
|
6777
7112
|
composerHorizontalPadding: 0,
|
|
6778
7113
|
listRef,
|
|
6779
7114
|
onNearBottomChange: setNearBottom,
|
|
6780
|
-
overlay: /* @__PURE__ */ (0,
|
|
7115
|
+
overlay: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
6781
7116
|
ScrollToBottomButton,
|
|
6782
7117
|
{
|
|
6783
7118
|
visible: !nearBottom,
|
|
6784
7119
|
onPress: handleScrollToBottom,
|
|
6785
7120
|
style: { bottom: 80 },
|
|
6786
|
-
children: /* @__PURE__ */ (0,
|
|
7121
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(IconArrowDown, { size: 20, colorToken: "floatingContent" })
|
|
6787
7122
|
}
|
|
6788
7123
|
),
|
|
6789
7124
|
composer: {
|
|
@@ -6792,7 +7127,6 @@ function ChatPanel({
|
|
|
6792
7127
|
disabled: Boolean(loading) || Boolean(forking),
|
|
6793
7128
|
sendDisabled: Boolean(sendDisabled) || Boolean(loading) || Boolean(forking),
|
|
6794
7129
|
sending: Boolean(sending),
|
|
6795
|
-
autoFocus: autoFocusComposer,
|
|
6796
7130
|
onSend: handleSend,
|
|
6797
7131
|
attachments,
|
|
6798
7132
|
onRemoveAttachment,
|
|
@@ -6805,11 +7139,11 @@ function ChatPanel({
|
|
|
6805
7139
|
|
|
6806
7140
|
// src/components/dialogs/ConfirmMergeRequestDialog.tsx
|
|
6807
7141
|
var React42 = __toESM(require("react"));
|
|
6808
|
-
var
|
|
7142
|
+
var import_react_native55 = require("react-native");
|
|
6809
7143
|
|
|
6810
7144
|
// src/components/primitives/Modal.tsx
|
|
6811
|
-
var
|
|
6812
|
-
var
|
|
7145
|
+
var import_react_native54 = require("react-native");
|
|
7146
|
+
var import_jsx_runtime56 = require("react/jsx-runtime");
|
|
6813
7147
|
function Modal({
|
|
6814
7148
|
visible,
|
|
6815
7149
|
onRequestClose,
|
|
@@ -6818,30 +7152,30 @@ function Modal({
|
|
|
6818
7152
|
contentStyle
|
|
6819
7153
|
}) {
|
|
6820
7154
|
const theme = useTheme();
|
|
6821
|
-
return /* @__PURE__ */ (0,
|
|
6822
|
-
|
|
7155
|
+
return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
7156
|
+
import_react_native54.Modal,
|
|
6823
7157
|
{
|
|
6824
7158
|
visible,
|
|
6825
7159
|
transparent: true,
|
|
6826
7160
|
animationType: "fade",
|
|
6827
7161
|
onRequestClose,
|
|
6828
|
-
children: /* @__PURE__ */ (0,
|
|
6829
|
-
/* @__PURE__ */ (0,
|
|
6830
|
-
|
|
7162
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_react_native54.View, { style: { flex: 1, backgroundColor: theme.colors.backdrop, justifyContent: "center", padding: theme.spacing.lg }, children: [
|
|
7163
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
7164
|
+
import_react_native54.Pressable,
|
|
6831
7165
|
{
|
|
6832
7166
|
accessibilityRole: "button",
|
|
6833
7167
|
onPress: dismissOnBackdropPress ? onRequestClose : void 0,
|
|
6834
7168
|
style: { position: "absolute", inset: 0 }
|
|
6835
7169
|
}
|
|
6836
7170
|
),
|
|
6837
|
-
/* @__PURE__ */ (0,
|
|
7171
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Card, { variant: "surfaceRaised", padded: true, style: [{ borderRadius: theme.radii.xl }, contentStyle], children })
|
|
6838
7172
|
] })
|
|
6839
7173
|
}
|
|
6840
7174
|
);
|
|
6841
7175
|
}
|
|
6842
7176
|
|
|
6843
7177
|
// src/components/dialogs/ConfirmMergeRequestDialog.tsx
|
|
6844
|
-
var
|
|
7178
|
+
var import_jsx_runtime57 = require("react/jsx-runtime");
|
|
6845
7179
|
function ConfirmMergeRequestDialog({
|
|
6846
7180
|
visible,
|
|
6847
7181
|
onOpenChange,
|
|
@@ -6871,7 +7205,7 @@ function ConfirmMergeRequestDialog({
|
|
|
6871
7205
|
justifyContent: "center",
|
|
6872
7206
|
alignSelf: "stretch"
|
|
6873
7207
|
};
|
|
6874
|
-
return /* @__PURE__ */ (0,
|
|
7208
|
+
return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
|
|
6875
7209
|
Modal,
|
|
6876
7210
|
{
|
|
6877
7211
|
visible,
|
|
@@ -6882,7 +7216,7 @@ function ConfirmMergeRequestDialog({
|
|
|
6882
7216
|
backgroundColor: theme.colors.background
|
|
6883
7217
|
},
|
|
6884
7218
|
children: [
|
|
6885
|
-
/* @__PURE__ */ (0,
|
|
7219
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_react_native55.View, { children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
6886
7220
|
Text,
|
|
6887
7221
|
{
|
|
6888
7222
|
style: {
|
|
@@ -6894,9 +7228,9 @@ function ConfirmMergeRequestDialog({
|
|
|
6894
7228
|
children: "Are you sure you want to approve this merge request?"
|
|
6895
7229
|
}
|
|
6896
7230
|
) }),
|
|
6897
|
-
/* @__PURE__ */ (0,
|
|
6898
|
-
/* @__PURE__ */ (0,
|
|
6899
|
-
|
|
7231
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_react_native55.View, { style: { marginTop: 16 }, children: [
|
|
7232
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
7233
|
+
import_react_native55.View,
|
|
6900
7234
|
{
|
|
6901
7235
|
style: [
|
|
6902
7236
|
fullWidthButtonBase,
|
|
@@ -6905,22 +7239,22 @@ function ConfirmMergeRequestDialog({
|
|
|
6905
7239
|
opacity: canConfirm ? 1 : 0.5
|
|
6906
7240
|
}
|
|
6907
7241
|
],
|
|
6908
|
-
children: /* @__PURE__ */ (0,
|
|
6909
|
-
|
|
7242
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
7243
|
+
import_react_native55.Pressable,
|
|
6910
7244
|
{
|
|
6911
7245
|
accessibilityRole: "button",
|
|
6912
7246
|
accessibilityLabel: "Approve Merge",
|
|
6913
7247
|
disabled: !canConfirm,
|
|
6914
7248
|
onPress: handleConfirm,
|
|
6915
7249
|
style: [fullWidthButtonBase, { flex: 1 }],
|
|
6916
|
-
children: /* @__PURE__ */ (0,
|
|
7250
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Text, { style: { textAlign: "center", color: theme.colors.onPrimary }, children: "Approve Merge" })
|
|
6917
7251
|
}
|
|
6918
7252
|
)
|
|
6919
7253
|
}
|
|
6920
7254
|
),
|
|
6921
|
-
/* @__PURE__ */ (0,
|
|
6922
|
-
/* @__PURE__ */ (0,
|
|
6923
|
-
|
|
7255
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_react_native55.View, { style: { height: 8 } }),
|
|
7256
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
7257
|
+
import_react_native55.View,
|
|
6924
7258
|
{
|
|
6925
7259
|
style: [
|
|
6926
7260
|
fullWidthButtonBase,
|
|
@@ -6931,22 +7265,22 @@ function ConfirmMergeRequestDialog({
|
|
|
6931
7265
|
opacity: isBuilding || !mergeRequest ? 0.5 : 1
|
|
6932
7266
|
}
|
|
6933
7267
|
],
|
|
6934
|
-
children: /* @__PURE__ */ (0,
|
|
6935
|
-
|
|
7268
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
7269
|
+
import_react_native55.Pressable,
|
|
6936
7270
|
{
|
|
6937
7271
|
accessibilityRole: "button",
|
|
6938
7272
|
accessibilityLabel: isBuilding ? "Preparing\u2026" : "Test edits first",
|
|
6939
7273
|
disabled: isBuilding || !mergeRequest,
|
|
6940
7274
|
onPress: handleTestFirst,
|
|
6941
7275
|
style: [fullWidthButtonBase, { flex: 1 }],
|
|
6942
|
-
children: /* @__PURE__ */ (0,
|
|
7276
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Text, { style: { textAlign: "center", color: theme.colors.text }, children: isBuilding ? "Preparing\u2026" : "Test edits first" })
|
|
6943
7277
|
}
|
|
6944
7278
|
)
|
|
6945
7279
|
}
|
|
6946
7280
|
),
|
|
6947
|
-
/* @__PURE__ */ (0,
|
|
6948
|
-
/* @__PURE__ */ (0,
|
|
6949
|
-
|
|
7281
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_react_native55.View, { style: { height: 8 } }),
|
|
7282
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
7283
|
+
import_react_native55.View,
|
|
6950
7284
|
{
|
|
6951
7285
|
style: [
|
|
6952
7286
|
fullWidthButtonBase,
|
|
@@ -6956,14 +7290,14 @@ function ConfirmMergeRequestDialog({
|
|
|
6956
7290
|
borderColor: theme.colors.border
|
|
6957
7291
|
}
|
|
6958
7292
|
],
|
|
6959
|
-
children: /* @__PURE__ */ (0,
|
|
6960
|
-
|
|
7293
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
7294
|
+
import_react_native55.Pressable,
|
|
6961
7295
|
{
|
|
6962
7296
|
accessibilityRole: "button",
|
|
6963
7297
|
accessibilityLabel: "Cancel",
|
|
6964
7298
|
onPress: close,
|
|
6965
7299
|
style: [fullWidthButtonBase, { flex: 1 }],
|
|
6966
|
-
children: /* @__PURE__ */ (0,
|
|
7300
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Text, { style: { textAlign: "center", color: theme.colors.text }, children: "Cancel" })
|
|
6967
7301
|
}
|
|
6968
7302
|
)
|
|
6969
7303
|
}
|
|
@@ -6975,7 +7309,7 @@ function ConfirmMergeRequestDialog({
|
|
|
6975
7309
|
}
|
|
6976
7310
|
|
|
6977
7311
|
// src/studio/ui/ConfirmMergeFlow.tsx
|
|
6978
|
-
var
|
|
7312
|
+
var import_jsx_runtime58 = require("react/jsx-runtime");
|
|
6979
7313
|
function ConfirmMergeFlow({
|
|
6980
7314
|
visible,
|
|
6981
7315
|
onOpenChange,
|
|
@@ -6986,7 +7320,7 @@ function ConfirmMergeFlow({
|
|
|
6986
7320
|
onConfirm,
|
|
6987
7321
|
onTestFirst
|
|
6988
7322
|
}) {
|
|
6989
|
-
return /* @__PURE__ */ (0,
|
|
7323
|
+
return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
6990
7324
|
ConfirmMergeRequestDialog,
|
|
6991
7325
|
{
|
|
6992
7326
|
visible,
|
|
@@ -7084,19 +7418,61 @@ function useOptimisticChatMessages({
|
|
|
7084
7418
|
const createdAtIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
7085
7419
|
const baseServerLastId = chatMessages.length > 0 ? chatMessages[chatMessages.length - 1].id : null;
|
|
7086
7420
|
const id = makeOptimisticId();
|
|
7087
|
-
|
|
7421
|
+
const normalizedAttachments = attachments && attachments.length > 0 ? [...attachments] : void 0;
|
|
7422
|
+
setOptimisticChat((prev) => [
|
|
7423
|
+
...prev,
|
|
7424
|
+
{
|
|
7425
|
+
id,
|
|
7426
|
+
content: text,
|
|
7427
|
+
attachments: normalizedAttachments,
|
|
7428
|
+
createdAtIso,
|
|
7429
|
+
baseServerLastId,
|
|
7430
|
+
failed: false,
|
|
7431
|
+
retrying: false
|
|
7432
|
+
}
|
|
7433
|
+
]);
|
|
7088
7434
|
void Promise.resolve(onSendChat(text, attachments)).catch(() => {
|
|
7089
7435
|
setOptimisticChat((prev) => prev.map((m) => m.id === id ? { ...m, failed: true } : m));
|
|
7090
7436
|
});
|
|
7091
7437
|
},
|
|
7092
7438
|
[chatMessages, disableOptimistic, onSendChat, shouldForkOnEdit]
|
|
7093
7439
|
);
|
|
7094
|
-
|
|
7440
|
+
const onRetry = React43.useCallback(
|
|
7441
|
+
async (messageId) => {
|
|
7442
|
+
if (shouldForkOnEdit || disableOptimistic) return;
|
|
7443
|
+
const target = optimisticChat.find((m) => m.id === messageId);
|
|
7444
|
+
if (!target || target.retrying) return;
|
|
7445
|
+
const baseServerLastId = chatMessages.length > 0 ? chatMessages[chatMessages.length - 1].id : null;
|
|
7446
|
+
setOptimisticChat(
|
|
7447
|
+
(prev) => prev.map(
|
|
7448
|
+
(m) => m.id === messageId ? { ...m, failed: false, retrying: true, baseServerLastId } : m
|
|
7449
|
+
)
|
|
7450
|
+
);
|
|
7451
|
+
try {
|
|
7452
|
+
await onSendChat(target.content, target.attachments);
|
|
7453
|
+
setOptimisticChat(
|
|
7454
|
+
(prev) => prev.map((m) => m.id === messageId ? { ...m, retrying: false } : m)
|
|
7455
|
+
);
|
|
7456
|
+
} catch {
|
|
7457
|
+
setOptimisticChat(
|
|
7458
|
+
(prev) => prev.map((m) => m.id === messageId ? { ...m, failed: true, retrying: false } : m)
|
|
7459
|
+
);
|
|
7460
|
+
}
|
|
7461
|
+
},
|
|
7462
|
+
[chatMessages, disableOptimistic, onSendChat, optimisticChat, shouldForkOnEdit]
|
|
7463
|
+
);
|
|
7464
|
+
const isRetrying = React43.useCallback(
|
|
7465
|
+
(messageId) => {
|
|
7466
|
+
return optimisticChat.some((m) => m.id === messageId && m.retrying);
|
|
7467
|
+
},
|
|
7468
|
+
[optimisticChat]
|
|
7469
|
+
);
|
|
7470
|
+
return { messages, onSend, onRetry, isRetrying };
|
|
7095
7471
|
}
|
|
7096
7472
|
|
|
7097
7473
|
// src/studio/ui/StudioOverlay.tsx
|
|
7098
7474
|
var import_studio_control = require("@comergehq/studio-control");
|
|
7099
|
-
var
|
|
7475
|
+
var import_jsx_runtime59 = require("react/jsx-runtime");
|
|
7100
7476
|
function StudioOverlay({
|
|
7101
7477
|
captureTargetRef,
|
|
7102
7478
|
app,
|
|
@@ -7104,6 +7480,7 @@ function StudioOverlay({
|
|
|
7104
7480
|
isOwner,
|
|
7105
7481
|
shouldForkOnEdit,
|
|
7106
7482
|
isTesting,
|
|
7483
|
+
isBaseBundleDownloading = false,
|
|
7107
7484
|
onRestoreBase,
|
|
7108
7485
|
incomingMergeRequests,
|
|
7109
7486
|
outgoingMergeRequests,
|
|
@@ -7133,7 +7510,7 @@ function StudioOverlay({
|
|
|
7133
7510
|
studioControlOptions
|
|
7134
7511
|
}) {
|
|
7135
7512
|
const theme = useTheme();
|
|
7136
|
-
const { width } = (0,
|
|
7513
|
+
const { width } = (0, import_react_native56.useWindowDimensions)();
|
|
7137
7514
|
const [sheetOpen, setSheetOpen] = React44.useState(false);
|
|
7138
7515
|
const sheetOpenRef = React44.useRef(sheetOpen);
|
|
7139
7516
|
const [activePage, setActivePage] = React44.useState("preview");
|
|
@@ -7159,7 +7536,7 @@ function StudioOverlay({
|
|
|
7159
7536
|
);
|
|
7160
7537
|
const handleSheetOpenChange = React44.useCallback((open) => {
|
|
7161
7538
|
setSheetOpen(open);
|
|
7162
|
-
if (!open)
|
|
7539
|
+
if (!open) import_react_native56.Keyboard.dismiss();
|
|
7163
7540
|
}, []);
|
|
7164
7541
|
const closeSheet = React44.useCallback(() => {
|
|
7165
7542
|
handleSheetOpenChange(false);
|
|
@@ -7170,8 +7547,8 @@ function StudioOverlay({
|
|
|
7170
7547
|
openSheet();
|
|
7171
7548
|
}, [openSheet]);
|
|
7172
7549
|
const backToPreview = React44.useCallback(() => {
|
|
7173
|
-
if (
|
|
7174
|
-
|
|
7550
|
+
if (import_react_native56.Platform.OS !== "ios") {
|
|
7551
|
+
import_react_native56.Keyboard.dismiss();
|
|
7175
7552
|
setActivePage("preview");
|
|
7176
7553
|
return;
|
|
7177
7554
|
}
|
|
@@ -7183,9 +7560,9 @@ function StudioOverlay({
|
|
|
7183
7560
|
clearTimeout(t);
|
|
7184
7561
|
setActivePage("preview");
|
|
7185
7562
|
};
|
|
7186
|
-
const sub =
|
|
7563
|
+
const sub = import_react_native56.Keyboard.addListener("keyboardDidHide", finalize);
|
|
7187
7564
|
const t = setTimeout(finalize, 350);
|
|
7188
|
-
|
|
7565
|
+
import_react_native56.Keyboard.dismiss();
|
|
7189
7566
|
}, []);
|
|
7190
7567
|
const startDraw = React44.useCallback(() => {
|
|
7191
7568
|
setDrawing(true);
|
|
@@ -7234,14 +7611,14 @@ function StudioOverlay({
|
|
|
7234
7611
|
React44.useEffect(() => {
|
|
7235
7612
|
void (0, import_studio_control.publishComergeStudioUIState)(sheetOpen, studioControlOptions);
|
|
7236
7613
|
}, [sheetOpen, studioControlOptions]);
|
|
7237
|
-
return /* @__PURE__ */ (0,
|
|
7238
|
-
/* @__PURE__ */ (0,
|
|
7239
|
-
/* @__PURE__ */ (0,
|
|
7614
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(import_jsx_runtime59.Fragment, { children: [
|
|
7615
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)(EdgeGlowFrame, { visible: isTesting, role: "accent", thickness: 40, intensity: 1 }),
|
|
7616
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)(StudioBottomSheet, { open: sheetOpen, onOpenChange: handleSheetOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
7240
7617
|
StudioSheetPager,
|
|
7241
7618
|
{
|
|
7242
7619
|
activePage,
|
|
7243
7620
|
width,
|
|
7244
|
-
preview: /* @__PURE__ */ (0,
|
|
7621
|
+
preview: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
7245
7622
|
PreviewPanel,
|
|
7246
7623
|
{
|
|
7247
7624
|
app,
|
|
@@ -7270,7 +7647,7 @@ function StudioOverlay({
|
|
|
7270
7647
|
commentCountOverride: commentsCount ?? void 0
|
|
7271
7648
|
}
|
|
7272
7649
|
),
|
|
7273
|
-
chat: /* @__PURE__ */ (0,
|
|
7650
|
+
chat: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
7274
7651
|
ChatPanel,
|
|
7275
7652
|
{
|
|
7276
7653
|
messages: optimistic.messages,
|
|
@@ -7279,7 +7656,6 @@ function StudioOverlay({
|
|
|
7279
7656
|
sendDisabled: chatSendDisabled,
|
|
7280
7657
|
forking: chatForking,
|
|
7281
7658
|
sending: chatSending,
|
|
7282
|
-
autoFocusComposer: sheetOpen && activePage === "chat",
|
|
7283
7659
|
shouldForkOnEdit,
|
|
7284
7660
|
attachments: chatAttachments,
|
|
7285
7661
|
onRemoveAttachment: (idx) => setChatAttachments((prev) => prev.filter((_, i) => i !== idx)),
|
|
@@ -7289,24 +7665,27 @@ function StudioOverlay({
|
|
|
7289
7665
|
onNavigateHome,
|
|
7290
7666
|
onStartDraw: startDraw,
|
|
7291
7667
|
onSend: optimistic.onSend,
|
|
7668
|
+
onRetryMessage: optimistic.onRetry,
|
|
7669
|
+
isRetryingMessage: optimistic.isRetrying,
|
|
7292
7670
|
queueItems: queueItemsForChat,
|
|
7293
7671
|
onRemoveQueueItem
|
|
7294
7672
|
}
|
|
7295
7673
|
)
|
|
7296
7674
|
}
|
|
7297
7675
|
) }),
|
|
7298
|
-
showBubble && /* @__PURE__ */ (0,
|
|
7676
|
+
showBubble && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
7299
7677
|
Bubble,
|
|
7300
7678
|
{
|
|
7301
7679
|
visible: !sheetOpen && !drawing,
|
|
7302
7680
|
ariaLabel: sheetOpen ? "Hide studio" : "Show studio",
|
|
7303
7681
|
badgeCount: incomingMergeRequests.length,
|
|
7304
7682
|
onPress: toggleSheet,
|
|
7305
|
-
isLoading: (app == null ? void 0 : app.status) === "editing",
|
|
7306
|
-
|
|
7683
|
+
isLoading: (app == null ? void 0 : app.status) === "editing" || isBaseBundleDownloading,
|
|
7684
|
+
loadingBorderTone: isBaseBundleDownloading ? "warning" : "default",
|
|
7685
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(import_react_native56.View, { style: { width: 28, height: 28, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(MergeIcon, { width: 24, height: 24, color: theme.colors.floatingContent }) })
|
|
7307
7686
|
}
|
|
7308
7687
|
),
|
|
7309
|
-
/* @__PURE__ */ (0,
|
|
7688
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
7310
7689
|
DrawModeOverlay,
|
|
7311
7690
|
{
|
|
7312
7691
|
visible: drawing,
|
|
@@ -7315,7 +7694,7 @@ function StudioOverlay({
|
|
|
7315
7694
|
onCapture: handleDrawCapture
|
|
7316
7695
|
}
|
|
7317
7696
|
),
|
|
7318
|
-
/* @__PURE__ */ (0,
|
|
7697
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
7319
7698
|
ConfirmMergeFlow,
|
|
7320
7699
|
{
|
|
7321
7700
|
visible: Boolean(confirmMr),
|
|
@@ -7324,11 +7703,12 @@ function StudioOverlay({
|
|
|
7324
7703
|
},
|
|
7325
7704
|
mergeRequest: confirmMr,
|
|
7326
7705
|
toSummary: toMergeRequestSummary,
|
|
7706
|
+
isBuilding: isBuildingMrTest,
|
|
7327
7707
|
onConfirm: (mr) => onApprove == null ? void 0 : onApprove(mr),
|
|
7328
7708
|
onTestFirst: handleTestMr
|
|
7329
7709
|
}
|
|
7330
7710
|
),
|
|
7331
|
-
/* @__PURE__ */ (0,
|
|
7711
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
7332
7712
|
AppCommentsSheet,
|
|
7333
7713
|
{
|
|
7334
7714
|
appId: commentsAppId,
|
|
@@ -7521,7 +7901,7 @@ function useEditQueueActions(appId) {
|
|
|
7521
7901
|
}
|
|
7522
7902
|
|
|
7523
7903
|
// src/studio/ComergeStudio.tsx
|
|
7524
|
-
var
|
|
7904
|
+
var import_jsx_runtime60 = require("react/jsx-runtime");
|
|
7525
7905
|
function ComergeStudio({
|
|
7526
7906
|
appId,
|
|
7527
7907
|
clientKey: clientKey2,
|
|
@@ -7535,14 +7915,14 @@ function ComergeStudio({
|
|
|
7535
7915
|
const [activeAppId, setActiveAppId] = React47.useState(appId);
|
|
7536
7916
|
const [runtimeAppId, setRuntimeAppId] = React47.useState(appId);
|
|
7537
7917
|
const [pendingRuntimeTargetAppId, setPendingRuntimeTargetAppId] = React47.useState(null);
|
|
7538
|
-
const platform = React47.useMemo(() =>
|
|
7918
|
+
const platform = React47.useMemo(() => import_react_native57.Platform.OS === "ios" ? "ios" : "android", []);
|
|
7539
7919
|
React47.useEffect(() => {
|
|
7540
7920
|
setActiveAppId(appId);
|
|
7541
7921
|
setRuntimeAppId(appId);
|
|
7542
7922
|
setPendingRuntimeTargetAppId(null);
|
|
7543
7923
|
}, [appId]);
|
|
7544
7924
|
const captureTargetRef = React47.useRef(null);
|
|
7545
|
-
return /* @__PURE__ */ (0,
|
|
7925
|
+
return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(StudioBootstrap, { clientKey: clientKey2, fallback: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(import_react_native57.View, { style: { flex: 1 } }), children: ({ userId }) => /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(import_bottom_sheet6.BottomSheetModalProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(LiquidGlassResetProvider, { resetTriggers: [appId, activeAppId, runtimeAppId], children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
|
|
7546
7926
|
ComergeStudioInner,
|
|
7547
7927
|
{
|
|
7548
7928
|
userId,
|
|
@@ -7691,6 +8071,8 @@ function ComergeStudioInner({
|
|
|
7691
8071
|
const [testingMrId, setTestingMrId] = React47.useState(null);
|
|
7692
8072
|
const [syncingUpstream, setSyncingUpstream] = React47.useState(false);
|
|
7693
8073
|
const [upstreamSyncStatus, setUpstreamSyncStatus] = React47.useState(null);
|
|
8074
|
+
const isMrTestBuildInProgress = bundle.loading && bundle.loadingMode === "test";
|
|
8075
|
+
const isBaseBundleDownloading = bundle.loading && bundle.loadingMode === "base" && !bundle.isTesting;
|
|
7694
8076
|
const chatShowTypingIndicator = React47.useMemo(() => {
|
|
7695
8077
|
var _a;
|
|
7696
8078
|
if (!thread.raw || thread.raw.length === 0) return false;
|
|
@@ -7737,8 +8119,8 @@ function ComergeStudioInner({
|
|
|
7737
8119
|
}
|
|
7738
8120
|
return editQueue.items;
|
|
7739
8121
|
}, [editQueue.items, lastEditQueueInfo, suppressQueueUntilResponse]);
|
|
7740
|
-
return /* @__PURE__ */ (0,
|
|
7741
|
-
/* @__PURE__ */ (0,
|
|
8122
|
+
return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(import_react_native57.View, { style: [{ flex: 1 }, style], children: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_react_native57.View, { ref: captureTargetRef, style: { flex: 1 }, collapsable: false, children: [
|
|
8123
|
+
/* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
|
|
7742
8124
|
RuntimeRenderer,
|
|
7743
8125
|
{
|
|
7744
8126
|
appKey,
|
|
@@ -7748,7 +8130,7 @@ function ComergeStudioInner({
|
|
|
7748
8130
|
allowInitialPreparing: !embeddedBaseBundles
|
|
7749
8131
|
}
|
|
7750
8132
|
),
|
|
7751
|
-
/* @__PURE__ */ (0,
|
|
8133
|
+
/* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
|
|
7752
8134
|
StudioOverlay,
|
|
7753
8135
|
{
|
|
7754
8136
|
captureTargetRef,
|
|
@@ -7757,6 +8139,7 @@ function ComergeStudioInner({
|
|
|
7757
8139
|
isOwner: actions.isOwner,
|
|
7758
8140
|
shouldForkOnEdit: actions.shouldForkOnEdit,
|
|
7759
8141
|
isTesting: bundle.isTesting,
|
|
8142
|
+
isBaseBundleDownloading,
|
|
7760
8143
|
onRestoreBase: async () => {
|
|
7761
8144
|
setTestingMrId(null);
|
|
7762
8145
|
await bundle.restoreBase();
|
|
@@ -7765,10 +8148,10 @@ function ComergeStudioInner({
|
|
|
7765
8148
|
outgoingMergeRequests: mergeRequests.lists.outgoing,
|
|
7766
8149
|
creatorStatsById: mergeRequests.creatorStatsById,
|
|
7767
8150
|
processingMrId,
|
|
7768
|
-
isBuildingMrTest:
|
|
8151
|
+
isBuildingMrTest: isMrTestBuildInProgress,
|
|
7769
8152
|
testingMrId,
|
|
7770
8153
|
toMergeRequestSummary: mergeRequests.toSummary,
|
|
7771
|
-
onSubmitMergeRequest: (app == null ? void 0 : app.forkedFromAppId) && actions.isOwner && !hasOpenOutgoingMr ? async () => {
|
|
8154
|
+
onSubmitMergeRequest: (app == null ? void 0 : app.forkedFromAppId) && actions.isOwner && !mergeRequests.loading && !hasOpenOutgoingMr ? async () => {
|
|
7772
8155
|
await mergeRequests.actions.openMergeRequest(activeAppId);
|
|
7773
8156
|
} : void 0,
|
|
7774
8157
|
onSyncUpstream: actions.isOwner && (app == null ? void 0 : app.forkedFromAppId) ? handleSyncUpstream : void 0,
|
|
@@ -7793,6 +8176,7 @@ function ComergeStudioInner({
|
|
|
7793
8176
|
}
|
|
7794
8177
|
},
|
|
7795
8178
|
onTestMr: async (mr) => {
|
|
8179
|
+
if (testingMrId === mr.id || bundle.loadingMode === "test") return;
|
|
7796
8180
|
setTestingMrId(mr.id);
|
|
7797
8181
|
await bundle.loadTest({ appId: mr.sourceAppId, commitId: mr.sourceTipCommitId ?? mr.sourceCommitId });
|
|
7798
8182
|
},
|
|
@@ -7815,6 +8199,7 @@ function ComergeStudioInner({
|
|
|
7815
8199
|
// Annotate the CommonJS export names for ESM import in node:
|
|
7816
8200
|
0 && (module.exports = {
|
|
7817
8201
|
ComergeStudio,
|
|
8202
|
+
resetRealtimeState,
|
|
7818
8203
|
setSupabaseClient
|
|
7819
8204
|
});
|
|
7820
8205
|
//# sourceMappingURL=index.js.map
|