@ottocode/web-sdk 0.1.272 → 0.1.273
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 +3 -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 +5000 -3678
- package/dist/components/index.js.map +47 -43
- 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/MessagePartItem.d.ts.map +1 -1
- package/dist/components/messages/TopupApprovalCard.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 +522 -17
- package/dist/hooks/index.js.map +10 -10
- 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/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 +5026 -3699
- package/dist/index.js.map +49 -45
- 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 +108 -11
- package/dist/stores/index.js.map +3 -3
- package/dist/stores/viewerTabsStore.d.ts +51 -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,9 @@ import { create } from "zustand";
|
|
|
1221
1239
|
function titleFromPath(path) {
|
|
1222
1240
|
return path.split("/").pop() || path;
|
|
1223
1241
|
}
|
|
1242
|
+
function fileTabId(path) {
|
|
1243
|
+
return `file:${path}`;
|
|
1244
|
+
}
|
|
1224
1245
|
function upsertTab(tabs, tab) {
|
|
1225
1246
|
const existingIndex = tabs.findIndex((item) => item.id === tab.id);
|
|
1226
1247
|
if (existingIndex === -1) {
|
|
@@ -1230,9 +1251,25 @@ function upsertTab(tabs, tab) {
|
|
|
1230
1251
|
next[existingIndex] = tab;
|
|
1231
1252
|
return next;
|
|
1232
1253
|
}
|
|
1254
|
+
function isSamePatchCall(existing, preview) {
|
|
1255
|
+
if (!existing)
|
|
1256
|
+
return false;
|
|
1257
|
+
if (preview.callId || existing.callId) {
|
|
1258
|
+
return Boolean(preview.callId && existing.callId === preview.callId);
|
|
1259
|
+
}
|
|
1260
|
+
if (preview.status === "streaming" && existing.status !== "streaming") {
|
|
1261
|
+
return false;
|
|
1262
|
+
}
|
|
1263
|
+
if (!preview.patch || !existing.patch)
|
|
1264
|
+
return existing.status === "streaming";
|
|
1265
|
+
return preview.patch === existing.patch || preview.patch.startsWith(existing.patch) || existing.patch.startsWith(preview.patch);
|
|
1266
|
+
}
|
|
1233
1267
|
var useViewerTabsStore = create((set) => ({
|
|
1234
1268
|
tabs: [],
|
|
1235
1269
|
activeTabId: null,
|
|
1270
|
+
followToolActivity: false,
|
|
1271
|
+
toggleFollowToolActivity: () => set((state) => ({ followToolActivity: !state.followToolActivity })),
|
|
1272
|
+
setFollowToolActivity: (enabled) => set({ followToolActivity: enabled }),
|
|
1236
1273
|
openGitDiffTab: (path, staged) => {
|
|
1237
1274
|
const id = `git-diff:${staged ? "staged" : "unstaged"}:${path}`;
|
|
1238
1275
|
set((state) => ({
|
|
@@ -1261,16 +1298,94 @@ var useViewerTabsStore = create((set) => ({
|
|
|
1261
1298
|
}));
|
|
1262
1299
|
},
|
|
1263
1300
|
openFileTab: (path) => {
|
|
1264
|
-
const id =
|
|
1265
|
-
set((state) =>
|
|
1266
|
-
tabs
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1301
|
+
const id = fileTabId(path);
|
|
1302
|
+
set((state) => {
|
|
1303
|
+
const tabs = state.tabs.filter((tab) => !(tab.type === "tool-preview" && tab.path === path && tab.id !== id));
|
|
1304
|
+
return {
|
|
1305
|
+
tabs: upsertTab(tabs, {
|
|
1306
|
+
id,
|
|
1307
|
+
type: "file",
|
|
1308
|
+
title: titleFromPath(path),
|
|
1309
|
+
path
|
|
1310
|
+
}),
|
|
1311
|
+
activeTabId: id
|
|
1312
|
+
};
|
|
1313
|
+
});
|
|
1314
|
+
},
|
|
1315
|
+
openToolReadTab: (path, highlight) => {
|
|
1316
|
+
const id = fileTabId(path);
|
|
1317
|
+
set((state) => {
|
|
1318
|
+
const tabs = state.tabs.filter((tab) => !(tab.type === "tool-preview" && tab.path === path && tab.id !== id));
|
|
1319
|
+
return {
|
|
1320
|
+
tabs: upsertTab(tabs, {
|
|
1321
|
+
id,
|
|
1322
|
+
type: "file",
|
|
1323
|
+
title: titleFromPath(path),
|
|
1324
|
+
path,
|
|
1325
|
+
highlight
|
|
1326
|
+
}),
|
|
1327
|
+
activeTabId: id
|
|
1328
|
+
};
|
|
1329
|
+
});
|
|
1330
|
+
},
|
|
1331
|
+
openToolPreviewTab: (preview) => {
|
|
1332
|
+
const id = fileTabId(preview.path);
|
|
1333
|
+
set((state) => {
|
|
1334
|
+
const existingFile = state.tabs.find((tab) => tab.id === id && tab.type === "file");
|
|
1335
|
+
const existing = state.tabs.find((tab) => tab.id === id && tab.type === "tool-preview");
|
|
1336
|
+
const tabs = state.tabs.filter((tab) => !(tab.type === "tool-preview" && tab.id !== id && (tab.path === preview.path || Boolean(preview.callId && tab.callId === preview.callId))));
|
|
1337
|
+
if (preview.toolName === "apply_patch" && existingFile) {
|
|
1338
|
+
const existingPatchPreview = existingFile.patchPreview;
|
|
1339
|
+
const samePatchCall = isSamePatchCall(existingPatchPreview, preview);
|
|
1340
|
+
const baseContent2 = preview.baseContent ?? (samePatchCall ? existingPatchPreview?.baseContent : existingPatchPreview?.resultContent ?? existingPatchPreview?.baseContent);
|
|
1341
|
+
return {
|
|
1342
|
+
tabs: upsertTab(tabs, {
|
|
1343
|
+
...existingFile,
|
|
1344
|
+
highlight: undefined,
|
|
1345
|
+
patchPreview: {
|
|
1346
|
+
path: preview.path,
|
|
1347
|
+
toolName: "apply_patch",
|
|
1348
|
+
callId: preview.callId ?? existingPatchPreview?.callId,
|
|
1349
|
+
baseContent: baseContent2,
|
|
1350
|
+
patch: preview.patch ?? existingPatchPreview?.patch,
|
|
1351
|
+
changedLines: preview.changedLines ?? (samePatchCall ? existingPatchPreview?.changedLines : undefined),
|
|
1352
|
+
previewContent: preview.previewContent ?? (samePatchCall ? existingPatchPreview?.previewContent : undefined),
|
|
1353
|
+
resultContent: preview.resultContent ?? (samePatchCall ? existingPatchPreview?.resultContent : undefined),
|
|
1354
|
+
previewLineTones: preview.previewLineTones ?? (samePatchCall ? existingPatchPreview?.previewLineTones : undefined),
|
|
1355
|
+
previewFirstLine: preview.previewFirstLine ?? (samePatchCall ? existingPatchPreview?.previewFirstLine : undefined),
|
|
1356
|
+
previewLatestLine: preview.previewLatestLine ?? (samePatchCall ? existingPatchPreview?.previewLatestLine : undefined),
|
|
1357
|
+
status: preview.status,
|
|
1358
|
+
error: preview.error ?? existingPatchPreview?.error
|
|
1359
|
+
}
|
|
1360
|
+
}),
|
|
1361
|
+
activeTabId: id
|
|
1362
|
+
};
|
|
1363
|
+
}
|
|
1364
|
+
const sameToolPreviewCall = isSamePatchCall(existing, preview);
|
|
1365
|
+
const baseContent = preview.toolName === "apply_patch" ? preview.baseContent ?? (sameToolPreviewCall ? existing?.baseContent : existing?.resultContent ?? existing?.baseContent) : undefined;
|
|
1366
|
+
return {
|
|
1367
|
+
tabs: upsertTab(tabs, {
|
|
1368
|
+
id,
|
|
1369
|
+
type: "tool-preview",
|
|
1370
|
+
title: titleFromPath(preview.path),
|
|
1371
|
+
path: preview.path,
|
|
1372
|
+
toolName: preview.toolName,
|
|
1373
|
+
callId: preview.callId,
|
|
1374
|
+
content: preview.content ?? existing?.content,
|
|
1375
|
+
baseContent,
|
|
1376
|
+
patch: preview.patch ?? existing?.patch,
|
|
1377
|
+
changedLines: preview.changedLines ?? existing?.changedLines,
|
|
1378
|
+
previewContent: preview.previewContent ?? (sameToolPreviewCall ? existing?.previewContent : undefined),
|
|
1379
|
+
resultContent: preview.resultContent ?? (sameToolPreviewCall ? existing?.resultContent : undefined),
|
|
1380
|
+
previewLineTones: preview.previewLineTones ?? (sameToolPreviewCall ? existing?.previewLineTones : undefined),
|
|
1381
|
+
previewFirstLine: preview.previewFirstLine ?? (sameToolPreviewCall ? existing?.previewFirstLine : undefined),
|
|
1382
|
+
previewLatestLine: preview.previewLatestLine ?? (sameToolPreviewCall ? existing?.previewLatestLine : undefined),
|
|
1383
|
+
status: preview.status,
|
|
1384
|
+
error: preview.error ?? existing?.error
|
|
1385
|
+
}),
|
|
1386
|
+
activeTabId: id
|
|
1387
|
+
};
|
|
1388
|
+
});
|
|
1274
1389
|
},
|
|
1275
1390
|
openSkillFileTab: (skill, file) => {
|
|
1276
1391
|
const displayFile = file ?? "SKILL.md";
|
|
@@ -1811,6 +1926,16 @@ function usePullChanges() {
|
|
|
1811
1926
|
}
|
|
1812
1927
|
});
|
|
1813
1928
|
}
|
|
1929
|
+
function useGitRebaseAction() {
|
|
1930
|
+
const queryClient = useQueryClient2();
|
|
1931
|
+
return useMutation2({
|
|
1932
|
+
mutationFn: (action) => apiClient.performRebaseAction(action),
|
|
1933
|
+
onSuccess: () => {
|
|
1934
|
+
queryClient.invalidateQueries({ queryKey: ["git", "status"] });
|
|
1935
|
+
queryClient.invalidateQueries({ queryKey: ["git", "branch"] });
|
|
1936
|
+
}
|
|
1937
|
+
});
|
|
1938
|
+
}
|
|
1814
1939
|
function useGitInit() {
|
|
1815
1940
|
const queryClient = useQueryClient2();
|
|
1816
1941
|
return useMutation2({
|
|
@@ -2125,10 +2250,22 @@ var useToolApprovalStore = create10((set) => ({
|
|
|
2125
2250
|
}));
|
|
2126
2251
|
|
|
2127
2252
|
// src/hooks/useSessionStream.ts
|
|
2253
|
+
var TOOL_PREVIEW_THROTTLE_MS = 500;
|
|
2254
|
+
var TOOL_PREVIEW_THROTTLE_MIN_CHARS = 8000;
|
|
2255
|
+
var TOOL_PREVIEW_THROTTLE_MIN_DELTA_CHARS = 16000;
|
|
2256
|
+
var STREAMING_WRITE_CONTENT_PREVIEW_CHARS = 24000;
|
|
2257
|
+
var STREAMING_PATCH_PREVIEW_HEAD_CHARS = 12000;
|
|
2258
|
+
var STREAMING_PATCH_PREVIEW_TAIL_CHARS = 24000;
|
|
2259
|
+
var STREAMING_TOOL_INPUT_HEAD_CHARS = 8000;
|
|
2260
|
+
var STREAMING_TOOL_INPUT_TAIL_CHARS = 16000;
|
|
2261
|
+
var STREAMING_TOOL_MESSAGE_THROTTLE_MS = 500;
|
|
2128
2262
|
function useSessionStream(sessionId, enabled = true) {
|
|
2129
2263
|
const queryClient = useQueryClient5();
|
|
2130
2264
|
const clientRef = useRef(null);
|
|
2131
2265
|
const assistantMessageIdRef = useRef(null);
|
|
2266
|
+
const toolInputBuffersRef = useRef(new Map);
|
|
2267
|
+
const toolPreviewEmitRef = useRef(new Map);
|
|
2268
|
+
const toolMessageEmitRef = useRef(new Map);
|
|
2132
2269
|
const {
|
|
2133
2270
|
addPendingApproval,
|
|
2134
2271
|
removePendingApproval,
|
|
@@ -2140,6 +2277,9 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2140
2277
|
return;
|
|
2141
2278
|
}
|
|
2142
2279
|
assistantMessageIdRef.current = null;
|
|
2280
|
+
toolInputBuffersRef.current.clear();
|
|
2281
|
+
toolPreviewEmitRef.current.clear();
|
|
2282
|
+
toolMessageEmitRef.current.clear();
|
|
2143
2283
|
let lastSessionInvalidation = 0;
|
|
2144
2284
|
apiClient.getPendingApprovals(sessionId).then((result) => {
|
|
2145
2285
|
if (result.ok && result.pending.length > 0) {
|
|
@@ -2194,6 +2334,347 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2194
2334
|
return typeof payload?.toolName === "string" ? payload.toolName : null;
|
|
2195
2335
|
};
|
|
2196
2336
|
const getToolEventArgs = (payload) => payload?.args ?? payload?.input;
|
|
2337
|
+
const getToolBufferKey = (payload) => {
|
|
2338
|
+
const callId = getToolEventCallId(payload);
|
|
2339
|
+
if (callId)
|
|
2340
|
+
return callId;
|
|
2341
|
+
const name = getToolEventName(payload);
|
|
2342
|
+
return name ? `name:${name}` : null;
|
|
2343
|
+
};
|
|
2344
|
+
const parseArgsRecord = (value) => {
|
|
2345
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
2346
|
+
return value;
|
|
2347
|
+
}
|
|
2348
|
+
if (typeof value !== "string")
|
|
2349
|
+
return null;
|
|
2350
|
+
try {
|
|
2351
|
+
const parsed = JSON.parse(value);
|
|
2352
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
2353
|
+
} catch {
|
|
2354
|
+
return null;
|
|
2355
|
+
}
|
|
2356
|
+
};
|
|
2357
|
+
const normalizeLineNumber = (value) => {
|
|
2358
|
+
const parsed = typeof value === "number" ? value : typeof value === "string" ? Number.parseInt(value, 10) : Number.NaN;
|
|
2359
|
+
return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : undefined;
|
|
2360
|
+
};
|
|
2361
|
+
const parseLineRange = (value) => {
|
|
2362
|
+
if (typeof value !== "string")
|
|
2363
|
+
return {};
|
|
2364
|
+
const match = value.match(/@(\d+)(?:-(\d+))?/);
|
|
2365
|
+
if (!match)
|
|
2366
|
+
return {};
|
|
2367
|
+
return {
|
|
2368
|
+
startLine: normalizeLineNumber(match[1]),
|
|
2369
|
+
endLine: normalizeLineNumber(match[2] ?? match[1])
|
|
2370
|
+
};
|
|
2371
|
+
};
|
|
2372
|
+
const getBoundedStreamingToolInput = (value) => {
|
|
2373
|
+
const maxLength = STREAMING_TOOL_INPUT_HEAD_CHARS + STREAMING_TOOL_INPUT_TAIL_CHARS;
|
|
2374
|
+
if (value.length <= maxLength)
|
|
2375
|
+
return value;
|
|
2376
|
+
return `${value.slice(0, STREAMING_TOOL_INPUT_HEAD_CHARS)}
|
|
2377
|
+
… streamed tool input truncated for UI responsiveness …
|
|
2378
|
+
${value.slice(-STREAMING_TOOL_INPUT_TAIL_CHARS)}`;
|
|
2379
|
+
};
|
|
2380
|
+
const getToolArgsForViewer = (payload, delta) => {
|
|
2381
|
+
const args = parseArgsRecord(getToolEventArgs(payload));
|
|
2382
|
+
if (args)
|
|
2383
|
+
return args;
|
|
2384
|
+
const key = getToolBufferKey(payload);
|
|
2385
|
+
if (!key)
|
|
2386
|
+
return null;
|
|
2387
|
+
const previous = toolInputBuffersRef.current.get(key) ?? "";
|
|
2388
|
+
if (!delta)
|
|
2389
|
+
return parseArgsRecord(previous);
|
|
2390
|
+
const next = getBoundedStreamingToolInput(`${previous}${delta}`);
|
|
2391
|
+
toolInputBuffersRef.current.set(key, next);
|
|
2392
|
+
return parseArgsRecord(next);
|
|
2393
|
+
};
|
|
2394
|
+
const bestEffortUnescapeJsonString = (value) => {
|
|
2395
|
+
try {
|
|
2396
|
+
return JSON.parse(`"${value.replace(/\\$/, "")}"`);
|
|
2397
|
+
} catch {
|
|
2398
|
+
return value.replace(/\\n/g, `
|
|
2399
|
+
`).replace(/\\t/g, "\t").replace(/\\r/g, "\r").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
2400
|
+
}
|
|
2401
|
+
};
|
|
2402
|
+
const extractJsonStringField = (text, field, requireClosed = false) => {
|
|
2403
|
+
const marker = `"${field}"`;
|
|
2404
|
+
const markerIndex = text.indexOf(marker);
|
|
2405
|
+
if (markerIndex === -1)
|
|
2406
|
+
return;
|
|
2407
|
+
const colonIndex = text.indexOf(":", markerIndex + marker.length);
|
|
2408
|
+
if (colonIndex === -1)
|
|
2409
|
+
return;
|
|
2410
|
+
const quoteIndex = text.indexOf('"', colonIndex + 1);
|
|
2411
|
+
if (quoteIndex === -1)
|
|
2412
|
+
return;
|
|
2413
|
+
let escaped = "";
|
|
2414
|
+
let escaping = false;
|
|
2415
|
+
let closed = false;
|
|
2416
|
+
for (let i = quoteIndex + 1;i < text.length; i += 1) {
|
|
2417
|
+
const char = text[i];
|
|
2418
|
+
if (escaping) {
|
|
2419
|
+
escaped += `\\${char}`;
|
|
2420
|
+
escaping = false;
|
|
2421
|
+
continue;
|
|
2422
|
+
}
|
|
2423
|
+
if (char === "\\") {
|
|
2424
|
+
escaping = true;
|
|
2425
|
+
continue;
|
|
2426
|
+
}
|
|
2427
|
+
if (char === '"') {
|
|
2428
|
+
closed = true;
|
|
2429
|
+
break;
|
|
2430
|
+
}
|
|
2431
|
+
escaped += char;
|
|
2432
|
+
}
|
|
2433
|
+
if (requireClosed && !closed)
|
|
2434
|
+
return;
|
|
2435
|
+
return bestEffortUnescapeJsonString(escaped);
|
|
2436
|
+
};
|
|
2437
|
+
const getBufferedToolInput = (payload) => {
|
|
2438
|
+
const key = getToolBufferKey(payload);
|
|
2439
|
+
return key ? toolInputBuffersRef.current.get(key) ?? "" : "";
|
|
2440
|
+
};
|
|
2441
|
+
const getStringArg = (args, buffer, field, requireClosed = false) => {
|
|
2442
|
+
const value = args?.[field];
|
|
2443
|
+
if (typeof value === "string")
|
|
2444
|
+
return value;
|
|
2445
|
+
return extractJsonStringField(buffer, field, requireClosed);
|
|
2446
|
+
};
|
|
2447
|
+
const getStreamingWritePreviewContent = (args, buffer) => {
|
|
2448
|
+
const argContent = args?.content;
|
|
2449
|
+
if (typeof argContent === "string") {
|
|
2450
|
+
if (argContent.length <= STREAMING_WRITE_CONTENT_PREVIEW_CHARS) {
|
|
2451
|
+
return argContent;
|
|
2452
|
+
}
|
|
2453
|
+
return `… showing latest streamed content only …
|
|
2454
|
+
${argContent.slice(-STREAMING_WRITE_CONTENT_PREVIEW_CHARS)}`;
|
|
2455
|
+
}
|
|
2456
|
+
const marker = '"content"';
|
|
2457
|
+
const markerIndex = buffer.indexOf(marker);
|
|
2458
|
+
if (markerIndex === -1)
|
|
2459
|
+
return;
|
|
2460
|
+
const colonIndex = buffer.indexOf(":", markerIndex + marker.length);
|
|
2461
|
+
if (colonIndex === -1)
|
|
2462
|
+
return;
|
|
2463
|
+
const quoteIndex = buffer.indexOf('"', colonIndex + 1);
|
|
2464
|
+
if (quoteIndex === -1)
|
|
2465
|
+
return;
|
|
2466
|
+
const valueStart = quoteIndex + 1;
|
|
2467
|
+
if (buffer.length - valueStart <= STREAMING_WRITE_CONTENT_PREVIEW_CHARS) {
|
|
2468
|
+
return extractJsonStringField(buffer, "content");
|
|
2469
|
+
}
|
|
2470
|
+
const rawTail = buffer.slice(Math.max(valueStart, buffer.length - STREAMING_WRITE_CONTENT_PREVIEW_CHARS));
|
|
2471
|
+
return `… showing latest streamed content only …
|
|
2472
|
+
${bestEffortUnescapeJsonString(rawTail)}`;
|
|
2473
|
+
};
|
|
2474
|
+
const getStreamingPatchPreviewContent = (args, buffer) => {
|
|
2475
|
+
const argPatch = args?.patch;
|
|
2476
|
+
if (typeof argPatch === "string") {
|
|
2477
|
+
if (argPatch.length <= STREAMING_PATCH_PREVIEW_HEAD_CHARS + STREAMING_PATCH_PREVIEW_TAIL_CHARS) {
|
|
2478
|
+
return argPatch;
|
|
2479
|
+
}
|
|
2480
|
+
return `${argPatch.slice(0, STREAMING_PATCH_PREVIEW_HEAD_CHARS)}
|
|
2481
|
+
… patch preview truncated while streaming …
|
|
2482
|
+
${argPatch.slice(-STREAMING_PATCH_PREVIEW_TAIL_CHARS)}`;
|
|
2483
|
+
}
|
|
2484
|
+
const marker = '"patch"';
|
|
2485
|
+
const markerIndex = buffer.indexOf(marker);
|
|
2486
|
+
if (markerIndex === -1)
|
|
2487
|
+
return;
|
|
2488
|
+
const colonIndex = buffer.indexOf(":", markerIndex + marker.length);
|
|
2489
|
+
if (colonIndex === -1)
|
|
2490
|
+
return;
|
|
2491
|
+
const quoteIndex = buffer.indexOf('"', colonIndex + 1);
|
|
2492
|
+
if (quoteIndex === -1)
|
|
2493
|
+
return;
|
|
2494
|
+
const valueStart = quoteIndex + 1;
|
|
2495
|
+
const rawLength = buffer.length - valueStart;
|
|
2496
|
+
if (rawLength <= STREAMING_PATCH_PREVIEW_HEAD_CHARS + STREAMING_PATCH_PREVIEW_TAIL_CHARS) {
|
|
2497
|
+
return extractJsonStringField(buffer, "patch");
|
|
2498
|
+
}
|
|
2499
|
+
const rawHead = buffer.slice(valueStart, valueStart + STREAMING_PATCH_PREVIEW_HEAD_CHARS);
|
|
2500
|
+
const rawTail = buffer.slice(-STREAMING_PATCH_PREVIEW_TAIL_CHARS);
|
|
2501
|
+
return `${bestEffortUnescapeJsonString(rawHead)}
|
|
2502
|
+
… patch preview truncated while streaming …
|
|
2503
|
+
${bestEffortUnescapeJsonString(rawTail)}`;
|
|
2504
|
+
};
|
|
2505
|
+
const getResultRecord = (payload) => payload?.result && typeof payload.result === "object" && !Array.isArray(payload.result) ? payload.result : null;
|
|
2506
|
+
const getArtifactRecord = (payload) => payload?.artifact && typeof payload.artifact === "object" && !Array.isArray(payload.artifact) ? payload.artifact : null;
|
|
2507
|
+
const extractErrorMessage2 = (payload) => {
|
|
2508
|
+
const result = getResultRecord(payload);
|
|
2509
|
+
if (typeof payload?.error === "string")
|
|
2510
|
+
return payload.error;
|
|
2511
|
+
return typeof result?.error === "string" ? result.error : undefined;
|
|
2512
|
+
};
|
|
2513
|
+
const normalizePatchPath = (path) => path.replace(/^a\//, "").replace(/^b\//, "").trim();
|
|
2514
|
+
const patchPathMatches = (patchPath, targetPath) => {
|
|
2515
|
+
const normalizedPatch = normalizePatchPath(patchPath);
|
|
2516
|
+
const normalizedTarget = normalizePatchPath(targetPath);
|
|
2517
|
+
return normalizedPatch === normalizedTarget || normalizedPatch.endsWith(`/${normalizedTarget}`) || normalizedTarget.endsWith(`/${normalizedPatch}`);
|
|
2518
|
+
};
|
|
2519
|
+
const extractPathsFromPatch = (patch) => {
|
|
2520
|
+
const paths = new Set;
|
|
2521
|
+
for (const line of patch.split(`
|
|
2522
|
+
`)) {
|
|
2523
|
+
const directive = line.match(/^\*\*\* (?:Update|Add|Delete) File: (.+)$/);
|
|
2524
|
+
if (directive?.[1]) {
|
|
2525
|
+
paths.add(directive[1].trim());
|
|
2526
|
+
continue;
|
|
2527
|
+
}
|
|
2528
|
+
const unified = line.match(/^\+\+\+ (?:b\/)?(.+)$/);
|
|
2529
|
+
if (unified?.[1] && unified[1] !== "/dev/null") {
|
|
2530
|
+
paths.add(unified[1].trim());
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2533
|
+
return [...paths];
|
|
2534
|
+
};
|
|
2535
|
+
const getChangedLinesForPath = (result, path) => {
|
|
2536
|
+
const changes = Array.isArray(result?.changes) ? result.changes : [];
|
|
2537
|
+
const lines = new Set;
|
|
2538
|
+
for (const change of changes) {
|
|
2539
|
+
if (!change || typeof change !== "object")
|
|
2540
|
+
continue;
|
|
2541
|
+
const record = change;
|
|
2542
|
+
if (typeof record.filePath !== "string")
|
|
2543
|
+
continue;
|
|
2544
|
+
if (!patchPathMatches(record.filePath, path))
|
|
2545
|
+
continue;
|
|
2546
|
+
if (!Array.isArray(record.hunks))
|
|
2547
|
+
continue;
|
|
2548
|
+
for (const hunk of record.hunks) {
|
|
2549
|
+
if (!hunk || typeof hunk !== "object")
|
|
2550
|
+
continue;
|
|
2551
|
+
const hunkRecord = hunk;
|
|
2552
|
+
const newStart = typeof hunkRecord.newStart === "number" ? hunkRecord.newStart : undefined;
|
|
2553
|
+
const newLines = typeof hunkRecord.newLines === "number" ? hunkRecord.newLines : undefined;
|
|
2554
|
+
if (!newStart || !newLines)
|
|
2555
|
+
continue;
|
|
2556
|
+
for (let line = newStart;line < newStart + newLines; line += 1) {
|
|
2557
|
+
lines.add(line);
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
return lines.size > 0 ? [...lines] : undefined;
|
|
2562
|
+
};
|
|
2563
|
+
const handleReadToolActivity = (eventType, payload, delta) => {
|
|
2564
|
+
const viewerStore = useViewerTabsStore.getState();
|
|
2565
|
+
if (!viewerStore.followToolActivity)
|
|
2566
|
+
return;
|
|
2567
|
+
const name = getToolEventName(payload);
|
|
2568
|
+
if (name !== "read")
|
|
2569
|
+
return;
|
|
2570
|
+
const args = getToolArgsForViewer(payload, delta);
|
|
2571
|
+
const path = typeof args?.path === "string" ? args.path : null;
|
|
2572
|
+
if (!path)
|
|
2573
|
+
return;
|
|
2574
|
+
const result = payload?.result && typeof payload.result === "object" && !Array.isArray(payload.result) ? payload.result : null;
|
|
2575
|
+
const rangeFromResult = parseLineRange(result?.lineRange);
|
|
2576
|
+
const startLine = normalizeLineNumber(args.startLine) ?? normalizeLineNumber(args.start_line) ?? rangeFromResult.startLine;
|
|
2577
|
+
const endLine = normalizeLineNumber(args.endLine) ?? normalizeLineNumber(args.end_line) ?? rangeFromResult.endLine ?? startLine;
|
|
2578
|
+
const failed = result?.ok === false || eventType === "error";
|
|
2579
|
+
viewerStore.openToolReadTab(path, {
|
|
2580
|
+
startLine,
|
|
2581
|
+
endLine,
|
|
2582
|
+
reason: "read",
|
|
2583
|
+
callId: getToolEventCallId(payload) ?? undefined,
|
|
2584
|
+
status: failed ? "error" : eventType === "tool.result" ? "success" : "streaming"
|
|
2585
|
+
});
|
|
2586
|
+
};
|
|
2587
|
+
const handleWriteToolActivity = (eventType, payload, delta) => {
|
|
2588
|
+
const viewerStore = useViewerTabsStore.getState();
|
|
2589
|
+
if (!viewerStore.followToolActivity)
|
|
2590
|
+
return;
|
|
2591
|
+
const name = getToolEventName(payload);
|
|
2592
|
+
if (name !== "write")
|
|
2593
|
+
return;
|
|
2594
|
+
const args = getToolArgsForViewer(payload, delta);
|
|
2595
|
+
const buffer = getBufferedToolInput(payload);
|
|
2596
|
+
const result = getResultRecord(payload);
|
|
2597
|
+
const path = (typeof result?.path === "string" ? result.path : undefined) ?? getStringArg(args, buffer, "path", true);
|
|
2598
|
+
if (!path)
|
|
2599
|
+
return;
|
|
2600
|
+
const failed = result?.ok === false || eventType === "error";
|
|
2601
|
+
const callId = getToolEventCallId(payload) ?? undefined;
|
|
2602
|
+
const status = failed ? "error" : eventType === "tool.result" ? "success" : "streaming";
|
|
2603
|
+
const content = status === "streaming" ? getStreamingWritePreviewContent(args, buffer) : getStringArg(args, buffer, "content");
|
|
2604
|
+
if (status === "streaming" && content !== undefined && content.length >= TOOL_PREVIEW_THROTTLE_MIN_CHARS) {
|
|
2605
|
+
const previewKey = callId ?? path;
|
|
2606
|
+
const now = Date.now();
|
|
2607
|
+
const last = toolPreviewEmitRef.current.get(previewKey);
|
|
2608
|
+
const contentDelta = Math.abs(content.length - (last?.contentLength ?? 0));
|
|
2609
|
+
if (last && now - last.emittedAt < TOOL_PREVIEW_THROTTLE_MS && contentDelta < TOOL_PREVIEW_THROTTLE_MIN_DELTA_CHARS) {
|
|
2610
|
+
return;
|
|
2611
|
+
}
|
|
2612
|
+
toolPreviewEmitRef.current.set(previewKey, {
|
|
2613
|
+
emittedAt: now,
|
|
2614
|
+
contentLength: content.length
|
|
2615
|
+
});
|
|
2616
|
+
}
|
|
2617
|
+
viewerStore.openToolPreviewTab({
|
|
2618
|
+
path,
|
|
2619
|
+
toolName: "write",
|
|
2620
|
+
callId,
|
|
2621
|
+
content,
|
|
2622
|
+
status,
|
|
2623
|
+
error: extractErrorMessage2(payload)
|
|
2624
|
+
});
|
|
2625
|
+
};
|
|
2626
|
+
const handleApplyPatchToolActivity = (eventType, payload, delta) => {
|
|
2627
|
+
const viewerStore = useViewerTabsStore.getState();
|
|
2628
|
+
if (!viewerStore.followToolActivity)
|
|
2629
|
+
return;
|
|
2630
|
+
const name = getToolEventName(payload);
|
|
2631
|
+
if (name !== "apply_patch")
|
|
2632
|
+
return;
|
|
2633
|
+
const args = getToolArgsForViewer(payload, delta);
|
|
2634
|
+
const buffer = getBufferedToolInput(payload);
|
|
2635
|
+
const artifact = getArtifactRecord(payload);
|
|
2636
|
+
const result = getResultRecord(payload);
|
|
2637
|
+
const failed = result?.ok === false || eventType === "error";
|
|
2638
|
+
const status = failed ? "error" : eventType === "tool.result" ? "success" : "streaming";
|
|
2639
|
+
const callId = getToolEventCallId(payload) ?? undefined;
|
|
2640
|
+
if (status === "streaming" && buffer.length >= TOOL_PREVIEW_THROTTLE_MIN_CHARS) {
|
|
2641
|
+
const previewKey = callId ?? "apply_patch";
|
|
2642
|
+
const now = Date.now();
|
|
2643
|
+
const last = toolPreviewEmitRef.current.get(previewKey);
|
|
2644
|
+
const contentDelta = Math.abs(buffer.length - (last?.contentLength ?? 0));
|
|
2645
|
+
if (last && now - last.emittedAt < TOOL_PREVIEW_THROTTLE_MS && contentDelta < TOOL_PREVIEW_THROTTLE_MIN_DELTA_CHARS) {
|
|
2646
|
+
return;
|
|
2647
|
+
}
|
|
2648
|
+
toolPreviewEmitRef.current.set(previewKey, {
|
|
2649
|
+
emittedAt: now,
|
|
2650
|
+
contentLength: buffer.length
|
|
2651
|
+
});
|
|
2652
|
+
}
|
|
2653
|
+
const patch = (typeof artifact?.patch === "string" ? artifact.patch : undefined) ?? (status === "streaming" ? getStreamingPatchPreviewContent(args, buffer) : getStringArg(args, buffer, "patch"));
|
|
2654
|
+
if (!patch)
|
|
2655
|
+
return;
|
|
2656
|
+
for (const path of extractPathsFromPatch(patch)) {
|
|
2657
|
+
viewerStore.openToolPreviewTab({
|
|
2658
|
+
path,
|
|
2659
|
+
toolName: "apply_patch",
|
|
2660
|
+
callId,
|
|
2661
|
+
patch,
|
|
2662
|
+
changedLines: getChangedLinesForPath(result, path),
|
|
2663
|
+
status,
|
|
2664
|
+
error: extractErrorMessage2(payload)
|
|
2665
|
+
});
|
|
2666
|
+
}
|
|
2667
|
+
};
|
|
2668
|
+
const handleToolActivityViewerEvent = (eventType, payload, delta) => {
|
|
2669
|
+
const name = getToolEventName(payload);
|
|
2670
|
+
if (name === "read")
|
|
2671
|
+
handleReadToolActivity(eventType, payload, delta);
|
|
2672
|
+
if (name === "write")
|
|
2673
|
+
handleWriteToolActivity(eventType, payload, delta);
|
|
2674
|
+
if (name === "apply_patch") {
|
|
2675
|
+
handleApplyPatchToolActivity(eventType, payload, delta);
|
|
2676
|
+
}
|
|
2677
|
+
};
|
|
2197
2678
|
const getToolInputDelta = (payload) => {
|
|
2198
2679
|
if (typeof payload?.delta === "string")
|
|
2199
2680
|
return payload.delta;
|
|
@@ -2331,6 +2812,18 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2331
2812
|
const name = getToolEventName(payload);
|
|
2332
2813
|
if (!name)
|
|
2333
2814
|
return;
|
|
2815
|
+
if (name === "write" || name === "apply_patch") {
|
|
2816
|
+
const bufferKey = getToolBufferKey(payload);
|
|
2817
|
+
const bufferedLength = bufferKey ? toolInputBuffersRef.current.get(bufferKey)?.length ?? 0 : 0;
|
|
2818
|
+
if (bufferedLength >= TOOL_PREVIEW_THROTTLE_MIN_CHARS) {
|
|
2819
|
+
const emitKey = callId ?? `name:${name}`;
|
|
2820
|
+
const now = Date.now();
|
|
2821
|
+
const last = toolMessageEmitRef.current.get(emitKey) ?? 0;
|
|
2822
|
+
if (now - last < STREAMING_TOOL_MESSAGE_THROTTLE_MS)
|
|
2823
|
+
return;
|
|
2824
|
+
toolMessageEmitRef.current.set(emitKey, now);
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2334
2827
|
queryClient.setQueryData(["messages", sessionId], (oldMessages) => {
|
|
2335
2828
|
if (!oldMessages)
|
|
2336
2829
|
return oldMessages;
|
|
@@ -2434,7 +2927,7 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2434
2927
|
if (partIndex === -1) {
|
|
2435
2928
|
const contentJsonBase = {
|
|
2436
2929
|
name,
|
|
2437
|
-
_streamedInput: delta
|
|
2930
|
+
_streamedInput: getBoundedStreamingToolInput(delta)
|
|
2438
2931
|
};
|
|
2439
2932
|
if (callId)
|
|
2440
2933
|
contentJsonBase.callId = callId;
|
|
@@ -2462,7 +2955,7 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2462
2955
|
const prev = typeof existing.contentJson?._streamedInput === "string" ? existing.contentJson._streamedInput : "";
|
|
2463
2956
|
const nextContentJson = {
|
|
2464
2957
|
...typeof existing.contentJson === "object" && !Array.isArray(existing.contentJson) ? existing.contentJson : {},
|
|
2465
|
-
_streamedInput: prev + delta
|
|
2958
|
+
_streamedInput: getBoundedStreamingToolInput(prev + delta)
|
|
2466
2959
|
};
|
|
2467
2960
|
parts[partIndex] = {
|
|
2468
2961
|
...existing,
|
|
@@ -2750,8 +3243,10 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2750
3243
|
if (channel === "input" || channel == null && delta) {
|
|
2751
3244
|
if (delta) {
|
|
2752
3245
|
accumulateToolInputDelta(payload, delta);
|
|
3246
|
+
handleToolActivityViewerEvent("tool.delta", payload, delta);
|
|
2753
3247
|
} else {
|
|
2754
3248
|
upsertEphemeralToolCall(payload);
|
|
3249
|
+
handleToolActivityViewerEvent("tool.delta", payload);
|
|
2755
3250
|
}
|
|
2756
3251
|
} else if (channel === "output" && delta) {
|
|
2757
3252
|
accumulateToolOutputDelta(payload, delta);
|
|
@@ -2760,10 +3255,15 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2760
3255
|
}
|
|
2761
3256
|
case "tool.call": {
|
|
2762
3257
|
upsertEphemeralToolCall(payload);
|
|
3258
|
+
handleToolActivityViewerEvent("tool.call", payload);
|
|
2763
3259
|
break;
|
|
2764
3260
|
}
|
|
2765
3261
|
case "tool.result": {
|
|
2766
3262
|
resolveEphemeralToolCall(payload);
|
|
3263
|
+
handleToolActivityViewerEvent("tool.result", payload);
|
|
3264
|
+
const key = getToolBufferKey(payload);
|
|
3265
|
+
if (key)
|
|
3266
|
+
toolInputBuffersRef.current.delete(key);
|
|
2767
3267
|
break;
|
|
2768
3268
|
}
|
|
2769
3269
|
case "tool.approval.required": {
|
|
@@ -2798,6 +3298,7 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2798
3298
|
break;
|
|
2799
3299
|
}
|
|
2800
3300
|
case "error": {
|
|
3301
|
+
handleToolActivityViewerEvent("error", payload);
|
|
2801
3302
|
removeEphemeralToolCall(payload);
|
|
2802
3303
|
const messageId = typeof payload?.messageId === "string" ? payload.messageId : null;
|
|
2803
3304
|
if (messageId) {
|
|
@@ -3022,6 +3523,9 @@ function sendBrowserNotification(notification) {
|
|
|
3022
3523
|
};
|
|
3023
3524
|
return true;
|
|
3024
3525
|
}
|
|
3526
|
+
function isAppForeground() {
|
|
3527
|
+
return getPlatformWindowFocused() ?? document.visibilityState === "visible";
|
|
3528
|
+
}
|
|
3025
3529
|
function updateSessionStatusInCache(queryClient, status) {
|
|
3026
3530
|
queryClient.setQueryData(sessionsQueryKey, (old) => {
|
|
3027
3531
|
if (!old)
|
|
@@ -3167,7 +3671,7 @@ function useClientEvents(activeSessionId) {
|
|
|
3167
3671
|
}
|
|
3168
3672
|
if (event.event === "notification") {
|
|
3169
3673
|
const notification = payload;
|
|
3170
|
-
const isActiveVisibleSession = notification.sessionId === activeSessionIdRef.current &&
|
|
3674
|
+
const isActiveVisibleSession = notification.sessionId === activeSessionIdRef.current && isAppForeground();
|
|
3171
3675
|
const isSessionNotification = notification.source === "session" || !!notification.sessionId;
|
|
3172
3676
|
let sentSystemNotification = false;
|
|
3173
3677
|
if (!isActiveVisibleSession) {
|
|
@@ -3423,7 +3927,7 @@ function useKeyboardShortcuts({
|
|
|
3423
3927
|
}
|
|
3424
3928
|
return;
|
|
3425
3929
|
}
|
|
3426
|
-
if ((e.ctrlKey || e.metaKey) && e.key === "
|
|
3930
|
+
if ((e.ctrlKey || e.metaKey) && e.key === "b") {
|
|
3427
3931
|
e.preventDefault();
|
|
3428
3932
|
if (currentFocus === "sessions") {
|
|
3429
3933
|
document.activeElement?.blur();
|
|
@@ -3446,7 +3950,7 @@ function useKeyboardShortcuts({
|
|
|
3446
3950
|
}
|
|
3447
3951
|
return;
|
|
3448
3952
|
}
|
|
3449
|
-
if ((e.ctrlKey || e.metaKey) && e.key === "
|
|
3953
|
+
if ((e.ctrlKey || e.metaKey) && !e.shiftKey && e.key === "r") {
|
|
3450
3954
|
e.preventDefault();
|
|
3451
3955
|
if (currentFocus === "git") {
|
|
3452
3956
|
document.activeElement?.blur();
|
|
@@ -5767,6 +6271,7 @@ export {
|
|
|
5767
6271
|
useImageUpload,
|
|
5768
6272
|
useGitStatus,
|
|
5769
6273
|
useGitRemotes,
|
|
6274
|
+
useGitRebaseAction,
|
|
5770
6275
|
useGitInit,
|
|
5771
6276
|
useGitDiffFullFile,
|
|
5772
6277
|
useGitDiff,
|
|
@@ -5797,4 +6302,4 @@ export {
|
|
|
5797
6302
|
sessionsQueryKey
|
|
5798
6303
|
};
|
|
5799
6304
|
|
|
5800
|
-
//# debugId=
|
|
6305
|
+
//# debugId=88EDF96A27BB9BCF64756E2164756E21
|