@nextclaw/agent-chat-ui 0.3.5 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +52 -1
- package/dist/index.js +149 -35
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -164,7 +164,13 @@ type ChatFileOperationBlockViewModel = {
|
|
|
164
164
|
display?: "preview" | "diff";
|
|
165
165
|
caption?: string;
|
|
166
166
|
lines: ChatFileOperationLineViewModel[];
|
|
167
|
+
fullLines?: ChatFileOperationLineViewModel[];
|
|
167
168
|
rawText?: string;
|
|
169
|
+
beforeText?: string;
|
|
170
|
+
afterText?: string;
|
|
171
|
+
patchText?: string;
|
|
172
|
+
oldStartLine?: number;
|
|
173
|
+
newStartLine?: number;
|
|
168
174
|
truncated?: boolean;
|
|
169
175
|
};
|
|
170
176
|
type ChatToolActionViewModel = {
|
|
@@ -175,6 +181,20 @@ type ChatToolActionViewModel = {
|
|
|
175
181
|
label?: string;
|
|
176
182
|
parentSessionId?: string;
|
|
177
183
|
};
|
|
184
|
+
type ChatFileOpenActionViewModel = {
|
|
185
|
+
path: string;
|
|
186
|
+
label?: string;
|
|
187
|
+
viewMode: "preview" | "diff";
|
|
188
|
+
line?: number;
|
|
189
|
+
column?: number;
|
|
190
|
+
rawText?: string;
|
|
191
|
+
beforeText?: string;
|
|
192
|
+
afterText?: string;
|
|
193
|
+
patchText?: string;
|
|
194
|
+
oldStartLine?: number;
|
|
195
|
+
newStartLine?: number;
|
|
196
|
+
fullLines?: ChatFileOperationLineViewModel[];
|
|
197
|
+
};
|
|
178
198
|
type ChatToolPartViewModel = {
|
|
179
199
|
kind: "call" | "result";
|
|
180
200
|
toolName: string;
|
|
@@ -262,6 +282,7 @@ type ChatMessageListProps = {
|
|
|
262
282
|
texts: ChatMessageTexts;
|
|
263
283
|
className?: string;
|
|
264
284
|
onToolAction?: (action: ChatToolActionViewModel) => void;
|
|
285
|
+
onFileOpen?: (action: ChatFileOpenActionViewModel) => void;
|
|
265
286
|
renderToolAgent?: (agentId: string) => ReactNode;
|
|
266
287
|
};
|
|
267
288
|
//#endregion
|
|
@@ -279,6 +300,36 @@ declare const ChatInputBar: _$react.ForwardRefExoticComponent<ChatInputBarProps
|
|
|
279
300
|
//#region src/components/chat/ui/chat-message-list/chat-message-list.d.ts
|
|
280
301
|
declare function ChatMessageList(props: ChatMessageListProps): _$react_jsx_runtime0.JSX.Element;
|
|
281
302
|
//#endregion
|
|
303
|
+
//#region src/components/chat/ui/chat-message-list/chat-message-markdown.d.ts
|
|
304
|
+
type ChatMessageMarkdownProps = {
|
|
305
|
+
text: string;
|
|
306
|
+
role: ChatMessageRole;
|
|
307
|
+
texts: Pick<ChatMessageTexts, 'copyCodeLabel' | 'copiedCodeLabel'>;
|
|
308
|
+
inline?: boolean;
|
|
309
|
+
onFileOpen?: (action: ChatFileOpenActionViewModel) => void;
|
|
310
|
+
};
|
|
311
|
+
declare function ChatMessageMarkdown({
|
|
312
|
+
text,
|
|
313
|
+
role,
|
|
314
|
+
texts,
|
|
315
|
+
inline,
|
|
316
|
+
onFileOpen
|
|
317
|
+
}: ChatMessageMarkdownProps): _$react_jsx_runtime0.JSX.Element;
|
|
318
|
+
//#endregion
|
|
319
|
+
//#region src/components/chat/ui/chat-message-list/tool-card/tool-card-file-operation-lines.d.ts
|
|
320
|
+
declare function FileOperationCodeSurface({
|
|
321
|
+
block,
|
|
322
|
+
layout
|
|
323
|
+
}: {
|
|
324
|
+
block: ChatFileOperationBlockViewModel;
|
|
325
|
+
layout?: "compact" | "workspace";
|
|
326
|
+
}): _$react_jsx_runtime0.JSX.Element;
|
|
327
|
+
declare function FileOperationLinesGrid({
|
|
328
|
+
block
|
|
329
|
+
}: {
|
|
330
|
+
block: ChatFileOperationBlockViewModel;
|
|
331
|
+
}): _$react_jsx_runtime0.JSX.Element;
|
|
332
|
+
//#endregion
|
|
282
333
|
//#region src/components/chat/hooks/use-active-item-scroll.d.ts
|
|
283
334
|
type UseActiveItemScrollParams = {
|
|
284
335
|
containerRef: RefObject<HTMLElement>;
|
|
@@ -345,4 +396,4 @@ declare function resolveChatComposerSlashTrigger(nodes: ChatComposerNode[], sele
|
|
|
345
396
|
end: number;
|
|
346
397
|
} | null;
|
|
347
398
|
//#endregion
|
|
348
|
-
export { type ChatComposerNode, type ChatComposerSelection, type ChatComposerTextNode, type ChatComposerTokenKind, type ChatComposerTokenNode, type ChatFileOperationBlockViewModel, type ChatFileOperationLineViewModel, type ChatInlineContentSegmentViewModel, type ChatInlineHint, type ChatInlineTokenViewModel, ChatInputBar, type ChatInputBarActionsProps, type ChatInputBarHandle, type ChatInputBarProps, type ChatInputBarToolbarProps, ChatMessageList, type ChatMessageListProps, type ChatMessagePartViewModel, type ChatMessageRole, type ChatMessageTexts, type ChatMessageViewModel, type ChatSelectedItem, type ChatSkillPickerOption, type ChatSkillPickerProps, type ChatSlashItem, type ChatSlashMenuProps, type ChatTexts, type ChatToolActionViewModel, type ChatToolPartViewModel, type ChatToolbarAccessory, type ChatToolbarAccessoryIcon, type ChatToolbarIcon, type ChatToolbarSelect, type ChatToolbarSelectGroup, type ChatToolbarSelectOption, copyText, createChatComposerNodesFromText, createChatComposerTextNode, createChatComposerTokenNode, createEmptyChatComposerNodes, extractChatComposerTokenKeys, normalizeChatComposerNodes, removeChatComposerTokenNodes, replaceChatComposerRange, resolveChatComposerSlashTrigger, serializeChatComposerDocument, serializeChatComposerPlainText, useActiveItemScroll, useCopyFeedback, useElementWidth, useStickyBottomScroll };
|
|
399
|
+
export { type ChatComposerNode, type ChatComposerSelection, type ChatComposerTextNode, type ChatComposerTokenKind, type ChatComposerTokenNode, type ChatFileOpenActionViewModel, type ChatFileOperationBlockViewModel, type ChatFileOperationLineViewModel, type ChatInlineContentSegmentViewModel, type ChatInlineHint, type ChatInlineTokenViewModel, ChatInputBar, type ChatInputBarActionsProps, type ChatInputBarHandle, type ChatInputBarProps, type ChatInputBarToolbarProps, ChatMessageList, type ChatMessageListProps, ChatMessageMarkdown, type ChatMessagePartViewModel, type ChatMessageRole, type ChatMessageTexts, type ChatMessageViewModel, type ChatSelectedItem, type ChatSkillPickerOption, type ChatSkillPickerProps, type ChatSlashItem, type ChatSlashMenuProps, type ChatTexts, type ChatToolActionViewModel, type ChatToolPartViewModel, type ChatToolbarAccessory, type ChatToolbarAccessoryIcon, type ChatToolbarIcon, type ChatToolbarSelect, type ChatToolbarSelectGroup, type ChatToolbarSelectOption, FileOperationCodeSurface, FileOperationLinesGrid, copyText, createChatComposerNodesFromText, createChatComposerTextNode, createChatComposerTokenNode, createEmptyChatComposerNodes, extractChatComposerTokenKeys, normalizeChatComposerNodes, removeChatComposerTokenNodes, replaceChatComposerRange, resolveChatComposerSlashTrigger, serializeChatComposerDocument, serializeChatComposerPlainText, useActiveItemScroll, useCopyFeedback, useElementWidth, useStickyBottomScroll };
|
package/dist/index.js
CHANGED
|
@@ -2047,7 +2047,26 @@ function resolveSafeHref(href) {
|
|
|
2047
2047
|
function isExternalHref(href) {
|
|
2048
2048
|
return /^https?:\/\//i.test(href);
|
|
2049
2049
|
}
|
|
2050
|
-
function
|
|
2050
|
+
function looksLikeLocalFileHref(href) {
|
|
2051
|
+
return href.startsWith("./") || href.startsWith("../") || href.startsWith("/Users/") || href.startsWith("/home/") || href.startsWith("/tmp/") || href.startsWith("/var/") || /^\/.+\.[A-Za-z0-9_-]+(?::\d+(?::\d+)?)?$/.test(href);
|
|
2052
|
+
}
|
|
2053
|
+
function parseLocalFileAction(href) {
|
|
2054
|
+
const normalizedHref = href.split("#")[0]?.split("?")[0] ?? href;
|
|
2055
|
+
const decodedHref = decodeURIComponent(normalizedHref);
|
|
2056
|
+
if (!looksLikeLocalFileHref(decodedHref)) return null;
|
|
2057
|
+
const lineMatch = /^(.*?)(?::(\d+)(?::(\d+))?)$/.exec(decodedHref);
|
|
2058
|
+
const rawPath = lineMatch?.[1] ?? decodedHref;
|
|
2059
|
+
const line = lineMatch?.[2] ? Number(lineMatch[2]) : void 0;
|
|
2060
|
+
const column = lineMatch?.[3] ? Number(lineMatch[3]) : void 0;
|
|
2061
|
+
return {
|
|
2062
|
+
path: rawPath,
|
|
2063
|
+
label: rawPath.split("/").filter(Boolean).pop() ?? rawPath,
|
|
2064
|
+
viewMode: "preview",
|
|
2065
|
+
...typeof line === "number" ? { line } : {},
|
|
2066
|
+
...typeof column === "number" ? { column } : {}
|
|
2067
|
+
};
|
|
2068
|
+
}
|
|
2069
|
+
function ChatMessageMarkdown({ text, role, texts, inline = false, onFileOpen }) {
|
|
2051
2070
|
const isUser = role === "user";
|
|
2052
2071
|
const markdownComponents = useMemo(() => ({
|
|
2053
2072
|
p: ({ children }) => inline ? /* @__PURE__ */ jsx(Fragment$1, { children }) : /* @__PURE__ */ jsx("p", { children }),
|
|
@@ -2058,9 +2077,17 @@ function ChatMessageMarkdown({ text, role, texts, inline = false }) {
|
|
|
2058
2077
|
children
|
|
2059
2078
|
});
|
|
2060
2079
|
const external = isExternalHref(safeHref);
|
|
2080
|
+
const localFileAction = external ? null : parseLocalFileAction(safeHref);
|
|
2081
|
+
const handleClick = (event) => {
|
|
2082
|
+
if (!onFileOpen || !localFileAction) return;
|
|
2083
|
+
if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
2084
|
+
event.preventDefault();
|
|
2085
|
+
onFileOpen(localFileAction);
|
|
2086
|
+
};
|
|
2061
2087
|
return /* @__PURE__ */ jsx("a", {
|
|
2062
2088
|
...rest,
|
|
2063
2089
|
href: safeHref,
|
|
2090
|
+
onClick: handleClick,
|
|
2064
2091
|
target: external ? "_blank" : void 0,
|
|
2065
2092
|
rel: external ? "noreferrer noopener" : void 0,
|
|
2066
2093
|
children
|
|
@@ -2110,7 +2137,11 @@ function ChatMessageMarkdown({ text, role, texts, inline = false }) {
|
|
|
2110
2137
|
children
|
|
2111
2138
|
});
|
|
2112
2139
|
}
|
|
2113
|
-
}), [
|
|
2140
|
+
}), [
|
|
2141
|
+
inline,
|
|
2142
|
+
onFileOpen,
|
|
2143
|
+
texts
|
|
2144
|
+
]);
|
|
2114
2145
|
return /* @__PURE__ */ jsx(inline ? "span" : "div", {
|
|
2115
2146
|
className: cn("chat-markdown", isUser ? "chat-markdown-user" : "chat-markdown-assistant"),
|
|
2116
2147
|
children: /* @__PURE__ */ jsx(ReactMarkdown, {
|
|
@@ -2158,7 +2189,7 @@ function ChatInlineTokenBadge({ kind, label, isUser }) {
|
|
|
2158
2189
|
})]
|
|
2159
2190
|
});
|
|
2160
2191
|
}
|
|
2161
|
-
function ChatMessageInlineContent({ segments, role, texts }) {
|
|
2192
|
+
function ChatMessageInlineContent({ segments, role, texts, onFileOpen }) {
|
|
2162
2193
|
const isUser = role === "user";
|
|
2163
2194
|
return /* @__PURE__ */ jsx("div", {
|
|
2164
2195
|
className: "whitespace-pre-wrap break-words leading-6",
|
|
@@ -2176,7 +2207,8 @@ function ChatMessageInlineContent({ segments, role, texts }) {
|
|
|
2176
2207
|
text: segment.text,
|
|
2177
2208
|
role,
|
|
2178
2209
|
texts,
|
|
2179
|
-
inline: true
|
|
2210
|
+
inline: true,
|
|
2211
|
+
onFileOpen
|
|
2180
2212
|
}, `markdown-${index}`);
|
|
2181
2213
|
})
|
|
2182
2214
|
});
|
|
@@ -2568,7 +2600,7 @@ function ChatReasoningBlock({ label, text, isUser, isInProgress }) {
|
|
|
2568
2600
|
ref: scrollRef,
|
|
2569
2601
|
onScroll,
|
|
2570
2602
|
"data-reasoning-scroll": "true",
|
|
2571
|
-
className: cn("mt-2 w-fit max-w-[500px] max-h-56 overflow-y-auto
|
|
2603
|
+
className: cn("mt-2 w-fit max-w-[500px] max-h-56 overflow-y-auto rounded-lg custom-scrollbar-amber", isUser ? "bg-primary-700/60" : "bg-gray-100"),
|
|
2572
2604
|
children: /* @__PURE__ */ jsx("pre", {
|
|
2573
2605
|
className: "min-w-0 whitespace-pre-wrap break-all p-2 text-[11px]",
|
|
2574
2606
|
children: text
|
|
@@ -2648,15 +2680,15 @@ function ToolCardSessionActionButton({ action, onAction }) {
|
|
|
2648
2680
|
function ToolCardHeader({ card, icon: Icon, expanded, canExpand, hideSummary = false, actionSlot, onToggle }) {
|
|
2649
2681
|
const summaryPart = hideSummary ? "" : card.summary?.replace(/^(command|path|args|query|input):\s*/i, "") ?? "";
|
|
2650
2682
|
return /* @__PURE__ */ jsxs("div", {
|
|
2651
|
-
className: cn("flex items-center
|
|
2683
|
+
className: cn("flex items-center gap-3 px-3 py-2.5 transition-colors bg-transparent", canExpand ? "cursor-pointer hover:bg-amber-100/30" : ""),
|
|
2652
2684
|
onClick: onToggle,
|
|
2653
2685
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
2654
|
-
className: "flex items-center gap-2 font-mono
|
|
2686
|
+
className: "flex min-w-0 flex-1 items-center gap-2 overflow-hidden font-mono text-amber-950/80",
|
|
2655
2687
|
children: [/* @__PURE__ */ jsx(Icon, {
|
|
2656
2688
|
className: "h-4 w-4 text-amber-600/80 shrink-0",
|
|
2657
2689
|
strokeWidth: 3
|
|
2658
2690
|
}), /* @__PURE__ */ jsxs("div", {
|
|
2659
|
-
className: "flex items-center gap-1.5
|
|
2691
|
+
className: "flex min-w-0 flex-1 items-center gap-1.5 overflow-hidden",
|
|
2660
2692
|
children: [/* @__PURE__ */ jsx("span", {
|
|
2661
2693
|
className: "font-bold shrink-0 tracking-tight",
|
|
2662
2694
|
children: card.toolName
|
|
@@ -2664,7 +2696,7 @@ function ToolCardHeader({ card, icon: Icon, expanded, canExpand, hideSummary = f
|
|
|
2664
2696
|
className: "text-amber-300 font-bold select-none shrink-0",
|
|
2665
2697
|
children: "›"
|
|
2666
2698
|
}), /* @__PURE__ */ jsx("span", {
|
|
2667
|
-
className: "
|
|
2699
|
+
className: "block min-w-0 flex-1 truncate font-normal",
|
|
2668
2700
|
title: summaryPart,
|
|
2669
2701
|
children: summaryPart
|
|
2670
2702
|
})] })]
|
|
@@ -2693,8 +2725,9 @@ function ToolCardHeaderSessionAction({ action, onAction }) {
|
|
|
2693
2725
|
}
|
|
2694
2726
|
//#endregion
|
|
2695
2727
|
//#region src/components/chat/ui/chat-message-list/tool-card/tool-card-file-operation-lines.tsx
|
|
2696
|
-
const
|
|
2697
|
-
const
|
|
2728
|
+
const FILE_TEXT_CLASS_NAME = "font-mono text-[11px] leading-5";
|
|
2729
|
+
const FILE_ROW_CLASS_NAME = `h-5 ${FILE_TEXT_CLASS_NAME}`;
|
|
2730
|
+
const FILE_LINE_NUMBER_CELL_CLASS_NAME = "flex h-5 items-center justify-center px-2.5 tabular-nums select-none";
|
|
2698
2731
|
function formatLineNumber(value) {
|
|
2699
2732
|
return typeof value === "number" ? String(value) : "";
|
|
2700
2733
|
}
|
|
@@ -2731,6 +2764,22 @@ function getCodeRowTone(line) {
|
|
|
2731
2764
|
if (line.kind === "add") return "bg-emerald-50 text-emerald-950";
|
|
2732
2765
|
return "bg-white text-amber-950/80";
|
|
2733
2766
|
}
|
|
2767
|
+
function FileOperationLineNumberCell({ layout, line, lineNumberColumnWidth }) {
|
|
2768
|
+
const lineNumberCellClassName = layout === "compact" ? "sticky left-0 z-[1]" : "w-full shrink-0";
|
|
2769
|
+
return /* @__PURE__ */ jsx("span", {
|
|
2770
|
+
"data-file-line-number-cell": "true",
|
|
2771
|
+
style: layout === "compact" ? { width: lineNumberColumnWidth } : void 0,
|
|
2772
|
+
className: cn(FILE_LINE_NUMBER_CELL_CLASS_NAME, lineNumberCellClassName, getLineNumberTone(line)),
|
|
2773
|
+
children: readVisibleLineNumber(line)
|
|
2774
|
+
});
|
|
2775
|
+
}
|
|
2776
|
+
function FileOperationCodeCell({ line }) {
|
|
2777
|
+
return /* @__PURE__ */ jsx("span", {
|
|
2778
|
+
"data-file-code-row": "true",
|
|
2779
|
+
className: cn("block min-w-full whitespace-pre px-2.5", getCodeRowTone(line)),
|
|
2780
|
+
children: line.text || " "
|
|
2781
|
+
});
|
|
2782
|
+
}
|
|
2734
2783
|
function FileOperationLineRow({ line, showLineNumbers, lineNumberColumnWidth }) {
|
|
2735
2784
|
return /* @__PURE__ */ jsxs("div", {
|
|
2736
2785
|
"data-file-line-row": "true",
|
|
@@ -2739,22 +2788,50 @@ function FileOperationLineRow({ line, showLineNumbers, lineNumberColumnWidth })
|
|
|
2739
2788
|
showLineNumbers,
|
|
2740
2789
|
lineNumberColumnWidth
|
|
2741
2790
|
}),
|
|
2742
|
-
children: [showLineNumbers ? /* @__PURE__ */ jsx(
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2791
|
+
children: [showLineNumbers ? /* @__PURE__ */ jsx(FileOperationLineNumberCell, {
|
|
2792
|
+
layout: "compact",
|
|
2793
|
+
line,
|
|
2794
|
+
lineNumberColumnWidth
|
|
2795
|
+
}) : null, /* @__PURE__ */ jsx(FileOperationCodeCell, { line })]
|
|
2796
|
+
});
|
|
2797
|
+
}
|
|
2798
|
+
function FileOperationWorkspaceSurface({ block }) {
|
|
2799
|
+
const showLineNumbers = readHasBlockLineNumbers(block);
|
|
2800
|
+
const lineNumberColumnWidth = readLineNumberColumnWidth(block);
|
|
2801
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
2802
|
+
"data-file-code-surface": "true",
|
|
2803
|
+
"data-file-code-surface-layout": "workspace",
|
|
2804
|
+
className: "flex h-full min-h-full min-w-full bg-white",
|
|
2805
|
+
children: [showLineNumbers ? /* @__PURE__ */ jsxs("div", {
|
|
2806
|
+
"data-file-code-gutter": "true",
|
|
2807
|
+
style: {
|
|
2808
|
+
width: lineNumberColumnWidth,
|
|
2809
|
+
minWidth: lineNumberColumnWidth
|
|
2810
|
+
},
|
|
2811
|
+
className: cn("flex h-full min-h-full shrink-0 flex-col", FILE_TEXT_CLASS_NAME),
|
|
2812
|
+
children: [block.lines.map((line, index) => /* @__PURE__ */ jsx(FileOperationLineNumberCell, {
|
|
2813
|
+
layout: "workspace",
|
|
2814
|
+
line,
|
|
2815
|
+
lineNumberColumnWidth
|
|
2816
|
+
}, readLineKey("gutter", line, index))), /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 border-r border-stone-200 bg-stone-100" })]
|
|
2817
|
+
}) : null, /* @__PURE__ */ jsxs("div", {
|
|
2818
|
+
"data-file-code-canvas": "true",
|
|
2819
|
+
className: "flex h-full min-h-full min-w-0 flex-1 flex-col bg-white",
|
|
2820
|
+
children: [block.lines.map((line, index) => /* @__PURE__ */ jsx("div", {
|
|
2821
|
+
"data-file-code-canvas-row": "true",
|
|
2822
|
+
className: FILE_ROW_CLASS_NAME,
|
|
2823
|
+
children: /* @__PURE__ */ jsx(FileOperationCodeCell, { line })
|
|
2824
|
+
}, readLineKey("code", line, index))), /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 bg-white" })]
|
|
2751
2825
|
})]
|
|
2752
2826
|
});
|
|
2753
2827
|
}
|
|
2754
|
-
function
|
|
2828
|
+
function FileOperationCodeSurface({ block, layout = "compact" }) {
|
|
2829
|
+
if (layout === "workspace") return /* @__PURE__ */ jsx(FileOperationWorkspaceSurface, { block });
|
|
2755
2830
|
const showLineNumbers = readHasBlockLineNumbers(block);
|
|
2756
2831
|
const lineNumberColumnWidth = readLineNumberColumnWidth(block);
|
|
2757
2832
|
return /* @__PURE__ */ jsx("div", {
|
|
2833
|
+
"data-file-code-surface": "true",
|
|
2834
|
+
"data-file-code-surface-layout": "compact",
|
|
2758
2835
|
className: "overflow-x-auto custom-scrollbar-amber bg-white",
|
|
2759
2836
|
children: block.lines.map((line, index) => /* @__PURE__ */ jsx(FileOperationLineRow, {
|
|
2760
2837
|
line,
|
|
@@ -2763,6 +2840,12 @@ function FileOperationLinesGrid({ block }) {
|
|
|
2763
2840
|
}, readLineKey("row", line, index)))
|
|
2764
2841
|
});
|
|
2765
2842
|
}
|
|
2843
|
+
function FileOperationLinesGrid({ block }) {
|
|
2844
|
+
return /* @__PURE__ */ jsx(FileOperationCodeSurface, {
|
|
2845
|
+
block,
|
|
2846
|
+
layout: "compact"
|
|
2847
|
+
});
|
|
2848
|
+
}
|
|
2766
2849
|
//#endregion
|
|
2767
2850
|
//#region src/components/chat/ui/chat-message-list/tool-card/tool-card-file-operation.tsx
|
|
2768
2851
|
function isPreviewBlock(block) {
|
|
@@ -2796,6 +2879,20 @@ function renderCaption(caption) {
|
|
|
2796
2879
|
})] }, `${part}-${index}`))
|
|
2797
2880
|
});
|
|
2798
2881
|
}
|
|
2882
|
+
function buildFileOpenAction(block) {
|
|
2883
|
+
return {
|
|
2884
|
+
path: block.path,
|
|
2885
|
+
label: block.path.split("/").filter(Boolean).pop() ?? block.path,
|
|
2886
|
+
viewMode: block.display === "diff" ? "diff" : "preview",
|
|
2887
|
+
...block.rawText ? { rawText: block.rawText } : {},
|
|
2888
|
+
...block.beforeText ? { beforeText: block.beforeText } : {},
|
|
2889
|
+
...block.afterText ? { afterText: block.afterText } : {},
|
|
2890
|
+
...block.patchText ? { patchText: block.patchText } : {},
|
|
2891
|
+
...typeof block.oldStartLine === "number" ? { oldStartLine: block.oldStartLine } : {},
|
|
2892
|
+
...typeof block.newStartLine === "number" ? { newStartLine: block.newStartLine } : {},
|
|
2893
|
+
fullLines: block.fullLines ?? block.lines
|
|
2894
|
+
};
|
|
2895
|
+
}
|
|
2799
2896
|
function StickyFileOperationScrollArea({ children, contentVersion, resetKey, className, scrollKind }) {
|
|
2800
2897
|
const scrollRef = useRef(null);
|
|
2801
2898
|
const { onScroll } = useStickyBottomScroll({
|
|
@@ -2810,14 +2907,18 @@ function StickyFileOperationScrollArea({ children, contentVersion, resetKey, cla
|
|
|
2810
2907
|
ref: scrollRef,
|
|
2811
2908
|
onScroll,
|
|
2812
2909
|
"data-file-scroll-kind": scrollKind,
|
|
2813
|
-
className: cn("overflow-y-auto
|
|
2910
|
+
className: cn("overflow-y-auto bg-white custom-scrollbar-amber", className),
|
|
2814
2911
|
children
|
|
2815
2912
|
});
|
|
2816
2913
|
}
|
|
2817
|
-
function FileOperationBlock({ block, showPathRow, isFirst }) {
|
|
2914
|
+
function FileOperationBlock({ block, showPathRow, isFirst, onFileOpen }) {
|
|
2818
2915
|
const { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } = ChatUiPrimitives;
|
|
2819
2916
|
const previewBlock = isPreviewBlock(block);
|
|
2820
2917
|
const showMetaRow = showPathRow || Boolean(block.caption);
|
|
2918
|
+
const handlePathClick = () => {
|
|
2919
|
+
if (!onFileOpen) return;
|
|
2920
|
+
onFileOpen(buildFileOpenAction(block));
|
|
2921
|
+
};
|
|
2821
2922
|
return /* @__PURE__ */ jsxs("section", {
|
|
2822
2923
|
className: cn("overflow-hidden bg-white", !isFirst && "border-t border-stone-200/80"),
|
|
2823
2924
|
children: [
|
|
@@ -2829,8 +2930,10 @@ function FileOperationBlock({ block, showPathRow, isFirst }) {
|
|
|
2829
2930
|
delayDuration: 250,
|
|
2830
2931
|
children: /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
|
|
2831
2932
|
asChild: true,
|
|
2832
|
-
children: /* @__PURE__ */ jsx("
|
|
2833
|
-
|
|
2933
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
2934
|
+
type: "button",
|
|
2935
|
+
onClick: handlePathClick,
|
|
2936
|
+
className: cn("w-full truncate whitespace-nowrap text-left font-mono text-[12px] font-medium text-stone-700", onFileOpen && "transition-colors hover:text-amber-900 hover:underline"),
|
|
2834
2937
|
title: block.path,
|
|
2835
2938
|
children: block.path
|
|
2836
2939
|
})
|
|
@@ -2868,7 +2971,7 @@ function FileOperationBlock({ block, showPathRow, isFirst }) {
|
|
|
2868
2971
|
]
|
|
2869
2972
|
});
|
|
2870
2973
|
}
|
|
2871
|
-
function ToolCardFileOperationContent({ card, className }) {
|
|
2974
|
+
function ToolCardFileOperationContent({ card, className, onFileOpen }) {
|
|
2872
2975
|
const blocks = card.fileOperation?.blocks ?? [];
|
|
2873
2976
|
const output = card.output?.trim() ?? "";
|
|
2874
2977
|
if (blocks.length === 0 && !output) return null;
|
|
@@ -2878,7 +2981,8 @@ function ToolCardFileOperationContent({ card, className }) {
|
|
|
2878
2981
|
return /* @__PURE__ */ jsx(FileOperationBlock, {
|
|
2879
2982
|
block,
|
|
2880
2983
|
showPathRow: true,
|
|
2881
|
-
isFirst: index === 0
|
|
2984
|
+
isFirst: index === 0,
|
|
2985
|
+
onFileOpen
|
|
2882
2986
|
}, block.key);
|
|
2883
2987
|
}), output ? /* @__PURE__ */ jsx(StickyFileOperationScrollArea, {
|
|
2884
2988
|
resetKey: `output:${card.toolName}:${card.summary ?? "none"}`,
|
|
@@ -3074,7 +3178,7 @@ function TerminalExecutionView({ card }) {
|
|
|
3074
3178
|
children: [output, isRunning && /* @__PURE__ */ jsx("span", { className: "inline-block w-1.5 h-3 ml-1 bg-amber-500/60 animate-pulse align-middle" })]
|
|
3075
3179
|
}) })] })] });
|
|
3076
3180
|
}
|
|
3077
|
-
function FileOperationView({ card }) {
|
|
3181
|
+
function FileOperationView({ card, onFileOpen }) {
|
|
3078
3182
|
const output = card.output?.trim() ?? "";
|
|
3079
3183
|
const isRunning = card.statusTone === "running";
|
|
3080
3184
|
const hasStructuredPreview = Boolean(card.fileOperation?.blocks.length);
|
|
@@ -3102,7 +3206,10 @@ function FileOperationView({ card }) {
|
|
|
3102
3206
|
onToggle
|
|
3103
3207
|
}), expanded && hasContent && /* @__PURE__ */ jsx(ToolCardContent, {
|
|
3104
3208
|
className: "border-t border-amber-200/20 bg-transparent px-0 pt-0 pb-0",
|
|
3105
|
-
children: /* @__PURE__ */ jsx(ToolCardFileOperationContent, {
|
|
3209
|
+
children: /* @__PURE__ */ jsx(ToolCardFileOperationContent, {
|
|
3210
|
+
card,
|
|
3211
|
+
onFileOpen
|
|
3212
|
+
})
|
|
3106
3213
|
})] });
|
|
3107
3214
|
}
|
|
3108
3215
|
function SearchSnippetView({ card }) {
|
|
@@ -3181,9 +3288,12 @@ function isSearchTool(name) {
|
|
|
3181
3288
|
const lowered = name.toLowerCase();
|
|
3182
3289
|
return lowered === "grep_search" || lowered === "find_files" || lowered.includes("search");
|
|
3183
3290
|
}
|
|
3184
|
-
function ChatToolCard({ card, onToolAction, renderToolAgent }) {
|
|
3291
|
+
function ChatToolCard({ card, onToolAction, onFileOpen, renderToolAgent }) {
|
|
3185
3292
|
if (isTerminalTool(card.toolName)) return /* @__PURE__ */ jsx(TerminalExecutionView, { card });
|
|
3186
|
-
if (isFileEditTool(card.toolName)) return /* @__PURE__ */ jsx(FileOperationView, {
|
|
3293
|
+
if (isFileEditTool(card.toolName)) return /* @__PURE__ */ jsx(FileOperationView, {
|
|
3294
|
+
card,
|
|
3295
|
+
onFileOpen
|
|
3296
|
+
});
|
|
3187
3297
|
if (isSearchTool(card.toolName)) return /* @__PURE__ */ jsx(SearchSnippetView, { card });
|
|
3188
3298
|
return /* @__PURE__ */ jsx(GenericToolCard, {
|
|
3189
3299
|
card,
|
|
@@ -3212,7 +3322,7 @@ function ChatUnknownPart(props) {
|
|
|
3212
3322
|
//#endregion
|
|
3213
3323
|
//#region src/components/chat/ui/chat-message-list/chat-message.tsx
|
|
3214
3324
|
const ChatMessage = memo(function ChatMessage(props) {
|
|
3215
|
-
const { message, texts, onToolAction, renderToolAgent } = props;
|
|
3325
|
+
const { message, texts, onToolAction, onFileOpen, renderToolAgent } = props;
|
|
3216
3326
|
const { role } = message;
|
|
3217
3327
|
const isUser = role === "user";
|
|
3218
3328
|
const isMessageInProgress = message.status === "pending" || message.status === "streaming";
|
|
@@ -3225,12 +3335,14 @@ const ChatMessage = memo(function ChatMessage(props) {
|
|
|
3225
3335
|
if (type === "markdown") return /* @__PURE__ */ jsx(ChatMessageMarkdown, {
|
|
3226
3336
|
text: part.text,
|
|
3227
3337
|
role,
|
|
3228
|
-
texts
|
|
3338
|
+
texts,
|
|
3339
|
+
onFileOpen
|
|
3229
3340
|
}, `markdown-${index}`);
|
|
3230
3341
|
if (type === "inline-content") return /* @__PURE__ */ jsx(ChatMessageInlineContent, {
|
|
3231
3342
|
segments: part.segments,
|
|
3232
3343
|
role,
|
|
3233
|
-
texts
|
|
3344
|
+
texts,
|
|
3345
|
+
onFileOpen
|
|
3234
3346
|
}, `inline-content-${index}`);
|
|
3235
3347
|
if (type === "reasoning") return /* @__PURE__ */ jsx(ChatReasoningBlock, {
|
|
3236
3348
|
label: part.label,
|
|
@@ -3243,6 +3355,7 @@ const ChatMessage = memo(function ChatMessage(props) {
|
|
|
3243
3355
|
children: /* @__PURE__ */ jsx(ChatToolCard, {
|
|
3244
3356
|
card: part.card,
|
|
3245
3357
|
onToolAction,
|
|
3358
|
+
onFileOpen,
|
|
3246
3359
|
renderToolAgent
|
|
3247
3360
|
})
|
|
3248
3361
|
}, `tool-${index}`);
|
|
@@ -3339,6 +3452,7 @@ function ChatMessageList(props) {
|
|
|
3339
3452
|
message,
|
|
3340
3453
|
texts: props.texts,
|
|
3341
3454
|
onToolAction: props.onToolAction,
|
|
3455
|
+
onFileOpen: props.onFileOpen,
|
|
3342
3456
|
renderToolAgent: props.renderToolAgent
|
|
3343
3457
|
}), /* @__PURE__ */ jsx("div", {
|
|
3344
3458
|
className: cn("flex items-center gap-2", isUser && "justify-end"),
|
|
@@ -3365,4 +3479,4 @@ function ChatMessageList(props) {
|
|
|
3365
3479
|
});
|
|
3366
3480
|
}
|
|
3367
3481
|
//#endregion
|
|
3368
|
-
export { ChatInputBar, ChatMessageList, copyText, createChatComposerNodesFromText, createChatComposerTextNode, createChatComposerTokenNode, createEmptyChatComposerNodes, extractChatComposerTokenKeys, normalizeChatComposerNodes, removeChatComposerTokenNodes, replaceChatComposerRange, resolveChatComposerSlashTrigger, serializeChatComposerDocument, serializeChatComposerPlainText, useActiveItemScroll, useCopyFeedback, useElementWidth, useStickyBottomScroll };
|
|
3482
|
+
export { ChatInputBar, ChatMessageList, ChatMessageMarkdown, FileOperationCodeSurface, FileOperationLinesGrid, copyText, createChatComposerNodesFromText, createChatComposerTextNode, createChatComposerTokenNode, createEmptyChatComposerNodes, extractChatComposerTokenKeys, normalizeChatComposerNodes, removeChatComposerTokenNodes, replaceChatComposerRange, resolveChatComposerSlashTrigger, serializeChatComposerDocument, serializeChatComposerPlainText, useActiveItemScroll, useCopyFeedback, useElementWidth, useStickyBottomScroll };
|