@ottocode/web-sdk 0.1.275 → 0.1.276
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/chat/ChatInputContainer.d.ts.map +1 -1
- package/dist/components/file-browser/FileViewerPanel.d.ts +2 -1
- package/dist/components/file-browser/FileViewerPanel.d.ts.map +1 -1
- package/dist/components/index.js +884 -292
- package/dist/components/index.js.map +18 -18
- package/dist/components/messages/MessagePartItem.d.ts.map +1 -1
- package/dist/components/messages/renderers/DiffView.d.ts.map +1 -1
- package/dist/components/ui/Toaster.d.ts.map +1 -1
- package/dist/components/workspace/ToolPreviewPanel.d.ts.map +1 -1
- package/dist/components/workspace/ViewerTabs.d.ts.map +1 -1
- package/dist/hooks/index.js +301 -60
- package/dist/hooks/index.js.map +8 -8
- package/dist/hooks/useProviderUsage.d.ts +1 -1
- package/dist/hooks/useProviderUsage.d.ts.map +1 -1
- package/dist/hooks/useQueueState.d.ts +9 -0
- package/dist/hooks/useQueueState.d.ts.map +1 -1
- package/dist/hooks/useSessionStream.d.ts.map +1 -1
- package/dist/index.js +885 -292
- package/dist/index.js.map +18 -18
- package/dist/lib/api-client/index.d.ts +6 -0
- package/dist/lib/api-client/index.d.ts.map +1 -1
- package/dist/lib/api-client/sessions.d.ts +6 -0
- package/dist/lib/api-client/sessions.d.ts.map +1 -1
- package/dist/lib/commands.d.ts.map +1 -1
- package/dist/lib/index.js +17 -1
- package/dist/lib/index.js.map +4 -4
- package/dist/stores/index.js +77 -16
- package/dist/stores/index.js.map +3 -3
- package/dist/stores/viewerTabsStore.d.ts +9 -0
- package/dist/stores/viewerTabsStore.d.ts.map +1 -1
- package/dist/types/api.d.ts +1 -1
- package/dist/types/api.d.ts.map +1 -1
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -480,6 +480,8 @@ function ToastItem({ toast: toast2 }) {
|
|
|
480
480
|
};
|
|
481
481
|
const style = typeStyles[toast2.type];
|
|
482
482
|
const transitionClass = phase === "enter" ? "opacity-0 translate-y-2 scale-95" : phase === "exit" ? "opacity-0 translate-y-1 scale-95" : "opacity-100 translate-y-0 scale-100";
|
|
483
|
+
const rowAlignmentClass = toast2.type === "loading" ? "items-center" : "items-start";
|
|
484
|
+
const iconOffsetClass = toast2.type === "loading" ? "" : "mt-px";
|
|
483
485
|
return /* @__PURE__ */ jsxs3("div", {
|
|
484
486
|
className: `
|
|
485
487
|
relative overflow-hidden
|
|
@@ -494,10 +496,10 @@ function ToastItem({ toast: toast2 }) {
|
|
|
494
496
|
role: "alert",
|
|
495
497
|
children: [
|
|
496
498
|
/* @__PURE__ */ jsxs3("div", {
|
|
497
|
-
className:
|
|
499
|
+
className: `flex ${rowAlignmentClass} gap-2.5 px-3 py-2.5`,
|
|
498
500
|
children: [
|
|
499
501
|
/* @__PURE__ */ jsx7("span", {
|
|
500
|
-
className:
|
|
502
|
+
className: `${iconOffsetClass} shrink-0`,
|
|
501
503
|
children: style.icon
|
|
502
504
|
}),
|
|
503
505
|
/* @__PURE__ */ jsx7("div", {
|
|
@@ -1191,6 +1193,21 @@ var sessionsMixin = {
|
|
|
1191
1193
|
throw new Error(extractErrorMessage(response.error));
|
|
1192
1194
|
return response.data;
|
|
1193
1195
|
},
|
|
1196
|
+
async createHandoff(sessionId) {
|
|
1197
|
+
const response = await fetch(`${getBaseUrl()}/v1/sessions/${encodeURIComponent(sessionId)}/handoff`, { method: "POST" });
|
|
1198
|
+
const data = await response.json().catch(() => null);
|
|
1199
|
+
if (!response.ok)
|
|
1200
|
+
throw new Error(extractErrorMessage(data));
|
|
1201
|
+
if (!data?.session || !data?.sessionId) {
|
|
1202
|
+
throw new Error("No data returned from handoff");
|
|
1203
|
+
}
|
|
1204
|
+
return {
|
|
1205
|
+
session: convertSession(data.session),
|
|
1206
|
+
sessionId: String(data.sessionId),
|
|
1207
|
+
sourceSessionId: String(data.sourceSessionId),
|
|
1208
|
+
message: String(data.message ?? "")
|
|
1209
|
+
};
|
|
1210
|
+
},
|
|
1194
1211
|
async abortSession(sessionId) {
|
|
1195
1212
|
const response = await apiAbortSession({ path: { sessionId } });
|
|
1196
1213
|
if (response.error)
|
|
@@ -1925,6 +1942,7 @@ class ApiClient {
|
|
|
1925
1942
|
updateSession = sessionsMixin.updateSession;
|
|
1926
1943
|
markSessionViewed = sessionsMixin.markSessionViewed;
|
|
1927
1944
|
deleteSession = sessionsMixin.deleteSession;
|
|
1945
|
+
createHandoff = sessionsMixin.createHandoff;
|
|
1928
1946
|
abortSession = sessionsMixin.abortSession;
|
|
1929
1947
|
abortMessage = sessionsMixin.abortMessage;
|
|
1930
1948
|
getQueueState = sessionsMixin.getQueueState;
|
|
@@ -2199,7 +2217,8 @@ import {
|
|
|
2199
2217
|
Trash2,
|
|
2200
2218
|
Share2,
|
|
2201
2219
|
RefreshCw,
|
|
2202
|
-
FileText as FileText2
|
|
2220
|
+
FileText as FileText2,
|
|
2221
|
+
ArrowRightLeft
|
|
2203
2222
|
} from "lucide-react";
|
|
2204
2223
|
var COMMANDS = [
|
|
2205
2224
|
{
|
|
@@ -2268,6 +2287,12 @@ var COMMANDS = [
|
|
|
2268
2287
|
description: "Generate AGENTS.md and .agents docs from the real repo structure",
|
|
2269
2288
|
icon: FileText2
|
|
2270
2289
|
},
|
|
2290
|
+
{
|
|
2291
|
+
id: "handoff",
|
|
2292
|
+
label: "/handoff",
|
|
2293
|
+
description: "Create a new session with current context",
|
|
2294
|
+
icon: ArrowRightLeft
|
|
2295
|
+
},
|
|
2271
2296
|
{
|
|
2272
2297
|
id: "branch",
|
|
2273
2298
|
label: "/branch",
|
|
@@ -3840,14 +3865,26 @@ import { useQuery as useQuery4 } from "@tanstack/react-query";
|
|
|
3840
3865
|
var defaultQueueState = {
|
|
3841
3866
|
currentMessageId: null,
|
|
3842
3867
|
queuedMessages: [],
|
|
3843
|
-
queueLength: 0
|
|
3868
|
+
queueLength: 0,
|
|
3869
|
+
isRunning: false
|
|
3844
3870
|
};
|
|
3871
|
+
function normalizeQueueState(state) {
|
|
3872
|
+
const isRunning = state.isRunning ?? Boolean(state.currentMessageId);
|
|
3873
|
+
const currentMessageId = isRunning ? state.currentMessageId : null;
|
|
3874
|
+
const hasActiveTurn = Boolean(currentMessageId);
|
|
3875
|
+
const queuedMessages = hasActiveTurn ? state.queuedMessages : [];
|
|
3876
|
+
return {
|
|
3877
|
+
currentMessageId,
|
|
3878
|
+
queuedMessages,
|
|
3879
|
+
queueLength: queuedMessages.length,
|
|
3880
|
+
isRunning: hasActiveTurn
|
|
3881
|
+
};
|
|
3882
|
+
}
|
|
3845
3883
|
function optimisticallyQueueMessage(queryClient, sessionId, messageId) {
|
|
3846
3884
|
queryClient.setQueryData(["queueState", sessionId], (current) => {
|
|
3847
3885
|
if (!current)
|
|
3848
3886
|
return current;
|
|
3849
|
-
|
|
3850
|
-
if (!isBusy)
|
|
3887
|
+
if (!current.isRunning || !current.currentMessageId)
|
|
3851
3888
|
return current;
|
|
3852
3889
|
if (current.currentMessageId === messageId)
|
|
3853
3890
|
return current;
|
|
@@ -3872,11 +3909,7 @@ function useQueueState(sessionId) {
|
|
|
3872
3909
|
if (!sessionId)
|
|
3873
3910
|
return defaultQueueState;
|
|
3874
3911
|
const queueState = await apiClient.getQueueState(sessionId);
|
|
3875
|
-
return
|
|
3876
|
-
currentMessageId: queueState.currentMessageId,
|
|
3877
|
-
queuedMessages: queueState.queuedMessages,
|
|
3878
|
-
queueLength: queueState.queuedMessages.length
|
|
3879
|
-
};
|
|
3912
|
+
return normalizeQueueState(queueState);
|
|
3880
3913
|
},
|
|
3881
3914
|
enabled: !!sessionId,
|
|
3882
3915
|
placeholderData: defaultQueueState,
|
|
@@ -5219,6 +5252,53 @@ function mergeChangedLines(existing, incoming) {
|
|
|
5219
5252
|
return existing;
|
|
5220
5253
|
return [...new Set([...existing, ...incoming])].sort((a, b) => a - b);
|
|
5221
5254
|
}
|
|
5255
|
+
function countContentLines(content) {
|
|
5256
|
+
return content.length === 0 ? 1 : content.split(`
|
|
5257
|
+
`).length;
|
|
5258
|
+
}
|
|
5259
|
+
function annotationId(preview, targetPath) {
|
|
5260
|
+
return `${preview.toolName}:${preview.callId ?? `${normalizeViewerPath(targetPath)}:${preview.patch ?? preview.content ?? ""}`}`;
|
|
5261
|
+
}
|
|
5262
|
+
function buildAnnotation(preview, targetPath, existing) {
|
|
5263
|
+
if (preview.status === "error")
|
|
5264
|
+
return existing;
|
|
5265
|
+
const id = annotationId(preview, targetPath);
|
|
5266
|
+
if (preview.toolName === "write") {
|
|
5267
|
+
const content = preview.content;
|
|
5268
|
+
if (content === undefined)
|
|
5269
|
+
return existing;
|
|
5270
|
+
return {
|
|
5271
|
+
id,
|
|
5272
|
+
reason: "write",
|
|
5273
|
+
callId: preview.callId,
|
|
5274
|
+
status: preview.status,
|
|
5275
|
+
lineTones: Array.from({ length: countContentLines(content) }, (_, index) => [index + 1, "add"]),
|
|
5276
|
+
createdAt: existing?.createdAt ?? Date.now()
|
|
5277
|
+
};
|
|
5278
|
+
}
|
|
5279
|
+
const lineTones = preview.previewLineTones?.length ? preview.previewLineTones : preview.changedLines?.length ? preview.changedLines.map((line) => [line, "add"]) : existing?.lineTones;
|
|
5280
|
+
if (!lineTones?.length)
|
|
5281
|
+
return existing;
|
|
5282
|
+
return {
|
|
5283
|
+
id,
|
|
5284
|
+
reason: "apply_patch",
|
|
5285
|
+
callId: preview.callId,
|
|
5286
|
+
status: preview.status,
|
|
5287
|
+
lineTones,
|
|
5288
|
+
createdAt: existing?.createdAt ?? Date.now()
|
|
5289
|
+
};
|
|
5290
|
+
}
|
|
5291
|
+
function upsertAnnotation(annotations, annotation) {
|
|
5292
|
+
if (!annotation)
|
|
5293
|
+
return annotations;
|
|
5294
|
+
const existing = annotations ?? [];
|
|
5295
|
+
const index = existing.findIndex((item) => item.id === annotation.id);
|
|
5296
|
+
if (index === -1)
|
|
5297
|
+
return [...existing, annotation];
|
|
5298
|
+
const next = [...existing];
|
|
5299
|
+
next[index] = annotation;
|
|
5300
|
+
return next;
|
|
5301
|
+
}
|
|
5222
5302
|
var useViewerTabsStore = create8((set) => ({
|
|
5223
5303
|
tabs: [],
|
|
5224
5304
|
activeTabId: null,
|
|
@@ -5265,7 +5345,11 @@ var useViewerTabsStore = create8((set) => ({
|
|
|
5265
5345
|
id: targetId,
|
|
5266
5346
|
type: "file",
|
|
5267
5347
|
title: existingFile?.title ?? titleFromPath(targetPath),
|
|
5268
|
-
path: targetPath
|
|
5348
|
+
path: targetPath,
|
|
5349
|
+
highlight: existingFile?.highlight,
|
|
5350
|
+
annotations: existingFile?.annotations,
|
|
5351
|
+
patchPreview: existingFile?.patchPreview,
|
|
5352
|
+
writePreview: existingFile?.writePreview
|
|
5269
5353
|
}),
|
|
5270
5354
|
activeTabId: targetId
|
|
5271
5355
|
};
|
|
@@ -5286,6 +5370,7 @@ var useViewerTabsStore = create8((set) => ({
|
|
|
5286
5370
|
title: existingFile?.title ?? titleFromPath(targetPath),
|
|
5287
5371
|
path: targetPath,
|
|
5288
5372
|
highlight,
|
|
5373
|
+
annotations: existingFile?.annotations,
|
|
5289
5374
|
patchPreview: undefined,
|
|
5290
5375
|
writePreview: undefined
|
|
5291
5376
|
}),
|
|
@@ -5307,6 +5392,12 @@ var useViewerTabsStore = create8((set) => ({
|
|
|
5307
5392
|
const samePatchCall = isSamePatchCall(existingPatchPreview, preview);
|
|
5308
5393
|
const baseContent = preview.baseContent ?? (samePatchCall ? existingPatchPreview?.baseContent : existingPatchPreview?.resultContent ?? existingPatchPreview?.baseContent);
|
|
5309
5394
|
const changedLines = samePatchCall ? preview.changedLines ?? existingPatchPreview?.changedLines : mergeChangedLines(existingPatchPreview?.changedLines, preview.changedLines);
|
|
5395
|
+
const annotationPreview = {
|
|
5396
|
+
...preview,
|
|
5397
|
+
changedLines: preview.changedLines
|
|
5398
|
+
};
|
|
5399
|
+
const existingAnnotation = existingFile?.annotations?.find((annotation2) => annotation2.id === annotationId(annotationPreview, targetPath));
|
|
5400
|
+
const annotations = upsertAnnotation(existingFile?.annotations, buildAnnotation(annotationPreview, targetPath, existingAnnotation));
|
|
5310
5401
|
return {
|
|
5311
5402
|
tabs: upsertTab(tabs, {
|
|
5312
5403
|
id: targetId,
|
|
@@ -5314,6 +5405,7 @@ var useViewerTabsStore = create8((set) => ({
|
|
|
5314
5405
|
title: existingFile?.title ?? titleFromPath(targetPath),
|
|
5315
5406
|
path: targetPath,
|
|
5316
5407
|
highlight: undefined,
|
|
5408
|
+
annotations,
|
|
5317
5409
|
writePreview: undefined,
|
|
5318
5410
|
patchPreview: {
|
|
5319
5411
|
path: targetPath,
|
|
@@ -5336,10 +5428,13 @@ var useViewerTabsStore = create8((set) => ({
|
|
|
5336
5428
|
}
|
|
5337
5429
|
if (existingFile) {
|
|
5338
5430
|
const existingWritePreview = existingFile.writePreview;
|
|
5431
|
+
const existingAnnotation = existingFile.annotations?.find((annotation2) => annotation2.id === annotationId(preview, targetPath));
|
|
5432
|
+
const annotations = upsertAnnotation(existingFile.annotations, buildAnnotation(preview, targetPath, existingAnnotation));
|
|
5339
5433
|
return {
|
|
5340
5434
|
tabs: upsertTab(tabs, {
|
|
5341
5435
|
...existingFile,
|
|
5342
5436
|
highlight: undefined,
|
|
5437
|
+
annotations,
|
|
5343
5438
|
patchPreview: undefined,
|
|
5344
5439
|
writePreview: {
|
|
5345
5440
|
path: targetPath,
|
|
@@ -5354,25 +5449,24 @@ var useViewerTabsStore = create8((set) => ({
|
|
|
5354
5449
|
};
|
|
5355
5450
|
}
|
|
5356
5451
|
const existingWrite = existing?.toolName === "write" ? existing : undefined;
|
|
5452
|
+
const annotation = buildAnnotation(preview, preview.path);
|
|
5357
5453
|
return {
|
|
5358
5454
|
tabs: upsertTab(tabs, {
|
|
5359
5455
|
id,
|
|
5360
|
-
type: "
|
|
5456
|
+
type: "file",
|
|
5361
5457
|
title: titleFromPath(preview.path),
|
|
5362
5458
|
path: preview.path,
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
status: preview.status,
|
|
5375
|
-
error: preview.error ?? existingWrite?.error
|
|
5459
|
+
highlight: undefined,
|
|
5460
|
+
annotations: annotation ? [annotation] : undefined,
|
|
5461
|
+
patchPreview: undefined,
|
|
5462
|
+
writePreview: {
|
|
5463
|
+
path: preview.path,
|
|
5464
|
+
toolName: "write",
|
|
5465
|
+
callId: preview.callId,
|
|
5466
|
+
content: preview.content ?? existingWrite?.content,
|
|
5467
|
+
status: preview.status,
|
|
5468
|
+
error: preview.error ?? existingWrite?.error
|
|
5469
|
+
}
|
|
5376
5470
|
}),
|
|
5377
5471
|
activeTabId: id
|
|
5378
5472
|
};
|
|
@@ -7280,6 +7374,24 @@ ${content}` : content;
|
|
|
7280
7374
|
handleSendMessage("/compact");
|
|
7281
7375
|
} else if (commandId === "init") {
|
|
7282
7376
|
handleSendMessage("/init");
|
|
7377
|
+
} else if (commandId === "handoff") {
|
|
7378
|
+
const toastId2 = toast.loading("Creating handoff...");
|
|
7379
|
+
try {
|
|
7380
|
+
const result = await apiClient.createHandoff(sessionId);
|
|
7381
|
+
queryClient.invalidateQueries({ queryKey: ["sessions"] });
|
|
7382
|
+
queryClient.invalidateQueries({
|
|
7383
|
+
queryKey: ["messages", sessionId]
|
|
7384
|
+
});
|
|
7385
|
+
queryClient.invalidateQueries({
|
|
7386
|
+
queryKey: ["messages", result.sessionId]
|
|
7387
|
+
});
|
|
7388
|
+
openPlatformSession(result.sessionId);
|
|
7389
|
+
toast.success("Handoff created");
|
|
7390
|
+
} catch (error) {
|
|
7391
|
+
toast.error(error instanceof Error ? error.message : "Failed to create handoff");
|
|
7392
|
+
} finally {
|
|
7393
|
+
useToastStore.getState().removeToast(toastId2);
|
|
7394
|
+
}
|
|
7283
7395
|
} else if (commandId === "delete") {
|
|
7284
7396
|
deleteSession.mutate(sessionId, {
|
|
7285
7397
|
onSuccess: () => {
|
|
@@ -7928,6 +8040,11 @@ function parseDiff(patch) {
|
|
|
7928
8040
|
let inHunk = false;
|
|
7929
8041
|
let filePath = "";
|
|
7930
8042
|
for (const line of lines) {
|
|
8043
|
+
const lineModePath = line.match(/^\*\*\* (?:Delete Lines in|Replace Lines in|Insert Before in|Insert After in): (.+)$/);
|
|
8044
|
+
if (lineModePath?.[1]) {
|
|
8045
|
+
filePath = lineModePath[1];
|
|
8046
|
+
inHunk = false;
|
|
8047
|
+
}
|
|
7931
8048
|
if (line.startsWith("*** Update File:") || line.startsWith("*** Add File:")) {
|
|
7932
8049
|
const match = line.match(/\*\*\* (?:Update|Add) File: (.+)/);
|
|
7933
8050
|
if (match)
|
|
@@ -12913,101 +13030,83 @@ var MessagePartItem = memo10(function MessagePartItem2({
|
|
|
12913
13030
|
} else if (data) {
|
|
12914
13031
|
content = JSON.stringify(data, null, 2);
|
|
12915
13032
|
}
|
|
12916
|
-
return /* @__PURE__ */
|
|
13033
|
+
return /* @__PURE__ */ jsx59("div", {
|
|
12917
13034
|
className: "relative group",
|
|
12918
|
-
children:
|
|
12919
|
-
|
|
12920
|
-
|
|
12921
|
-
|
|
12922
|
-
|
|
12923
|
-
|
|
12924
|
-
|
|
12925
|
-
|
|
12926
|
-
|
|
12927
|
-
|
|
12928
|
-
|
|
12929
|
-
|
|
12930
|
-
|
|
12931
|
-
|
|
12932
|
-
|
|
12933
|
-
href
|
|
12934
|
-
|
|
12935
|
-
|
|
12936
|
-
|
|
12937
|
-
|
|
12938
|
-
|
|
12939
|
-
|
|
12940
|
-
|
|
12941
|
-
|
|
12942
|
-
|
|
12943
|
-
|
|
12944
|
-
|
|
12945
|
-
|
|
12946
|
-
|
|
12947
|
-
|
|
13035
|
+
children: /* @__PURE__ */ jsx59("div", {
|
|
13036
|
+
className: `${isCompactThread ? "text-[16.5px]" : "text-[17px]"} text-foreground leading-relaxed markdown-content max-w-full overflow-x-auto`,
|
|
13037
|
+
children: /* @__PURE__ */ jsx59(ReactMarkdown, {
|
|
13038
|
+
remarkPlugins: [remarkGfm],
|
|
13039
|
+
components: {
|
|
13040
|
+
a: ({
|
|
13041
|
+
href,
|
|
13042
|
+
children,
|
|
13043
|
+
...props
|
|
13044
|
+
}) => /* @__PURE__ */ jsx59("a", {
|
|
13045
|
+
href,
|
|
13046
|
+
target: "_blank",
|
|
13047
|
+
rel: "noopener noreferrer",
|
|
13048
|
+
className: "text-primary underline decoration-primary/35 underline-offset-2 transition-colors hover:text-primary/90 hover:decoration-primary",
|
|
13049
|
+
onClick: (e) => {
|
|
13050
|
+
if (window.self !== window.top && href) {
|
|
13051
|
+
e.preventDefault();
|
|
13052
|
+
window.parent.postMessage({
|
|
13053
|
+
type: "otto-open-url",
|
|
13054
|
+
url: href
|
|
13055
|
+
}, "*");
|
|
13056
|
+
}
|
|
13057
|
+
},
|
|
13058
|
+
...props,
|
|
13059
|
+
children
|
|
13060
|
+
}),
|
|
13061
|
+
pre: ({
|
|
13062
|
+
children,
|
|
13063
|
+
...props
|
|
13064
|
+
}) => {
|
|
13065
|
+
const codeContent = (() => {
|
|
13066
|
+
if (!children)
|
|
13067
|
+
return "";
|
|
13068
|
+
const child = Array.isArray(children) ? children[0] : children;
|
|
13069
|
+
if (child && typeof child === "object" && "props" in child) {
|
|
13070
|
+
const codeProps = child.props;
|
|
13071
|
+
if (typeof codeProps.children === "string") {
|
|
13072
|
+
return codeProps.children;
|
|
12948
13073
|
}
|
|
12949
|
-
}
|
|
13074
|
+
}
|
|
13075
|
+
return "";
|
|
13076
|
+
})();
|
|
13077
|
+
return /* @__PURE__ */ jsxs50("div", {
|
|
13078
|
+
className: "relative group/code my-3",
|
|
13079
|
+
children: [
|
|
13080
|
+
/* @__PURE__ */ jsx59("div", {
|
|
13081
|
+
className: "absolute top-2 right-2 opacity-0 group-hover/code:opacity-100 transition-opacity z-10",
|
|
13082
|
+
children: /* @__PURE__ */ jsx59(CopyButton, {
|
|
13083
|
+
text: codeContent,
|
|
13084
|
+
className: "bg-background/80 backdrop-blur-sm border border-border/50 shadow-sm",
|
|
13085
|
+
size: "sm"
|
|
13086
|
+
})
|
|
13087
|
+
}),
|
|
13088
|
+
/* @__PURE__ */ jsx59("pre", {
|
|
13089
|
+
...props,
|
|
13090
|
+
className: "overflow-x-auto",
|
|
13091
|
+
children
|
|
13092
|
+
})
|
|
13093
|
+
]
|
|
13094
|
+
});
|
|
13095
|
+
},
|
|
13096
|
+
table: ({
|
|
13097
|
+
children,
|
|
13098
|
+
...props
|
|
13099
|
+
}) => /* @__PURE__ */ jsx59("div", {
|
|
13100
|
+
className: "overflow-x-auto max-w-full min-w-0 my-3",
|
|
13101
|
+
children: /* @__PURE__ */ jsx59("table", {
|
|
12950
13102
|
...props,
|
|
12951
13103
|
children
|
|
12952
|
-
}),
|
|
12953
|
-
pre: ({
|
|
12954
|
-
children,
|
|
12955
|
-
...props
|
|
12956
|
-
}) => {
|
|
12957
|
-
const codeContent = (() => {
|
|
12958
|
-
if (!children)
|
|
12959
|
-
return "";
|
|
12960
|
-
const child = Array.isArray(children) ? children[0] : children;
|
|
12961
|
-
if (child && typeof child === "object" && "props" in child) {
|
|
12962
|
-
const codeProps = child.props;
|
|
12963
|
-
if (typeof codeProps.children === "string") {
|
|
12964
|
-
return codeProps.children;
|
|
12965
|
-
}
|
|
12966
|
-
}
|
|
12967
|
-
return "";
|
|
12968
|
-
})();
|
|
12969
|
-
return /* @__PURE__ */ jsxs50("div", {
|
|
12970
|
-
className: "relative group/code my-3",
|
|
12971
|
-
children: [
|
|
12972
|
-
/* @__PURE__ */ jsx59("div", {
|
|
12973
|
-
className: "absolute top-2 right-2 opacity-0 group-hover/code:opacity-100 transition-opacity z-10",
|
|
12974
|
-
children: /* @__PURE__ */ jsx59(CopyButton, {
|
|
12975
|
-
text: codeContent,
|
|
12976
|
-
className: "bg-background/80 backdrop-blur-sm border border-border/50 shadow-sm",
|
|
12977
|
-
size: "sm"
|
|
12978
|
-
})
|
|
12979
|
-
}),
|
|
12980
|
-
/* @__PURE__ */ jsx59("pre", {
|
|
12981
|
-
...props,
|
|
12982
|
-
className: "overflow-x-auto",
|
|
12983
|
-
children
|
|
12984
|
-
})
|
|
12985
|
-
]
|
|
12986
|
-
});
|
|
12987
|
-
},
|
|
12988
|
-
table: ({
|
|
12989
|
-
children,
|
|
12990
|
-
...props
|
|
12991
|
-
}) => /* @__PURE__ */ jsx59("div", {
|
|
12992
|
-
className: "overflow-x-auto max-w-full min-w-0 my-3",
|
|
12993
|
-
children: /* @__PURE__ */ jsx59("table", {
|
|
12994
|
-
...props,
|
|
12995
|
-
children
|
|
12996
|
-
})
|
|
12997
13104
|
})
|
|
12998
|
-
}
|
|
12999
|
-
|
|
13000
|
-
|
|
13001
|
-
}),
|
|
13002
|
-
content.length > 500 && /* @__PURE__ */ jsx59("div", {
|
|
13003
|
-
className: "absolute -bottom-1 right-0 opacity-0 group-hover:opacity-100 transition-opacity z-10",
|
|
13004
|
-
children: /* @__PURE__ */ jsx59(CopyButton, {
|
|
13005
|
-
text: content,
|
|
13006
|
-
className: "bg-background/80 backdrop-blur-sm border border-border/50 shadow-sm",
|
|
13007
|
-
size: "md"
|
|
13008
|
-
})
|
|
13105
|
+
})
|
|
13106
|
+
},
|
|
13107
|
+
children: content
|
|
13009
13108
|
})
|
|
13010
|
-
|
|
13109
|
+
})
|
|
13011
13110
|
});
|
|
13012
13111
|
}
|
|
13013
13112
|
if (part.type === "error") {
|
|
@@ -14059,7 +14158,7 @@ function ActionToolBox({ part, showLine, compact }) {
|
|
|
14059
14158
|
},
|
|
14060
14159
|
children: /* @__PURE__ */ jsx61("pre", {
|
|
14061
14160
|
ref: contentMeasureRef,
|
|
14062
|
-
className: "px-1 pt-2.5 pb-1 text-[12px] leading-relaxed text-foreground/60 font-mono whitespace-pre-wrap break-
|
|
14161
|
+
className: "px-1 pt-2.5 pb-1 text-[12px] leading-relaxed text-foreground/60 font-mono whitespace-pre-wrap break-words",
|
|
14063
14162
|
children: displayContent
|
|
14064
14163
|
})
|
|
14065
14164
|
})
|
|
@@ -14123,20 +14222,10 @@ function extractJsonStringField(raw, field) {
|
|
|
14123
14222
|
let result = "";
|
|
14124
14223
|
let i = start;
|
|
14125
14224
|
while (i < raw.length) {
|
|
14126
|
-
|
|
14127
|
-
|
|
14128
|
-
|
|
14129
|
-
|
|
14130
|
-
`;
|
|
14131
|
-
else if (next === "t")
|
|
14132
|
-
result += "\t";
|
|
14133
|
-
else if (next === '"')
|
|
14134
|
-
result += '"';
|
|
14135
|
-
else if (next === "\\")
|
|
14136
|
-
result += "\\";
|
|
14137
|
-
else
|
|
14138
|
-
result += next;
|
|
14139
|
-
i += 2;
|
|
14225
|
+
const decoded = decodeJsonStringChar(raw, i);
|
|
14226
|
+
if (decoded) {
|
|
14227
|
+
result += decoded.value;
|
|
14228
|
+
i = decoded.nextIndex;
|
|
14140
14229
|
} else if (raw[i] === '"') {
|
|
14141
14230
|
break;
|
|
14142
14231
|
} else {
|
|
@@ -14146,6 +14235,38 @@ function extractJsonStringField(raw, field) {
|
|
|
14146
14235
|
}
|
|
14147
14236
|
return result;
|
|
14148
14237
|
}
|
|
14238
|
+
function decodeJsonStringChar(raw, index) {
|
|
14239
|
+
if (raw[index] !== "\\" || index + 1 >= raw.length)
|
|
14240
|
+
return null;
|
|
14241
|
+
const next = raw[index + 1];
|
|
14242
|
+
if (next === "n")
|
|
14243
|
+
return { value: `
|
|
14244
|
+
`, nextIndex: index + 2 };
|
|
14245
|
+
if (next === "t")
|
|
14246
|
+
return { value: "\t", nextIndex: index + 2 };
|
|
14247
|
+
if (next === "r")
|
|
14248
|
+
return { value: "\r", nextIndex: index + 2 };
|
|
14249
|
+
if (next === "b")
|
|
14250
|
+
return { value: "\b", nextIndex: index + 2 };
|
|
14251
|
+
if (next === "f")
|
|
14252
|
+
return { value: "\f", nextIndex: index + 2 };
|
|
14253
|
+
if (next === '"')
|
|
14254
|
+
return { value: '"', nextIndex: index + 2 };
|
|
14255
|
+
if (next === "\\")
|
|
14256
|
+
return { value: "\\", nextIndex: index + 2 };
|
|
14257
|
+
if (next === "/")
|
|
14258
|
+
return { value: "/", nextIndex: index + 2 };
|
|
14259
|
+
if (next === "u" && index + 5 < raw.length) {
|
|
14260
|
+
const hex = raw.slice(index + 2, index + 6);
|
|
14261
|
+
if (/^[0-9a-fA-F]{4}$/.test(hex)) {
|
|
14262
|
+
return {
|
|
14263
|
+
value: String.fromCharCode(Number.parseInt(hex, 16)),
|
|
14264
|
+
nextIndex: index + 6
|
|
14265
|
+
};
|
|
14266
|
+
}
|
|
14267
|
+
}
|
|
14268
|
+
return { value: next, nextIndex: index + 2 };
|
|
14269
|
+
}
|
|
14149
14270
|
function extractJsonStringFieldPreview(raw, field) {
|
|
14150
14271
|
const pattern = new RegExp(`"${field}"\\s*:\\s*"`);
|
|
14151
14272
|
const m = pattern.exec(raw);
|
|
@@ -14155,8 +14276,25 @@ function extractJsonStringFieldPreview(raw, field) {
|
|
|
14155
14276
|
if (raw.length - start <= LIVE_TOOL_CONTENT_PREVIEW_CHARS) {
|
|
14156
14277
|
return extractJsonStringField(raw, field);
|
|
14157
14278
|
}
|
|
14279
|
+
let result = "";
|
|
14280
|
+
let i = start;
|
|
14281
|
+
while (i < raw.length) {
|
|
14282
|
+
const decoded = decodeJsonStringChar(raw, i);
|
|
14283
|
+
if (decoded) {
|
|
14284
|
+
result += decoded.value;
|
|
14285
|
+
i = decoded.nextIndex;
|
|
14286
|
+
} else if (raw[i] === '"') {
|
|
14287
|
+
break;
|
|
14288
|
+
} else {
|
|
14289
|
+
result += raw[i];
|
|
14290
|
+
i += 1;
|
|
14291
|
+
}
|
|
14292
|
+
if (result.length > LIVE_TOOL_CONTENT_PREVIEW_CHARS) {
|
|
14293
|
+
result = result.slice(-LIVE_TOOL_CONTENT_PREVIEW_CHARS);
|
|
14294
|
+
}
|
|
14295
|
+
}
|
|
14158
14296
|
return `… showing latest streamed content only …
|
|
14159
|
-
${
|
|
14297
|
+
${result}`;
|
|
14160
14298
|
}
|
|
14161
14299
|
function getLiveToolContentPreview(toolName, content) {
|
|
14162
14300
|
if (toolName !== "write" && toolName !== "apply_patch" && content.length <= LIVE_TOOL_CONTENT_PREVIEW_CHARS) {
|
|
@@ -15837,21 +15975,23 @@ var UsageModal = memo14(function UsageModal2() {
|
|
|
15837
15975
|
// src/hooks/useProviderUsage.ts
|
|
15838
15976
|
import { useEffect as useEffect23, useCallback as useCallback15, useRef as useRef15 } from "react";
|
|
15839
15977
|
var POLL_INTERVAL = 60000;
|
|
15840
|
-
var STALE_THRESHOLD =
|
|
15978
|
+
var STALE_THRESHOLD = 60000;
|
|
15841
15979
|
var inflight = new Set;
|
|
15842
15980
|
function useProviderUsage(provider, authType) {
|
|
15843
15981
|
const setUsage = useUsageStore((s) => s.setUsage);
|
|
15844
15982
|
const setLoading = useUsageStore((s) => s.setLoading);
|
|
15845
15983
|
const setLastFetched = useUsageStore((s) => s.setLastFetched);
|
|
15984
|
+
const isModalOpen = useUsageStore((s) => s.isModalOpen);
|
|
15985
|
+
const modalProvider = useUsageStore((s) => s.modalProvider);
|
|
15846
15986
|
const usage = useUsageStore((s) => provider ? s.usage[provider] : undefined);
|
|
15847
15987
|
const isOAuthProvider = authType === "oauth" && (provider === "anthropic" || provider === "openai");
|
|
15848
|
-
const fetchUsage = useCallback15(async () => {
|
|
15988
|
+
const fetchUsage = useCallback15(async (force = false) => {
|
|
15849
15989
|
if (!provider || !isOAuthProvider)
|
|
15850
15990
|
return;
|
|
15851
15991
|
if (inflight.has(provider))
|
|
15852
15992
|
return;
|
|
15853
15993
|
const last = useUsageStore.getState().lastFetched[provider] ?? 0;
|
|
15854
|
-
if (last && Date.now() - last < STALE_THRESHOLD)
|
|
15994
|
+
if (!force && last && Date.now() - last < STALE_THRESHOLD)
|
|
15855
15995
|
return;
|
|
15856
15996
|
inflight.add(provider);
|
|
15857
15997
|
setLoading(provider, true);
|
|
@@ -15870,9 +16010,15 @@ function useProviderUsage(provider, authType) {
|
|
|
15870
16010
|
if (!provider || !isOAuthProvider)
|
|
15871
16011
|
return;
|
|
15872
16012
|
fetchRef.current();
|
|
16013
|
+
}, [isOAuthProvider, provider]);
|
|
16014
|
+
useEffect23(() => {
|
|
16015
|
+
if (!provider || !isOAuthProvider || !isModalOpen || modalProvider !== provider) {
|
|
16016
|
+
return;
|
|
16017
|
+
}
|
|
16018
|
+
fetchRef.current(true);
|
|
15873
16019
|
const interval = setInterval(() => fetchRef.current(), POLL_INTERVAL);
|
|
15874
16020
|
return () => clearInterval(interval);
|
|
15875
|
-
}, [isOAuthProvider, provider]);
|
|
16021
|
+
}, [isModalOpen, isOAuthProvider, modalProvider, provider]);
|
|
15876
16022
|
return {
|
|
15877
16023
|
usage,
|
|
15878
16024
|
fetchUsage,
|
|
@@ -17163,22 +17309,30 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
17163
17309
|
return;
|
|
17164
17310
|
let changeLines = 0;
|
|
17165
17311
|
let stableChangeLength = 0;
|
|
17312
|
+
let lineDirectiveCount = 0;
|
|
17166
17313
|
for (const line of stablePatch.split(`
|
|
17167
17314
|
`)) {
|
|
17168
17315
|
if (line.startsWith("+") && !line.startsWith("+++") || line.startsWith("-") && !line.startsWith("---")) {
|
|
17169
17316
|
changeLines += 1;
|
|
17170
17317
|
stableChangeLength += line.length;
|
|
17318
|
+
} else if (/^\*\*\* (?:Delete Lines in|Replace Lines in|Insert Before in|Insert After in): /.test(line) || line.startsWith("*** Lines:") || line.startsWith("*** Line:") || line.startsWith("*** With:")) {
|
|
17319
|
+
lineDirectiveCount += 1;
|
|
17171
17320
|
}
|
|
17172
17321
|
}
|
|
17173
|
-
|
|
17322
|
+
if (changeLines > 0)
|
|
17323
|
+
return `${changeLines}:${stableChangeLength}`;
|
|
17324
|
+
return lineDirectiveCount > 0 ? `lines:${lineDirectiveCount}:${stablePatch.length}` : undefined;
|
|
17174
17325
|
};
|
|
17175
17326
|
const extractPathsFromPatch = (patch) => {
|
|
17176
17327
|
const paths = new Set;
|
|
17177
17328
|
for (const line of patch.split(`
|
|
17178
17329
|
`)) {
|
|
17179
17330
|
const directive = line.match(/^\*\*\* (?:Update|Add|Delete) File: (.+)$/);
|
|
17180
|
-
|
|
17181
|
-
|
|
17331
|
+
const replaceDirective = line.match(/^\*\*\* Replace in: (.+)$/);
|
|
17332
|
+
const lineDirective = line.match(/^\*\*\* (?:Delete Lines in|Replace Lines in|Insert Before in|Insert After in): (.+)$/);
|
|
17333
|
+
const path = directive?.[1] ?? replaceDirective?.[1] ?? lineDirective?.[1];
|
|
17334
|
+
if (path) {
|
|
17335
|
+
paths.add(path.trim());
|
|
17182
17336
|
continue;
|
|
17183
17337
|
}
|
|
17184
17338
|
const unified = line.match(/^\+\+\+ (?:b\/)?(.+)$/);
|
|
@@ -17188,6 +17342,47 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
17188
17342
|
}
|
|
17189
17343
|
return [...paths];
|
|
17190
17344
|
};
|
|
17345
|
+
const getExtension = (path) => path.split(".").pop()?.toLowerCase() ?? "";
|
|
17346
|
+
const updateFileContentCache = (path, content) => {
|
|
17347
|
+
queryClient.setQueryData(["files", "read", path], {
|
|
17348
|
+
content,
|
|
17349
|
+
path,
|
|
17350
|
+
extension: getExtension(path),
|
|
17351
|
+
lineCount: content.split(`
|
|
17352
|
+
`).length
|
|
17353
|
+
});
|
|
17354
|
+
};
|
|
17355
|
+
const mergeReadResultIntoFileCache = (path, result, startLine, endLine) => {
|
|
17356
|
+
if (typeof result?.content !== "string")
|
|
17357
|
+
return;
|
|
17358
|
+
const readContent = result.content;
|
|
17359
|
+
if (!startLine || !endLine) {
|
|
17360
|
+
updateFileContentCache(path, readContent);
|
|
17361
|
+
return;
|
|
17362
|
+
}
|
|
17363
|
+
queryClient.setQueryData(["files", "read", path], (current) => {
|
|
17364
|
+
if (!current?.content)
|
|
17365
|
+
return current;
|
|
17366
|
+
const lines = current.content.split(`
|
|
17367
|
+
`);
|
|
17368
|
+
if (lines.at(-1) === "")
|
|
17369
|
+
lines.pop();
|
|
17370
|
+
const readLines = readContent.split(`
|
|
17371
|
+
`);
|
|
17372
|
+
lines.splice(startLine - 1, endLine - startLine + 1, ...readLines);
|
|
17373
|
+
const content = `${lines.join(`
|
|
17374
|
+
`)}
|
|
17375
|
+
`;
|
|
17376
|
+
return {
|
|
17377
|
+
...current,
|
|
17378
|
+
content,
|
|
17379
|
+
lineCount: typeof result.totalLines === "number" ? result.totalLines : lines.length
|
|
17380
|
+
};
|
|
17381
|
+
});
|
|
17382
|
+
};
|
|
17383
|
+
const invalidateFileContentCache = (path) => {
|
|
17384
|
+
queryClient.invalidateQueries({ queryKey: ["files", "read", path] });
|
|
17385
|
+
};
|
|
17191
17386
|
const getChangedLinesForPath = (result, path) => {
|
|
17192
17387
|
const changes = Array.isArray(result?.changes) ? result.changes : [];
|
|
17193
17388
|
const lines = new Set;
|
|
@@ -17217,9 +17412,6 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
17217
17412
|
return lines.size > 0 ? [...lines] : undefined;
|
|
17218
17413
|
};
|
|
17219
17414
|
const handleReadToolActivity = (eventType, payload, delta) => {
|
|
17220
|
-
const viewerStore = useViewerTabsStore.getState();
|
|
17221
|
-
if (!viewerStore.followToolActivity)
|
|
17222
|
-
return;
|
|
17223
17415
|
const name = getToolEventName(payload);
|
|
17224
17416
|
if (name !== "read")
|
|
17225
17417
|
return;
|
|
@@ -17232,6 +17424,12 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
17232
17424
|
const startLine = normalizeLineNumber(args.startLine) ?? normalizeLineNumber(args.start_line) ?? rangeFromResult.startLine;
|
|
17233
17425
|
const endLine = normalizeLineNumber(args.endLine) ?? normalizeLineNumber(args.end_line) ?? rangeFromResult.endLine ?? startLine;
|
|
17234
17426
|
const failed = result?.ok === false || eventType === "error";
|
|
17427
|
+
if (eventType === "tool.result" && !failed) {
|
|
17428
|
+
mergeReadResultIntoFileCache(path, result, startLine, endLine);
|
|
17429
|
+
}
|
|
17430
|
+
const viewerStore = useViewerTabsStore.getState();
|
|
17431
|
+
if (!viewerStore.followToolActivity)
|
|
17432
|
+
return;
|
|
17235
17433
|
viewerStore.openToolReadTab(path, {
|
|
17236
17434
|
startLine,
|
|
17237
17435
|
endLine,
|
|
@@ -17241,9 +17439,6 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
17241
17439
|
});
|
|
17242
17440
|
};
|
|
17243
17441
|
const handleWriteToolActivity = (eventType, payload, delta) => {
|
|
17244
|
-
const viewerStore = useViewerTabsStore.getState();
|
|
17245
|
-
if (!viewerStore.followToolActivity)
|
|
17246
|
-
return;
|
|
17247
17442
|
const name = getToolEventName(payload);
|
|
17248
17443
|
if (name !== "write")
|
|
17249
17444
|
return;
|
|
@@ -17257,6 +17452,15 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
17257
17452
|
const callId = getToolEventCallId(payload) ?? undefined;
|
|
17258
17453
|
const status = failed ? "error" : eventType === "tool.result" ? "success" : "streaming";
|
|
17259
17454
|
const content = status === "streaming" ? getStreamingWritePreviewContent(args, buffer) : getStringArg(args, buffer, "content");
|
|
17455
|
+
if (status === "success") {
|
|
17456
|
+
if (content !== undefined)
|
|
17457
|
+
updateFileContentCache(path, content);
|
|
17458
|
+
else
|
|
17459
|
+
invalidateFileContentCache(path);
|
|
17460
|
+
}
|
|
17461
|
+
const viewerStore = useViewerTabsStore.getState();
|
|
17462
|
+
if (!viewerStore.followToolActivity)
|
|
17463
|
+
return;
|
|
17260
17464
|
if (status === "streaming" && content !== undefined && content.length >= TOOL_PREVIEW_THROTTLE_MIN_CHARS) {
|
|
17261
17465
|
const previewKey = callId ?? path;
|
|
17262
17466
|
const now = Date.now();
|
|
@@ -17280,9 +17484,6 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
17280
17484
|
});
|
|
17281
17485
|
};
|
|
17282
17486
|
const handleApplyPatchToolActivity = (eventType, payload, delta) => {
|
|
17283
|
-
const viewerStore = useViewerTabsStore.getState();
|
|
17284
|
-
if (!viewerStore.followToolActivity)
|
|
17285
|
-
return;
|
|
17286
17487
|
const name = getToolEventName(payload);
|
|
17287
17488
|
if (name !== "apply_patch")
|
|
17288
17489
|
return;
|
|
@@ -17306,6 +17507,13 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
17306
17507
|
const patchPaths = extractPathsFromPatch(patch);
|
|
17307
17508
|
if (patchPaths.length === 0)
|
|
17308
17509
|
return;
|
|
17510
|
+
if (status === "success") {
|
|
17511
|
+
for (const path of patchPaths)
|
|
17512
|
+
invalidateFileContentCache(path);
|
|
17513
|
+
}
|
|
17514
|
+
const viewerStore = useViewerTabsStore.getState();
|
|
17515
|
+
if (!viewerStore.followToolActivity)
|
|
17516
|
+
return;
|
|
17309
17517
|
const matchingFileTabs = viewerStore.tabs.filter((tab) => tab.type === "file" && patchPaths.some((path) => patchPathMayReferToTarget(path, tab.path)));
|
|
17310
17518
|
const activeMatchingFileTab = matchingFileTabs.find((tab) => tab.id === viewerStore.activeTabId);
|
|
17311
17519
|
const fallbackPath = patchPaths.find(isLikelyCompletePatchPath);
|
|
@@ -17411,6 +17619,11 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
17411
17619
|
const applyMessageDelta = (payload) => {
|
|
17412
17620
|
const messageId = typeof payload?.messageId === "string" ? payload.messageId : null;
|
|
17413
17621
|
const partId = typeof payload?.partId === "string" ? payload.partId : null;
|
|
17622
|
+
const payloadType = typeof payload?.type === "string" ? payload.type : undefined;
|
|
17623
|
+
if (payloadType === "error") {
|
|
17624
|
+
upsertErrorPart(payload);
|
|
17625
|
+
return;
|
|
17626
|
+
}
|
|
17414
17627
|
const delta = typeof payload?.delta === "string" ? payload.delta : null;
|
|
17415
17628
|
if (!messageId || !partId || delta === null)
|
|
17416
17629
|
return;
|
|
@@ -17461,6 +17674,90 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
17461
17674
|
return nextMessages;
|
|
17462
17675
|
});
|
|
17463
17676
|
};
|
|
17677
|
+
const toRecord = (value) => {
|
|
17678
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
17679
|
+
return value;
|
|
17680
|
+
}
|
|
17681
|
+
return null;
|
|
17682
|
+
};
|
|
17683
|
+
const parseErrorContent = (payload) => {
|
|
17684
|
+
const contentRecord = toRecord(payload.content);
|
|
17685
|
+
if (contentRecord)
|
|
17686
|
+
return contentRecord;
|
|
17687
|
+
if (typeof payload.content === "string") {
|
|
17688
|
+
try {
|
|
17689
|
+
const parsed = JSON.parse(payload.content);
|
|
17690
|
+
const parsedRecord = toRecord(parsed);
|
|
17691
|
+
if (parsedRecord)
|
|
17692
|
+
return parsedRecord;
|
|
17693
|
+
} catch {}
|
|
17694
|
+
}
|
|
17695
|
+
const message = typeof payload.error === "string" ? payload.error : typeof payload.message === "string" ? payload.message : "Assistant run failed";
|
|
17696
|
+
return {
|
|
17697
|
+
message,
|
|
17698
|
+
type: typeof payload.errorType === "string" ? payload.errorType : "error",
|
|
17699
|
+
details: toRecord(payload.details) ?? undefined,
|
|
17700
|
+
isAborted: payload.isAborted === true,
|
|
17701
|
+
autoCompacted: payload.autoCompacted === true
|
|
17702
|
+
};
|
|
17703
|
+
};
|
|
17704
|
+
const upsertErrorPart = (payload) => {
|
|
17705
|
+
const messageId = typeof payload?.messageId === "string" ? payload.messageId : null;
|
|
17706
|
+
if (!payload || !messageId)
|
|
17707
|
+
return;
|
|
17708
|
+
const contentJson = parseErrorContent(payload);
|
|
17709
|
+
const content = JSON.stringify(contentJson);
|
|
17710
|
+
const errorMessage = typeof contentJson.message === "string" ? contentJson.message : typeof payload.error === "string" ? payload.error : "Assistant run failed";
|
|
17711
|
+
const stepIndex = typeof payload.stepIndex === "number" ? payload.stepIndex : null;
|
|
17712
|
+
const partId = typeof payload.partId === "string" ? payload.partId : `error-${messageId}`;
|
|
17713
|
+
queryClient.setQueryData(["messages", sessionId], (oldMessages) => {
|
|
17714
|
+
if (!oldMessages)
|
|
17715
|
+
return oldMessages;
|
|
17716
|
+
const nextMessages = [...oldMessages];
|
|
17717
|
+
const messageIndex = nextMessages.findIndex((message) => message.id === messageId);
|
|
17718
|
+
if (messageIndex === -1)
|
|
17719
|
+
return oldMessages;
|
|
17720
|
+
const targetMessage = nextMessages[messageIndex];
|
|
17721
|
+
const parts = targetMessage.parts ? [...targetMessage.parts] : [];
|
|
17722
|
+
const partIndex = parts.findIndex((part) => part.id === partId);
|
|
17723
|
+
if (partIndex === -1) {
|
|
17724
|
+
const newPart = {
|
|
17725
|
+
id: partId,
|
|
17726
|
+
messageId,
|
|
17727
|
+
index: getOptimisticPartIndex(parts, stepIndex),
|
|
17728
|
+
stepIndex,
|
|
17729
|
+
type: "error",
|
|
17730
|
+
content,
|
|
17731
|
+
contentJson,
|
|
17732
|
+
agent: targetMessage.agent,
|
|
17733
|
+
provider: targetMessage.provider,
|
|
17734
|
+
model: targetMessage.model,
|
|
17735
|
+
startedAt: Date.now(),
|
|
17736
|
+
completedAt: Date.now(),
|
|
17737
|
+
toolName: null,
|
|
17738
|
+
toolCallId: null,
|
|
17739
|
+
toolDurationMs: null
|
|
17740
|
+
};
|
|
17741
|
+
parts.push(newPart);
|
|
17742
|
+
} else {
|
|
17743
|
+
parts[partIndex] = {
|
|
17744
|
+
...parts[partIndex],
|
|
17745
|
+
content,
|
|
17746
|
+
contentJson,
|
|
17747
|
+
stepIndex: stepIndex ?? parts[partIndex].stepIndex ?? null,
|
|
17748
|
+
completedAt: Date.now()
|
|
17749
|
+
};
|
|
17750
|
+
}
|
|
17751
|
+
nextMessages[messageIndex] = {
|
|
17752
|
+
...targetMessage,
|
|
17753
|
+
status: "error",
|
|
17754
|
+
completedAt: targetMessage.completedAt ?? Date.now(),
|
|
17755
|
+
error: errorMessage,
|
|
17756
|
+
parts
|
|
17757
|
+
};
|
|
17758
|
+
return nextMessages;
|
|
17759
|
+
});
|
|
17760
|
+
};
|
|
17464
17761
|
const upsertEphemeralToolCall = (payload) => {
|
|
17465
17762
|
if (!payload)
|
|
17466
17763
|
return;
|
|
@@ -17890,6 +18187,17 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
17890
18187
|
}
|
|
17891
18188
|
markMessageCompleted(payload);
|
|
17892
18189
|
clearEphemeralForMessage(id);
|
|
18190
|
+
if (id) {
|
|
18191
|
+
queryClient.setQueryData(["queueState", sessionId], (current) => {
|
|
18192
|
+
if (!current || current.currentMessageId !== id)
|
|
18193
|
+
return current;
|
|
18194
|
+
return normalizeQueueState({
|
|
18195
|
+
currentMessageId: null,
|
|
18196
|
+
queuedMessages: [],
|
|
18197
|
+
isRunning: false
|
|
18198
|
+
});
|
|
18199
|
+
});
|
|
18200
|
+
}
|
|
17893
18201
|
queryClient.invalidateQueries({ queryKey: ["messages", sessionId] });
|
|
17894
18202
|
queryClient.invalidateQueries({ queryKey: sessionsQueryKey });
|
|
17895
18203
|
break;
|
|
@@ -17963,22 +18271,7 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
17963
18271
|
assistantMessageIdRef.current = null;
|
|
17964
18272
|
}
|
|
17965
18273
|
clearEphemeralForMessage(messageId);
|
|
17966
|
-
|
|
17967
|
-
queryClient.setQueryData(["messages", sessionId], (oldMessages) => {
|
|
17968
|
-
if (!oldMessages)
|
|
17969
|
-
return oldMessages;
|
|
17970
|
-
const idx = oldMessages.findIndex((m) => m.id === messageId);
|
|
17971
|
-
if (idx === -1)
|
|
17972
|
-
return oldMessages;
|
|
17973
|
-
const next = [...oldMessages];
|
|
17974
|
-
next[idx] = {
|
|
17975
|
-
...next[idx],
|
|
17976
|
-
status: "error",
|
|
17977
|
-
completedAt: next[idx].completedAt ?? Date.now(),
|
|
17978
|
-
error: errorMessage
|
|
17979
|
-
};
|
|
17980
|
-
return next;
|
|
17981
|
-
});
|
|
18274
|
+
upsertErrorPart(payload);
|
|
17982
18275
|
}
|
|
17983
18276
|
queryClient.invalidateQueries({ queryKey: ["messages", sessionId] });
|
|
17984
18277
|
break;
|
|
@@ -18013,11 +18306,11 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
18013
18306
|
break;
|
|
18014
18307
|
}
|
|
18015
18308
|
case "queue.updated": {
|
|
18016
|
-
const queueState = {
|
|
18309
|
+
const queueState = normalizeQueueState({
|
|
18017
18310
|
currentMessageId: payload?.currentMessageId,
|
|
18018
18311
|
queuedMessages: payload?.queuedMessages ?? [],
|
|
18019
|
-
|
|
18020
|
-
};
|
|
18312
|
+
isRunning: typeof payload?.isRunning === "boolean" ? payload.isRunning : undefined
|
|
18313
|
+
});
|
|
18021
18314
|
queryClient.setQueryData(["queueState", sessionId], queueState);
|
|
18022
18315
|
break;
|
|
18023
18316
|
}
|
|
@@ -19579,7 +19872,7 @@ var syntaxTheme = HighlightStyle.define([
|
|
|
19579
19872
|
{ tag: tags.invalid, color: "var(--otto-cm-invalid)" }
|
|
19580
19873
|
]);
|
|
19581
19874
|
function lineDecorationsExtension(highlightedLines, highlightTone = "primary", lineTones) {
|
|
19582
|
-
return EditorView.decorations.compute([], (state) => {
|
|
19875
|
+
return EditorView.decorations.compute(["doc"], (state) => {
|
|
19583
19876
|
const decorations = [];
|
|
19584
19877
|
for (const [line, tone] of lineTones ?? []) {
|
|
19585
19878
|
if (line > 0)
|
|
@@ -27412,6 +27705,35 @@ function getStablePatchLines(patch) {
|
|
|
27412
27705
|
lines.pop();
|
|
27413
27706
|
return lines;
|
|
27414
27707
|
}
|
|
27708
|
+
function getEnvelopedPatchPath(line) {
|
|
27709
|
+
const directive = line.match(/^\*\*\* (?:Update|Add|Delete) File: (.+)$/);
|
|
27710
|
+
const replaceDirective = line.match(/^\*\*\* Replace in: (.+)$/);
|
|
27711
|
+
const lineDirective = line.match(/^\*\*\* (?:Delete Lines in|Replace Lines in|Insert Before in|Insert After in): (.+)$/);
|
|
27712
|
+
return directive?.[1] ?? replaceDirective?.[1] ?? lineDirective?.[1];
|
|
27713
|
+
}
|
|
27714
|
+
function parsePatchLineNumber(value) {
|
|
27715
|
+
const trimmed = value.trim();
|
|
27716
|
+
if (!/^\d+$/.test(trimmed))
|
|
27717
|
+
return;
|
|
27718
|
+
const line = Number.parseInt(trimmed, 10);
|
|
27719
|
+
return line > 0 ? line : undefined;
|
|
27720
|
+
}
|
|
27721
|
+
function parsePatchLineRange(value) {
|
|
27722
|
+
const match = /^(\d+)(?:\s*-\s*(\d+|end|eof|\$))?$/i.exec(value.trim());
|
|
27723
|
+
if (!match)
|
|
27724
|
+
return;
|
|
27725
|
+
const startLine = parsePatchLineNumber(match[1]);
|
|
27726
|
+
if (!startLine)
|
|
27727
|
+
return;
|
|
27728
|
+
if (!match[2])
|
|
27729
|
+
return { startLine, endLine: startLine };
|
|
27730
|
+
const endLine = /^(end|eof|\$)$/i.test(match[2]) ? "end" : parsePatchLineNumber(match[2]);
|
|
27731
|
+
if (!endLine)
|
|
27732
|
+
return;
|
|
27733
|
+
if (typeof endLine === "number" && endLine < startLine)
|
|
27734
|
+
return;
|
|
27735
|
+
return { startLine, endLine };
|
|
27736
|
+
}
|
|
27415
27737
|
function getPatchLineHighlights(patch, targetPath, fallbackLines) {
|
|
27416
27738
|
const highlighted = new Set(fallbackLines ?? []);
|
|
27417
27739
|
if (!patch)
|
|
@@ -27427,9 +27749,9 @@ function getPatchLineHighlights(patch, targetPath, fallbackLines) {
|
|
|
27427
27749
|
let inHunk = false;
|
|
27428
27750
|
let newLine = 0;
|
|
27429
27751
|
for (const line of getStablePatchLines(patch)) {
|
|
27430
|
-
const
|
|
27431
|
-
if (
|
|
27432
|
-
activeFile = patchPathMatches(
|
|
27752
|
+
const directivePath = getEnvelopedPatchPath(line);
|
|
27753
|
+
if (directivePath) {
|
|
27754
|
+
activeFile = patchPathMatches(directivePath, targetPath);
|
|
27433
27755
|
sawFileDirective = true;
|
|
27434
27756
|
inHunk = false;
|
|
27435
27757
|
newLine = 0;
|
|
@@ -27523,10 +27845,10 @@ function collectEnvelopedPatchHunks(patch, targetPath) {
|
|
|
27523
27845
|
current = [];
|
|
27524
27846
|
};
|
|
27525
27847
|
for (const line of getStablePatchLines(patch)) {
|
|
27526
|
-
const
|
|
27527
|
-
if (
|
|
27848
|
+
const directivePath = getEnvelopedPatchPath(line);
|
|
27849
|
+
if (directivePath) {
|
|
27528
27850
|
flush();
|
|
27529
|
-
activeFile = patchPathMatches(
|
|
27851
|
+
activeFile = patchPathMatches(directivePath, targetPath);
|
|
27530
27852
|
sawFileDirective = true;
|
|
27531
27853
|
inHunk = activeFile;
|
|
27532
27854
|
continue;
|
|
@@ -27615,9 +27937,152 @@ function buildEnvelopedPatchPreview(content, patch, targetPath) {
|
|
|
27615
27937
|
latestLine: changedLines.length > 0 ? Math.max(...changedLines) : undefined
|
|
27616
27938
|
};
|
|
27617
27939
|
}
|
|
27940
|
+
function collectLineNumberPatchOperations(patch, targetPath) {
|
|
27941
|
+
const operations = [];
|
|
27942
|
+
let current = null;
|
|
27943
|
+
let activeFile = false;
|
|
27944
|
+
let phase = "directives";
|
|
27945
|
+
const flush = () => {
|
|
27946
|
+
if (current && activeFile)
|
|
27947
|
+
operations.push(current);
|
|
27948
|
+
current = null;
|
|
27949
|
+
phase = "directives";
|
|
27950
|
+
};
|
|
27951
|
+
for (const line of getStablePatchLines(patch)) {
|
|
27952
|
+
const directive = line.match(/^\*\*\* (Delete Lines in|Replace Lines in|Insert Before in|Insert After in): (.+)$/);
|
|
27953
|
+
if (directive?.[1] && directive[2]) {
|
|
27954
|
+
flush();
|
|
27955
|
+
activeFile = patchPathMatches(directive[2], targetPath);
|
|
27956
|
+
if (directive[1] === "Delete Lines in") {
|
|
27957
|
+
current = { kind: "delete", filePath: directive[2], lines: [] };
|
|
27958
|
+
} else if (directive[1] === "Replace Lines in") {
|
|
27959
|
+
current = { kind: "replace", filePath: directive[2], lines: [] };
|
|
27960
|
+
} else {
|
|
27961
|
+
current = {
|
|
27962
|
+
kind: "insert",
|
|
27963
|
+
filePath: directive[2],
|
|
27964
|
+
position: directive[1] === "Insert Before in" ? "before" : "after",
|
|
27965
|
+
lines: []
|
|
27966
|
+
};
|
|
27967
|
+
}
|
|
27968
|
+
continue;
|
|
27969
|
+
}
|
|
27970
|
+
if (!current)
|
|
27971
|
+
continue;
|
|
27972
|
+
if (line.startsWith("*** End Patch")) {
|
|
27973
|
+
flush();
|
|
27974
|
+
continue;
|
|
27975
|
+
}
|
|
27976
|
+
if (line.startsWith("*** Begin Patch"))
|
|
27977
|
+
continue;
|
|
27978
|
+
if (phase === "with") {
|
|
27979
|
+
current.lines.push(line);
|
|
27980
|
+
continue;
|
|
27981
|
+
}
|
|
27982
|
+
if (line.startsWith("*** Lines:") && current.kind !== "insert") {
|
|
27983
|
+
const range = parsePatchLineRange(line.slice("*** Lines:".length));
|
|
27984
|
+
if (range) {
|
|
27985
|
+
current.startLine = range.startLine;
|
|
27986
|
+
current.endLine = range.endLine;
|
|
27987
|
+
}
|
|
27988
|
+
continue;
|
|
27989
|
+
}
|
|
27990
|
+
if (line.startsWith("*** Line:") && current.kind === "insert") {
|
|
27991
|
+
current.line = parsePatchLineNumber(line.slice("*** Line:".length));
|
|
27992
|
+
continue;
|
|
27993
|
+
}
|
|
27994
|
+
if (line.startsWith("*** With:")) {
|
|
27995
|
+
phase = "with";
|
|
27996
|
+
}
|
|
27997
|
+
}
|
|
27998
|
+
flush();
|
|
27999
|
+
return operations;
|
|
28000
|
+
}
|
|
28001
|
+
function getCurrentRecordPosition(records, currentIndex) {
|
|
28002
|
+
let seen = 0;
|
|
28003
|
+
for (let index = 0;index < records.length; index += 1) {
|
|
28004
|
+
if (records[index].removed)
|
|
28005
|
+
continue;
|
|
28006
|
+
if (seen === currentIndex)
|
|
28007
|
+
return index;
|
|
28008
|
+
seen += 1;
|
|
28009
|
+
}
|
|
28010
|
+
return records.length;
|
|
28011
|
+
}
|
|
28012
|
+
function buildLineNumberPatchPreview(content, patch, targetPath) {
|
|
28013
|
+
const operations = collectLineNumberPatchOperations(patch, targetPath);
|
|
28014
|
+
if (operations.length === 0)
|
|
28015
|
+
return null;
|
|
28016
|
+
const contentLines = content.split(`
|
|
28017
|
+
`);
|
|
28018
|
+
if (contentLines.at(-1) === "")
|
|
28019
|
+
contentLines.pop();
|
|
28020
|
+
const records = contentLines.map((line) => ({
|
|
28021
|
+
text: line
|
|
28022
|
+
}));
|
|
28023
|
+
for (const operation of operations) {
|
|
28024
|
+
const currentLines = records.filter((record) => !record.removed);
|
|
28025
|
+
if (operation.kind === "insert") {
|
|
28026
|
+
if (!operation.line)
|
|
28027
|
+
continue;
|
|
28028
|
+
const insertIndex = operation.position === "before" ? operation.line - 1 : operation.line;
|
|
28029
|
+
if (insertIndex < 0 || insertIndex > currentLines.length)
|
|
28030
|
+
continue;
|
|
28031
|
+
const recordIndex2 = getCurrentRecordPosition(records, insertIndex);
|
|
28032
|
+
records.splice(recordIndex2, 0, ...operation.lines.map((line) => ({
|
|
28033
|
+
text: line,
|
|
28034
|
+
tone: "add"
|
|
28035
|
+
})));
|
|
28036
|
+
continue;
|
|
28037
|
+
}
|
|
28038
|
+
if (!operation.startLine || !operation.endLine)
|
|
28039
|
+
continue;
|
|
28040
|
+
const endLine = operation.endLine === "end" ? currentLines.length : operation.endLine;
|
|
28041
|
+
if (operation.startLine > currentLines.length || endLine > currentLines.length)
|
|
28042
|
+
continue;
|
|
28043
|
+
const startIndex = operation.startLine - 1;
|
|
28044
|
+
const endIndex = endLine - 1;
|
|
28045
|
+
const recordIndex = getCurrentRecordPosition(records, startIndex);
|
|
28046
|
+
for (let index = startIndex;index <= endIndex; index += 1) {
|
|
28047
|
+
const position = getCurrentRecordPosition(records, startIndex);
|
|
28048
|
+
if (!records[position])
|
|
28049
|
+
continue;
|
|
28050
|
+
records[position].tone = "remove";
|
|
28051
|
+
records[position].removed = true;
|
|
28052
|
+
}
|
|
28053
|
+
if (operation.kind === "replace") {
|
|
28054
|
+
records.splice(recordIndex, 0, ...operation.lines.map((line) => ({
|
|
28055
|
+
text: line,
|
|
28056
|
+
tone: "add"
|
|
28057
|
+
})));
|
|
28058
|
+
}
|
|
28059
|
+
}
|
|
28060
|
+
const lineTones = new Map;
|
|
28061
|
+
const renderedLines = records.map((record, index) => {
|
|
28062
|
+
if (record.tone)
|
|
28063
|
+
lineTones.set(index + 1, record.tone);
|
|
28064
|
+
return record.text;
|
|
28065
|
+
});
|
|
28066
|
+
if (lineTones.size === 0)
|
|
28067
|
+
return null;
|
|
28068
|
+
const resultLines = records.filter((record) => !record.removed).map((record) => record.text);
|
|
28069
|
+
const changedLines = [...lineTones.keys()];
|
|
28070
|
+
return {
|
|
28071
|
+
content: renderedLines.join(`
|
|
28072
|
+
`),
|
|
28073
|
+
resultContent: resultLines.join(`
|
|
28074
|
+
`),
|
|
28075
|
+
lineTones,
|
|
28076
|
+
firstLine: Math.min(...changedLines),
|
|
28077
|
+
latestLine: Math.max(...changedLines)
|
|
28078
|
+
};
|
|
28079
|
+
}
|
|
27618
28080
|
function buildLivePatchPreview(content, patch, targetPath) {
|
|
27619
28081
|
if (!patch)
|
|
27620
28082
|
return null;
|
|
28083
|
+
const lineNumberPreview = buildLineNumberPatchPreview(content, patch, targetPath);
|
|
28084
|
+
if (lineNumberPreview)
|
|
28085
|
+
return lineNumberPreview;
|
|
27621
28086
|
const insertions = new Map;
|
|
27622
28087
|
const removals = new Set;
|
|
27623
28088
|
let activeFile = false;
|
|
@@ -27885,26 +28350,6 @@ function ToolPreviewPanel({ tab }) {
|
|
|
27885
28350
|
return /* @__PURE__ */ jsxs96("div", {
|
|
27886
28351
|
className: "h-full w-full bg-transparent flex flex-col",
|
|
27887
28352
|
children: [
|
|
27888
|
-
/* @__PURE__ */ jsxs96("div", {
|
|
27889
|
-
className: "shrink-0 border-b border-sidebar-border bg-sidebar-accent/30 px-3 py-1.5 text-[12px] text-muted-foreground flex items-center gap-2",
|
|
27890
|
-
children: [
|
|
27891
|
-
/* @__PURE__ */ jsx109(StatusIcon, {
|
|
27892
|
-
status: tab.status
|
|
27893
|
-
}),
|
|
27894
|
-
/* @__PURE__ */ jsx109("span", {
|
|
27895
|
-
children: statusLabel
|
|
27896
|
-
}),
|
|
27897
|
-
/* @__PURE__ */ jsx109("span", {
|
|
27898
|
-
className: "text-muted-foreground/60",
|
|
27899
|
-
children: "·"
|
|
27900
|
-
}),
|
|
27901
|
-
/* @__PURE__ */ jsx109("span", {
|
|
27902
|
-
className: "font-mono truncate",
|
|
27903
|
-
title: tab.path,
|
|
27904
|
-
children: tab.path
|
|
27905
|
-
})
|
|
27906
|
-
]
|
|
27907
|
-
}),
|
|
27908
28353
|
tab.error && /* @__PURE__ */ jsx109("div", {
|
|
27909
28354
|
className: "shrink-0 border-b border-red-500/20 bg-red-500/10 px-3 py-2 text-[12px] text-red-700 dark:text-red-300",
|
|
27910
28355
|
children: tab.error
|
|
@@ -27952,6 +28397,26 @@ function ToolPreviewPanel({ tab }) {
|
|
|
27952
28397
|
className: "h-full flex items-center justify-center text-sm text-muted-foreground",
|
|
27953
28398
|
children: "Waiting for write content..."
|
|
27954
28399
|
})
|
|
28400
|
+
}),
|
|
28401
|
+
/* @__PURE__ */ jsxs96("div", {
|
|
28402
|
+
className: "shrink-0 border-t border-sidebar-border bg-sidebar-accent/30 px-3 py-1.5 text-[12px] text-muted-foreground flex items-center gap-2",
|
|
28403
|
+
children: [
|
|
28404
|
+
/* @__PURE__ */ jsx109(StatusIcon, {
|
|
28405
|
+
status: tab.status
|
|
28406
|
+
}),
|
|
28407
|
+
/* @__PURE__ */ jsx109("span", {
|
|
28408
|
+
children: statusLabel
|
|
28409
|
+
}),
|
|
28410
|
+
/* @__PURE__ */ jsx109("span", {
|
|
28411
|
+
className: "text-muted-foreground/60",
|
|
28412
|
+
children: "·"
|
|
28413
|
+
}),
|
|
28414
|
+
/* @__PURE__ */ jsx109("span", {
|
|
28415
|
+
className: "font-mono truncate",
|
|
28416
|
+
title: tab.path,
|
|
28417
|
+
children: tab.path
|
|
28418
|
+
})
|
|
28419
|
+
]
|
|
27955
28420
|
})
|
|
27956
28421
|
]
|
|
27957
28422
|
});
|
|
@@ -28061,6 +28526,7 @@ var FileViewerPanel = memo47(function FileViewerPanel2({
|
|
|
28061
28526
|
open,
|
|
28062
28527
|
file,
|
|
28063
28528
|
highlight,
|
|
28529
|
+
annotations,
|
|
28064
28530
|
patchPreview,
|
|
28065
28531
|
writePreview,
|
|
28066
28532
|
onClose
|
|
@@ -28139,6 +28605,28 @@ var FileViewerPanel = memo47(function FileViewerPanel2({
|
|
|
28139
28605
|
const highlightStart = effectiveHighlight?.startLine;
|
|
28140
28606
|
const highlightEnd = effectiveHighlight?.endLine ?? highlightStart;
|
|
28141
28607
|
const patchChangedLines = patchPreview?.changedLines;
|
|
28608
|
+
const persistentLineTones = useMemo29(() => {
|
|
28609
|
+
if (!annotations?.length)
|
|
28610
|
+
return;
|
|
28611
|
+
const tones = new Map;
|
|
28612
|
+
for (const annotation of annotations) {
|
|
28613
|
+
for (const [line, tone] of annotation.lineTones) {
|
|
28614
|
+
if (line > 0)
|
|
28615
|
+
tones.set(line, tone);
|
|
28616
|
+
}
|
|
28617
|
+
}
|
|
28618
|
+
return tones.size > 0 ? tones : undefined;
|
|
28619
|
+
}, [annotations]);
|
|
28620
|
+
const writePreviewLineTones = useMemo29(() => {
|
|
28621
|
+
if (writePreview?.content === undefined)
|
|
28622
|
+
return;
|
|
28623
|
+
const tones = new Map;
|
|
28624
|
+
const lineCount = writePreview.content.length === 0 ? 1 : writePreview.content.split(`
|
|
28625
|
+
`).length;
|
|
28626
|
+
for (let line = 1;line <= lineCount; line += 1)
|
|
28627
|
+
tones.set(line, "add");
|
|
28628
|
+
return tones;
|
|
28629
|
+
}, [writePreview?.content]);
|
|
28142
28630
|
const highlightedLines = useMemo29(() => {
|
|
28143
28631
|
if (highlightStart && highlightEnd) {
|
|
28144
28632
|
return new Set(Array.from({ length: highlightEnd - highlightStart + 1 }, (_, index) => highlightStart + index));
|
|
@@ -28152,18 +28640,21 @@ var FileViewerPanel = memo47(function FileViewerPanel2({
|
|
|
28152
28640
|
const scrollToHighlightLine = highlightStart ?? fallbackPatchHighlightStart;
|
|
28153
28641
|
const activePatchLineTones = useMemo29(() => {
|
|
28154
28642
|
if (!activePatchPreview)
|
|
28155
|
-
return;
|
|
28156
|
-
const tones = new Map(
|
|
28643
|
+
return persistentLineTones;
|
|
28644
|
+
const tones = new Map(persistentLineTones);
|
|
28645
|
+
for (const [line, tone] of activePatchPreview.lineTones) {
|
|
28646
|
+
tones.set(line, tone);
|
|
28647
|
+
}
|
|
28157
28648
|
for (const line of patchChangedLines ?? []) {
|
|
28158
28649
|
if (!tones.has(line))
|
|
28159
28650
|
tones.set(line, "add");
|
|
28160
28651
|
}
|
|
28161
28652
|
return tones;
|
|
28162
|
-
}, [activePatchPreview, patchChangedLines]);
|
|
28653
|
+
}, [activePatchPreview, patchChangedLines, persistentLineTones]);
|
|
28163
28654
|
if (!isViewerOpen || !selectedFile)
|
|
28164
28655
|
return null;
|
|
28165
28656
|
const language = inferLanguage(selectedFile);
|
|
28166
|
-
const renderMarkdown = isMarkdownFile(selectedFile) && !effectiveHighlight && !activePatchPreview && !writePreview?.content;
|
|
28657
|
+
const renderMarkdown = isMarkdownFile(selectedFile) && !effectiveHighlight && !persistentLineTones && !activePatchPreview && !writePreview?.content;
|
|
28167
28658
|
return /* @__PURE__ */ jsxs97("div", {
|
|
28168
28659
|
className: mode === "pane" ? "h-full w-full bg-transparent flex flex-col" : "absolute inset-0 bg-background z-50 flex flex-col animate-in slide-in-from-left duration-300",
|
|
28169
28660
|
children: [
|
|
@@ -28208,7 +28699,8 @@ var FileViewerPanel = memo47(function FileViewerPanel2({
|
|
|
28208
28699
|
className: "flex-1 overflow-auto",
|
|
28209
28700
|
children: writePreview?.content !== undefined ? /* @__PURE__ */ jsx110(CodeMirrorViewer, {
|
|
28210
28701
|
content: writePreview.content,
|
|
28211
|
-
path: selectedFile
|
|
28702
|
+
path: selectedFile,
|
|
28703
|
+
lineTones: writePreviewLineTones
|
|
28212
28704
|
}) : activePatchPreview ? /* @__PURE__ */ jsx110(CodeMirrorViewer, {
|
|
28213
28705
|
content: activePatchPreview.content,
|
|
28214
28706
|
path: selectedFile,
|
|
@@ -28259,6 +28751,7 @@ var FileViewerPanel = memo47(function FileViewerPanel2({
|
|
|
28259
28751
|
content: data.content,
|
|
28260
28752
|
path: selectedFile,
|
|
28261
28753
|
highlightedLines,
|
|
28754
|
+
lineTones: persistentLineTones,
|
|
28262
28755
|
scrollToLine: scrollToHighlightLine
|
|
28263
28756
|
}) : /* @__PURE__ */ jsx110("div", {
|
|
28264
28757
|
className: "h-full flex items-center justify-center text-muted-foreground",
|
|
@@ -28514,20 +29007,170 @@ function HighlightedPath({ path, query }) {
|
|
|
28514
29007
|
});
|
|
28515
29008
|
}
|
|
28516
29009
|
// src/components/workspace/ViewerTabs.tsx
|
|
29010
|
+
import { Icon, addCollection } from "@iconify/react";
|
|
29011
|
+
import { icons as materialIconTheme } from "@iconify-json/material-icon-theme";
|
|
28517
29012
|
import { memo as memo49, useEffect as useEffect53 } from "react";
|
|
28518
|
-
import {
|
|
28519
|
-
Braces as Braces2,
|
|
28520
|
-
File as File3,
|
|
28521
|
-
FileCode as FileCode5,
|
|
28522
|
-
FileJson as FileJson2,
|
|
28523
|
-
FileText as FileText8,
|
|
28524
|
-
FileType as FileType2,
|
|
28525
|
-
GitCommit as GitCommit5,
|
|
28526
|
-
Image as Image2,
|
|
28527
|
-
Settings as Settings4,
|
|
28528
|
-
X as X21
|
|
28529
|
-
} from "lucide-react";
|
|
29013
|
+
import { GitCommit as GitCommit5, X as X21 } from "lucide-react";
|
|
28530
29014
|
import { jsx as jsx112, jsxs as jsxs99 } from "react/jsx-runtime";
|
|
29015
|
+
addCollection(materialIconTheme);
|
|
29016
|
+
var ICON_CLASS = "h-3.5 w-3.5 shrink-0";
|
|
29017
|
+
var FILENAME_ICON_MAP = {
|
|
29018
|
+
".dockerignore": "docker",
|
|
29019
|
+
".editorconfig": "editorconfig",
|
|
29020
|
+
".env": "settings",
|
|
29021
|
+
".env.example": "settings",
|
|
29022
|
+
".env.local": "settings",
|
|
29023
|
+
".eslintignore": "eslint",
|
|
29024
|
+
".eslintrc": "eslint",
|
|
29025
|
+
".gitattributes": "git",
|
|
29026
|
+
".gitignore": "git",
|
|
29027
|
+
".prettierrc": "prettier",
|
|
29028
|
+
"astro.config.mjs": "astro-config",
|
|
29029
|
+
"astro.config.ts": "astro-config",
|
|
29030
|
+
"biome.json": "biome",
|
|
29031
|
+
"bun.lock": "bun",
|
|
29032
|
+
"bun.lockb": "bun",
|
|
29033
|
+
"bunfig.toml": "bun",
|
|
29034
|
+
"cargo.lock": "lock",
|
|
29035
|
+
"cargo.toml": "rust",
|
|
29036
|
+
"compose.yaml": "docker",
|
|
29037
|
+
"compose.yml": "docker",
|
|
29038
|
+
"docker-compose.yaml": "docker",
|
|
29039
|
+
"docker-compose.yml": "docker",
|
|
29040
|
+
dockerfile: "docker",
|
|
29041
|
+
"eslint.config.js": "eslint",
|
|
29042
|
+
"eslint.config.mjs": "eslint",
|
|
29043
|
+
"eslint.config.ts": "eslint",
|
|
29044
|
+
gemfile: "gemfile",
|
|
29045
|
+
"go.mod": "go-mod",
|
|
29046
|
+
"go.sum": "go-mod",
|
|
29047
|
+
"jsconfig.json": "jsconfig",
|
|
29048
|
+
license: "license",
|
|
29049
|
+
makefile: "makefile",
|
|
29050
|
+
"next.config.js": "next",
|
|
29051
|
+
"next.config.mjs": "next",
|
|
29052
|
+
"next.config.ts": "next",
|
|
29053
|
+
"package-lock.json": "npm",
|
|
29054
|
+
"package.json": "npm",
|
|
29055
|
+
"pnpm-lock.yaml": "pnpm",
|
|
29056
|
+
"postcss.config.js": "postcss",
|
|
29057
|
+
"postcss.config.mjs": "postcss",
|
|
29058
|
+
"postcss.config.ts": "postcss",
|
|
29059
|
+
"prettier.config.js": "prettier",
|
|
29060
|
+
"prettier.config.mjs": "prettier",
|
|
29061
|
+
"prettier.config.ts": "prettier",
|
|
29062
|
+
"readme.md": "readme",
|
|
29063
|
+
"readme.mdx": "readme",
|
|
29064
|
+
"rollup.config.js": "rollup",
|
|
29065
|
+
"rollup.config.mjs": "rollup",
|
|
29066
|
+
"rollup.config.ts": "rollup",
|
|
29067
|
+
"svelte.config.js": "svelte",
|
|
29068
|
+
"svelte.config.ts": "svelte",
|
|
29069
|
+
"tailwind.config.js": "tailwindcss",
|
|
29070
|
+
"tailwind.config.ts": "tailwindcss",
|
|
29071
|
+
"tauri.conf.json": "tauri",
|
|
29072
|
+
"tsconfig.json": "tsconfig",
|
|
29073
|
+
"vite.config.js": "vite",
|
|
29074
|
+
"vite.config.mjs": "vite",
|
|
29075
|
+
"vite.config.ts": "vite",
|
|
29076
|
+
"vitest.config.js": "vitest",
|
|
29077
|
+
"vitest.config.mjs": "vitest",
|
|
29078
|
+
"vitest.config.ts": "vitest",
|
|
29079
|
+
"vue.config.js": "vue-config",
|
|
29080
|
+
"vue.config.ts": "vue-config",
|
|
29081
|
+
"yarn.lock": "lock"
|
|
29082
|
+
};
|
|
29083
|
+
var EXTENSION_ICON_MAP = {
|
|
29084
|
+
ai: "image",
|
|
29085
|
+
astro: "astro",
|
|
29086
|
+
avif: "image",
|
|
29087
|
+
bash: "console",
|
|
29088
|
+
bmp: "image",
|
|
29089
|
+
c: "c",
|
|
29090
|
+
cc: "cpp",
|
|
29091
|
+
clj: "clojure",
|
|
29092
|
+
cljc: "clojure",
|
|
29093
|
+
cljs: "clojure",
|
|
29094
|
+
cpp: "cpp",
|
|
29095
|
+
cs: "csharp",
|
|
29096
|
+
css: "css",
|
|
29097
|
+
cxx: "cpp",
|
|
29098
|
+
dart: "dart",
|
|
29099
|
+
dockerfile: "docker",
|
|
29100
|
+
ex: "elixir",
|
|
29101
|
+
exs: "elixir",
|
|
29102
|
+
erl: "erlang",
|
|
29103
|
+
fish: "console",
|
|
29104
|
+
gif: "image",
|
|
29105
|
+
go: "go",
|
|
29106
|
+
graphql: "graphql",
|
|
29107
|
+
gql: "graphql",
|
|
29108
|
+
groovy: "groovy",
|
|
29109
|
+
h: "c",
|
|
29110
|
+
hpp: "cpp",
|
|
29111
|
+
hrl: "erlang",
|
|
29112
|
+
hs: "haskell",
|
|
29113
|
+
htm: "html",
|
|
29114
|
+
html: "html",
|
|
29115
|
+
hxx: "cpp",
|
|
29116
|
+
ico: "favicon",
|
|
29117
|
+
java: "java",
|
|
29118
|
+
jpeg: "image",
|
|
29119
|
+
jpg: "image",
|
|
29120
|
+
js: "javascript",
|
|
29121
|
+
json: "json",
|
|
29122
|
+
jsonc: "json",
|
|
29123
|
+
jsx: "react",
|
|
29124
|
+
jl: "julia",
|
|
29125
|
+
kt: "kotlin",
|
|
29126
|
+
kts: "kotlin",
|
|
29127
|
+
less: "less",
|
|
29128
|
+
log: "log",
|
|
29129
|
+
lua: "lua",
|
|
29130
|
+
luau: "luau",
|
|
29131
|
+
mjs: "javascript",
|
|
29132
|
+
ml: "ocaml",
|
|
29133
|
+
mli: "ocaml",
|
|
29134
|
+
mov: "video",
|
|
29135
|
+
mp3: "audio",
|
|
29136
|
+
mp4: "video",
|
|
29137
|
+
md: "markdown",
|
|
29138
|
+
mdx: "markdown",
|
|
29139
|
+
nim: "nim",
|
|
29140
|
+
pdf: "pdf",
|
|
29141
|
+
php: "php-elephant",
|
|
29142
|
+
png: "image",
|
|
29143
|
+
prisma: "prisma",
|
|
29144
|
+
proto: "proto",
|
|
29145
|
+
ps1: "powershell",
|
|
29146
|
+
py: "python",
|
|
29147
|
+
pyw: "python",
|
|
29148
|
+
r: "r",
|
|
29149
|
+
rb: "ruby",
|
|
29150
|
+
rs: "rust",
|
|
29151
|
+
sass: "sass",
|
|
29152
|
+
scala: "scala",
|
|
29153
|
+
scss: "sass",
|
|
29154
|
+
sh: "console",
|
|
29155
|
+
sql: "database",
|
|
29156
|
+
svg: "svg",
|
|
29157
|
+
svelte: "svelte",
|
|
29158
|
+
swift: "swift",
|
|
29159
|
+
toml: "toml",
|
|
29160
|
+
ts: "typescript",
|
|
29161
|
+
tsx: "react-ts",
|
|
29162
|
+
txt: "document",
|
|
29163
|
+
vue: "vue",
|
|
29164
|
+
wav: "audio",
|
|
29165
|
+
webm: "video",
|
|
29166
|
+
webp: "image",
|
|
29167
|
+
xml: "xml",
|
|
29168
|
+
yaml: "yaml",
|
|
29169
|
+
yml: "yaml",
|
|
29170
|
+
zig: "zig",
|
|
29171
|
+
zip: "zip",
|
|
29172
|
+
zsh: "console"
|
|
29173
|
+
};
|
|
28531
29174
|
function tabKindLabel(tab) {
|
|
28532
29175
|
switch (tab.type) {
|
|
28533
29176
|
case "git-diff":
|
|
@@ -28557,86 +29200,34 @@ function getFileExtension2(path) {
|
|
|
28557
29200
|
const extension = path.split(".").pop()?.toLowerCase() ?? "";
|
|
28558
29201
|
return extension && extension !== path.toLowerCase() ? extension : "";
|
|
28559
29202
|
}
|
|
28560
|
-
function
|
|
28561
|
-
|
|
28562
|
-
|
|
28563
|
-
|
|
28564
|
-
|
|
28565
|
-
|
|
28566
|
-
|
|
28567
|
-
|
|
28568
|
-
|
|
28569
|
-
|
|
28570
|
-
|
|
28571
|
-
|
|
28572
|
-
|
|
28573
|
-
|
|
28574
|
-
|
|
28575
|
-
|
|
28576
|
-
|
|
28577
|
-
|
|
28578
|
-
className: "inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-[3px] bg-gradient-to-br from-[#3776ab] to-[#ffd43b] text-[7px] font-bold leading-none text-white",
|
|
28579
|
-
children: "Py"
|
|
28580
|
-
});
|
|
28581
|
-
case "go":
|
|
28582
|
-
return /* @__PURE__ */ jsx112("span", {
|
|
28583
|
-
className: "inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-full bg-[#00add8] text-[7px] font-bold leading-none text-white",
|
|
28584
|
-
children: "Go"
|
|
28585
|
-
});
|
|
28586
|
-
case "rs":
|
|
28587
|
-
return /* @__PURE__ */ jsx112("span", {
|
|
28588
|
-
className: "inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-full bg-[#ce422b] text-[8px] font-bold leading-none text-white",
|
|
28589
|
-
children: "R"
|
|
28590
|
-
});
|
|
28591
|
-
case "json":
|
|
28592
|
-
return /* @__PURE__ */ jsx112(FileJson2, {
|
|
28593
|
-
className: "h-3.5 w-3.5 shrink-0 text-yellow-500"
|
|
28594
|
-
});
|
|
28595
|
-
case "md":
|
|
28596
|
-
case "mdx":
|
|
28597
|
-
return /* @__PURE__ */ jsx112(FileText8, {
|
|
28598
|
-
className: "h-3.5 w-3.5 shrink-0 text-sky-500"
|
|
28599
|
-
});
|
|
28600
|
-
case "env":
|
|
28601
|
-
case "toml":
|
|
28602
|
-
case "yaml":
|
|
28603
|
-
case "yml":
|
|
28604
|
-
return /* @__PURE__ */ jsx112(Settings4, {
|
|
28605
|
-
className: "h-3.5 w-3.5 shrink-0 text-violet-500"
|
|
28606
|
-
});
|
|
28607
|
-
case "css":
|
|
28608
|
-
case "scss":
|
|
28609
|
-
case "sass":
|
|
28610
|
-
case "less":
|
|
28611
|
-
return /* @__PURE__ */ jsx112(Braces2, {
|
|
28612
|
-
className: "h-3.5 w-3.5 shrink-0 text-blue-500"
|
|
28613
|
-
});
|
|
28614
|
-
case "html":
|
|
28615
|
-
case "xml":
|
|
28616
|
-
return /* @__PURE__ */ jsx112(FileType2, {
|
|
28617
|
-
className: "h-3.5 w-3.5 shrink-0 text-orange-500"
|
|
28618
|
-
});
|
|
28619
|
-
case "png":
|
|
28620
|
-
case "jpg":
|
|
28621
|
-
case "jpeg":
|
|
28622
|
-
case "gif":
|
|
28623
|
-
case "svg":
|
|
28624
|
-
case "webp":
|
|
28625
|
-
return /* @__PURE__ */ jsx112(Image2, {
|
|
28626
|
-
className: "h-3.5 w-3.5 shrink-0 text-pink-500"
|
|
28627
|
-
});
|
|
28628
|
-
case "txt":
|
|
28629
|
-
case "log":
|
|
28630
|
-
return /* @__PURE__ */ jsx112(FileText8, {
|
|
28631
|
-
className: "h-3.5 w-3.5 shrink-0 text-muted-foreground"
|
|
28632
|
-
});
|
|
28633
|
-
default:
|
|
28634
|
-
return extension ? /* @__PURE__ */ jsx112(FileCode5, {
|
|
28635
|
-
className: "h-3.5 w-3.5 shrink-0 text-muted-foreground/80"
|
|
28636
|
-
}) : /* @__PURE__ */ jsx112(File3, {
|
|
28637
|
-
className: "h-3.5 w-3.5 shrink-0 text-muted-foreground/80"
|
|
28638
|
-
});
|
|
29203
|
+
function getFileName3(path) {
|
|
29204
|
+
return path.split(/[\\/]/).pop()?.toLowerCase() ?? path.toLowerCase();
|
|
29205
|
+
}
|
|
29206
|
+
function getIconNameForPath(path) {
|
|
29207
|
+
const fileName = getFileName3(path);
|
|
29208
|
+
const fileIcon = FILENAME_ICON_MAP[fileName];
|
|
29209
|
+
if (fileIcon)
|
|
29210
|
+
return fileIcon;
|
|
29211
|
+
if (fileName.endsWith(".d.ts"))
|
|
29212
|
+
return "typescript-def";
|
|
29213
|
+
if (fileName.endsWith(".test.ts") || fileName.endsWith(".spec.ts")) {
|
|
29214
|
+
return "test-ts";
|
|
29215
|
+
}
|
|
29216
|
+
if (fileName.endsWith(".test.js") || fileName.endsWith(".spec.js")) {
|
|
29217
|
+
return "test-js";
|
|
29218
|
+
}
|
|
29219
|
+
if (fileName.endsWith(".test.jsx") || fileName.endsWith(".spec.jsx") || fileName.endsWith(".test.tsx") || fileName.endsWith(".spec.tsx")) {
|
|
29220
|
+
return "test-jsx";
|
|
28639
29221
|
}
|
|
29222
|
+
const extension = getFileExtension2(fileName);
|
|
29223
|
+
return EXTENSION_ICON_MAP[extension] ?? "document";
|
|
29224
|
+
}
|
|
29225
|
+
function renderFileIcon(path) {
|
|
29226
|
+
return /* @__PURE__ */ jsx112(Icon, {
|
|
29227
|
+
"aria-hidden": "true",
|
|
29228
|
+
className: ICON_CLASS,
|
|
29229
|
+
icon: `material-icon-theme:${getIconNameForPath(path)}`
|
|
29230
|
+
});
|
|
28640
29231
|
}
|
|
28641
29232
|
function renderTabIcon(tab) {
|
|
28642
29233
|
if (tab.type === "git-diff") {
|
|
@@ -28654,10 +29245,10 @@ function renderTabIcon(tab) {
|
|
|
28654
29245
|
className: `h-3.5 w-3.5 shrink-0 ${tab.status === "error" ? "text-red-500" : tab.status === "success" ? "text-emerald-500" : "text-blue-500"}`
|
|
28655
29246
|
});
|
|
28656
29247
|
}
|
|
28657
|
-
const
|
|
29248
|
+
const path = getTabPath(tab);
|
|
28658
29249
|
return /* @__PURE__ */ jsx112("span", {
|
|
28659
29250
|
className: "shrink-0 inline-flex items-center text-muted-foreground/80",
|
|
28660
|
-
children:
|
|
29251
|
+
children: renderFileIcon(path)
|
|
28661
29252
|
});
|
|
28662
29253
|
}
|
|
28663
29254
|
function renderTabContent(tab, closeTab, updateSessionFileOperationIndex) {
|
|
@@ -28686,6 +29277,7 @@ function renderTabContent(tab, closeTab, updateSessionFileOperationIndex) {
|
|
|
28686
29277
|
open: true,
|
|
28687
29278
|
file: tab.path,
|
|
28688
29279
|
highlight: tab.highlight,
|
|
29280
|
+
annotations: tab.annotations,
|
|
28689
29281
|
patchPreview: tab.patchPreview,
|
|
28690
29282
|
writePreview: tab.writePreview,
|
|
28691
29283
|
onClose: () => closeTab(tab.id)
|
|
@@ -31967,6 +32559,7 @@ export {
|
|
|
31967
32559
|
openPlatformUrl,
|
|
31968
32560
|
openPlatformSession,
|
|
31969
32561
|
notifyPlatformFontFamilyChanged,
|
|
32562
|
+
normalizeQueueState,
|
|
31970
32563
|
listPlatformSystemFonts,
|
|
31971
32564
|
hasPlatformSystemFonts,
|
|
31972
32565
|
hasPlatformOpenUrl,
|
|
@@ -32052,4 +32645,4 @@ export {
|
|
|
32052
32645
|
API_BASE_URL
|
|
32053
32646
|
};
|
|
32054
32647
|
|
|
32055
|
-
//# debugId=
|
|
32648
|
+
//# debugId=9AF775CD8BC5AA3D64756E2164756E21
|