@ottocode/web-sdk 0.1.272 → 0.1.274
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/components/branch/BranchModal.d.ts.map +1 -1
- package/dist/components/chat/ChatInputContainer.d.ts +1 -0
- package/dist/components/chat/ChatInputContainer.d.ts.map +1 -1
- package/dist/components/chat/ConfigSelector.d.ts.map +1 -1
- package/dist/components/file-browser/FileBrowserSidebar.d.ts.map +1 -1
- package/dist/components/file-browser/FileViewerPanel.d.ts +4 -0
- package/dist/components/file-browser/FileViewerPanel.d.ts.map +1 -1
- package/dist/components/git/GitCommitModal.d.ts.map +1 -1
- package/dist/components/git/GitDiffViewer.d.ts.map +1 -1
- package/dist/components/git/GitFileList.d.ts.map +1 -1
- package/dist/components/git/GitSidebar.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +5927 -4065
- package/dist/components/index.js.map +57 -52
- package/dist/components/mcp/AddMCPServerModal.d.ts.map +1 -1
- package/dist/components/mcp/MCPSidebar.d.ts.map +1 -1
- package/dist/components/messages/ActionToolBox.d.ts.map +1 -1
- package/dist/components/messages/AssistantMessageGroup.d.ts.map +1 -1
- package/dist/components/messages/CompactActivityGroup.d.ts.map +1 -1
- package/dist/components/messages/MessagePartItem.d.ts.map +1 -1
- package/dist/components/messages/MessageThread.d.ts.map +1 -1
- package/dist/components/messages/TopupApprovalCard.d.ts.map +1 -1
- package/dist/components/messages/compactActivity.d.ts.map +1 -1
- package/dist/components/messages/renderers/CopyIntoRenderer.d.ts +3 -0
- package/dist/components/messages/renderers/CopyIntoRenderer.d.ts.map +1 -0
- package/dist/components/messages/renderers/DatabaseToolRenderer.d.ts.map +1 -1
- package/dist/components/messages/renderers/index.d.ts.map +1 -1
- package/dist/components/messages/renderers/types.d.ts +22 -0
- package/dist/components/messages/renderers/types.d.ts.map +1 -1
- package/dist/components/onboarding/steps/DefaultsStep.d.ts.map +1 -1
- package/dist/components/onboarding/steps/ProviderSetupStep.d.ts.map +1 -1
- package/dist/components/session-files/SessionFilesDiffPanel.d.ts.map +1 -1
- package/dist/components/session-files/SessionFilesSidebar.d.ts.map +1 -1
- package/dist/components/sessions/LeanHeader.d.ts.map +1 -1
- package/dist/components/sessions/SessionHeader.d.ts.map +1 -1
- package/dist/components/sessions/SessionItem.d.ts.map +1 -1
- package/dist/components/sessions/SessionListContainer.d.ts.map +1 -1
- package/dist/components/settings/OttoRouterTopupModal.d.ts.map +1 -1
- package/dist/components/skills/SkillViewerPanel.d.ts.map +1 -1
- package/dist/components/skills/SkillsSidebar.d.ts.map +1 -1
- package/dist/components/terminals/TerminalViewer.d.ts.map +1 -1
- package/dist/components/tunnel/TunnelSidebar.d.ts.map +1 -1
- package/dist/components/ui/CodeMirrorViewer.d.ts +14 -0
- package/dist/components/ui/CodeMirrorViewer.d.ts.map +1 -0
- package/dist/components/ui/StableSpinner.d.ts +15 -0
- package/dist/components/ui/StableSpinner.d.ts.map +1 -0
- package/dist/components/ui/Toaster.d.ts.map +1 -1
- package/dist/components/workspace/ToolActivityToggle.d.ts +6 -0
- package/dist/components/workspace/ToolActivityToggle.d.ts.map +1 -0
- package/dist/components/workspace/ToolPreviewPanel.d.ts +17 -0
- package/dist/components/workspace/ToolPreviewPanel.d.ts.map +1 -0
- package/dist/components/workspace/ViewerTabs.d.ts.map +1 -1
- package/dist/hooks/index.js +720 -78
- package/dist/hooks/index.js.map +13 -13
- package/dist/hooks/useBranch.d.ts +2 -2
- package/dist/hooks/useBranch.d.ts.map +1 -1
- package/dist/hooks/useClientEvents.d.ts.map +1 -1
- package/dist/hooks/useConfig.d.ts +5 -5
- package/dist/hooks/useConfig.d.ts.map +1 -1
- package/dist/hooks/useFileBrowser.d.ts +5 -5
- package/dist/hooks/useFileBrowser.d.ts.map +1 -1
- package/dist/hooks/useFiles.d.ts +2 -2
- package/dist/hooks/useFiles.d.ts.map +1 -1
- package/dist/hooks/useGit.d.ts +5 -4
- package/dist/hooks/useGit.d.ts.map +1 -1
- package/dist/hooks/useMCP.d.ts +3 -3
- package/dist/hooks/useMCP.d.ts.map +1 -1
- package/dist/hooks/useMessages.d.ts +1 -1
- package/dist/hooks/useMessages.d.ts.map +1 -1
- package/dist/hooks/useQueueState.d.ts +2 -0
- package/dist/hooks/useQueueState.d.ts.map +1 -1
- package/dist/hooks/useResearch.d.ts +1 -1
- package/dist/hooks/useResearch.d.ts.map +1 -1
- package/dist/hooks/useSessionFiles.d.ts +1 -1
- package/dist/hooks/useSessionFiles.d.ts.map +1 -1
- package/dist/hooks/useSessionStream.d.ts.map +1 -1
- package/dist/hooks/useSkills.d.ts +6 -6
- package/dist/hooks/useSkills.d.ts.map +1 -1
- package/dist/hooks/useTerminals.d.ts +2 -2
- package/dist/hooks/useTerminals.d.ts.map +1 -1
- package/dist/hooks/useTunnel.d.ts +2 -2
- package/dist/hooks/useTunnel.d.ts.map +1 -1
- package/dist/index.js +5943 -4075
- package/dist/index.js.map +59 -54
- package/dist/lib/api-client/git.d.ts +2 -1
- package/dist/lib/api-client/git.d.ts.map +1 -1
- package/dist/lib/api-client/index.d.ts +1 -0
- package/dist/lib/api-client/index.d.ts.map +1 -1
- package/dist/lib/index.js +21 -2
- package/dist/lib/index.js.map +5 -5
- package/dist/lib/platform.d.ts +1 -0
- package/dist/lib/platform.d.ts.map +1 -1
- package/dist/stores/index.js +159 -11
- package/dist/stores/index.js.map +3 -3
- package/dist/stores/viewerTabsStore.d.ts +55 -0
- package/dist/stores/viewerTabsStore.d.ts.map +1 -1
- package/dist/types/api.d.ts +16 -0
- package/dist/types/api.d.ts.map +1 -1
- package/package.json +17 -3
package/dist/hooks/index.js
CHANGED
|
@@ -228,6 +228,7 @@ import {
|
|
|
228
228
|
generateCommitMessage as apiGenerateCommitMessage,
|
|
229
229
|
pushCommits as apiPushCommits,
|
|
230
230
|
pullChanges as apiPullChanges,
|
|
231
|
+
performGitRebaseAction as apiPerformGitRebaseAction,
|
|
231
232
|
initGitRepo as apiInitGitRepo,
|
|
232
233
|
getGitRemotes as apiGetGitRemotes,
|
|
233
234
|
addGitRemote as apiAddGitRemote,
|
|
@@ -235,7 +236,9 @@ import {
|
|
|
235
236
|
} from "@ottocode/api";
|
|
236
237
|
var gitMixin = {
|
|
237
238
|
async initGitRepo() {
|
|
238
|
-
const response = await apiInitGitRepo(
|
|
239
|
+
const response = await apiInitGitRepo({
|
|
240
|
+
body: {}
|
|
241
|
+
});
|
|
239
242
|
if (response.error)
|
|
240
243
|
throw new Error(extractErrorMessage(response.error));
|
|
241
244
|
return response.data?.data;
|
|
@@ -336,6 +339,14 @@ var gitMixin = {
|
|
|
336
339
|
throw new Error(extractErrorMessage(response.error));
|
|
337
340
|
return response.data?.data;
|
|
338
341
|
},
|
|
342
|
+
async performRebaseAction(action) {
|
|
343
|
+
const response = await apiPerformGitRebaseAction({
|
|
344
|
+
body: { action }
|
|
345
|
+
});
|
|
346
|
+
if (response.error)
|
|
347
|
+
throw new Error(extractErrorMessage(response.error));
|
|
348
|
+
return response.data?.data;
|
|
349
|
+
},
|
|
339
350
|
async getRemotes() {
|
|
340
351
|
const response = await apiGetGitRemotes();
|
|
341
352
|
if (response.error)
|
|
@@ -903,6 +914,7 @@ class ApiClient {
|
|
|
903
914
|
getGitBranch = gitMixin.getGitBranch;
|
|
904
915
|
pushCommits = gitMixin.pushCommits;
|
|
905
916
|
pullChanges = gitMixin.pullChanges;
|
|
917
|
+
performRebaseAction = gitMixin.performRebaseAction;
|
|
906
918
|
getRemotes = gitMixin.getRemotes;
|
|
907
919
|
addRemote = gitMixin.addRemote;
|
|
908
920
|
removeRemote = gitMixin.removeRemote;
|
|
@@ -1057,6 +1069,12 @@ function openPlatformSession(sessionId) {
|
|
|
1057
1069
|
win.OTTO_OPEN_SESSION(sessionId);
|
|
1058
1070
|
return true;
|
|
1059
1071
|
}
|
|
1072
|
+
function getPlatformWindowFocused() {
|
|
1073
|
+
const win = getPlatformWindow();
|
|
1074
|
+
if (!win?.OTTO_IS_WINDOW_FOCUSED)
|
|
1075
|
+
return null;
|
|
1076
|
+
return win.OTTO_IS_WINDOW_FOCUSED();
|
|
1077
|
+
}
|
|
1060
1078
|
function hasPlatformOpenUrl() {
|
|
1061
1079
|
return !!getPlatformWindow()?.OTTO_OPEN_URL;
|
|
1062
1080
|
}
|
|
@@ -1221,6 +1239,17 @@ import { create } from "zustand";
|
|
|
1221
1239
|
function titleFromPath(path) {
|
|
1222
1240
|
return path.split("/").pop() || path;
|
|
1223
1241
|
}
|
|
1242
|
+
function normalizeViewerPath(path) {
|
|
1243
|
+
return path.trim().replace(/^a\//, "").replace(/^b\//, "").replace(/^\.\//, "").replace(/\/+/g, "/").replace(/\/+$/, "");
|
|
1244
|
+
}
|
|
1245
|
+
function viewerPathsMatch(left, right) {
|
|
1246
|
+
const normalizedLeft = normalizeViewerPath(left);
|
|
1247
|
+
const normalizedRight = normalizeViewerPath(right);
|
|
1248
|
+
return normalizedLeft === normalizedRight || normalizedLeft.endsWith(`/${normalizedRight}`) || normalizedRight.endsWith(`/${normalizedLeft}`);
|
|
1249
|
+
}
|
|
1250
|
+
function fileTabId(path) {
|
|
1251
|
+
return `file:${normalizeViewerPath(path)}`;
|
|
1252
|
+
}
|
|
1224
1253
|
function upsertTab(tabs, tab) {
|
|
1225
1254
|
const existingIndex = tabs.findIndex((item) => item.id === tab.id);
|
|
1226
1255
|
if (existingIndex === -1) {
|
|
@@ -1230,9 +1259,32 @@ function upsertTab(tabs, tab) {
|
|
|
1230
1259
|
next[existingIndex] = tab;
|
|
1231
1260
|
return next;
|
|
1232
1261
|
}
|
|
1262
|
+
function isSamePatchCall(existing, preview) {
|
|
1263
|
+
if (!existing)
|
|
1264
|
+
return false;
|
|
1265
|
+
if (preview.callId || existing.callId) {
|
|
1266
|
+
return Boolean(preview.callId && existing.callId === preview.callId);
|
|
1267
|
+
}
|
|
1268
|
+
if (preview.status === "streaming" && existing.status !== "streaming") {
|
|
1269
|
+
return false;
|
|
1270
|
+
}
|
|
1271
|
+
if (!preview.patch || !existing.patch)
|
|
1272
|
+
return existing.status === "streaming";
|
|
1273
|
+
return preview.patch === existing.patch || preview.patch.startsWith(existing.patch) || existing.patch.startsWith(preview.patch);
|
|
1274
|
+
}
|
|
1275
|
+
function mergeChangedLines(existing, incoming) {
|
|
1276
|
+
if (!existing?.length)
|
|
1277
|
+
return incoming;
|
|
1278
|
+
if (!incoming?.length)
|
|
1279
|
+
return existing;
|
|
1280
|
+
return [...new Set([...existing, ...incoming])].sort((a, b) => a - b);
|
|
1281
|
+
}
|
|
1233
1282
|
var useViewerTabsStore = create((set) => ({
|
|
1234
1283
|
tabs: [],
|
|
1235
1284
|
activeTabId: null,
|
|
1285
|
+
followToolActivity: false,
|
|
1286
|
+
toggleFollowToolActivity: () => set((state) => ({ followToolActivity: !state.followToolActivity })),
|
|
1287
|
+
setFollowToolActivity: (enabled) => set({ followToolActivity: enabled }),
|
|
1236
1288
|
openGitDiffTab: (path, staged) => {
|
|
1237
1289
|
const id = `git-diff:${staged ? "staged" : "unstaged"}:${path}`;
|
|
1238
1290
|
set((state) => ({
|
|
@@ -1261,16 +1313,130 @@ var useViewerTabsStore = create((set) => ({
|
|
|
1261
1313
|
}));
|
|
1262
1314
|
},
|
|
1263
1315
|
openFileTab: (path) => {
|
|
1264
|
-
const id =
|
|
1265
|
-
set((state) =>
|
|
1266
|
-
tabs
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1316
|
+
const id = fileTabId(path);
|
|
1317
|
+
set((state) => {
|
|
1318
|
+
const matchingFileTabs = state.tabs.filter((tab) => tab.type === "file" && viewerPathsMatch(tab.path, path));
|
|
1319
|
+
const existingFile = matchingFileTabs.find((tab) => tab.id === state.activeTabId) ?? matchingFileTabs[0];
|
|
1320
|
+
const targetId = existingFile?.id ?? id;
|
|
1321
|
+
const targetPath = existingFile?.path ?? path;
|
|
1322
|
+
const tabs = state.tabs.filter((tab) => !((tab.type === "tool-preview" || tab.type === "file") && tab.id !== targetId && viewerPathsMatch(tab.path, path)));
|
|
1323
|
+
return {
|
|
1324
|
+
tabs: upsertTab(tabs, {
|
|
1325
|
+
id: targetId,
|
|
1326
|
+
type: "file",
|
|
1327
|
+
title: existingFile?.title ?? titleFromPath(targetPath),
|
|
1328
|
+
path: targetPath
|
|
1329
|
+
}),
|
|
1330
|
+
activeTabId: targetId
|
|
1331
|
+
};
|
|
1332
|
+
});
|
|
1333
|
+
},
|
|
1334
|
+
openToolReadTab: (path, highlight) => {
|
|
1335
|
+
const id = fileTabId(path);
|
|
1336
|
+
set((state) => {
|
|
1337
|
+
const matchingFileTabs = state.tabs.filter((tab) => tab.type === "file" && viewerPathsMatch(tab.path, path));
|
|
1338
|
+
const existingFile = matchingFileTabs.find((tab) => tab.id === state.activeTabId) ?? matchingFileTabs[0];
|
|
1339
|
+
const targetId = existingFile?.id ?? id;
|
|
1340
|
+
const targetPath = existingFile?.path ?? path;
|
|
1341
|
+
const tabs = state.tabs.filter((tab) => !((tab.type === "tool-preview" || tab.type === "file") && tab.id !== targetId && viewerPathsMatch(tab.path, path)));
|
|
1342
|
+
return {
|
|
1343
|
+
tabs: upsertTab(tabs, {
|
|
1344
|
+
id: targetId,
|
|
1345
|
+
type: "file",
|
|
1346
|
+
title: existingFile?.title ?? titleFromPath(targetPath),
|
|
1347
|
+
path: targetPath,
|
|
1348
|
+
highlight,
|
|
1349
|
+
patchPreview: undefined,
|
|
1350
|
+
writePreview: undefined
|
|
1351
|
+
}),
|
|
1352
|
+
activeTabId: targetId
|
|
1353
|
+
};
|
|
1354
|
+
});
|
|
1355
|
+
},
|
|
1356
|
+
openToolPreviewTab: (preview) => {
|
|
1357
|
+
const id = fileTabId(preview.path);
|
|
1358
|
+
set((state) => {
|
|
1359
|
+
const matchingFileTabs = state.tabs.filter((tab) => tab.type === "file" && viewerPathsMatch(tab.path, preview.path));
|
|
1360
|
+
const existingFile = matchingFileTabs.find((tab) => tab.id === state.activeTabId) ?? matchingFileTabs[0];
|
|
1361
|
+
const targetId = existingFile?.id ?? id;
|
|
1362
|
+
const targetPath = existingFile?.path ?? preview.path;
|
|
1363
|
+
const existing = state.tabs.find((tab) => tab.type === "tool-preview" && viewerPathsMatch(tab.path, preview.path));
|
|
1364
|
+
const tabs = state.tabs.filter((tab) => !((tab.type === "tool-preview" || tab.type === "file") && tab.id !== targetId && (viewerPathsMatch(tab.path, preview.path) || Boolean(preview.callId && "toolName" in tab && tab.callId === preview.callId))));
|
|
1365
|
+
if (preview.toolName === "apply_patch") {
|
|
1366
|
+
const existingPatchPreview = existingFile?.patchPreview ?? (existing?.toolName === "apply_patch" ? existing : undefined);
|
|
1367
|
+
const samePatchCall = isSamePatchCall(existingPatchPreview, preview);
|
|
1368
|
+
const baseContent = preview.baseContent ?? (samePatchCall ? existingPatchPreview?.baseContent : existingPatchPreview?.resultContent ?? existingPatchPreview?.baseContent);
|
|
1369
|
+
const changedLines = samePatchCall ? preview.changedLines ?? existingPatchPreview?.changedLines : mergeChangedLines(existingPatchPreview?.changedLines, preview.changedLines);
|
|
1370
|
+
return {
|
|
1371
|
+
tabs: upsertTab(tabs, {
|
|
1372
|
+
id: targetId,
|
|
1373
|
+
type: "file",
|
|
1374
|
+
title: existingFile?.title ?? titleFromPath(targetPath),
|
|
1375
|
+
path: targetPath,
|
|
1376
|
+
highlight: undefined,
|
|
1377
|
+
writePreview: undefined,
|
|
1378
|
+
patchPreview: {
|
|
1379
|
+
path: targetPath,
|
|
1380
|
+
toolName: "apply_patch",
|
|
1381
|
+
callId: preview.callId ?? existingPatchPreview?.callId,
|
|
1382
|
+
baseContent,
|
|
1383
|
+
patch: preview.patch ?? existingPatchPreview?.patch,
|
|
1384
|
+
changedLines,
|
|
1385
|
+
previewContent: preview.previewContent ?? (samePatchCall ? existingPatchPreview?.previewContent : undefined),
|
|
1386
|
+
resultContent: preview.resultContent ?? (samePatchCall ? existingPatchPreview?.resultContent : undefined),
|
|
1387
|
+
previewLineTones: preview.previewLineTones ?? (samePatchCall ? existingPatchPreview?.previewLineTones : undefined),
|
|
1388
|
+
previewFirstLine: preview.previewFirstLine ?? (samePatchCall ? existingPatchPreview?.previewFirstLine : undefined),
|
|
1389
|
+
previewLatestLine: preview.previewLatestLine ?? (samePatchCall ? existingPatchPreview?.previewLatestLine : undefined),
|
|
1390
|
+
status: preview.status,
|
|
1391
|
+
error: preview.error ?? existingPatchPreview?.error
|
|
1392
|
+
}
|
|
1393
|
+
}),
|
|
1394
|
+
activeTabId: targetId
|
|
1395
|
+
};
|
|
1396
|
+
}
|
|
1397
|
+
if (existingFile) {
|
|
1398
|
+
const existingWritePreview = existingFile.writePreview;
|
|
1399
|
+
return {
|
|
1400
|
+
tabs: upsertTab(tabs, {
|
|
1401
|
+
...existingFile,
|
|
1402
|
+
highlight: undefined,
|
|
1403
|
+
patchPreview: undefined,
|
|
1404
|
+
writePreview: {
|
|
1405
|
+
path: targetPath,
|
|
1406
|
+
toolName: "write",
|
|
1407
|
+
callId: preview.callId ?? existingWritePreview?.callId,
|
|
1408
|
+
content: preview.content ?? existingWritePreview?.content,
|
|
1409
|
+
status: preview.status,
|
|
1410
|
+
error: preview.error ?? existingWritePreview?.error
|
|
1411
|
+
}
|
|
1412
|
+
}),
|
|
1413
|
+
activeTabId: targetId
|
|
1414
|
+
};
|
|
1415
|
+
}
|
|
1416
|
+
const existingWrite = existing?.toolName === "write" ? existing : undefined;
|
|
1417
|
+
return {
|
|
1418
|
+
tabs: upsertTab(tabs, {
|
|
1419
|
+
id,
|
|
1420
|
+
type: "tool-preview",
|
|
1421
|
+
title: titleFromPath(preview.path),
|
|
1422
|
+
path: preview.path,
|
|
1423
|
+
toolName: preview.toolName,
|
|
1424
|
+
callId: preview.callId,
|
|
1425
|
+
content: preview.content ?? existingWrite?.content,
|
|
1426
|
+
baseContent: undefined,
|
|
1427
|
+
patch: undefined,
|
|
1428
|
+
changedLines: undefined,
|
|
1429
|
+
previewContent: undefined,
|
|
1430
|
+
resultContent: undefined,
|
|
1431
|
+
previewLineTones: undefined,
|
|
1432
|
+
previewFirstLine: undefined,
|
|
1433
|
+
previewLatestLine: undefined,
|
|
1434
|
+
status: preview.status,
|
|
1435
|
+
error: preview.error ?? existingWrite?.error
|
|
1436
|
+
}),
|
|
1437
|
+
activeTabId: id
|
|
1438
|
+
};
|
|
1439
|
+
});
|
|
1274
1440
|
},
|
|
1275
1441
|
openSkillFileTab: (skill, file) => {
|
|
1276
1442
|
const displayFile = file ?? "SKILL.md";
|
|
@@ -1811,6 +1977,16 @@ function usePullChanges() {
|
|
|
1811
1977
|
}
|
|
1812
1978
|
});
|
|
1813
1979
|
}
|
|
1980
|
+
function useGitRebaseAction() {
|
|
1981
|
+
const queryClient = useQueryClient2();
|
|
1982
|
+
return useMutation2({
|
|
1983
|
+
mutationFn: (action) => apiClient.performRebaseAction(action),
|
|
1984
|
+
onSuccess: () => {
|
|
1985
|
+
queryClient.invalidateQueries({ queryKey: ["git", "status"] });
|
|
1986
|
+
queryClient.invalidateQueries({ queryKey: ["git", "branch"] });
|
|
1987
|
+
}
|
|
1988
|
+
});
|
|
1989
|
+
}
|
|
1814
1990
|
function useGitInit() {
|
|
1815
1991
|
const queryClient = useQueryClient2();
|
|
1816
1992
|
return useMutation2({
|
|
@@ -1852,7 +2028,71 @@ function useRemoveRemote() {
|
|
|
1852
2028
|
});
|
|
1853
2029
|
}
|
|
1854
2030
|
// src/hooks/useMessages.ts
|
|
1855
|
-
import { useQuery as
|
|
2031
|
+
import { useQuery as useQuery5, useMutation as useMutation4, useQueryClient as useQueryClient4 } from "@tanstack/react-query";
|
|
2032
|
+
|
|
2033
|
+
// src/hooks/useQueueState.ts
|
|
2034
|
+
import { useQuery as useQuery4 } from "@tanstack/react-query";
|
|
2035
|
+
var defaultQueueState = {
|
|
2036
|
+
currentMessageId: null,
|
|
2037
|
+
queuedMessages: [],
|
|
2038
|
+
queueLength: 0
|
|
2039
|
+
};
|
|
2040
|
+
function optimisticallyQueueMessage(queryClient, sessionId, messageId) {
|
|
2041
|
+
queryClient.setQueryData(["queueState", sessionId], (current) => {
|
|
2042
|
+
if (!current)
|
|
2043
|
+
return current;
|
|
2044
|
+
const isBusy = Boolean(current.currentMessageId) || current.queuedMessages.length > 0 || current.queueLength > 0;
|
|
2045
|
+
if (!isBusy)
|
|
2046
|
+
return current;
|
|
2047
|
+
if (current.currentMessageId === messageId)
|
|
2048
|
+
return current;
|
|
2049
|
+
if (current.queuedMessages.some((item) => item.messageId === messageId)) {
|
|
2050
|
+
return current;
|
|
2051
|
+
}
|
|
2052
|
+
const queuedMessages = [
|
|
2053
|
+
...current.queuedMessages,
|
|
2054
|
+
{ messageId, position: current.queuedMessages.length }
|
|
2055
|
+
];
|
|
2056
|
+
return {
|
|
2057
|
+
...current,
|
|
2058
|
+
queuedMessages,
|
|
2059
|
+
queueLength: queuedMessages.length
|
|
2060
|
+
};
|
|
2061
|
+
});
|
|
2062
|
+
}
|
|
2063
|
+
function useQueueState(sessionId) {
|
|
2064
|
+
const { data } = useQuery4({
|
|
2065
|
+
queryKey: ["queueState", sessionId],
|
|
2066
|
+
queryFn: async () => {
|
|
2067
|
+
if (!sessionId)
|
|
2068
|
+
return defaultQueueState;
|
|
2069
|
+
const queueState = await apiClient.getQueueState(sessionId);
|
|
2070
|
+
return {
|
|
2071
|
+
currentMessageId: queueState.currentMessageId,
|
|
2072
|
+
queuedMessages: queueState.queuedMessages,
|
|
2073
|
+
queueLength: queueState.queuedMessages.length
|
|
2074
|
+
};
|
|
2075
|
+
},
|
|
2076
|
+
enabled: !!sessionId,
|
|
2077
|
+
placeholderData: defaultQueueState,
|
|
2078
|
+
staleTime: Infinity
|
|
2079
|
+
});
|
|
2080
|
+
return data ?? defaultQueueState;
|
|
2081
|
+
}
|
|
2082
|
+
function useMessageQueuePosition(sessionId, messageId) {
|
|
2083
|
+
const queueState = useQueueState(sessionId);
|
|
2084
|
+
if (!sessionId || !queueState) {
|
|
2085
|
+
return { isQueued: false, isRunning: false, position: null };
|
|
2086
|
+
}
|
|
2087
|
+
if (queueState.currentMessageId === messageId) {
|
|
2088
|
+
return { isQueued: false, isRunning: true, position: null };
|
|
2089
|
+
}
|
|
2090
|
+
const queuedItem = queueState.queuedMessages.find((item) => item.messageId === messageId);
|
|
2091
|
+
if (queuedItem) {
|
|
2092
|
+
return { isQueued: true, isRunning: false, position: queuedItem.position };
|
|
2093
|
+
}
|
|
2094
|
+
return { isQueued: false, isRunning: false, position: null };
|
|
2095
|
+
}
|
|
1856
2096
|
|
|
1857
2097
|
// src/hooks/useSessions.ts
|
|
1858
2098
|
import {
|
|
@@ -1963,7 +2203,7 @@ function useDeleteSession() {
|
|
|
1963
2203
|
// src/hooks/useMessages.ts
|
|
1964
2204
|
function useMessages(sessionId, options = {}) {
|
|
1965
2205
|
const { enabled = true, staleTime = 15000 } = options;
|
|
1966
|
-
return
|
|
2206
|
+
return useQuery5({
|
|
1967
2207
|
queryKey: ["messages", sessionId],
|
|
1968
2208
|
queryFn: () => {
|
|
1969
2209
|
if (!sessionId) {
|
|
@@ -1985,7 +2225,8 @@ function useSendMessage(sessionId) {
|
|
|
1985
2225
|
});
|
|
1986
2226
|
return apiClient.sendMessage(sessionId, data);
|
|
1987
2227
|
},
|
|
1988
|
-
onSuccess: () => {
|
|
2228
|
+
onSuccess: (result) => {
|
|
2229
|
+
optimisticallyQueueMessage(queryClient, sessionId, result.messageId);
|
|
1989
2230
|
queryClient.invalidateQueries({ queryKey: ["messages", sessionId] });
|
|
1990
2231
|
queryClient.invalidateQueries({ queryKey: sessionsQueryKey });
|
|
1991
2232
|
}
|
|
@@ -2125,10 +2366,22 @@ var useToolApprovalStore = create10((set) => ({
|
|
|
2125
2366
|
}));
|
|
2126
2367
|
|
|
2127
2368
|
// src/hooks/useSessionStream.ts
|
|
2369
|
+
var TOOL_PREVIEW_THROTTLE_MS = 500;
|
|
2370
|
+
var TOOL_PREVIEW_THROTTLE_MIN_CHARS = 8000;
|
|
2371
|
+
var TOOL_PREVIEW_THROTTLE_MIN_DELTA_CHARS = 16000;
|
|
2372
|
+
var STREAMING_WRITE_CONTENT_PREVIEW_CHARS = 24000;
|
|
2373
|
+
var STREAMING_PATCH_PREVIEW_HEAD_CHARS = 12000;
|
|
2374
|
+
var STREAMING_PATCH_PREVIEW_TAIL_CHARS = 24000;
|
|
2375
|
+
var STREAMING_TOOL_INPUT_HEAD_CHARS = 8000;
|
|
2376
|
+
var STREAMING_TOOL_INPUT_TAIL_CHARS = 16000;
|
|
2377
|
+
var STREAMING_TOOL_MESSAGE_THROTTLE_MS = 500;
|
|
2128
2378
|
function useSessionStream(sessionId, enabled = true) {
|
|
2129
2379
|
const queryClient = useQueryClient5();
|
|
2130
2380
|
const clientRef = useRef(null);
|
|
2131
2381
|
const assistantMessageIdRef = useRef(null);
|
|
2382
|
+
const toolInputBuffersRef = useRef(new Map);
|
|
2383
|
+
const toolPreviewEmitRef = useRef(new Map);
|
|
2384
|
+
const toolMessageEmitRef = useRef(new Map);
|
|
2132
2385
|
const {
|
|
2133
2386
|
addPendingApproval,
|
|
2134
2387
|
removePendingApproval,
|
|
@@ -2140,6 +2393,9 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2140
2393
|
return;
|
|
2141
2394
|
}
|
|
2142
2395
|
assistantMessageIdRef.current = null;
|
|
2396
|
+
toolInputBuffersRef.current.clear();
|
|
2397
|
+
toolPreviewEmitRef.current.clear();
|
|
2398
|
+
toolMessageEmitRef.current.clear();
|
|
2143
2399
|
let lastSessionInvalidation = 0;
|
|
2144
2400
|
apiClient.getPendingApprovals(sessionId).then((result) => {
|
|
2145
2401
|
if (result.ok && result.pending.length > 0) {
|
|
@@ -2163,7 +2419,7 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2163
2419
|
}
|
|
2164
2420
|
for (let i = messages.length - 1;i >= 0; i -= 1) {
|
|
2165
2421
|
const candidate = messages[i];
|
|
2166
|
-
if (candidate.role === "assistant" && candidate.status
|
|
2422
|
+
if (candidate.role === "assistant" && candidate.status === "pending") {
|
|
2167
2423
|
return i;
|
|
2168
2424
|
}
|
|
2169
2425
|
}
|
|
@@ -2194,6 +2450,388 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2194
2450
|
return typeof payload?.toolName === "string" ? payload.toolName : null;
|
|
2195
2451
|
};
|
|
2196
2452
|
const getToolEventArgs = (payload) => payload?.args ?? payload?.input;
|
|
2453
|
+
const getToolBufferKey = (payload) => {
|
|
2454
|
+
const callId = getToolEventCallId(payload);
|
|
2455
|
+
if (callId)
|
|
2456
|
+
return callId;
|
|
2457
|
+
const name = getToolEventName(payload);
|
|
2458
|
+
return name ? `name:${name}` : null;
|
|
2459
|
+
};
|
|
2460
|
+
const parseArgsRecord = (value) => {
|
|
2461
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
2462
|
+
return value;
|
|
2463
|
+
}
|
|
2464
|
+
if (typeof value !== "string")
|
|
2465
|
+
return null;
|
|
2466
|
+
try {
|
|
2467
|
+
const parsed = JSON.parse(value);
|
|
2468
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
2469
|
+
} catch {
|
|
2470
|
+
return null;
|
|
2471
|
+
}
|
|
2472
|
+
};
|
|
2473
|
+
const normalizeLineNumber = (value) => {
|
|
2474
|
+
const parsed = typeof value === "number" ? value : typeof value === "string" ? Number.parseInt(value, 10) : Number.NaN;
|
|
2475
|
+
return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : undefined;
|
|
2476
|
+
};
|
|
2477
|
+
const parseLineRange = (value) => {
|
|
2478
|
+
if (typeof value !== "string")
|
|
2479
|
+
return {};
|
|
2480
|
+
const match = value.match(/@(\d+)(?:-(\d+))?/);
|
|
2481
|
+
if (!match)
|
|
2482
|
+
return {};
|
|
2483
|
+
return {
|
|
2484
|
+
startLine: normalizeLineNumber(match[1]),
|
|
2485
|
+
endLine: normalizeLineNumber(match[2] ?? match[1])
|
|
2486
|
+
};
|
|
2487
|
+
};
|
|
2488
|
+
const getBoundedStreamingToolInput = (value) => {
|
|
2489
|
+
const maxLength = STREAMING_TOOL_INPUT_HEAD_CHARS + STREAMING_TOOL_INPUT_TAIL_CHARS;
|
|
2490
|
+
if (value.length <= maxLength)
|
|
2491
|
+
return value;
|
|
2492
|
+
return `${value.slice(0, STREAMING_TOOL_INPUT_HEAD_CHARS)}
|
|
2493
|
+
… streamed tool input truncated for UI responsiveness …
|
|
2494
|
+
${value.slice(-STREAMING_TOOL_INPUT_TAIL_CHARS)}`;
|
|
2495
|
+
};
|
|
2496
|
+
const getToolArgsForViewer = (payload, delta) => {
|
|
2497
|
+
const args = parseArgsRecord(getToolEventArgs(payload));
|
|
2498
|
+
if (args)
|
|
2499
|
+
return args;
|
|
2500
|
+
const key = getToolBufferKey(payload);
|
|
2501
|
+
if (!key)
|
|
2502
|
+
return null;
|
|
2503
|
+
const previous = toolInputBuffersRef.current.get(key) ?? "";
|
|
2504
|
+
if (!delta)
|
|
2505
|
+
return parseArgsRecord(previous);
|
|
2506
|
+
const next = getBoundedStreamingToolInput(`${previous}${delta}`);
|
|
2507
|
+
toolInputBuffersRef.current.set(key, next);
|
|
2508
|
+
return parseArgsRecord(next);
|
|
2509
|
+
};
|
|
2510
|
+
const bestEffortUnescapeJsonString = (value) => {
|
|
2511
|
+
try {
|
|
2512
|
+
return JSON.parse(`"${value.replace(/\\$/, "")}"`);
|
|
2513
|
+
} catch {
|
|
2514
|
+
return value.replace(/\\n/g, `
|
|
2515
|
+
`).replace(/\\t/g, "\t").replace(/\\r/g, "\r").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
2516
|
+
}
|
|
2517
|
+
};
|
|
2518
|
+
const extractJsonStringField = (text, field, requireClosed = false) => {
|
|
2519
|
+
const marker = `"${field}"`;
|
|
2520
|
+
const markerIndex = text.indexOf(marker);
|
|
2521
|
+
if (markerIndex === -1)
|
|
2522
|
+
return;
|
|
2523
|
+
const colonIndex = text.indexOf(":", markerIndex + marker.length);
|
|
2524
|
+
if (colonIndex === -1)
|
|
2525
|
+
return;
|
|
2526
|
+
const quoteIndex = text.indexOf('"', colonIndex + 1);
|
|
2527
|
+
if (quoteIndex === -1)
|
|
2528
|
+
return;
|
|
2529
|
+
let escaped = "";
|
|
2530
|
+
let escaping = false;
|
|
2531
|
+
let closed = false;
|
|
2532
|
+
for (let i = quoteIndex + 1;i < text.length; i += 1) {
|
|
2533
|
+
const char = text[i];
|
|
2534
|
+
if (escaping) {
|
|
2535
|
+
escaped += `\\${char}`;
|
|
2536
|
+
escaping = false;
|
|
2537
|
+
continue;
|
|
2538
|
+
}
|
|
2539
|
+
if (char === "\\") {
|
|
2540
|
+
escaping = true;
|
|
2541
|
+
continue;
|
|
2542
|
+
}
|
|
2543
|
+
if (char === '"') {
|
|
2544
|
+
closed = true;
|
|
2545
|
+
break;
|
|
2546
|
+
}
|
|
2547
|
+
escaped += char;
|
|
2548
|
+
}
|
|
2549
|
+
if (requireClosed && !closed)
|
|
2550
|
+
return;
|
|
2551
|
+
return bestEffortUnescapeJsonString(escaped);
|
|
2552
|
+
};
|
|
2553
|
+
const getBufferedToolInput = (payload) => {
|
|
2554
|
+
const key = getToolBufferKey(payload);
|
|
2555
|
+
return key ? toolInputBuffersRef.current.get(key) ?? "" : "";
|
|
2556
|
+
};
|
|
2557
|
+
const getStringArg = (args, buffer, field, requireClosed = false) => {
|
|
2558
|
+
const value = args?.[field];
|
|
2559
|
+
if (typeof value === "string")
|
|
2560
|
+
return value;
|
|
2561
|
+
return extractJsonStringField(buffer, field, requireClosed);
|
|
2562
|
+
};
|
|
2563
|
+
const getStreamingWritePreviewContent = (args, buffer) => {
|
|
2564
|
+
const argContent = args?.content;
|
|
2565
|
+
if (typeof argContent === "string") {
|
|
2566
|
+
if (argContent.length <= STREAMING_WRITE_CONTENT_PREVIEW_CHARS) {
|
|
2567
|
+
return argContent;
|
|
2568
|
+
}
|
|
2569
|
+
return `… showing latest streamed content only …
|
|
2570
|
+
${argContent.slice(-STREAMING_WRITE_CONTENT_PREVIEW_CHARS)}`;
|
|
2571
|
+
}
|
|
2572
|
+
const marker = '"content"';
|
|
2573
|
+
const markerIndex = buffer.indexOf(marker);
|
|
2574
|
+
if (markerIndex === -1)
|
|
2575
|
+
return;
|
|
2576
|
+
const colonIndex = buffer.indexOf(":", markerIndex + marker.length);
|
|
2577
|
+
if (colonIndex === -1)
|
|
2578
|
+
return;
|
|
2579
|
+
const quoteIndex = buffer.indexOf('"', colonIndex + 1);
|
|
2580
|
+
if (quoteIndex === -1)
|
|
2581
|
+
return;
|
|
2582
|
+
const valueStart = quoteIndex + 1;
|
|
2583
|
+
if (buffer.length - valueStart <= STREAMING_WRITE_CONTENT_PREVIEW_CHARS) {
|
|
2584
|
+
return extractJsonStringField(buffer, "content");
|
|
2585
|
+
}
|
|
2586
|
+
const rawTail = buffer.slice(Math.max(valueStart, buffer.length - STREAMING_WRITE_CONTENT_PREVIEW_CHARS));
|
|
2587
|
+
return `… showing latest streamed content only …
|
|
2588
|
+
${bestEffortUnescapeJsonString(rawTail)}`;
|
|
2589
|
+
};
|
|
2590
|
+
const getStreamingPatchPreviewContent = (args, buffer) => {
|
|
2591
|
+
const argPatch = args?.patch;
|
|
2592
|
+
if (typeof argPatch === "string") {
|
|
2593
|
+
if (argPatch.length <= STREAMING_PATCH_PREVIEW_HEAD_CHARS + STREAMING_PATCH_PREVIEW_TAIL_CHARS) {
|
|
2594
|
+
return argPatch;
|
|
2595
|
+
}
|
|
2596
|
+
return `${argPatch.slice(0, STREAMING_PATCH_PREVIEW_HEAD_CHARS)}
|
|
2597
|
+
… patch preview truncated while streaming …
|
|
2598
|
+
${argPatch.slice(-STREAMING_PATCH_PREVIEW_TAIL_CHARS)}`;
|
|
2599
|
+
}
|
|
2600
|
+
const marker = '"patch"';
|
|
2601
|
+
const markerIndex = buffer.indexOf(marker);
|
|
2602
|
+
if (markerIndex === -1)
|
|
2603
|
+
return;
|
|
2604
|
+
const colonIndex = buffer.indexOf(":", markerIndex + marker.length);
|
|
2605
|
+
if (colonIndex === -1)
|
|
2606
|
+
return;
|
|
2607
|
+
const quoteIndex = buffer.indexOf('"', colonIndex + 1);
|
|
2608
|
+
if (quoteIndex === -1)
|
|
2609
|
+
return;
|
|
2610
|
+
const valueStart = quoteIndex + 1;
|
|
2611
|
+
const rawLength = buffer.length - valueStart;
|
|
2612
|
+
if (rawLength <= STREAMING_PATCH_PREVIEW_HEAD_CHARS + STREAMING_PATCH_PREVIEW_TAIL_CHARS) {
|
|
2613
|
+
return extractJsonStringField(buffer, "patch");
|
|
2614
|
+
}
|
|
2615
|
+
const rawHead = buffer.slice(valueStart, valueStart + STREAMING_PATCH_PREVIEW_HEAD_CHARS);
|
|
2616
|
+
const rawTail = buffer.slice(-STREAMING_PATCH_PREVIEW_TAIL_CHARS);
|
|
2617
|
+
return `${bestEffortUnescapeJsonString(rawHead)}
|
|
2618
|
+
… patch preview truncated while streaming …
|
|
2619
|
+
${bestEffortUnescapeJsonString(rawTail)}`;
|
|
2620
|
+
};
|
|
2621
|
+
const getResultRecord = (payload) => payload?.result && typeof payload.result === "object" && !Array.isArray(payload.result) ? payload.result : null;
|
|
2622
|
+
const getArtifactRecord = (payload) => payload?.artifact && typeof payload.artifact === "object" && !Array.isArray(payload.artifact) ? payload.artifact : null;
|
|
2623
|
+
const extractErrorMessage2 = (payload) => {
|
|
2624
|
+
const result = getResultRecord(payload);
|
|
2625
|
+
if (typeof payload?.error === "string")
|
|
2626
|
+
return payload.error;
|
|
2627
|
+
return typeof result?.error === "string" ? result.error : undefined;
|
|
2628
|
+
};
|
|
2629
|
+
const normalizePatchPath = (path) => path.replace(/^a\//, "").replace(/^b\//, "").trim();
|
|
2630
|
+
const patchPathMatches = (patchPath, targetPath) => {
|
|
2631
|
+
const normalizedPatch = normalizePatchPath(patchPath);
|
|
2632
|
+
const normalizedTarget = normalizePatchPath(targetPath);
|
|
2633
|
+
return normalizedPatch === normalizedTarget || normalizedPatch.endsWith(`/${normalizedTarget}`) || normalizedTarget.endsWith(`/${normalizedPatch}`);
|
|
2634
|
+
};
|
|
2635
|
+
const patchPathMayReferToTarget = (patchPath, targetPath) => {
|
|
2636
|
+
const normalizedPatch = normalizePatchPath(patchPath).replace(/\/+$/, "");
|
|
2637
|
+
const normalizedTarget = normalizePatchPath(targetPath);
|
|
2638
|
+
if (!normalizedPatch)
|
|
2639
|
+
return false;
|
|
2640
|
+
return patchPathMatches(patchPath, targetPath) || normalizedTarget.startsWith(`${normalizedPatch}/`);
|
|
2641
|
+
};
|
|
2642
|
+
const isLikelyCompletePatchPath = (path) => {
|
|
2643
|
+
const normalized = normalizePatchPath(path);
|
|
2644
|
+
if (!normalized || normalized.endsWith("/"))
|
|
2645
|
+
return false;
|
|
2646
|
+
const name = normalized.split("/").pop() ?? "";
|
|
2647
|
+
return name.includes(".");
|
|
2648
|
+
};
|
|
2649
|
+
const getCompletedPatchChangeLineSignature = (patch) => {
|
|
2650
|
+
const stablePatch = patch.endsWith(`
|
|
2651
|
+
`) ? patch : patch.slice(0, patch.lastIndexOf(`
|
|
2652
|
+
`) + 1);
|
|
2653
|
+
if (!stablePatch)
|
|
2654
|
+
return;
|
|
2655
|
+
let changeLines = 0;
|
|
2656
|
+
let stableChangeLength = 0;
|
|
2657
|
+
for (const line of stablePatch.split(`
|
|
2658
|
+
`)) {
|
|
2659
|
+
if (line.startsWith("+") && !line.startsWith("+++") || line.startsWith("-") && !line.startsWith("---")) {
|
|
2660
|
+
changeLines += 1;
|
|
2661
|
+
stableChangeLength += line.length;
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
return changeLines > 0 ? `${changeLines}:${stableChangeLength}` : undefined;
|
|
2665
|
+
};
|
|
2666
|
+
const extractPathsFromPatch = (patch) => {
|
|
2667
|
+
const paths = new Set;
|
|
2668
|
+
for (const line of patch.split(`
|
|
2669
|
+
`)) {
|
|
2670
|
+
const directive = line.match(/^\*\*\* (?:Update|Add|Delete) File: (.+)$/);
|
|
2671
|
+
if (directive?.[1]) {
|
|
2672
|
+
paths.add(directive[1].trim());
|
|
2673
|
+
continue;
|
|
2674
|
+
}
|
|
2675
|
+
const unified = line.match(/^\+\+\+ (?:b\/)?(.+)$/);
|
|
2676
|
+
if (unified?.[1] && unified[1] !== "/dev/null") {
|
|
2677
|
+
paths.add(unified[1].trim());
|
|
2678
|
+
}
|
|
2679
|
+
}
|
|
2680
|
+
return [...paths];
|
|
2681
|
+
};
|
|
2682
|
+
const getChangedLinesForPath = (result, path) => {
|
|
2683
|
+
const changes = Array.isArray(result?.changes) ? result.changes : [];
|
|
2684
|
+
const lines = new Set;
|
|
2685
|
+
for (const change of changes) {
|
|
2686
|
+
if (!change || typeof change !== "object")
|
|
2687
|
+
continue;
|
|
2688
|
+
const record = change;
|
|
2689
|
+
if (typeof record.filePath !== "string")
|
|
2690
|
+
continue;
|
|
2691
|
+
if (!patchPathMatches(record.filePath, path))
|
|
2692
|
+
continue;
|
|
2693
|
+
if (!Array.isArray(record.hunks))
|
|
2694
|
+
continue;
|
|
2695
|
+
for (const hunk of record.hunks) {
|
|
2696
|
+
if (!hunk || typeof hunk !== "object")
|
|
2697
|
+
continue;
|
|
2698
|
+
const hunkRecord = hunk;
|
|
2699
|
+
const newStart = typeof hunkRecord.newStart === "number" ? hunkRecord.newStart : undefined;
|
|
2700
|
+
const newLines = typeof hunkRecord.newLines === "number" ? hunkRecord.newLines : undefined;
|
|
2701
|
+
if (!newStart || !newLines)
|
|
2702
|
+
continue;
|
|
2703
|
+
for (let line = newStart;line < newStart + newLines; line += 1) {
|
|
2704
|
+
lines.add(line);
|
|
2705
|
+
}
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
return lines.size > 0 ? [...lines] : undefined;
|
|
2709
|
+
};
|
|
2710
|
+
const handleReadToolActivity = (eventType, payload, delta) => {
|
|
2711
|
+
const viewerStore = useViewerTabsStore.getState();
|
|
2712
|
+
if (!viewerStore.followToolActivity)
|
|
2713
|
+
return;
|
|
2714
|
+
const name = getToolEventName(payload);
|
|
2715
|
+
if (name !== "read")
|
|
2716
|
+
return;
|
|
2717
|
+
const args = getToolArgsForViewer(payload, delta);
|
|
2718
|
+
const path = typeof args?.path === "string" ? args.path : null;
|
|
2719
|
+
if (!path)
|
|
2720
|
+
return;
|
|
2721
|
+
const result = payload?.result && typeof payload.result === "object" && !Array.isArray(payload.result) ? payload.result : null;
|
|
2722
|
+
const rangeFromResult = parseLineRange(result?.lineRange);
|
|
2723
|
+
const startLine = normalizeLineNumber(args.startLine) ?? normalizeLineNumber(args.start_line) ?? rangeFromResult.startLine;
|
|
2724
|
+
const endLine = normalizeLineNumber(args.endLine) ?? normalizeLineNumber(args.end_line) ?? rangeFromResult.endLine ?? startLine;
|
|
2725
|
+
const failed = result?.ok === false || eventType === "error";
|
|
2726
|
+
viewerStore.openToolReadTab(path, {
|
|
2727
|
+
startLine,
|
|
2728
|
+
endLine,
|
|
2729
|
+
reason: "read",
|
|
2730
|
+
callId: getToolEventCallId(payload) ?? undefined,
|
|
2731
|
+
status: failed ? "error" : eventType === "tool.result" ? "success" : "streaming"
|
|
2732
|
+
});
|
|
2733
|
+
};
|
|
2734
|
+
const handleWriteToolActivity = (eventType, payload, delta) => {
|
|
2735
|
+
const viewerStore = useViewerTabsStore.getState();
|
|
2736
|
+
if (!viewerStore.followToolActivity)
|
|
2737
|
+
return;
|
|
2738
|
+
const name = getToolEventName(payload);
|
|
2739
|
+
if (name !== "write")
|
|
2740
|
+
return;
|
|
2741
|
+
const args = getToolArgsForViewer(payload, delta);
|
|
2742
|
+
const buffer = getBufferedToolInput(payload);
|
|
2743
|
+
const result = getResultRecord(payload);
|
|
2744
|
+
const path = (typeof result?.path === "string" ? result.path : undefined) ?? getStringArg(args, buffer, "path", true);
|
|
2745
|
+
if (!path)
|
|
2746
|
+
return;
|
|
2747
|
+
const failed = result?.ok === false || eventType === "error";
|
|
2748
|
+
const callId = getToolEventCallId(payload) ?? undefined;
|
|
2749
|
+
const status = failed ? "error" : eventType === "tool.result" ? "success" : "streaming";
|
|
2750
|
+
const content = status === "streaming" ? getStreamingWritePreviewContent(args, buffer) : getStringArg(args, buffer, "content");
|
|
2751
|
+
if (status === "streaming" && content !== undefined && content.length >= TOOL_PREVIEW_THROTTLE_MIN_CHARS) {
|
|
2752
|
+
const previewKey = callId ?? path;
|
|
2753
|
+
const now = Date.now();
|
|
2754
|
+
const last = toolPreviewEmitRef.current.get(previewKey);
|
|
2755
|
+
const contentDelta = Math.abs(content.length - (last?.contentLength ?? 0));
|
|
2756
|
+
if (last && now - last.emittedAt < TOOL_PREVIEW_THROTTLE_MS && contentDelta < TOOL_PREVIEW_THROTTLE_MIN_DELTA_CHARS) {
|
|
2757
|
+
return;
|
|
2758
|
+
}
|
|
2759
|
+
toolPreviewEmitRef.current.set(previewKey, {
|
|
2760
|
+
emittedAt: now,
|
|
2761
|
+
contentLength: content.length
|
|
2762
|
+
});
|
|
2763
|
+
}
|
|
2764
|
+
viewerStore.openToolPreviewTab({
|
|
2765
|
+
path,
|
|
2766
|
+
toolName: "write",
|
|
2767
|
+
callId,
|
|
2768
|
+
content,
|
|
2769
|
+
status,
|
|
2770
|
+
error: extractErrorMessage2(payload)
|
|
2771
|
+
});
|
|
2772
|
+
};
|
|
2773
|
+
const handleApplyPatchToolActivity = (eventType, payload, delta) => {
|
|
2774
|
+
const viewerStore = useViewerTabsStore.getState();
|
|
2775
|
+
if (!viewerStore.followToolActivity)
|
|
2776
|
+
return;
|
|
2777
|
+
const name = getToolEventName(payload);
|
|
2778
|
+
if (name !== "apply_patch")
|
|
2779
|
+
return;
|
|
2780
|
+
const args = getToolArgsForViewer(payload, delta);
|
|
2781
|
+
const buffer = getBufferedToolInput(payload);
|
|
2782
|
+
const artifact = getArtifactRecord(payload);
|
|
2783
|
+
const result = getResultRecord(payload);
|
|
2784
|
+
const failed = result?.ok === false || eventType === "error";
|
|
2785
|
+
const status = failed ? "error" : eventType === "tool.result" ? "success" : "streaming";
|
|
2786
|
+
const callId = getToolEventCallId(payload) ?? undefined;
|
|
2787
|
+
const patch = (typeof artifact?.patch === "string" ? artifact.patch : undefined) ?? (status === "streaming" ? getStreamingPatchPreviewContent(args, buffer) : getStringArg(args, buffer, "patch"));
|
|
2788
|
+
if (!patch)
|
|
2789
|
+
return;
|
|
2790
|
+
const previewKey = callId ?? "apply_patch";
|
|
2791
|
+
const lineSignature = status === "streaming" ? getCompletedPatchChangeLineSignature(patch) : undefined;
|
|
2792
|
+
if (status === "streaming") {
|
|
2793
|
+
const last = toolPreviewEmitRef.current.get(previewKey);
|
|
2794
|
+
if (last?.lineSignature === lineSignature)
|
|
2795
|
+
return;
|
|
2796
|
+
}
|
|
2797
|
+
const patchPaths = extractPathsFromPatch(patch);
|
|
2798
|
+
if (patchPaths.length === 0)
|
|
2799
|
+
return;
|
|
2800
|
+
const matchingFileTabs = viewerStore.tabs.filter((tab) => tab.type === "file" && patchPaths.some((path) => patchPathMayReferToTarget(path, tab.path)));
|
|
2801
|
+
const activeMatchingFileTab = matchingFileTabs.find((tab) => tab.id === viewerStore.activeTabId);
|
|
2802
|
+
const fallbackPath = patchPaths.find(isLikelyCompletePatchPath);
|
|
2803
|
+
if (!activeMatchingFileTab && !matchingFileTabs[0] && !fallbackPath)
|
|
2804
|
+
return;
|
|
2805
|
+
const targetPath = activeMatchingFileTab?.path ?? matchingFileTabs[0]?.path ?? fallbackPath;
|
|
2806
|
+
if (!targetPath)
|
|
2807
|
+
return;
|
|
2808
|
+
viewerStore.openToolPreviewTab({
|
|
2809
|
+
path: targetPath,
|
|
2810
|
+
toolName: "apply_patch",
|
|
2811
|
+
callId,
|
|
2812
|
+
patch,
|
|
2813
|
+
changedLines: getChangedLinesForPath(result, targetPath),
|
|
2814
|
+
status,
|
|
2815
|
+
error: extractErrorMessage2(payload)
|
|
2816
|
+
});
|
|
2817
|
+
if (status === "streaming") {
|
|
2818
|
+
toolPreviewEmitRef.current.set(previewKey, {
|
|
2819
|
+
emittedAt: Date.now(),
|
|
2820
|
+
contentLength: buffer.length,
|
|
2821
|
+
lineSignature
|
|
2822
|
+
});
|
|
2823
|
+
}
|
|
2824
|
+
};
|
|
2825
|
+
const handleToolActivityViewerEvent = (eventType, payload, delta) => {
|
|
2826
|
+
const name = getToolEventName(payload);
|
|
2827
|
+
if (name === "read")
|
|
2828
|
+
handleReadToolActivity(eventType, payload, delta);
|
|
2829
|
+
if (name === "write")
|
|
2830
|
+
handleWriteToolActivity(eventType, payload, delta);
|
|
2831
|
+
if (name === "apply_patch") {
|
|
2832
|
+
handleApplyPatchToolActivity(eventType, payload, delta);
|
|
2833
|
+
}
|
|
2834
|
+
};
|
|
2197
2835
|
const getToolInputDelta = (payload) => {
|
|
2198
2836
|
if (typeof payload?.delta === "string")
|
|
2199
2837
|
return payload.delta;
|
|
@@ -2204,19 +2842,9 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2204
2842
|
return payload.delta;
|
|
2205
2843
|
return typeof payload?.outputTextDelta === "string" ? payload.outputTextDelta : null;
|
|
2206
2844
|
};
|
|
2207
|
-
const getOptimisticPartIndex = (parts,
|
|
2208
|
-
const
|
|
2209
|
-
|
|
2210
|
-
return indexes.length > 0 ? Math.max(...indexes) + 0.001 : 0;
|
|
2211
|
-
})();
|
|
2212
|
-
if (typeof stepIndex !== "number") {
|
|
2213
|
-
return appendIndex;
|
|
2214
|
-
}
|
|
2215
|
-
const sameStepIndexes = parts.filter((part) => part.stepIndex === stepIndex).map((part) => part.index).filter((index) => Number.isFinite(index));
|
|
2216
|
-
if (sameStepIndexes.length > 0) {
|
|
2217
|
-
return Math.max(...sameStepIndexes) + 0.001;
|
|
2218
|
-
}
|
|
2219
|
-
return appendIndex;
|
|
2845
|
+
const getOptimisticPartIndex = (parts, _stepIndex) => {
|
|
2846
|
+
const indexes = parts.map((part) => part.index).filter((index) => Number.isFinite(index));
|
|
2847
|
+
return indexes.length > 0 ? Math.max(...indexes) + 0.001 : 0;
|
|
2220
2848
|
};
|
|
2221
2849
|
const applyReasoningDelta = (payload) => {
|
|
2222
2850
|
const messageId = typeof payload?.messageId === "string" ? payload.messageId : null;
|
|
@@ -2331,6 +2959,18 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2331
2959
|
const name = getToolEventName(payload);
|
|
2332
2960
|
if (!name)
|
|
2333
2961
|
return;
|
|
2962
|
+
if (name === "write" || name === "apply_patch") {
|
|
2963
|
+
const bufferKey = getToolBufferKey(payload);
|
|
2964
|
+
const bufferedLength = bufferKey ? toolInputBuffersRef.current.get(bufferKey)?.length ?? 0 : 0;
|
|
2965
|
+
if (bufferedLength >= TOOL_PREVIEW_THROTTLE_MIN_CHARS) {
|
|
2966
|
+
const emitKey = callId ?? `name:${name}`;
|
|
2967
|
+
const now = Date.now();
|
|
2968
|
+
const last = toolMessageEmitRef.current.get(emitKey) ?? 0;
|
|
2969
|
+
if (now - last < STREAMING_TOOL_MESSAGE_THROTTLE_MS)
|
|
2970
|
+
return;
|
|
2971
|
+
toolMessageEmitRef.current.set(emitKey, now);
|
|
2972
|
+
}
|
|
2973
|
+
}
|
|
2334
2974
|
queryClient.setQueryData(["messages", sessionId], (oldMessages) => {
|
|
2335
2975
|
if (!oldMessages)
|
|
2336
2976
|
return oldMessages;
|
|
@@ -2434,7 +3074,7 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2434
3074
|
if (partIndex === -1) {
|
|
2435
3075
|
const contentJsonBase = {
|
|
2436
3076
|
name,
|
|
2437
|
-
_streamedInput: delta
|
|
3077
|
+
_streamedInput: getBoundedStreamingToolInput(delta)
|
|
2438
3078
|
};
|
|
2439
3079
|
if (callId)
|
|
2440
3080
|
contentJsonBase.callId = callId;
|
|
@@ -2462,7 +3102,7 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2462
3102
|
const prev = typeof existing.contentJson?._streamedInput === "string" ? existing.contentJson._streamedInput : "";
|
|
2463
3103
|
const nextContentJson = {
|
|
2464
3104
|
...typeof existing.contentJson === "object" && !Array.isArray(existing.contentJson) ? existing.contentJson : {},
|
|
2465
|
-
_streamedInput: prev + delta
|
|
3105
|
+
_streamedInput: getBoundedStreamingToolInput(prev + delta)
|
|
2466
3106
|
};
|
|
2467
3107
|
parts[partIndex] = {
|
|
2468
3108
|
...existing,
|
|
@@ -2671,6 +3311,7 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2671
3311
|
const id = typeof payload?.id === "string" ? payload.id : null;
|
|
2672
3312
|
if (role === "assistant" && id) {
|
|
2673
3313
|
assistantMessageIdRef.current = id;
|
|
3314
|
+
optimisticallyQueueMessage(queryClient, sessionId, id);
|
|
2674
3315
|
}
|
|
2675
3316
|
if (id && role) {
|
|
2676
3317
|
const agent = typeof payload?.agent === "string" ? payload.agent : "";
|
|
@@ -2750,8 +3391,10 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2750
3391
|
if (channel === "input" || channel == null && delta) {
|
|
2751
3392
|
if (delta) {
|
|
2752
3393
|
accumulateToolInputDelta(payload, delta);
|
|
3394
|
+
handleToolActivityViewerEvent("tool.delta", payload, delta);
|
|
2753
3395
|
} else {
|
|
2754
3396
|
upsertEphemeralToolCall(payload);
|
|
3397
|
+
handleToolActivityViewerEvent("tool.delta", payload);
|
|
2755
3398
|
}
|
|
2756
3399
|
} else if (channel === "output" && delta) {
|
|
2757
3400
|
accumulateToolOutputDelta(payload, delta);
|
|
@@ -2760,10 +3403,15 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2760
3403
|
}
|
|
2761
3404
|
case "tool.call": {
|
|
2762
3405
|
upsertEphemeralToolCall(payload);
|
|
3406
|
+
handleToolActivityViewerEvent("tool.call", payload);
|
|
2763
3407
|
break;
|
|
2764
3408
|
}
|
|
2765
3409
|
case "tool.result": {
|
|
2766
3410
|
resolveEphemeralToolCall(payload);
|
|
3411
|
+
handleToolActivityViewerEvent("tool.result", payload);
|
|
3412
|
+
const key = getToolBufferKey(payload);
|
|
3413
|
+
if (key)
|
|
3414
|
+
toolInputBuffersRef.current.delete(key);
|
|
2767
3415
|
break;
|
|
2768
3416
|
}
|
|
2769
3417
|
case "tool.approval.required": {
|
|
@@ -2798,10 +3446,30 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2798
3446
|
break;
|
|
2799
3447
|
}
|
|
2800
3448
|
case "error": {
|
|
3449
|
+
handleToolActivityViewerEvent("error", payload);
|
|
2801
3450
|
removeEphemeralToolCall(payload);
|
|
2802
3451
|
const messageId = typeof payload?.messageId === "string" ? payload.messageId : null;
|
|
2803
3452
|
if (messageId) {
|
|
3453
|
+
if (assistantMessageIdRef.current === messageId) {
|
|
3454
|
+
assistantMessageIdRef.current = null;
|
|
3455
|
+
}
|
|
2804
3456
|
clearEphemeralForMessage(messageId);
|
|
3457
|
+
const errorMessage = typeof payload?.error === "string" ? payload.error : typeof payload?.message === "string" ? payload.message : "Assistant run failed";
|
|
3458
|
+
queryClient.setQueryData(["messages", sessionId], (oldMessages) => {
|
|
3459
|
+
if (!oldMessages)
|
|
3460
|
+
return oldMessages;
|
|
3461
|
+
const idx = oldMessages.findIndex((m) => m.id === messageId);
|
|
3462
|
+
if (idx === -1)
|
|
3463
|
+
return oldMessages;
|
|
3464
|
+
const next = [...oldMessages];
|
|
3465
|
+
next[idx] = {
|
|
3466
|
+
...next[idx],
|
|
3467
|
+
status: "error",
|
|
3468
|
+
completedAt: next[idx].completedAt ?? Date.now(),
|
|
3469
|
+
error: errorMessage
|
|
3470
|
+
};
|
|
3471
|
+
return next;
|
|
3472
|
+
});
|
|
2805
3473
|
}
|
|
2806
3474
|
queryClient.invalidateQueries({ queryKey: ["messages", sessionId] });
|
|
2807
3475
|
break;
|
|
@@ -2810,6 +3478,13 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2810
3478
|
const id = typeof payload?.id === "string" ? payload.id : null;
|
|
2811
3479
|
const status = typeof payload?.status === "string" ? payload.status : null;
|
|
2812
3480
|
if (id && status) {
|
|
3481
|
+
if (status !== "pending" && assistantMessageIdRef.current === id) {
|
|
3482
|
+
assistantMessageIdRef.current = null;
|
|
3483
|
+
}
|
|
3484
|
+
if (status !== "pending") {
|
|
3485
|
+
clearEphemeralForMessage(id);
|
|
3486
|
+
}
|
|
3487
|
+
const error = typeof payload?.error === "string" ? payload.error : undefined;
|
|
2813
3488
|
queryClient.setQueryData(["messages", sessionId], (oldMessages) => {
|
|
2814
3489
|
if (!oldMessages)
|
|
2815
3490
|
return oldMessages;
|
|
@@ -2819,7 +3494,9 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2819
3494
|
const next = [...oldMessages];
|
|
2820
3495
|
next[idx] = {
|
|
2821
3496
|
...next[idx],
|
|
2822
|
-
status
|
|
3497
|
+
status,
|
|
3498
|
+
completedAt: status === "pending" ? next[idx].completedAt : next[idx].completedAt ?? Date.now(),
|
|
3499
|
+
error: error ?? next[idx].error
|
|
2823
3500
|
};
|
|
2824
3501
|
return next;
|
|
2825
3502
|
});
|
|
@@ -3022,6 +3699,9 @@ function sendBrowserNotification(notification) {
|
|
|
3022
3699
|
};
|
|
3023
3700
|
return true;
|
|
3024
3701
|
}
|
|
3702
|
+
function isAppForeground() {
|
|
3703
|
+
return getPlatformWindowFocused() ?? document.visibilityState === "visible";
|
|
3704
|
+
}
|
|
3025
3705
|
function updateSessionStatusInCache(queryClient, status) {
|
|
3026
3706
|
queryClient.setQueryData(sessionsQueryKey, (old) => {
|
|
3027
3707
|
if (!old)
|
|
@@ -3167,7 +3847,7 @@ function useClientEvents(activeSessionId) {
|
|
|
3167
3847
|
}
|
|
3168
3848
|
if (event.event === "notification") {
|
|
3169
3849
|
const notification = payload;
|
|
3170
|
-
const isActiveVisibleSession = notification.sessionId === activeSessionIdRef.current &&
|
|
3850
|
+
const isActiveVisibleSession = notification.sessionId === activeSessionIdRef.current && isAppForeground();
|
|
3171
3851
|
const isSessionNotification = notification.source === "session" || !!notification.sessionId;
|
|
3172
3852
|
let sentSystemNotification = false;
|
|
3173
3853
|
if (!isActiveVisibleSession) {
|
|
@@ -3423,7 +4103,7 @@ function useKeyboardShortcuts({
|
|
|
3423
4103
|
}
|
|
3424
4104
|
return;
|
|
3425
4105
|
}
|
|
3426
|
-
if ((e.ctrlKey || e.metaKey) && e.key === "
|
|
4106
|
+
if ((e.ctrlKey || e.metaKey) && e.key === "b") {
|
|
3427
4107
|
e.preventDefault();
|
|
3428
4108
|
if (currentFocus === "sessions") {
|
|
3429
4109
|
document.activeElement?.blur();
|
|
@@ -3446,7 +4126,7 @@ function useKeyboardShortcuts({
|
|
|
3446
4126
|
}
|
|
3447
4127
|
return;
|
|
3448
4128
|
}
|
|
3449
|
-
if ((e.ctrlKey || e.metaKey) && e.key === "
|
|
4129
|
+
if ((e.ctrlKey || e.metaKey) && !e.shiftKey && e.key === "r") {
|
|
3450
4130
|
e.preventDefault();
|
|
3451
4131
|
if (currentFocus === "git") {
|
|
3452
4132
|
document.activeElement?.blur();
|
|
@@ -4162,10 +4842,10 @@ function useFileUpload(options = {}) {
|
|
|
4162
4842
|
};
|
|
4163
4843
|
}
|
|
4164
4844
|
// src/hooks/useSessionFiles.ts
|
|
4165
|
-
import { useQuery as
|
|
4845
|
+
import { useQuery as useQuery6 } from "@tanstack/react-query";
|
|
4166
4846
|
function useSessionFiles(sessionId, enabled = true) {
|
|
4167
4847
|
const isExpanded = useSessionFilesStore((state) => state.isExpanded);
|
|
4168
|
-
return
|
|
4848
|
+
return useQuery6({
|
|
4169
4849
|
queryKey: ["session", sessionId, "files"],
|
|
4170
4850
|
queryFn: () => sessionId ? apiClient.getSessionFiles(sessionId) : null,
|
|
4171
4851
|
enabled: !!sessionId && enabled,
|
|
@@ -4174,46 +4854,6 @@ function useSessionFiles(sessionId, enabled = true) {
|
|
|
4174
4854
|
staleTime: 3000
|
|
4175
4855
|
});
|
|
4176
4856
|
}
|
|
4177
|
-
// src/hooks/useQueueState.ts
|
|
4178
|
-
import { useQuery as useQuery6 } from "@tanstack/react-query";
|
|
4179
|
-
var defaultQueueState = {
|
|
4180
|
-
currentMessageId: null,
|
|
4181
|
-
queuedMessages: [],
|
|
4182
|
-
queueLength: 0
|
|
4183
|
-
};
|
|
4184
|
-
function useQueueState(sessionId) {
|
|
4185
|
-
const { data } = useQuery6({
|
|
4186
|
-
queryKey: ["queueState", sessionId],
|
|
4187
|
-
queryFn: async () => {
|
|
4188
|
-
if (!sessionId)
|
|
4189
|
-
return defaultQueueState;
|
|
4190
|
-
const queueState = await apiClient.getQueueState(sessionId);
|
|
4191
|
-
return {
|
|
4192
|
-
currentMessageId: queueState.currentMessageId,
|
|
4193
|
-
queuedMessages: queueState.queuedMessages,
|
|
4194
|
-
queueLength: queueState.queuedMessages.length
|
|
4195
|
-
};
|
|
4196
|
-
},
|
|
4197
|
-
enabled: !!sessionId,
|
|
4198
|
-
placeholderData: defaultQueueState,
|
|
4199
|
-
staleTime: Infinity
|
|
4200
|
-
});
|
|
4201
|
-
return data ?? defaultQueueState;
|
|
4202
|
-
}
|
|
4203
|
-
function useMessageQueuePosition(sessionId, messageId) {
|
|
4204
|
-
const queueState = useQueueState(sessionId);
|
|
4205
|
-
if (!sessionId || !queueState) {
|
|
4206
|
-
return { isQueued: false, isRunning: false, position: null };
|
|
4207
|
-
}
|
|
4208
|
-
if (queueState.currentMessageId === messageId) {
|
|
4209
|
-
return { isQueued: false, isRunning: true, position: null };
|
|
4210
|
-
}
|
|
4211
|
-
const queuedItem = queueState.queuedMessages.find((item) => item.messageId === messageId);
|
|
4212
|
-
if (queuedItem) {
|
|
4213
|
-
return { isQueued: true, isRunning: false, position: queuedItem.position };
|
|
4214
|
-
}
|
|
4215
|
-
return { isQueued: false, isRunning: false, position: null };
|
|
4216
|
-
}
|
|
4217
4857
|
// src/hooks/useBranch.ts
|
|
4218
4858
|
import { useQuery as useQuery7, useMutation as useMutation5, useQueryClient as useQueryClient7 } from "@tanstack/react-query";
|
|
4219
4859
|
function useCreateBranch(sessionId) {
|
|
@@ -5767,6 +6407,7 @@ export {
|
|
|
5767
6407
|
useImageUpload,
|
|
5768
6408
|
useGitStatus,
|
|
5769
6409
|
useGitRemotes,
|
|
6410
|
+
useGitRebaseAction,
|
|
5770
6411
|
useGitInit,
|
|
5771
6412
|
useGitDiffFullFile,
|
|
5772
6413
|
useGitDiff,
|
|
@@ -5794,7 +6435,8 @@ export {
|
|
|
5794
6435
|
useAllModels,
|
|
5795
6436
|
useAddRemote,
|
|
5796
6437
|
useAddMCPServer,
|
|
5797
|
-
sessionsQueryKey
|
|
6438
|
+
sessionsQueryKey,
|
|
6439
|
+
optimisticallyQueueMessage
|
|
5798
6440
|
};
|
|
5799
6441
|
|
|
5800
|
-
//# debugId=
|
|
6442
|
+
//# debugId=90296322954CBDC864756E2164756E21
|