replicas-cli 0.2.340 → 0.2.342
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +173 -131
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -7721,6 +7721,7 @@ var AGENT_MODELS = {
|
|
|
7721
7721
|
"gpt-5-mini",
|
|
7722
7722
|
"gemini-3.1-pro",
|
|
7723
7723
|
"gemini-3-flash",
|
|
7724
|
+
"grok-4.5",
|
|
7724
7725
|
"grok-4.3",
|
|
7725
7726
|
CLAUDE_HAIKU_4_5_MODEL,
|
|
7726
7727
|
"kimi-k2.5"
|
|
@@ -7758,6 +7759,7 @@ var MODEL_LABELS = {
|
|
|
7758
7759
|
[CLAUDE_HAIKU_4_5_MODEL]: "Haiku 4.5",
|
|
7759
7760
|
"gemini-3.1-pro": "Gemini 3.1 Pro",
|
|
7760
7761
|
"gemini-3-flash": "Gemini 3 Flash",
|
|
7762
|
+
"grok-4.5": "Grok 4.5",
|
|
7761
7763
|
"grok-4.3": "Grok 4.3",
|
|
7762
7764
|
"kimi-k2.5": "Kimi K2.5"
|
|
7763
7765
|
};
|
|
@@ -9597,7 +9599,7 @@ var HOOK_EXEC_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
|
|
|
9597
9599
|
var REPLICAS_CONFIG_FILENAMES = ["replicas.json", "replicas.yaml", "replicas.yml"];
|
|
9598
9600
|
|
|
9599
9601
|
// ../shared/src/cli-version.ts
|
|
9600
|
-
var CLI_VERSION = "0.2.
|
|
9602
|
+
var CLI_VERSION = "0.2.342";
|
|
9601
9603
|
|
|
9602
9604
|
// ../shared/src/engine/environment.ts
|
|
9603
9605
|
var DESKTOP_NOVNC_PORT = 6080;
|
|
@@ -16298,7 +16300,7 @@ import { createCliRenderer } from "@opentui/core";
|
|
|
16298
16300
|
import { createRoot } from "@opentui/react";
|
|
16299
16301
|
|
|
16300
16302
|
// src/interactive/App.tsx
|
|
16301
|
-
import { useState as
|
|
16303
|
+
import { useState as useState7, useEffect as useEffect2, useMemo as useMemo5, useCallback as useCallback9, useRef as useRef6 } from "react";
|
|
16302
16304
|
import { useKeyboard as useKeyboard5, useRenderer, useTerminalDimensions as useTerminalDimensions3 } from "@opentui/react";
|
|
16303
16305
|
import { QueryClient } from "@tanstack/react-query";
|
|
16304
16306
|
|
|
@@ -16320,8 +16322,74 @@ function useEffectOnMount(effect) {
|
|
|
16320
16322
|
useEffect(effect, []);
|
|
16321
16323
|
}
|
|
16322
16324
|
|
|
16325
|
+
// ../shared/src/hooks/useReconnectingSseStream.ts
|
|
16326
|
+
import { useCallback, useRef, useSyncExternalStore } from "react";
|
|
16327
|
+
function useReconnectingSseStream(options) {
|
|
16328
|
+
const { enabled, openStream, onEvent, onConnect, onNotOk, reconnectDelayMs = 1e3, coalesceMs } = options;
|
|
16329
|
+
const connectedRef = useRef(false);
|
|
16330
|
+
const subscribe = useCallback(
|
|
16331
|
+
(notify) => {
|
|
16332
|
+
if (!enabled) return () => {
|
|
16333
|
+
};
|
|
16334
|
+
const controller = new AbortController();
|
|
16335
|
+
let cancelled = false;
|
|
16336
|
+
let debounce = null;
|
|
16337
|
+
const setConnected = (value) => {
|
|
16338
|
+
if (connectedRef.current === value) return;
|
|
16339
|
+
connectedRef.current = value;
|
|
16340
|
+
notify();
|
|
16341
|
+
};
|
|
16342
|
+
const emit = (event) => {
|
|
16343
|
+
if (coalesceMs === void 0) {
|
|
16344
|
+
void onEvent(event);
|
|
16345
|
+
return;
|
|
16346
|
+
}
|
|
16347
|
+
if (debounce) clearTimeout(debounce);
|
|
16348
|
+
debounce = setTimeout(() => void onEvent(event), coalesceMs);
|
|
16349
|
+
};
|
|
16350
|
+
const connect = async () => {
|
|
16351
|
+
try {
|
|
16352
|
+
const response = await openStream(controller.signal);
|
|
16353
|
+
if (!response.ok || !response.body) {
|
|
16354
|
+
setConnected(false);
|
|
16355
|
+
return onNotOk?.(response) === "stop";
|
|
16356
|
+
}
|
|
16357
|
+
setConnected(true);
|
|
16358
|
+
onConnect?.();
|
|
16359
|
+
await readSseStream(response.body, emit, () => !cancelled);
|
|
16360
|
+
return false;
|
|
16361
|
+
} catch {
|
|
16362
|
+
setConnected(false);
|
|
16363
|
+
return false;
|
|
16364
|
+
}
|
|
16365
|
+
};
|
|
16366
|
+
const run = async () => {
|
|
16367
|
+
while (!cancelled) {
|
|
16368
|
+
const stop = await connect();
|
|
16369
|
+
if (cancelled || stop) break;
|
|
16370
|
+
await new Promise((resolve2) => setTimeout(resolve2, reconnectDelayMs));
|
|
16371
|
+
}
|
|
16372
|
+
};
|
|
16373
|
+
run().catch(() => setConnected(false));
|
|
16374
|
+
return () => {
|
|
16375
|
+
cancelled = true;
|
|
16376
|
+
controller.abort();
|
|
16377
|
+
if (debounce) clearTimeout(debounce);
|
|
16378
|
+
setConnected(false);
|
|
16379
|
+
};
|
|
16380
|
+
},
|
|
16381
|
+
[enabled, openStream, onEvent, onConnect, onNotOk, reconnectDelayMs, coalesceMs]
|
|
16382
|
+
);
|
|
16383
|
+
const connected = useSyncExternalStore(
|
|
16384
|
+
subscribe,
|
|
16385
|
+
() => connectedRef.current,
|
|
16386
|
+
() => false
|
|
16387
|
+
);
|
|
16388
|
+
return { connected };
|
|
16389
|
+
}
|
|
16390
|
+
|
|
16323
16391
|
// ../shared/src/hooks/fetch.ts
|
|
16324
|
-
import { useCallback } from "react";
|
|
16392
|
+
import { useCallback as useCallback2 } from "react";
|
|
16325
16393
|
var REDIRECT_STATUSES2 = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
16326
16394
|
var MAX_REDIRECTS2 = 5;
|
|
16327
16395
|
async function fetchWithRedirects2(url, init, attempt = 0) {
|
|
@@ -16347,7 +16415,7 @@ async function fetchWithRedirects2(url, init, attempt = 0) {
|
|
|
16347
16415
|
}
|
|
16348
16416
|
function useOrgFetch() {
|
|
16349
16417
|
const auth = useReplicasAuth();
|
|
16350
|
-
return
|
|
16418
|
+
return useCallback2(
|
|
16351
16419
|
async function orgFetch(url, options) {
|
|
16352
16420
|
const token = await auth.getAccessToken();
|
|
16353
16421
|
const orgId = auth.getOrganizationId();
|
|
@@ -16375,7 +16443,7 @@ function useOrgFetch() {
|
|
|
16375
16443
|
}
|
|
16376
16444
|
function useRawOrgFetch() {
|
|
16377
16445
|
const auth = useReplicasAuth();
|
|
16378
|
-
return
|
|
16446
|
+
return useCallback2(
|
|
16379
16447
|
async function rawOrgFetch(url, options) {
|
|
16380
16448
|
const token = await auth.getAccessToken();
|
|
16381
16449
|
const orgId = auth.getOrganizationId();
|
|
@@ -16392,7 +16460,7 @@ function useRawOrgFetch() {
|
|
|
16392
16460
|
}
|
|
16393
16461
|
|
|
16394
16462
|
// ../shared/src/hooks/useWorkspaces.ts
|
|
16395
|
-
import { useCallback as
|
|
16463
|
+
import { useCallback as useCallback3 } from "react";
|
|
16396
16464
|
import { useQuery, useMutation } from "@tanstack/react-query";
|
|
16397
16465
|
function useWorkspaces(viewModes, page = 1, limit = 100) {
|
|
16398
16466
|
const auth = useReplicasAuth();
|
|
@@ -16444,7 +16512,7 @@ function useWaitForWorkspaceActive() {
|
|
|
16444
16512
|
const auth = useReplicasAuth();
|
|
16445
16513
|
const orgFetch = useOrgFetch();
|
|
16446
16514
|
const orgId = auth.getOrganizationId();
|
|
16447
|
-
return
|
|
16515
|
+
return useCallback3(async (workspaceId) => {
|
|
16448
16516
|
try {
|
|
16449
16517
|
const result = await auth.queryClient.fetchQuery({
|
|
16450
16518
|
queryKey: ["workspace-wait-active", orgId, workspaceId],
|
|
@@ -16516,7 +16584,7 @@ function useGenerateWorkspaceName() {
|
|
|
16516
16584
|
}
|
|
16517
16585
|
|
|
16518
16586
|
// ../shared/src/hooks/useWorkspaceEngine.ts
|
|
16519
|
-
import { useCallback as
|
|
16587
|
+
import { useCallback as useCallback4 } from "react";
|
|
16520
16588
|
import { useQuery as useQuery2, useMutation as useMutation2 } from "@tanstack/react-query";
|
|
16521
16589
|
function upsertChat(chats, chat) {
|
|
16522
16590
|
const existingIndex = chats.findIndex((item) => item.id === chat.id);
|
|
@@ -16644,8 +16712,7 @@ function useWorkspaceEvents(workspaceId, enabled = true) {
|
|
|
16644
16712
|
const auth = useReplicasAuth();
|
|
16645
16713
|
const rawFetch = useRawOrgFetch();
|
|
16646
16714
|
const qc = auth.queryClient;
|
|
16647
|
-
const
|
|
16648
|
-
const handleEvent = useCallback3((event) => {
|
|
16715
|
+
const handleEvent = useCallback4((event) => {
|
|
16649
16716
|
if (!workspaceId) return;
|
|
16650
16717
|
const chatsKey = ["workspace-chats", workspaceId];
|
|
16651
16718
|
if (event.type === "chat.created" || event.type === "chat.updated") {
|
|
@@ -16723,43 +16790,18 @@ function useWorkspaceEvents(workspaceId, enabled = true) {
|
|
|
16723
16790
|
return;
|
|
16724
16791
|
}
|
|
16725
16792
|
}, [qc, workspaceId]);
|
|
16726
|
-
|
|
16727
|
-
|
|
16728
|
-
|
|
16729
|
-
|
|
16730
|
-
|
|
16731
|
-
|
|
16732
|
-
|
|
16733
|
-
|
|
16734
|
-
|
|
16735
|
-
|
|
16736
|
-
|
|
16737
|
-
|
|
16738
|
-
return false;
|
|
16739
|
-
}
|
|
16740
|
-
setConnected(true);
|
|
16741
|
-
await readSseStream(response.body, handleEvent, () => !cancelled);
|
|
16742
|
-
return false;
|
|
16743
|
-
} catch {
|
|
16744
|
-
setConnected(false);
|
|
16745
|
-
return false;
|
|
16746
|
-
}
|
|
16747
|
-
};
|
|
16748
|
-
const run = async () => {
|
|
16749
|
-
while (!cancelled) {
|
|
16750
|
-
await connect();
|
|
16751
|
-
if (cancelled) break;
|
|
16752
|
-
await new Promise((resolve2) => setTimeout(resolve2, 1e3));
|
|
16753
|
-
}
|
|
16754
|
-
};
|
|
16755
|
-
run().catch(() => setConnected(false));
|
|
16756
|
-
return () => {
|
|
16757
|
-
cancelled = true;
|
|
16758
|
-
controller.abort();
|
|
16759
|
-
setConnected(false);
|
|
16760
|
-
};
|
|
16761
|
-
}, [enabled, handleEvent, rawFetch, workspaceId]);
|
|
16762
|
-
return useMemo(() => ({ connected }), [connected]);
|
|
16793
|
+
const openStream = useCallback4(
|
|
16794
|
+
(signal) => rawFetch(`/v1/workspaces/${workspaceId}/events`, {
|
|
16795
|
+
headers: { Accept: "text/event-stream" },
|
|
16796
|
+
signal
|
|
16797
|
+
}),
|
|
16798
|
+
[rawFetch, workspaceId]
|
|
16799
|
+
);
|
|
16800
|
+
return useReconnectingSseStream({
|
|
16801
|
+
enabled: workspaceId != null && enabled,
|
|
16802
|
+
openStream,
|
|
16803
|
+
onEvent: handleEvent
|
|
16804
|
+
});
|
|
16763
16805
|
}
|
|
16764
16806
|
|
|
16765
16807
|
// ../shared/src/hooks/useRepositories.ts
|
|
@@ -16839,7 +16881,7 @@ function StatusBar({ focusPanel, viewingDiff, hasDiffAvailable }) {
|
|
|
16839
16881
|
}
|
|
16840
16882
|
|
|
16841
16883
|
// src/interactive/components/WorkspaceSidebar.tsx
|
|
16842
|
-
import { useState
|
|
16884
|
+
import { useState, useMemo, useCallback as useCallback5 } from "react";
|
|
16843
16885
|
import { useKeyboard, useTerminalDimensions } from "@opentui/react";
|
|
16844
16886
|
import { jsx as jsx2, jsxs as jsxs2 } from "@opentui/react/jsx-runtime";
|
|
16845
16887
|
function flattenGroups(groups, collapsedGroups) {
|
|
@@ -16885,17 +16927,17 @@ function WorkspaceSidebar({
|
|
|
16885
16927
|
loading
|
|
16886
16928
|
}) {
|
|
16887
16929
|
const { height: termHeight } = useTerminalDimensions();
|
|
16888
|
-
const [collapsedGroups, setCollapsedGroups] =
|
|
16889
|
-
const [cursorIndex, setCursorIndex] =
|
|
16890
|
-
const [scrollOffset, setScrollOffset] =
|
|
16891
|
-
const [confirmArchive, setConfirmArchive] =
|
|
16892
|
-
const items =
|
|
16930
|
+
const [collapsedGroups, setCollapsedGroups] = useState(/* @__PURE__ */ new Set());
|
|
16931
|
+
const [cursorIndex, setCursorIndex] = useState(0);
|
|
16932
|
+
const [scrollOffset, setScrollOffset] = useState(0);
|
|
16933
|
+
const [confirmArchive, setConfirmArchive] = useState(null);
|
|
16934
|
+
const items = useMemo(() => flattenGroups(groups, collapsedGroups), [groups, collapsedGroups]);
|
|
16893
16935
|
const clampedCursor = Math.min(cursorIndex, Math.max(0, items.length - 1));
|
|
16894
16936
|
if (clampedCursor !== cursorIndex) {
|
|
16895
16937
|
setCursorIndex(clampedCursor);
|
|
16896
16938
|
}
|
|
16897
16939
|
const visibleHeight = Math.max(1, termHeight - 4);
|
|
16898
|
-
const adjustScroll =
|
|
16940
|
+
const adjustScroll = useCallback5(
|
|
16899
16941
|
(newCursor) => {
|
|
16900
16942
|
let newOffset = scrollOffset;
|
|
16901
16943
|
if (newCursor < newOffset) {
|
|
@@ -16907,7 +16949,7 @@ function WorkspaceSidebar({
|
|
|
16907
16949
|
},
|
|
16908
16950
|
[scrollOffset, visibleHeight]
|
|
16909
16951
|
);
|
|
16910
|
-
const moveCursor =
|
|
16952
|
+
const moveCursor = useCallback5(
|
|
16911
16953
|
(next) => {
|
|
16912
16954
|
const len = items.length;
|
|
16913
16955
|
if (len === 0) return;
|
|
@@ -16917,7 +16959,7 @@ function WorkspaceSidebar({
|
|
|
16917
16959
|
},
|
|
16918
16960
|
[items.length, adjustScroll]
|
|
16919
16961
|
);
|
|
16920
|
-
const handleAction =
|
|
16962
|
+
const handleAction = useCallback5(
|
|
16921
16963
|
(item) => {
|
|
16922
16964
|
if (item.type === "group") {
|
|
16923
16965
|
setCollapsedGroups((prev) => {
|
|
@@ -16937,7 +16979,7 @@ function WorkspaceSidebar({
|
|
|
16937
16979
|
},
|
|
16938
16980
|
[onSelectWorkspace, onCreateWorkspace]
|
|
16939
16981
|
);
|
|
16940
|
-
const handleArchive =
|
|
16982
|
+
const handleArchive = useCallback5(() => {
|
|
16941
16983
|
const item = items[cursorIndex];
|
|
16942
16984
|
if (!item || item.type !== "workspace") return;
|
|
16943
16985
|
if (confirmArchive === item.workspaceId) {
|
|
@@ -16947,7 +16989,7 @@ function WorkspaceSidebar({
|
|
|
16947
16989
|
setConfirmArchive(item.workspaceId);
|
|
16948
16990
|
}
|
|
16949
16991
|
}, [items, cursorIndex, confirmArchive, onArchiveWorkspace]);
|
|
16950
|
-
const moveCursorAndClearConfirm =
|
|
16992
|
+
const moveCursorAndClearConfirm = useCallback5(
|
|
16951
16993
|
(next) => {
|
|
16952
16994
|
setConfirmArchive(null);
|
|
16953
16995
|
moveCursor(next);
|
|
@@ -17015,7 +17057,7 @@ function WorkspaceSidebar({
|
|
|
17015
17057
|
return;
|
|
17016
17058
|
}
|
|
17017
17059
|
});
|
|
17018
|
-
const handleItemClick =
|
|
17060
|
+
const handleItemClick = useCallback5(
|
|
17019
17061
|
(globalIndex) => {
|
|
17020
17062
|
setConfirmArchive(null);
|
|
17021
17063
|
setCursorIndex(globalIndex);
|
|
@@ -17024,7 +17066,7 @@ function WorkspaceSidebar({
|
|
|
17024
17066
|
},
|
|
17025
17067
|
[items, handleAction]
|
|
17026
17068
|
);
|
|
17027
|
-
const handleArchiveClick =
|
|
17069
|
+
const handleArchiveClick = useCallback5(
|
|
17028
17070
|
(workspaceId, e) => {
|
|
17029
17071
|
e?.preventDefault?.();
|
|
17030
17072
|
if (confirmArchive === workspaceId) {
|
|
@@ -17162,11 +17204,11 @@ function WorkspaceSidebar({
|
|
|
17162
17204
|
}
|
|
17163
17205
|
|
|
17164
17206
|
// src/interactive/components/ChatArea.tsx
|
|
17165
|
-
import { useRef as
|
|
17207
|
+
import { useRef as useRef3 } from "react";
|
|
17166
17208
|
import { useKeyboard as useKeyboard3 } from "@opentui/react";
|
|
17167
17209
|
|
|
17168
17210
|
// src/interactive/components/ChatMessage.tsx
|
|
17169
|
-
import { useState as
|
|
17211
|
+
import { useState as useState4, useMemo as useMemo3 } from "react";
|
|
17170
17212
|
|
|
17171
17213
|
// src/interactive/components/Spinner.tsx
|
|
17172
17214
|
import "opentui-spinner/react";
|
|
@@ -17181,10 +17223,10 @@ function SpinnerLabel({ color, label }) {
|
|
|
17181
17223
|
}
|
|
17182
17224
|
|
|
17183
17225
|
// src/interactive/components/StructuredUserMessage.tsx
|
|
17184
|
-
import { useState as
|
|
17226
|
+
import { useState as useState3 } from "react";
|
|
17185
17227
|
|
|
17186
17228
|
// src/interactive/components/diff-utils.tsx
|
|
17187
|
-
import React2, { useState as
|
|
17229
|
+
import React2, { useState as useState2, useMemo as useMemo2, useCallback as useCallback6, useRef as useRef2 } from "react";
|
|
17188
17230
|
import { SyntaxStyle } from "@opentui/core";
|
|
17189
17231
|
import { useKeyboard as useKeyboard2 } from "@opentui/react";
|
|
17190
17232
|
import { Fragment, jsx as jsx4, jsxs as jsxs4 } from "@opentui/react/jsx-runtime";
|
|
@@ -17314,7 +17356,7 @@ function diffProps(filePath) {
|
|
|
17314
17356
|
};
|
|
17315
17357
|
}
|
|
17316
17358
|
function DiffView({ diff, filePath }) {
|
|
17317
|
-
const hunks =
|
|
17359
|
+
const hunks = useMemo2(() => splitDiffByHunks(diff), [diff]);
|
|
17318
17360
|
const props = diffProps(filePath);
|
|
17319
17361
|
if (hunks.length <= 1) {
|
|
17320
17362
|
return /* @__PURE__ */ jsx4("diff", { diff: ensureUnifiedHeaders(diff, filePath), ...props });
|
|
@@ -17427,16 +17469,16 @@ function buildFileTree(files) {
|
|
|
17427
17469
|
}
|
|
17428
17470
|
var FILE_PANEL_WIDTH = 32;
|
|
17429
17471
|
function DiffViewer({ diff, repoName, focused }) {
|
|
17430
|
-
const files =
|
|
17431
|
-
const tree =
|
|
17432
|
-
const [selectedFileIndex, setSelectedFileIndex] =
|
|
17433
|
-
const [collapsedFolders, setCollapsedFolders] =
|
|
17434
|
-
const [cursorIndex, setCursorIndex] =
|
|
17435
|
-
const [innerFocus, setInnerFocus] =
|
|
17472
|
+
const files = useMemo2(() => splitDiffByFile(diff), [diff]);
|
|
17473
|
+
const tree = useMemo2(() => buildFileTree(files), [files]);
|
|
17474
|
+
const [selectedFileIndex, setSelectedFileIndex] = useState2(0);
|
|
17475
|
+
const [collapsedFolders, setCollapsedFolders] = useState2(/* @__PURE__ */ new Set());
|
|
17476
|
+
const [cursorIndex, setCursorIndex] = useState2(0);
|
|
17477
|
+
const [innerFocus, setInnerFocus] = useState2("files");
|
|
17436
17478
|
const safeFileIndex = Math.min(selectedFileIndex, Math.max(0, files.length - 1));
|
|
17437
|
-
const diffScrollRef =
|
|
17438
|
-
const fileTreeScrollRef =
|
|
17439
|
-
const visibleTree =
|
|
17479
|
+
const diffScrollRef = useRef2(null);
|
|
17480
|
+
const fileTreeScrollRef = useRef2(null);
|
|
17481
|
+
const visibleTree = useMemo2(() => {
|
|
17440
17482
|
const result = [];
|
|
17441
17483
|
let hideUntilDepth = null;
|
|
17442
17484
|
for (const node of tree) {
|
|
@@ -17452,12 +17494,12 @@ function DiffViewer({ diff, repoName, focused }) {
|
|
|
17452
17494
|
return result;
|
|
17453
17495
|
}, [tree, collapsedFolders]);
|
|
17454
17496
|
const safeCursorIndex = Math.min(cursorIndex, Math.max(0, visibleTree.length - 1));
|
|
17455
|
-
const scrollCursorIntoView =
|
|
17497
|
+
const scrollCursorIntoView = useCallback6((treeIdx) => {
|
|
17456
17498
|
const node = visibleTree[treeIdx];
|
|
17457
17499
|
if (!node) return;
|
|
17458
17500
|
fileTreeScrollRef.current?.scrollChildIntoView(`tree-${node.path}`);
|
|
17459
17501
|
}, [visibleTree]);
|
|
17460
|
-
const moveCursor =
|
|
17502
|
+
const moveCursor = useCallback6((next) => {
|
|
17461
17503
|
const len = visibleTree.length;
|
|
17462
17504
|
if (len === 0) return;
|
|
17463
17505
|
const wrapped = (next % len + len) % len;
|
|
@@ -17468,7 +17510,7 @@ function DiffViewer({ diff, repoName, focused }) {
|
|
|
17468
17510
|
setSelectedFileIndex(node.fileIndex);
|
|
17469
17511
|
}
|
|
17470
17512
|
}, [visibleTree, scrollCursorIntoView]);
|
|
17471
|
-
const toggleFolder =
|
|
17513
|
+
const toggleFolder = useCallback6((folderPath) => {
|
|
17472
17514
|
setCollapsedFolders((prev) => {
|
|
17473
17515
|
const next = new Set(prev);
|
|
17474
17516
|
if (next.has(folderPath)) next.delete(folderPath);
|
|
@@ -17476,7 +17518,7 @@ function DiffViewer({ diff, repoName, focused }) {
|
|
|
17476
17518
|
return next;
|
|
17477
17519
|
});
|
|
17478
17520
|
}, []);
|
|
17479
|
-
const selectFile =
|
|
17521
|
+
const selectFile = useCallback6((fileIndex, treeIndex) => {
|
|
17480
17522
|
setSelectedFileIndex(fileIndex);
|
|
17481
17523
|
setCursorIndex(treeIndex);
|
|
17482
17524
|
scrollCursorIntoView(treeIndex);
|
|
@@ -17513,7 +17555,7 @@ function DiffViewer({ diff, repoName, focused }) {
|
|
|
17513
17555
|
}
|
|
17514
17556
|
}
|
|
17515
17557
|
});
|
|
17516
|
-
const statsColumnWidth =
|
|
17558
|
+
const statsColumnWidth = useMemo2(() => {
|
|
17517
17559
|
let max = 0;
|
|
17518
17560
|
for (const f of files) {
|
|
17519
17561
|
const a = f.added > 0 ? `+${f.added}`.length : 0;
|
|
@@ -17697,7 +17739,7 @@ function MessageBody({ children }) {
|
|
|
17697
17739
|
return /* @__PURE__ */ jsx5("text", { fg: "#ffffff", selectable: true, children });
|
|
17698
17740
|
}
|
|
17699
17741
|
function ExpandableSection({ label, children }) {
|
|
17700
|
-
const [expanded, setExpanded] =
|
|
17742
|
+
const [expanded, setExpanded] = useState3(false);
|
|
17701
17743
|
if (!children) return null;
|
|
17702
17744
|
return /* @__PURE__ */ jsxs5("box", { flexDirection: "column", children: [
|
|
17703
17745
|
/* @__PURE__ */ jsx5("box", { onMouseDown: () => setExpanded((e) => !e), children: /* @__PURE__ */ jsxs5("text", { children: [
|
|
@@ -17711,7 +17753,7 @@ function ExpandableSection({ label, children }) {
|
|
|
17711
17753
|
] });
|
|
17712
17754
|
}
|
|
17713
17755
|
function ExpandableDiffSection({ label, diffContent, filePath }) {
|
|
17714
|
-
const [expanded, setExpanded] =
|
|
17756
|
+
const [expanded, setExpanded] = useState3(false);
|
|
17715
17757
|
if (!diffContent) return null;
|
|
17716
17758
|
return /* @__PURE__ */ jsxs5("box", { flexDirection: "column", children: [
|
|
17717
17759
|
/* @__PURE__ */ jsx5("box", { onMouseDown: () => setExpanded((e) => !e), children: /* @__PURE__ */ jsxs5("text", { children: [
|
|
@@ -17954,7 +17996,7 @@ function ExpandableAction({
|
|
|
17954
17996
|
status,
|
|
17955
17997
|
children
|
|
17956
17998
|
}) {
|
|
17957
|
-
const [expanded, setExpanded] =
|
|
17999
|
+
const [expanded, setExpanded] = useState4(false);
|
|
17958
18000
|
return /* @__PURE__ */ jsxs6("box", { flexDirection: "column", children: [
|
|
17959
18001
|
/* @__PURE__ */ jsx6(
|
|
17960
18002
|
ActionLine,
|
|
@@ -17979,9 +18021,9 @@ function getChangeStyle(action) {
|
|
|
17979
18021
|
return CHANGE_STYLE[action] ?? DEFAULT_CHANGE_STYLE;
|
|
17980
18022
|
}
|
|
17981
18023
|
function PatchOperation({ op, defaultExpanded = false }) {
|
|
17982
|
-
const [expanded, setExpanded] =
|
|
18024
|
+
const [expanded, setExpanded] = useState4(defaultExpanded);
|
|
17983
18025
|
const { color, sign } = getChangeStyle(op.action);
|
|
17984
|
-
const stats =
|
|
18026
|
+
const stats = useMemo3(() => op.diff ? countDiffStats(op.diff) : null, [op.diff]);
|
|
17985
18027
|
if (!op.diff) {
|
|
17986
18028
|
return /* @__PURE__ */ jsxs6("text", { children: [
|
|
17987
18029
|
/* @__PURE__ */ jsx6("span", { fg: color, children: sign }),
|
|
@@ -18021,7 +18063,7 @@ function isStructuredPrompt(p) {
|
|
|
18021
18063
|
return p.source !== "raw";
|
|
18022
18064
|
}
|
|
18023
18065
|
function UserMessageContent({ content }) {
|
|
18024
|
-
const parsed =
|
|
18066
|
+
const parsed = useMemo3(() => parseUserMessage(content), [content]);
|
|
18025
18067
|
return /* @__PURE__ */ jsx6(
|
|
18026
18068
|
"box",
|
|
18027
18069
|
{
|
|
@@ -18158,10 +18200,10 @@ function ChatArea({
|
|
|
18158
18200
|
agentLabel,
|
|
18159
18201
|
agentConnectHelp
|
|
18160
18202
|
}) {
|
|
18161
|
-
const textareaRef =
|
|
18162
|
-
const scrollboxRef =
|
|
18163
|
-
const isAtBottomRef =
|
|
18164
|
-
const onSendMessageRef =
|
|
18203
|
+
const textareaRef = useRef3(null);
|
|
18204
|
+
const scrollboxRef = useRef3(null);
|
|
18205
|
+
const isAtBottomRef = useRef3(true);
|
|
18206
|
+
const onSendMessageRef = useRef3(onSendMessage);
|
|
18165
18207
|
onSendMessageRef.current = onSendMessage;
|
|
18166
18208
|
const inputFocused = focusPanel === "chat-input";
|
|
18167
18209
|
const tabsFocused = focusPanel === "chat-tabs";
|
|
@@ -18333,7 +18375,7 @@ function ChatArea({
|
|
|
18333
18375
|
}
|
|
18334
18376
|
|
|
18335
18377
|
// src/interactive/components/WorkspaceInfo.tsx
|
|
18336
|
-
import React6, { useState as
|
|
18378
|
+
import React6, { useState as useState5, useMemo as useMemo4, useCallback as useCallback7, useRef as useRef4 } from "react";
|
|
18337
18379
|
import open4 from "open";
|
|
18338
18380
|
import { useKeyboard as useKeyboard4 } from "@opentui/react";
|
|
18339
18381
|
import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs8 } from "@opentui/react/jsx-runtime";
|
|
@@ -18521,19 +18563,19 @@ function ViewModeRow({
|
|
|
18521
18563
|
}
|
|
18522
18564
|
function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, agentAvailability, previews, onWakeWorkspace, onViewDiff, wakingWorkspaceId, viewMode, viewingDiffRepoName, onSelectChatMode, onSelectDiffMode, onCreatePr, isPlanMode }) {
|
|
18523
18565
|
const borderColor = focused ? "#3eeba3" : "#333333";
|
|
18524
|
-
const [cursorIndex, setCursorIndex] =
|
|
18525
|
-
const interactiveItems =
|
|
18566
|
+
const [cursorIndex, setCursorIndex] = useState5(0);
|
|
18567
|
+
const interactiveItems = useMemo4(() => {
|
|
18526
18568
|
if (!status || !workspaceName) return [];
|
|
18527
18569
|
return buildInteractiveItems(workspaceId, status, previews, wakingWorkspaceId);
|
|
18528
18570
|
}, [workspaceId, workspaceName, status, previews, wakingWorkspaceId]);
|
|
18529
|
-
const diffItems =
|
|
18571
|
+
const diffItems = useMemo4(
|
|
18530
18572
|
() => interactiveItems.filter((item) => item.type === "diff"),
|
|
18531
18573
|
[interactiveItems]
|
|
18532
18574
|
);
|
|
18533
18575
|
const hasAnyDiff = diffItems.length > 0;
|
|
18534
18576
|
const safeCursor = interactiveItems.length > 0 ? Math.min(cursorIndex, interactiveItems.length - 1) : 0;
|
|
18535
|
-
const scrollboxRef =
|
|
18536
|
-
const moveCursor =
|
|
18577
|
+
const scrollboxRef = useRef4(null);
|
|
18578
|
+
const moveCursor = useCallback7(
|
|
18537
18579
|
(next) => {
|
|
18538
18580
|
const len = interactiveItems.length;
|
|
18539
18581
|
if (len === 0) return;
|
|
@@ -18544,7 +18586,7 @@ function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, a
|
|
|
18544
18586
|
},
|
|
18545
18587
|
[interactiveItems]
|
|
18546
18588
|
);
|
|
18547
|
-
const handleAction =
|
|
18589
|
+
const handleAction = useCallback7(
|
|
18548
18590
|
(item) => {
|
|
18549
18591
|
if (!item) return;
|
|
18550
18592
|
switch (item.type) {
|
|
@@ -18613,7 +18655,7 @@ function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, a
|
|
|
18613
18655
|
return;
|
|
18614
18656
|
}
|
|
18615
18657
|
});
|
|
18616
|
-
const isHighlighted =
|
|
18658
|
+
const isHighlighted = useCallback7(
|
|
18617
18659
|
(item) => {
|
|
18618
18660
|
if (!focused) return false;
|
|
18619
18661
|
const idx = interactiveItems.indexOf(item);
|
|
@@ -18621,7 +18663,7 @@ function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, a
|
|
|
18621
18663
|
},
|
|
18622
18664
|
[focused, interactiveItems, safeCursor]
|
|
18623
18665
|
);
|
|
18624
|
-
const findItem =
|
|
18666
|
+
const findItem = useCallback7(
|
|
18625
18667
|
(type, key) => {
|
|
18626
18668
|
return interactiveItems.find((item) => {
|
|
18627
18669
|
if (item.type !== type) return false;
|
|
@@ -18915,7 +18957,7 @@ function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, a
|
|
|
18915
18957
|
import { useTerminalDimensions as useTerminalDimensions2 } from "@opentui/react";
|
|
18916
18958
|
|
|
18917
18959
|
// src/interactive/toast-context.tsx
|
|
18918
|
-
import { createContext as createContext2, useContext as useContext2, useState as
|
|
18960
|
+
import { createContext as createContext2, useContext as useContext2, useState as useState6, useCallback as useCallback8, useRef as useRef5 } from "react";
|
|
18919
18961
|
import { jsx as jsx9 } from "@opentui/react/jsx-runtime";
|
|
18920
18962
|
var ToastContext = createContext2(null);
|
|
18921
18963
|
function useToast() {
|
|
@@ -18924,9 +18966,9 @@ function useToast() {
|
|
|
18924
18966
|
return ctx;
|
|
18925
18967
|
}
|
|
18926
18968
|
function ToastProvider({ children }) {
|
|
18927
|
-
const [current, setCurrent] =
|
|
18928
|
-
const timeoutRef =
|
|
18929
|
-
const show =
|
|
18969
|
+
const [current, setCurrent] = useState6(null);
|
|
18970
|
+
const timeoutRef = useRef5(null);
|
|
18971
|
+
const show = useCallback8((options) => {
|
|
18930
18972
|
const { message, variant = "info", duration = 3e3 } = options;
|
|
18931
18973
|
setCurrent({ message, variant });
|
|
18932
18974
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
@@ -18934,7 +18976,7 @@ function ToastProvider({ children }) {
|
|
|
18934
18976
|
setCurrent(null);
|
|
18935
18977
|
}, duration);
|
|
18936
18978
|
}, []);
|
|
18937
|
-
const error =
|
|
18979
|
+
const error = useCallback8((err) => {
|
|
18938
18980
|
const message = err instanceof Error ? err.message : "An error occurred";
|
|
18939
18981
|
show({ message, variant: "error", duration: 5e3 });
|
|
18940
18982
|
}, [show]);
|
|
@@ -19013,7 +19055,7 @@ function AppInner() {
|
|
|
19013
19055
|
const renderer = useRenderer();
|
|
19014
19056
|
const { width } = useTerminalDimensions3();
|
|
19015
19057
|
const toast = useToast();
|
|
19016
|
-
const rendererRef =
|
|
19058
|
+
const rendererRef = useRef6(renderer);
|
|
19017
19059
|
rendererRef.current = renderer;
|
|
19018
19060
|
if (!workspacePollingStarted) {
|
|
19019
19061
|
workspacePollingStarted = true;
|
|
@@ -19022,7 +19064,7 @@ function AppInner() {
|
|
|
19022
19064
|
rendererRef.current.requestRender();
|
|
19023
19065
|
}, 3e4);
|
|
19024
19066
|
}
|
|
19025
|
-
|
|
19067
|
+
useEffect2(() => {
|
|
19026
19068
|
const handler = (selection) => {
|
|
19027
19069
|
const text = selection.getSelectedText();
|
|
19028
19070
|
if (text) {
|
|
@@ -19035,15 +19077,15 @@ function AppInner() {
|
|
|
19035
19077
|
renderer.off("selection", handler);
|
|
19036
19078
|
};
|
|
19037
19079
|
}, [renderer, toast]);
|
|
19038
|
-
const [selectedWorkspaceId, setSelectedWorkspaceId] =
|
|
19039
|
-
const [selectedChatId, setSelectedChatId] =
|
|
19040
|
-
const [focusPanel, setFocusPanel] =
|
|
19041
|
-
const [taskMode, setTaskMode] =
|
|
19042
|
-
const [mockMessages, setMockMessages] =
|
|
19043
|
-
const [mockThinking, setMockThinking] =
|
|
19044
|
-
const pendingMessageRef =
|
|
19045
|
-
const [viewingDiff, setViewingDiff] =
|
|
19046
|
-
const [lastViewedDiff, setLastViewedDiff] =
|
|
19080
|
+
const [selectedWorkspaceId, setSelectedWorkspaceId] = useState7(null);
|
|
19081
|
+
const [selectedChatId, setSelectedChatId] = useState7(null);
|
|
19082
|
+
const [focusPanel, setFocusPanel] = useState7("sidebar");
|
|
19083
|
+
const [taskMode, setTaskMode] = useState7("build");
|
|
19084
|
+
const [mockMessages, setMockMessages] = useState7([]);
|
|
19085
|
+
const [mockThinking, setMockThinking] = useState7(false);
|
|
19086
|
+
const pendingMessageRef = useRef6(/* @__PURE__ */ new Map());
|
|
19087
|
+
const [viewingDiff, setViewingDiff] = useState7(null);
|
|
19088
|
+
const [lastViewedDiff, setLastViewedDiff] = useState7(null);
|
|
19047
19089
|
const { data: workspacesData, isLoading: loadingWorkspaces } = useWorkspaces(WORKSPACE_SIDEBAR_VIEWS);
|
|
19048
19090
|
const { data: setsData } = useRepositorySets();
|
|
19049
19091
|
const { data: envsData } = useEnvironments();
|
|
@@ -19059,7 +19101,7 @@ function AppInner() {
|
|
|
19059
19101
|
);
|
|
19060
19102
|
const { data: chatsData } = useWorkspaceChats(isMockSelected ? null : selectedWorkspaceId);
|
|
19061
19103
|
const chats = isMockSelected ? MOCK_CHATS : chatsData?.chats ?? [];
|
|
19062
|
-
const resolvedChatId =
|
|
19104
|
+
const resolvedChatId = useMemo5(() => {
|
|
19063
19105
|
if (selectedChatId && chats.find((c) => c.id === selectedChatId)) {
|
|
19064
19106
|
return selectedChatId;
|
|
19065
19107
|
}
|
|
@@ -19078,13 +19120,13 @@ function AppInner() {
|
|
|
19078
19120
|
const archiveWorkspaceMutation = useArchiveWorkspace();
|
|
19079
19121
|
const wakeWorkspaceMutation = useWakeWorkspace();
|
|
19080
19122
|
const generateNameMutation = useGenerateWorkspaceName();
|
|
19081
|
-
const [wakingWorkspaceId, setWakingWorkspaceId] =
|
|
19123
|
+
const [wakingWorkspaceId, setWakingWorkspaceId] = useState7(null);
|
|
19082
19124
|
const sendMessageMutation = useSendChatMessage(selectedWorkspaceId, resolvedChatId);
|
|
19083
19125
|
const interruptMutation = useInterruptChat(selectedWorkspaceId, resolvedChatId);
|
|
19084
19126
|
const repositorySets = setsData?.repository_sets ?? [];
|
|
19085
19127
|
const environments = envsData?.environments ?? [];
|
|
19086
19128
|
const previews = previewsData?.previews ?? [];
|
|
19087
|
-
const groups =
|
|
19129
|
+
const groups = useMemo5(
|
|
19088
19130
|
() => buildGroups(workspaces, workspacesData, environments, repositorySets),
|
|
19089
19131
|
[workspaces, workspacesData, environments, repositorySets]
|
|
19090
19132
|
);
|
|
@@ -19094,7 +19136,7 @@ function AppInner() {
|
|
|
19094
19136
|
const agentAvailable = agentAvailability ? selectedAgent === "codex" ? agentAvailability.codex.available : selectedAgent === "cursor" ? agentAvailability.cursor.available : selectedAgent === "relay" ? agentAvailability.relay.available : agentAvailability.claude.available : true;
|
|
19095
19137
|
const agentLabel = getProviderDisplayName(selectedAgent, "long");
|
|
19096
19138
|
const agentConnectHelp = getAgentConnectHelp(selectedAgent);
|
|
19097
|
-
const displayMessages =
|
|
19139
|
+
const displayMessages = useMemo5(() => {
|
|
19098
19140
|
if (isMockSelected) return mockMessages;
|
|
19099
19141
|
const rawEvents = historyData?.events ?? [];
|
|
19100
19142
|
const events = rawEvents.filter(isAgentBackendEvent);
|
|
@@ -19103,7 +19145,7 @@ function AppInner() {
|
|
|
19103
19145
|
}, [isMockSelected, mockMessages, historyData, selectedChat?.provider]);
|
|
19104
19146
|
const showInfoPanel = width >= 100;
|
|
19105
19147
|
const showWorkspacePanel = width >= 60;
|
|
19106
|
-
const [prevIsMockSelected, setPrevIsMockSelected] =
|
|
19148
|
+
const [prevIsMockSelected, setPrevIsMockSelected] = useState7(isMockSelected);
|
|
19107
19149
|
if (prevIsMockSelected !== isMockSelected) {
|
|
19108
19150
|
setPrevIsMockSelected(isMockSelected);
|
|
19109
19151
|
if (prevIsMockSelected && !isMockSelected) {
|
|
@@ -19112,7 +19154,7 @@ function AppInner() {
|
|
|
19112
19154
|
setMockThinking(false);
|
|
19113
19155
|
}
|
|
19114
19156
|
}
|
|
19115
|
-
|
|
19157
|
+
useEffect2(() => {
|
|
19116
19158
|
if (!selectedWorkspaceId || isMockSelected) return;
|
|
19117
19159
|
if (!resolvedChatId || resolvedChatId.startsWith("mock-")) return;
|
|
19118
19160
|
if (statusData?.status !== "active") return;
|
|
@@ -19126,7 +19168,7 @@ function AppInner() {
|
|
|
19126
19168
|
}
|
|
19127
19169
|
sendMessageMutation.mutate({ message: pending });
|
|
19128
19170
|
}, [selectedWorkspaceId, resolvedChatId, isMockSelected, statusData?.status]);
|
|
19129
|
-
const handleSelectWorkspace =
|
|
19171
|
+
const handleSelectWorkspace = useCallback9((workspaceId) => {
|
|
19130
19172
|
setSelectedWorkspaceId(workspaceId);
|
|
19131
19173
|
setSelectedChatId(null);
|
|
19132
19174
|
setMockMessages([]);
|
|
@@ -19135,13 +19177,13 @@ function AppInner() {
|
|
|
19135
19177
|
setLastViewedDiff(null);
|
|
19136
19178
|
setFocusPanel("chat-input");
|
|
19137
19179
|
}, []);
|
|
19138
|
-
const handleFocus =
|
|
19180
|
+
const handleFocus = useCallback9((panel) => {
|
|
19139
19181
|
if (panel === "sidebar") {
|
|
19140
19182
|
queryClient.invalidateQueries({ queryKey: ["workspaces"] });
|
|
19141
19183
|
}
|
|
19142
19184
|
setFocusPanel(panel);
|
|
19143
19185
|
}, []);
|
|
19144
|
-
const handleCreateWorkspace =
|
|
19186
|
+
const handleCreateWorkspace = useCallback9(
|
|
19145
19187
|
async (group) => {
|
|
19146
19188
|
if (group.id === "__ungrouped__") {
|
|
19147
19189
|
toast.error("Cannot create a workspace in the Other / Ungrouped folder");
|
|
@@ -19159,7 +19201,7 @@ function AppInner() {
|
|
|
19159
19201
|
},
|
|
19160
19202
|
[createWorkspaceMutation, toast]
|
|
19161
19203
|
);
|
|
19162
|
-
const handleArchiveWorkspace =
|
|
19204
|
+
const handleArchiveWorkspace = useCallback9(
|
|
19163
19205
|
async (workspaceId) => {
|
|
19164
19206
|
try {
|
|
19165
19207
|
await archiveWorkspaceMutation.mutateAsync(workspaceId);
|
|
@@ -19170,7 +19212,7 @@ function AppInner() {
|
|
|
19170
19212
|
},
|
|
19171
19213
|
[archiveWorkspaceMutation]
|
|
19172
19214
|
);
|
|
19173
|
-
const handleWakeWorkspace =
|
|
19215
|
+
const handleWakeWorkspace = useCallback9(
|
|
19174
19216
|
async (workspaceId) => {
|
|
19175
19217
|
setWakingWorkspaceId(workspaceId);
|
|
19176
19218
|
try {
|
|
@@ -19184,7 +19226,7 @@ function AppInner() {
|
|
|
19184
19226
|
},
|
|
19185
19227
|
[wakeWorkspaceMutation, toast]
|
|
19186
19228
|
);
|
|
19187
|
-
const handleSelectChat =
|
|
19229
|
+
const handleSelectChat = useCallback9((chatId) => {
|
|
19188
19230
|
setSelectedChatId(chatId);
|
|
19189
19231
|
}, []);
|
|
19190
19232
|
useKeyboard5((key) => {
|
|
@@ -19242,16 +19284,16 @@ function AppInner() {
|
|
|
19242
19284
|
}
|
|
19243
19285
|
if (focusPanel === "chat-input") return;
|
|
19244
19286
|
});
|
|
19245
|
-
const handleViewDiff =
|
|
19287
|
+
const handleViewDiff = useCallback9((diff, repoName) => {
|
|
19246
19288
|
setViewingDiff({ diff, repoName });
|
|
19247
19289
|
setLastViewedDiff({ diff, repoName });
|
|
19248
19290
|
setFocusPanel("chat-history");
|
|
19249
19291
|
}, []);
|
|
19250
|
-
const handleSelectChatMode =
|
|
19292
|
+
const handleSelectChatMode = useCallback9(() => {
|
|
19251
19293
|
setViewingDiff(null);
|
|
19252
19294
|
setFocusPanel("chat-history");
|
|
19253
19295
|
}, []);
|
|
19254
|
-
const firstAvailableDiff =
|
|
19296
|
+
const firstAvailableDiff = useMemo5(() => {
|
|
19255
19297
|
if (lastViewedDiff) return lastViewedDiff;
|
|
19256
19298
|
const repos2 = statusData?.repoStatuses ?? [];
|
|
19257
19299
|
for (const repo of repos2) {
|
|
@@ -19261,14 +19303,14 @@ function AppInner() {
|
|
|
19261
19303
|
}
|
|
19262
19304
|
return null;
|
|
19263
19305
|
}, [lastViewedDiff, statusData?.repoStatuses]);
|
|
19264
|
-
const handleSelectDiffMode =
|
|
19306
|
+
const handleSelectDiffMode = useCallback9(() => {
|
|
19265
19307
|
if (firstAvailableDiff) {
|
|
19266
19308
|
setViewingDiff(firstAvailableDiff);
|
|
19267
19309
|
setLastViewedDiff(firstAvailableDiff);
|
|
19268
19310
|
setFocusPanel("chat-history");
|
|
19269
19311
|
}
|
|
19270
19312
|
}, [firstAvailableDiff]);
|
|
19271
|
-
const handleSendMessage =
|
|
19313
|
+
const handleSendMessage = useCallback9(
|
|
19272
19314
|
async (message) => {
|
|
19273
19315
|
if (!selectedWorkspaceId || !resolvedChatId) return;
|
|
19274
19316
|
if (isMockSelected) {
|