@townco/ui 0.1.32 → 0.1.34
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/core/hooks/use-chat-session.d.ts +1 -1
- package/dist/core/hooks/use-chat-session.js +33 -15
- package/dist/core/schemas/chat.d.ts +1 -1
- package/dist/core/store/chat-store.js +17 -2
- package/dist/gui/components/Button.js +1 -1
- package/dist/gui/components/ChatEmptyState.js +1 -1
- package/dist/gui/components/ChatHeader.js +2 -2
- package/dist/gui/components/ChatInput.js +1 -1
- package/dist/gui/components/ChatInputCommandMenu.js +1 -1
- package/dist/gui/components/ChatLayout.js +1 -1
- package/dist/gui/components/ChatPanelTabContent.d.ts +3 -0
- package/dist/gui/components/ChatPanelTabContent.js +24 -5
- package/dist/gui/components/ChatSecondaryPanel.js +3 -3
- package/dist/gui/components/ChatView.js +28 -9
- package/dist/gui/components/Dialog.js +2 -2
- package/dist/gui/components/DropdownMenu.js +7 -7
- package/dist/gui/components/FileSystemItem.d.ts +17 -0
- package/dist/gui/components/FileSystemItem.js +81 -0
- package/dist/gui/components/FileSystemView.d.ts +14 -0
- package/dist/gui/components/FileSystemView.js +46 -0
- package/dist/gui/components/Input.js +1 -1
- package/dist/gui/components/Label.js +1 -1
- package/dist/gui/components/MarkdownRenderer.js +5 -5
- package/dist/gui/components/Message.d.ts +1 -1
- package/dist/gui/components/MessageContent.js +8 -8
- package/dist/gui/components/PanelTabsHeader.js +1 -1
- package/dist/gui/components/Reasoning.js +2 -2
- package/dist/gui/components/Response.js +13 -11
- package/dist/gui/components/Select.js +3 -3
- package/dist/gui/components/SourceListItem.js +1 -1
- package/dist/gui/components/Tabs.js +1 -1
- package/dist/gui/components/Task.js +2 -2
- package/dist/gui/components/Textarea.js +1 -1
- package/dist/gui/components/ThinkingBlock.js +2 -2
- package/dist/gui/components/TodoList.js +1 -1
- package/dist/gui/components/ToolCall.js +67 -70
- package/dist/gui/components/ToolCallList.js +1 -1
- package/dist/gui/components/index.d.ts +4 -0
- package/dist/gui/components/index.js +4 -0
- package/dist/gui/data/mockFileSystemData.d.ts +21 -0
- package/dist/gui/data/mockFileSystemData.js +127 -0
- package/dist/gui/types/filesystem.d.ts +27 -0
- package/dist/gui/types/filesystem.js +5 -0
- package/dist/sdk/schemas/session.d.ts +12 -12
- package/package.json +3 -3
- package/src/styles/global.css +108 -0
- package/dist/core/lib/logger.d.ts +0 -59
- package/dist/core/lib/logger.js +0 -191
- package/dist/tui/components/LogsPanel.d.ts +0 -5
- package/dist/tui/components/LogsPanel.js +0 -29
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* FileSystemView component - main file tree/manager view
|
|
4
|
+
* Based on shadcn file manager design and Figma specifications
|
|
5
|
+
*/
|
|
6
|
+
import * as React from "react";
|
|
7
|
+
import { MockFileSystemProvider } from "../data/mockFileSystemData.js";
|
|
8
|
+
import { cn } from "../lib/utils.js";
|
|
9
|
+
import { FileSystemItem } from "./FileSystemItem.js";
|
|
10
|
+
// Create a default provider instance outside the component to avoid infinite loops
|
|
11
|
+
const defaultProvider = new MockFileSystemProvider();
|
|
12
|
+
export function FileSystemView({ className, provider = defaultProvider, onItemSelect, onDownload, onRename, onDelete, }) {
|
|
13
|
+
const [items, setItems] = React.useState([]);
|
|
14
|
+
const [selectedId, setSelectedId] = React.useState();
|
|
15
|
+
const [isLoading, setIsLoading] = React.useState(true);
|
|
16
|
+
const [error, setError] = React.useState();
|
|
17
|
+
// Load root items on mount
|
|
18
|
+
React.useEffect(() => {
|
|
19
|
+
const loadItems = async () => {
|
|
20
|
+
try {
|
|
21
|
+
setIsLoading(true);
|
|
22
|
+
const rootItems = await provider.getRootItems();
|
|
23
|
+
setItems(rootItems);
|
|
24
|
+
setError(undefined);
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
setError(err instanceof Error ? err.message : "Failed to load items");
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
setIsLoading(false);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
loadItems();
|
|
34
|
+
}, [provider]);
|
|
35
|
+
const handleItemSelect = (item) => {
|
|
36
|
+
setSelectedId(item.id);
|
|
37
|
+
onItemSelect?.(item);
|
|
38
|
+
};
|
|
39
|
+
if (isLoading) {
|
|
40
|
+
return (_jsx("div", { className: cn("p-4", className), children: _jsx("p", { className: "text-sm text-muted-foreground", children: "Loading..." }) }));
|
|
41
|
+
}
|
|
42
|
+
if (error) {
|
|
43
|
+
return (_jsx("div", { className: cn("p-4", className), children: _jsxs("p", { className: "text-sm text-destructive", children: ["Error: ", error] }) }));
|
|
44
|
+
}
|
|
45
|
+
return (_jsx("div", { className: cn("flex flex-col px-4 py-3", className), children: items.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "No items found" })) : (items.map((item) => (_jsx(FileSystemItem, { item: item, onSelect: handleItemSelect, ...(selectedId && { selectedId }), ...(onDownload && { onDownload }), ...(onRename && { onRename }), ...(onDelete && { onDelete }) }, item.id)))) }));
|
|
46
|
+
}
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { cva } from "class-variance-authority";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { cn } from "../lib/utils.js";
|
|
5
|
-
const inputVariants = cva("flex h-10 w-full rounded-md border bg-input-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", {
|
|
5
|
+
const inputVariants = cva("flex h-10 w-full rounded-md border bg-input-background px-3 py-2 text-paragraph-sm ring-offset-background file:border-0 file:bg-transparent file:text-paragraph-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", {
|
|
6
6
|
variants: {
|
|
7
7
|
variant: {
|
|
8
8
|
default: "border-input focus-visible:ring-ring",
|
|
@@ -2,6 +2,6 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { cn } from "../lib/utils.js";
|
|
5
|
-
const Label = React.forwardRef(({ className, ...props }, ref) => (_jsx(LabelPrimitive.Root, { ref: ref, className: cn("text-
|
|
5
|
+
const Label = React.forwardRef(({ className, ...props }, ref) => (_jsx(LabelPrimitive.Root, { ref: ref, className: cn("text-label font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", className), ...props })));
|
|
6
6
|
Label.displayName = LabelPrimitive.Root.displayName;
|
|
7
7
|
export { Label };
|
|
@@ -25,15 +25,15 @@ export function MarkdownRenderer({ content, className, }) {
|
|
|
25
25
|
code: ({ node, ...props }) => {
|
|
26
26
|
const inline = !props.className?.includes("language-");
|
|
27
27
|
if (inline) {
|
|
28
|
-
return (_jsx("code", { className: "px-1.5 py-0.5 bg-card border border-border rounded text-
|
|
28
|
+
return (_jsx("code", { className: "px-1.5 py-0.5 bg-card border border-border rounded text-code text-foreground", ...props }));
|
|
29
29
|
}
|
|
30
|
-
return (_jsx("code", { className: "block p-4 bg-card border border-border rounded-md overflow-x-auto text-
|
|
30
|
+
return (_jsx("code", { className: "block p-4 bg-card border border-border rounded-md overflow-x-auto text-code text-foreground", ...props }));
|
|
31
31
|
},
|
|
32
32
|
pre: ({ node, ...props }) => _jsx("pre", { className: "my-4", ...props }),
|
|
33
33
|
// Heading styling
|
|
34
|
-
h1: ({ node, ...props }) => (_jsx("h1", { className: "text-
|
|
35
|
-
h2: ({ node, ...props }) => (_jsx("h2", { className: "text-
|
|
36
|
-
h3: ({ node, ...props }) => (_jsx("h3", { className: "text-
|
|
34
|
+
h1: ({ node, ...props }) => (_jsx("h1", { className: "text-heading-3 mt-6 mb-4 text-foreground", ...props })),
|
|
35
|
+
h2: ({ node, ...props }) => (_jsx("h2", { className: "text-subheading mt-5 mb-3 text-foreground", ...props })),
|
|
36
|
+
h3: ({ node, ...props }) => (_jsx("h3", { className: "text-subheading mt-4 mb-2 text-foreground", ...props })),
|
|
37
37
|
// List styling
|
|
38
38
|
ul: ({ node, ...props }) => {
|
|
39
39
|
// Check if this is a task list by looking for checkbox inputs in children
|
|
@@ -7,7 +7,7 @@ import type { DisplayMessage } from "./MessageList.js";
|
|
|
7
7
|
*/
|
|
8
8
|
declare const messageVariants: (props?: ({
|
|
9
9
|
role?: "user" | "assistant" | "system" | null | undefined;
|
|
10
|
-
layout?: "default" | "
|
|
10
|
+
layout?: "default" | "compact" | "full" | null | undefined;
|
|
11
11
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
12
12
|
export interface MessageProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof messageVariants> {
|
|
13
13
|
/**
|
|
@@ -62,14 +62,14 @@ function WaitingElapsedTime({ startTime }) {
|
|
|
62
62
|
}, []);
|
|
63
63
|
const seconds = (elapsed / 1000).toFixed(1);
|
|
64
64
|
const animatedDots = DOT_ANIMATIONS[dotIndex];
|
|
65
|
-
return (_jsxs("span", { className: "text-muted-foreground text-sm", children: [thinkingWord, animatedDots, " ", seconds, "s"] }));
|
|
65
|
+
return (_jsxs("span", { className: "text-muted-foreground text-paragraph-sm", children: [thinkingWord, animatedDots, " ", seconds, "s"] }));
|
|
66
66
|
}
|
|
67
|
-
const messageContentVariants = cva("w-full
|
|
67
|
+
const messageContentVariants = cva("w-full rounded-2xl text-[var(--font-size)] font-[var(--font-family)] leading-relaxed break-words transition-colors", {
|
|
68
68
|
variants: {
|
|
69
69
|
role: {
|
|
70
|
-
user: "bg-
|
|
71
|
-
assistant: "text-foreground",
|
|
72
|
-
system: "bg-card border border-border text-foreground opacity-80 text-
|
|
70
|
+
user: "bg-secondary text-foreground px-4 py-4 text-paragraph",
|
|
71
|
+
assistant: "text-foreground text-paragraph-sm",
|
|
72
|
+
system: "bg-card border border-border text-foreground opacity-80 text-caption px-4 py-3",
|
|
73
73
|
},
|
|
74
74
|
variant: {
|
|
75
75
|
default: "",
|
|
@@ -109,7 +109,7 @@ export const MessageContent = React.forwardRef(({ role: roleProp, variant, isStr
|
|
|
109
109
|
// If no tool calls or they don't have positions, render old way
|
|
110
110
|
if (sortedToolCalls.length === 0 ||
|
|
111
111
|
!sortedToolCalls.some((tc) => tc.contentPosition !== undefined)) {
|
|
112
|
-
return (_jsxs(_Fragment, { children: [sortedToolCalls.length > 0 && (_jsx("div", { className: "flex flex-col gap-2 mb-
|
|
112
|
+
return (_jsxs(_Fragment, { children: [sortedToolCalls.length > 0 && (_jsx("div", { className: "flex flex-col gap-2 mb-1", children: sortedToolCalls.map((toolCall) => (_jsx(ToolCall, { toolCall: toolCall }, toolCall.id))) })), _jsx(Response, { content: message.content, isStreaming: message.isStreaming, showEmpty: false })] }));
|
|
113
113
|
}
|
|
114
114
|
// Render content interleaved with tool calls
|
|
115
115
|
const elements = [];
|
|
@@ -124,7 +124,7 @@ export const MessageContent = React.forwardRef(({ role: roleProp, variant, isStr
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
// Add the tool call
|
|
127
|
-
elements.push(_jsx("div", {
|
|
127
|
+
elements.push(_jsx("div", { children: _jsx(ToolCall, { toolCall: toolCall }) }, `tool-${toolCall.id}`));
|
|
128
128
|
currentPosition = position;
|
|
129
129
|
});
|
|
130
130
|
// Add remaining text after the last tool call
|
|
@@ -135,7 +135,7 @@ export const MessageContent = React.forwardRef(({ role: roleProp, variant, isStr
|
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
return _jsx(_Fragment, { children: elements });
|
|
138
|
-
})()) : (_jsx("div", { className: "whitespace-pre-wrap", children: message.content })), message.role === "assistant" && message.tokenUsage && (_jsx("div", { className: "mt-3 pt-2 border-t border-border/30 text-
|
|
138
|
+
})()) : (_jsx("div", { className: "whitespace-pre-wrap", children: message.content })), message.role === "assistant" && message.tokenUsage && (_jsx("div", { className: "mt-3 pt-2 border-t border-border/30 text-caption text-muted-foreground/60", children: _jsxs("span", { children: ["Context:", " ", formatTokenPercentage(message.tokenUsage.totalTokens ?? 0, currentModel ?? undefined), " ", "(", (message.tokenUsage.totalTokens ?? 0).toLocaleString(), " ", "tokens)"] }) }))] }));
|
|
139
139
|
}
|
|
140
140
|
return (_jsx("div", { ref: ref, className: cn(messageContentVariants({ role, variant }), isStreaming && "animate-pulse-subtle", className), ...props, children: content }));
|
|
141
141
|
});
|
|
@@ -30,7 +30,7 @@ export const PanelTabsHeader = React.forwardRef(({ showIcons = true, visibleTabs
|
|
|
30
30
|
const gap = variant === "compact" ? "gap-[4px]" : "gap-3";
|
|
31
31
|
return (_jsx(TabsList, { ref: ref, className: cn("w-full justify-start bg-transparent p-0 h-auto", gap, className), ...props, children: tabs.map((tab) => {
|
|
32
32
|
const Icon = tab.icon;
|
|
33
|
-
return (_jsxs(TabsTrigger, { value: tab.id, className: cn("gap-2 px-3 py-1.5 rounded-lg text-sm font-medium", "data-[state=active]:bg-zinc-100 data-[state=active]:text-foreground", "data-[state=inactive]:text-muted-foreground"), children: [showIcons && Icon && _jsx(Icon, { className: "size-4" }), tab.label] }, tab.id));
|
|
33
|
+
return (_jsxs(TabsTrigger, { value: tab.id, className: cn("gap-2 px-3 py-1.5 rounded-lg text-paragraph-sm font-medium", "data-[state=active]:bg-zinc-100 data-[state=active]:text-foreground", "data-[state=inactive]:text-muted-foreground"), children: [showIcons && Icon && _jsx(Icon, { className: "size-4" }), tab.label] }, tab.id));
|
|
34
34
|
}) }));
|
|
35
35
|
});
|
|
36
36
|
PanelTabsHeader.displayName = "PanelTabsHeader";
|
|
@@ -59,12 +59,12 @@ export const Reasoning = React.forwardRef(({ content, isStreaming = false, mode
|
|
|
59
59
|
}
|
|
60
60
|
// Inline mode - always visible
|
|
61
61
|
if (mode === "inline") {
|
|
62
|
-
return (_jsxs("div", { ref: ref, className: cn(reasoningContainerVariants({ variant }), "p-3", className), children: [_jsxs("div", { className: "flex items-start gap-2 mb-2", children: [_jsx("span", { className: "text-
|
|
62
|
+
return (_jsxs("div", { ref: ref, className: cn(reasoningContainerVariants({ variant }), "p-3", className), children: [_jsxs("div", { className: "flex items-start gap-2 mb-2", children: [_jsx("span", { className: "text-caption font-medium text-foreground opacity-60 uppercase tracking-wide", children: label }), isStreaming && (_jsx("span", { className: "inline-block w-2 h-2 bg-primary rounded-full animate-pulse" }))] }), _jsxs("div", { className: "text-paragraph-sm italic text-foreground opacity-80 leading-relaxed whitespace-pre-wrap", children: [content, isStreaming && content && (_jsx("span", { className: "inline-block animate-typing text-primary", children: "..." }))] })] }));
|
|
63
63
|
}
|
|
64
64
|
// Collapsible mode
|
|
65
65
|
return (_jsxs("div", { ref: ref, className: cn("mb-3", className), children: [_jsxs("button", { type: "button", onClick: () => {
|
|
66
66
|
setIsExpanded(!isExpanded);
|
|
67
67
|
setShouldAutoCollapse(false); // Disable auto-collapse on manual interaction
|
|
68
|
-
}, className: "w-full flex items-center justify-between p-2.5 rounded-lg bg-card border border-border hover:bg-card/80 hover:shadow-sm transition-all text-left", "aria-expanded": isExpanded, "aria-label": `${isExpanded ? "Collapse" : "Expand"} reasoning`, children: [_jsxs("div", { className: "flex items-center gap-2 flex-1 min-w-0", children: [_jsx("span", { className: "text-
|
|
68
|
+
}, className: "w-full flex items-center justify-between p-2.5 rounded-lg bg-card border border-border hover:bg-card/80 hover:shadow-sm transition-all text-left", "aria-expanded": isExpanded, "aria-label": `${isExpanded ? "Collapse" : "Expand"} reasoning`, children: [_jsxs("div", { className: "flex items-center gap-2 flex-1 min-w-0", children: [_jsx("span", { className: "text-caption font-medium text-foreground opacity-60 uppercase tracking-wide shrink-0", children: label }), isStreaming && (_jsx("span", { className: "inline-block w-2 h-2 bg-primary rounded-full animate-pulse shrink-0" })), !isExpanded && content && (_jsxs("span", { className: "text-caption text-foreground opacity-50 truncate", children: [content.substring(0, 60), content.length > 60 && "..."] }))] }), _jsx(ChevronDown, { className: reasoningIconVariants({ expanded: isExpanded }), "aria-hidden": "true" })] }), isExpanded && (_jsx("div", { className: cn(reasoningContainerVariants({ variant }), "mt-2 p-3 animate-fadeIn"), children: _jsxs("div", { className: "text-paragraph-sm italic text-foreground opacity-80 leading-relaxed whitespace-pre-wrap", children: [content, isStreaming && content && (_jsx("span", { className: "inline-block animate-typing text-primary", children: "..." }))] }) }))] }));
|
|
69
69
|
});
|
|
70
70
|
Reasoning.displayName = "Reasoning";
|
|
@@ -6,7 +6,7 @@ import { cn } from "../lib/utils.js";
|
|
|
6
6
|
export const Response = React.forwardRef(({ content, isStreaming = false, showEmpty = true, emptyMessage = "", className, ...props }, ref) => {
|
|
7
7
|
// Show empty state during streaming if no content yet
|
|
8
8
|
if (!content && isStreaming && showEmpty) {
|
|
9
|
-
return (_jsx("div", { ref: ref, className: cn("opacity-70 italic text-sm", className), ...props, children: emptyMessage }));
|
|
9
|
+
return (_jsx("div", { ref: ref, className: cn("opacity-70 italic text-paragraph-sm", className), ...props, children: emptyMessage }));
|
|
10
10
|
}
|
|
11
11
|
if (!content) {
|
|
12
12
|
return null;
|
|
@@ -30,16 +30,16 @@ export const Response = React.forwardRef(({ content, isStreaming = false, showEm
|
|
|
30
30
|
code: ({ node, ...props }) => {
|
|
31
31
|
const inline = !props.className?.includes("language-");
|
|
32
32
|
if (inline) {
|
|
33
|
-
return (_jsx("code", { className: "px-1.5 py-0.5 bg-card border border-border rounded text-
|
|
33
|
+
return (_jsx("code", { className: "px-1.5 py-0.5 bg-card border border-border rounded text-code text-foreground", ...props }));
|
|
34
34
|
}
|
|
35
|
-
return (_jsx("code", { className: "block p-4 bg-card border border-border rounded-md overflow-x-auto text-
|
|
35
|
+
return (_jsx("code", { className: "block p-4 bg-card border border-border rounded-md overflow-x-auto text-code text-foreground shadow-sm", ...props }));
|
|
36
36
|
},
|
|
37
37
|
pre: ({ node, ...props }) => (_jsx("pre", { className: "my-4 rounded-lg", ...props })),
|
|
38
38
|
// Heading styling with improved hierarchy
|
|
39
|
-
h1: ({ node, ...props }) => (_jsx("h1", { className: "text-
|
|
40
|
-
h2: ({ node, ...props }) => (_jsx("h2", { className: "text-
|
|
41
|
-
h3: ({ node, ...props }) => (_jsx("h3", { className: "text-
|
|
42
|
-
h4: ({ node, ...props }) => (_jsx("h4", { className: "text-
|
|
39
|
+
h1: ({ node, ...props }) => (_jsx("h1", { className: "text-heading-3 mt-6 mb-4 text-foreground border-b border-border pb-2", ...props })),
|
|
40
|
+
h2: ({ node, ...props }) => (_jsx("h2", { className: "text-subheading mt-5 mb-3 text-foreground border-b border-border/50 pb-1.5", ...props })),
|
|
41
|
+
h3: ({ node, ...props }) => (_jsx("h3", { className: "text-subheading mt-4 mb-2 text-foreground", ...props })),
|
|
42
|
+
h4: ({ node, ...props }) => (_jsx("h4", { className: "text-paragraph-sm font-semibold mt-3 mb-2 text-foreground", ...props })),
|
|
43
43
|
// List styling
|
|
44
44
|
ul: ({ node, ...props }) => {
|
|
45
45
|
// Check if this is a task list by looking for checkbox inputs in children
|
|
@@ -62,9 +62,11 @@ export const Response = React.forwardRef(({ content, isStreaming = false, showEm
|
|
|
62
62
|
grandChild.properties !== null &&
|
|
63
63
|
"type" in grandChild.properties &&
|
|
64
64
|
grandChild.properties.type === "checkbox"));
|
|
65
|
-
return (_jsx("ul", { className: cn("my-2 space-y-1 text-foreground", isTaskList
|
|
65
|
+
return (_jsx("ul", { className: cn("my-2 space-y-1 text-foreground", isTaskList
|
|
66
|
+
? "list-none space-y-2"
|
|
67
|
+
: "list-disc list-outside pl-4"), ...props }));
|
|
66
68
|
},
|
|
67
|
-
ol: ({ node, ...props }) => (_jsx("ol", { className: "list-decimal list-
|
|
69
|
+
ol: ({ node, ...props }) => (_jsx("ol", { className: "list-decimal list-outside pl-4 my-2 space-y-1 text-foreground", ...props })),
|
|
68
70
|
// List item styling
|
|
69
71
|
li: ({ node, ...props }) => {
|
|
70
72
|
// Check if this li contains a checkbox (task list item)
|
|
@@ -79,12 +81,12 @@ export const Response = React.forwardRef(({ content, isStreaming = false, showEm
|
|
|
79
81
|
child.properties !== null &&
|
|
80
82
|
"type" in child.properties &&
|
|
81
83
|
child.properties.type === "checkbox");
|
|
82
|
-
return (_jsx("li", { className: cn("flex items-start
|
|
84
|
+
return (_jsx("li", { className: cn(isTaskListItem ? "flex items-start gap-2" : ""), ...props }));
|
|
83
85
|
},
|
|
84
86
|
// Link styling with hover effect
|
|
85
87
|
a: ({ node, ...props }) => (_jsx("a", { className: "text-primary hover:underline decoration-2 underline-offset-2 transition-all", target: "_blank", rel: "noopener noreferrer", ...props })),
|
|
86
88
|
// Paragraph styling
|
|
87
|
-
p: ({ node, ...props }) => (_jsx("p", { className: "
|
|
89
|
+
p: ({ node, ...props }) => (_jsx("p", { className: "mb-2 text-foreground leading-relaxed", ...props })),
|
|
88
90
|
// Blockquote styling with enhanced visual
|
|
89
91
|
blockquote: ({ node, ...props }) => (_jsx("blockquote", { className: "border-l-4 border-[primary] pl-4 italic my-4 text-foreground bg-card py-2 rounded-r-md shadow-sm", ...props })),
|
|
90
92
|
// Horizontal rule
|
|
@@ -6,7 +6,7 @@ import { cn } from "../lib/utils.js";
|
|
|
6
6
|
const Select = SelectPrimitive.Root;
|
|
7
7
|
const SelectGroup = SelectPrimitive.Group;
|
|
8
8
|
const SelectValue = SelectPrimitive.Value;
|
|
9
|
-
const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(SelectPrimitive.Trigger, { ref: ref, className: cn("flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1", className), ...props, children: [children, _jsx(SelectPrimitive.Icon, { asChild: true, children: _jsx(ChevronsUpDown, { className: "h-4 w-4 opacity-50" }) })] })));
|
|
9
|
+
const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(SelectPrimitive.Trigger, { ref: ref, className: cn("flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-paragraph-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1", className), ...props, children: [children, _jsx(SelectPrimitive.Icon, { asChild: true, children: _jsx(ChevronsUpDown, { className: "h-4 w-4 opacity-50" }) })] })));
|
|
10
10
|
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
|
11
11
|
const SelectScrollUpButton = React.forwardRef(({ className, ...props }, ref) => (_jsx(SelectPrimitive.ScrollUpButton, { ref: ref, className: cn("flex cursor-default items-center justify-center py-1", className), ...props, children: _jsx(ChevronUp, { className: "h-4 w-4" }) })));
|
|
12
12
|
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
|
@@ -17,9 +17,9 @@ const SelectContent = React.forwardRef(({ className, children, position = "poppe
|
|
|
17
17
|
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", className), position: position, ...props, children: [_jsx(SelectScrollUpButton, {}), _jsx(SelectPrimitive.Viewport, { className: cn("p-1", position === "popper" &&
|
|
18
18
|
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"), children: children }), _jsx(SelectScrollDownButton, {})] }) })));
|
|
19
19
|
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
20
|
-
const SelectLabel = React.forwardRef(({ className, ...props }, ref) => (_jsx(SelectPrimitive.Label, { ref: ref, className: cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className), ...props })));
|
|
20
|
+
const SelectLabel = React.forwardRef(({ className, ...props }, ref) => (_jsx(SelectPrimitive.Label, { ref: ref, className: cn("py-1.5 pl-8 pr-2 text-paragraph-sm font-semibold", className), ...props })));
|
|
21
21
|
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
22
|
-
const SelectItem = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(SelectPrimitive.Item, { ref: ref, className: cn("relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className), ...props, children: [_jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: _jsx(SelectPrimitive.ItemIndicator, { children: _jsx(Check, { className: "h-4 w-4" }) }) }), _jsx(SelectPrimitive.ItemText, { children: children })] })));
|
|
22
|
+
const SelectItem = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(SelectPrimitive.Item, { ref: ref, className: cn("relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-paragraph-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className), ...props, children: [_jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: _jsx(SelectPrimitive.ItemIndicator, { children: _jsx(Check, { className: "h-4 w-4" }) }) }), _jsx(SelectPrimitive.ItemText, { children: children })] })));
|
|
23
23
|
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
24
24
|
const SelectSeparator = React.forwardRef(({ className, ...props }, ref) => (_jsx(SelectPrimitive.Separator, { ref: ref, className: cn("-mx-1 my-1 h-px bg-muted", className), ...props })));
|
|
25
25
|
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
|
@@ -2,6 +2,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { cn } from "../lib/utils.js";
|
|
4
4
|
export const SourceListItem = React.forwardRef(({ source, isSelected, className, ...props }, ref) => {
|
|
5
|
-
return (_jsxs("button", { ref: ref, type: "button", className: cn("flex w-full text-left gap-2 items-start p-3 rounded-lg transition-colors cursor-pointer border border-transparent", "hover:bg-accent-hover hover:border-border/50", isSelected && "bg-accent-hover border-border/50", className), onClick: () => window.open(source.url, "_blank"), ...props, children: [_jsx("div", { className: "flex gap-2 items-center py-[2px] shrink-0", children: _jsx("div", { className: "relative rounded-[3px] shrink-0 size-4 overflow-hidden bg-muted", children: source.favicon ? (_jsx("img", { alt: source.sourceName, className: "size-full object-cover", src: source.favicon })) : (_jsx("div", { className: "size-full bg-muted" })) }) }), _jsxs("div", { className: "flex flex-1 flex-col gap-1 min-w-0", children: [_jsxs("div", { className: "text-
|
|
5
|
+
return (_jsxs("button", { ref: ref, type: "button", className: cn("flex w-full text-left gap-2 items-start p-3 rounded-lg transition-colors cursor-pointer border border-transparent", "hover:bg-accent-hover hover:border-border/50", isSelected && "bg-accent-hover border-border/50", className), onClick: () => window.open(source.url, "_blank"), ...props, children: [_jsx("div", { className: "flex gap-2 items-center py-[2px] shrink-0", children: _jsx("div", { className: "relative rounded-[3px] shrink-0 size-4 overflow-hidden bg-muted", children: source.favicon ? (_jsx("img", { alt: source.sourceName, className: "size-full object-cover", src: source.favicon })) : (_jsx("div", { className: "size-full bg-muted" })) }) }), _jsxs("div", { className: "flex flex-1 flex-col gap-1 min-w-0", children: [_jsxs("div", { className: "text-caption leading-normal text-foreground", children: [_jsx("span", { className: "font-medium", children: source.sourceName }), _jsxs("span", { className: "text-muted-foreground", children: [" \u00B7 ", source.title] })] }), _jsx("p", { className: "text-caption leading-relaxed text-muted-foreground line-clamp-3", children: source.snippet })] })] }));
|
|
6
6
|
});
|
|
7
7
|
SourceListItem.displayName = "SourceListItem";
|
|
@@ -5,7 +5,7 @@ import { cn } from "../lib/utils.js";
|
|
|
5
5
|
const Tabs = TabsPrimitive.Root;
|
|
6
6
|
const TabsList = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.List, { ref: ref, className: cn("inline-flex h-10 items-center rounded-md bg-muted p-1 text-muted-foreground gap-1", className), ...props })));
|
|
7
7
|
TabsList.displayName = TabsPrimitive.List.displayName;
|
|
8
|
-
const TabsTrigger = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.Trigger, { ref: ref, className: cn("inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm", className), ...props })));
|
|
8
|
+
const TabsTrigger = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.Trigger, { ref: ref, className: cn("inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-paragraph-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm", className), ...props })));
|
|
9
9
|
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
|
|
10
10
|
const TabsContent = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.Content, { ref: ref, className: cn("mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", className), ...props })));
|
|
11
11
|
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
|
@@ -28,10 +28,10 @@ export const Task = React.forwardRef(({ task, collapsible = true, defaultExpande
|
|
|
28
28
|
}
|
|
29
29
|
onTaskClick?.(task);
|
|
30
30
|
};
|
|
31
|
-
return (_jsxs("div", { ref: ref, className: cn("rounded-lg border border-border bg-card transition-all", "hover:shadow-sm hover:border-border/80", className), ...props, children: [_jsxs("button", { type: "button", onClick: handleClick, className: cn("w-full flex items-center gap-3 px-3 py-2.5 text-left", hasDetails && collapsible && "cursor-pointer"), disabled: !hasDetails && !collapsible, children: [_jsx(StatusIcon, { className: cn("w-4 h-4 shrink-0", getStatusColor(), task.status === "in_progress" && "animate-spin") }), _jsx("span", { className: cn("flex-1 text-sm font-[var(--font-family)]", task.status === "completed" && "line-through opacity-60", task.status === "in_progress" && "font-medium"), children: task.text }), hasDetails && collapsible && (_jsx(ChevronDown, { className: cn("w-4 h-4 text-foreground opacity-50 transition-transform duration-200 shrink-0", isExpanded && "rotate-180"), "aria-hidden": "true" }))] }), hasDetails && isExpanded && (_jsxs("div", { className: "px-3 pb-3 pt-1 border-t border-border/50 animate-fadeIn", children: [task.details && (_jsx("p", { className: "text-sm text-foreground opacity-80 leading-relaxed mb-2", children: task.details })), task.files && task.files.length > 0 && (_jsxs("div", { className: "space-y-1", children: [_jsx("span", { className: "text-
|
|
31
|
+
return (_jsxs("div", { ref: ref, className: cn("rounded-lg border border-border bg-card transition-all", "hover:shadow-sm hover:border-border/80", className), ...props, children: [_jsxs("button", { type: "button", onClick: handleClick, className: cn("w-full flex items-center gap-3 px-3 py-2.5 text-left", hasDetails && collapsible && "cursor-pointer"), disabled: !hasDetails && !collapsible, children: [_jsx(StatusIcon, { className: cn("w-4 h-4 shrink-0", getStatusColor(), task.status === "in_progress" && "animate-spin") }), _jsx("span", { className: cn("flex-1 text-paragraph-sm font-[var(--font-family)]", task.status === "completed" && "line-through opacity-60", task.status === "in_progress" && "font-medium"), children: task.text }), hasDetails && collapsible && (_jsx(ChevronDown, { className: cn("w-4 h-4 text-foreground opacity-50 transition-transform duration-200 shrink-0", isExpanded && "rotate-180"), "aria-hidden": "true" }))] }), hasDetails && isExpanded && (_jsxs("div", { className: "px-3 pb-3 pt-1 border-t border-border/50 animate-fadeIn", children: [task.details && (_jsx("p", { className: "text-paragraph-sm text-foreground opacity-80 leading-relaxed mb-2", children: task.details })), task.files && task.files.length > 0 && (_jsxs("div", { className: "space-y-1", children: [_jsx("span", { className: "text-caption font-medium text-foreground opacity-60 uppercase tracking-wide", children: "Files:" }), _jsx("div", { className: "space-y-1", children: task.files.map((file) => (_jsx("div", { className: "text-caption font-mono text-foreground opacity-70 bg-background px-2 py-1 rounded border border-border/50", children: file }, file))) })] }))] }))] }));
|
|
32
32
|
});
|
|
33
33
|
Task.displayName = "Task";
|
|
34
34
|
export const TaskList = React.forwardRef(({ tasks, collapsible = true, onTaskClick, emptyMessage = "No tasks yet.", className, ...props }, ref) => {
|
|
35
|
-
return (_jsx("div", { ref: ref, className: cn("space-y-2 max-h-96 overflow-y-auto", className), ...props, children: tasks.length === 0 ? (_jsx("p", { className: "text-sm text-foreground opacity-60 italic py-4 text-center", children: emptyMessage })) : (tasks.map((task) => (_jsx(Task, { task: task, collapsible: collapsible, ...(onTaskClick ? { onTaskClick } : {}) }, task.id)))) }));
|
|
35
|
+
return (_jsx("div", { ref: ref, className: cn("space-y-2 max-h-96 overflow-y-auto", className), ...props, children: tasks.length === 0 ? (_jsx("p", { className: "text-paragraph-sm text-foreground opacity-60 italic py-4 text-center", children: emptyMessage })) : (tasks.map((task) => (_jsx(Task, { task: task, collapsible: collapsible, ...(onTaskClick ? { onTaskClick } : {}) }, task.id)))) }));
|
|
36
36
|
});
|
|
37
37
|
TaskList.displayName = "TaskList";
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { cva } from "class-variance-authority";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { cn } from "../lib/utils.js";
|
|
5
|
-
const textareaVariants = cva("flex min-h-[80px] w-full rounded-md border bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 resize-none", {
|
|
5
|
+
const textareaVariants = cva("flex min-h-[80px] w-full rounded-md border bg-background px-3 py-2 text-paragraph-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 resize-none", {
|
|
6
6
|
variants: {
|
|
7
7
|
variant: {
|
|
8
8
|
default: "border-input focus-visible:ring-ring",
|
|
@@ -33,8 +33,8 @@ export function ThinkingBlock({ thinking, isStreaming, displayMode = "collapsibl
|
|
|
33
33
|
}
|
|
34
34
|
// Inline mode - always visible
|
|
35
35
|
if (displayMode === "inline") {
|
|
36
|
-
return (_jsxs("div", { className: cn(thinkingBlockVariants({ variant }), className), children: [_jsxs("div", { className: "flex items-start gap-2", children: [_jsx("span", { className: "text-
|
|
36
|
+
return (_jsxs("div", { className: cn(thinkingBlockVariants({ variant }), className), children: [_jsxs("div", { className: "flex items-start gap-2", children: [_jsx("span", { className: "text-caption font-medium text-foreground opacity-60 uppercase tracking-wide", children: "Thinking" }), isStreaming && (_jsx("span", { className: "inline-block w-2 h-2 bg-primary rounded-full animate-pulse" }))] }), _jsxs("div", { className: "mt-2 text-paragraph-sm italic text-foreground opacity-80 leading-relaxed whitespace-pre-wrap", children: [thinking, isStreaming && thinking && (_jsx("span", { className: "inline-block animate-typing", children: "..." }))] })] }));
|
|
37
37
|
}
|
|
38
38
|
// Collapsible mode
|
|
39
|
-
return (_jsxs("div", { className: cn("mb-3", className), children: [_jsxs("button", { type: "button", onClick: () => setIsExpanded(!isExpanded), className: "w-full flex items-center justify-between p-2 rounded-lg bg-card border border-border hover:bg-card transition-colors text-left", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-
|
|
39
|
+
return (_jsxs("div", { className: cn("mb-3", className), children: [_jsxs("button", { type: "button", onClick: () => setIsExpanded(!isExpanded), className: "w-full flex items-center justify-between p-2 rounded-lg bg-card border border-border hover:bg-card transition-colors text-left", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-caption font-medium text-foreground opacity-60 uppercase tracking-wide", children: "Thinking" }), isStreaming && (_jsx("span", { className: "inline-block w-2 h-2 bg-primary rounded-full animate-pulse" })), !isExpanded && thinking && (_jsxs("span", { className: "text-caption text-foreground opacity-50 truncate max-w-[200px]", children: [thinking.substring(0, 50), "..."] }))] }), _jsx(ChevronDown, { className: thinkingIconVariants({ expanded: isExpanded }) })] }), isExpanded && (_jsx("div", { className: cn(thinkingBlockVariants({ variant }), "mt-2"), children: _jsxs("div", { className: "text-paragraph-sm italic text-foreground opacity-80 leading-relaxed whitespace-pre-wrap", children: [thinking, isStreaming && thinking && (_jsx("span", { className: "inline-block animate-typing", children: "..." }))] }) }))] }));
|
|
40
40
|
}
|
|
@@ -6,6 +6,6 @@ export const TodoList = React.forwardRef(({ client, todos, className, ...props }
|
|
|
6
6
|
// For now, just use prop-based todos
|
|
7
7
|
// Future: Add hook to get todos from store when available
|
|
8
8
|
const todosToDisplay = todos || [];
|
|
9
|
-
return (_jsx("div", { ref: ref, className: cn("space-y-2 max-h-64 overflow-y-auto", className), ...props, children: todosToDisplay.length === 0 ? (_jsx("p", { className: "text-sm text-foreground opacity-60 italic", children: "No tasks yet." })) : (todosToDisplay.map((todo) => (_jsx(TodoListItem, { todo: todo }, todo.id)))) }));
|
|
9
|
+
return (_jsx("div", { ref: ref, className: cn("space-y-2 max-h-64 overflow-y-auto", className), ...props, children: todosToDisplay.length === 0 ? (_jsx("p", { className: "text-paragraph-sm text-foreground opacity-60 italic", children: "No tasks yet." })) : (todosToDisplay.map((todo) => (_jsx(TodoListItem, { todo: todo }, todo.id)))) }));
|
|
10
10
|
});
|
|
11
11
|
TodoList.displayName = "TodoList";
|
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import JsonView from "@uiw/react-json-view";
|
|
3
|
-
import { Wrench } from "lucide-react";
|
|
3
|
+
import { ChevronDown, Wrench } from "lucide-react";
|
|
4
4
|
import { useState } from "react";
|
|
5
|
-
/**
|
|
6
|
-
* Tool call status badge styles
|
|
7
|
-
*/
|
|
8
|
-
const statusStyles = {
|
|
9
|
-
pending: "bg-transparent text-muted-foreground",
|
|
10
|
-
in_progress: "bg-transparent text-muted-foreground",
|
|
11
|
-
completed: "bg-transparent text-muted-foreground",
|
|
12
|
-
failed: "bg-transparent text-muted-foreground",
|
|
13
|
-
};
|
|
14
5
|
/**
|
|
15
6
|
* Tool call kind icons (using emoji for simplicity)
|
|
16
7
|
*/
|
|
@@ -31,70 +22,76 @@ const _kindIcons = {
|
|
|
31
22
|
*/
|
|
32
23
|
export function ToolCall({ toolCall }) {
|
|
33
24
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
34
|
-
return (_jsxs("div", { className: "flex flex-col", children: [
|
|
25
|
+
return (_jsxs("div", { className: "flex flex-col my-2", children: [_jsx("button", { type: "button", className: "flex items-center gap-2 cursor-pointer bg-transparent border-none p-0 text-left group w-fit", onClick: () => setIsExpanded(!isExpanded), "aria-expanded": isExpanded, children: _jsxs("div", { className: "flex items-center gap-1.5 text-[11px] font-medium text-zinc-500", children: [_jsx("div", { className: "text-zinc-500", children: _jsx(Wrench, { className: "h-3 w-3" }) }), _jsx("span", { className: "text-paragraph-sm text-zinc-500", children: toolCall.title }), _jsx(ChevronDown, { className: `h-3 w-3 text-zinc-400 transition-transform duration-200 ${isExpanded ? "rotate-180" : ""}` })] }) }), isExpanded && (_jsxs("div", { className: "mt-2 text-sm border border-zinc-200 rounded-lg bg-zinc-50 overflow-hidden w-full", children: [toolCall.locations && toolCall.locations.length > 0 && (_jsxs("div", { className: "p-3 border-b border-zinc-200", children: [_jsx("div", { className: "text-[10px] font-bold text-zinc-400 uppercase tracking-wider mb-1.5 font-sans", children: "Files" }), _jsx("ul", { className: "space-y-1", children: toolCall.locations.map((loc) => (_jsxs("li", { className: "font-mono text-[11px] text-zinc-700 bg-zinc-200/50 px-1.5 py-0.5 rounded w-fit", children: [loc.path, loc.line !== null &&
|
|
35
26
|
loc.line !== undefined &&
|
|
36
|
-
`:${loc.line}`] }, `${loc.path}:${loc.line ?? ""}`))) })] })), toolCall.rawInput && Object.keys(toolCall.rawInput).length > 0 && (_jsxs("div", { children: [_jsx("div", { className: "text-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
27
|
+
`:${loc.line}`] }, `${loc.path}:${loc.line ?? ""}`))) })] })), toolCall.rawInput && Object.keys(toolCall.rawInput).length > 0 && (_jsxs("div", { className: "p-3 border-b border-zinc-200", children: [_jsx("div", { className: "text-[10px] font-bold text-zinc-400 uppercase tracking-wider mb-1.5 font-sans", children: "Input" }), _jsx("div", { className: "text-[11px] font-mono text-zinc-700", children: _jsx(JsonView, { value: toolCall.rawInput, collapsed: false, displayDataTypes: false, displayObjectSize: false, enableClipboard: true, style: {
|
|
28
|
+
fontSize: "11px",
|
|
29
|
+
backgroundColor: "transparent",
|
|
30
|
+
fontFamily: "inherit",
|
|
31
|
+
} }) })] })), (toolCall.content && toolCall.content.length > 0) ||
|
|
32
|
+
toolCall.error ? (_jsxs("div", { className: "p-3 border-b border-zinc-200 last:border-0", children: [_jsx("div", { className: "text-[10px] font-bold text-zinc-400 uppercase tracking-wider mb-1.5 font-sans", children: "Output" }), _jsxs("div", { className: "space-y-2 text-[11px] text-zinc-700", children: [toolCall.content?.map((block, idx) => {
|
|
33
|
+
// Generate a stable key based on content
|
|
34
|
+
const getBlockKey = () => {
|
|
35
|
+
if (block.type === "diff" && "path" in block) {
|
|
36
|
+
return `diff-${block.path}-${idx}`;
|
|
37
|
+
}
|
|
38
|
+
if (block.type === "terminal" && "terminalId" in block) {
|
|
39
|
+
return `terminal-${block.terminalId}`;
|
|
40
|
+
}
|
|
41
|
+
if (block.type === "text" && "text" in block) {
|
|
42
|
+
return `text-${block.text.substring(0, 20)}-${idx}`;
|
|
43
|
+
}
|
|
44
|
+
if (block.type === "content" && "content" in block) {
|
|
45
|
+
const innerContent = block.content;
|
|
46
|
+
return `content-${innerContent.text?.substring(0, 20)}-${idx}`;
|
|
47
|
+
}
|
|
48
|
+
return `block-${idx}`;
|
|
49
|
+
};
|
|
50
|
+
// Helper to render text content (with JSON parsing if applicable)
|
|
51
|
+
const renderTextContent = (text, key) => {
|
|
52
|
+
// Try to parse as JSON
|
|
53
|
+
try {
|
|
54
|
+
const parsed = JSON.parse(text);
|
|
55
|
+
// If it's an object or array, render with JsonView
|
|
56
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
57
|
+
return (_jsx("div", { className: "text-[11px]", children: _jsx(JsonView, { value: parsed, collapsed: false, displayDataTypes: false, displayObjectSize: false, enableClipboard: true, style: {
|
|
58
|
+
fontSize: "11px",
|
|
59
|
+
backgroundColor: "transparent",
|
|
60
|
+
fontFamily: "inherit",
|
|
61
|
+
} }) }, key));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// Not valid JSON, render as plain text
|
|
66
|
+
}
|
|
67
|
+
// Render as plain text
|
|
68
|
+
return (_jsx("pre", { className: "whitespace-pre-wrap font-mono text-[11px] text-zinc-700 overflow-x-auto", children: text }, key));
|
|
69
|
+
};
|
|
70
|
+
// Handle nested content blocks (ACP format)
|
|
48
71
|
if (block.type === "content" && "content" in block) {
|
|
49
72
|
const innerContent = block.content;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return `block-${idx}`;
|
|
53
|
-
};
|
|
54
|
-
// Helper to render text content (with JSON parsing if applicable)
|
|
55
|
-
const renderTextContent = (text, key) => {
|
|
56
|
-
// Try to parse as JSON
|
|
57
|
-
try {
|
|
58
|
-
const parsed = JSON.parse(text);
|
|
59
|
-
// If it's an object or array, render with JsonView
|
|
60
|
-
if (typeof parsed === "object" && parsed !== null) {
|
|
61
|
-
return (_jsx("div", { className: "bg-muted p-2 rounded border border-border", children: _jsx(JsonView, { value: parsed, collapsed: false, displayDataTypes: false, displayObjectSize: false, enableClipboard: true, style: {
|
|
62
|
-
fontSize: "11px",
|
|
63
|
-
backgroundColor: "transparent",
|
|
64
|
-
} }) }, key));
|
|
73
|
+
if (innerContent.type === "text" && innerContent.text) {
|
|
74
|
+
return renderTextContent(innerContent.text, getBlockKey());
|
|
65
75
|
}
|
|
66
76
|
}
|
|
67
|
-
|
|
68
|
-
|
|
77
|
+
// Handle direct text blocks
|
|
78
|
+
if (block.type === "text" && "text" in block) {
|
|
79
|
+
return renderTextContent(block.text, getBlockKey());
|
|
80
|
+
}
|
|
81
|
+
// Handle diff blocks
|
|
82
|
+
if (block.type === "diff" &&
|
|
83
|
+
"path" in block &&
|
|
84
|
+
"oldText" in block &&
|
|
85
|
+
"newText" in block) {
|
|
86
|
+
return (_jsxs("div", { className: "border border-zinc-200 rounded bg-white", children: [_jsxs("div", { className: "bg-zinc-50 px-2 py-1 text-[10px] font-mono text-zinc-500 border-b border-zinc-200", children: [block.path, "line" in block &&
|
|
87
|
+
block.line !== null &&
|
|
88
|
+
block.line !== undefined &&
|
|
89
|
+
`:${block.line}`] }), _jsxs("div", { className: "p-2 font-mono text-[11px]", children: [_jsxs("div", { className: "text-red-600", children: ["- ", block.oldText] }), _jsxs("div", { className: "text-green-600", children: ["+ ", block.newText] })] })] }, getBlockKey()));
|
|
69
90
|
}
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// Handle nested content blocks (ACP format)
|
|
74
|
-
if (block.type === "content" && "content" in block) {
|
|
75
|
-
const innerContent = block.content;
|
|
76
|
-
if (innerContent.type === "text" && innerContent.text) {
|
|
77
|
-
return renderTextContent(innerContent.text, getBlockKey());
|
|
91
|
+
// Handle terminal blocks
|
|
92
|
+
if (block.type === "terminal" && "terminalId" in block) {
|
|
93
|
+
return (_jsxs("div", { className: "bg-zinc-900 text-zinc-100 p-2 rounded text-[11px] font-mono", children: ["Terminal: ", block.terminalId] }, getBlockKey()));
|
|
78
94
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (block.type === "text" && "text" in block) {
|
|
82
|
-
return renderTextContent(block.text, getBlockKey());
|
|
83
|
-
}
|
|
84
|
-
// Handle diff blocks
|
|
85
|
-
if (block.type === "diff" &&
|
|
86
|
-
"path" in block &&
|
|
87
|
-
"oldText" in block &&
|
|
88
|
-
"newText" in block) {
|
|
89
|
-
return (_jsxs("div", { className: "border rounded", children: [_jsxs("div", { className: "bg-muted px-2 py-1 text-xs font-mono", children: [block.path, "line" in block &&
|
|
90
|
-
block.line !== null &&
|
|
91
|
-
block.line !== undefined &&
|
|
92
|
-
`:${block.line}`] }), _jsxs("div", { className: "p-2 font-mono text-xs", children: [_jsxs("div", { className: "text-red-600", children: ["- ", block.oldText] }), _jsxs("div", { className: "text-green-600", children: ["+ ", block.newText] })] })] }, getBlockKey()));
|
|
93
|
-
}
|
|
94
|
-
// Handle terminal blocks
|
|
95
|
-
if (block.type === "terminal" && "terminalId" in block) {
|
|
96
|
-
return (_jsxs("div", { className: "bg-black text-green-400 p-2 rounded text-xs font-mono", children: ["Terminal: ", block.terminalId] }, getBlockKey()));
|
|
97
|
-
}
|
|
98
|
-
return null;
|
|
99
|
-
}) })] })), toolCall.error && (_jsxs("div", { className: "bg-destructive/10 border border-destructive/20 rounded p-2.5 text-destructive", children: [_jsx("div", { className: "text-xs font-semibold text-destructive uppercase tracking-wide mb-1.5", children: "Error" }), _jsx("div", { className: "text-xs", children: toolCall.error })] })), toolCall.tokenUsage && (_jsxs("div", { className: "bg-muted border border-border rounded p-2.5", children: [_jsx("div", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide mb-2", children: "Token Usage" }), _jsxs("div", { className: "grid grid-cols-3 gap-3 text-xs text-foreground", children: [toolCall.tokenUsage.inputTokens !== undefined && (_jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground text-[10px] uppercase tracking-wide mb-0.5", children: "Input" }), _jsx("div", { className: "font-medium", children: toolCall.tokenUsage.inputTokens.toLocaleString() })] })), toolCall.tokenUsage.outputTokens !== undefined && (_jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground text-[10px] uppercase tracking-wide mb-0.5", children: "Output" }), _jsx("div", { className: "font-medium", children: toolCall.tokenUsage.outputTokens.toLocaleString() })] })), toolCall.tokenUsage.totalTokens !== undefined && (_jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground text-[10px] uppercase tracking-wide mb-0.5", children: "Total" }), _jsx("div", { className: "font-medium", children: toolCall.tokenUsage.totalTokens.toLocaleString() })] }))] })] })), toolCall.startedAt && (_jsxs("div", { className: "text-xs text-muted-foreground", children: ["Started: ", new Date(toolCall.startedAt).toLocaleTimeString(), toolCall.completedAt && (_jsxs(_Fragment, { children: [" ", "| Completed:", " ", new Date(toolCall.completedAt).toLocaleTimeString(), " (", Math.round((toolCall.completedAt - toolCall.startedAt) / 1000), "s)"] }))] }))] }))] }));
|
|
95
|
+
return null;
|
|
96
|
+
}), toolCall.error && (_jsxs("div", { className: "text-red-600 font-mono text-[11px] mt-2", children: ["Error: ", toolCall.error] }))] })] })) : null, (toolCall.tokenUsage || toolCall.startedAt) && (_jsxs("div", { className: "p-2 bg-zinc-100/50 border-t border-zinc-200 flex flex-wrap gap-4 text-[10px] text-zinc-500 font-sans", children: [toolCall.tokenUsage && (_jsxs("div", { className: "flex gap-3", children: [toolCall.tokenUsage.inputTokens !== undefined && (_jsxs("div", { children: [_jsx("span", { className: "uppercase tracking-wide font-semibold mr-1", children: "Input:" }), toolCall.tokenUsage.inputTokens.toLocaleString()] })), toolCall.tokenUsage.outputTokens !== undefined && (_jsxs("div", { children: [_jsx("span", { className: "uppercase tracking-wide font-semibold mr-1", children: "Output:" }), toolCall.tokenUsage.outputTokens.toLocaleString()] })), toolCall.tokenUsage.totalTokens !== undefined && (_jsxs("div", { children: [_jsx("span", { className: "uppercase tracking-wide font-semibold mr-1", children: "Total:" }), toolCall.tokenUsage.totalTokens.toLocaleString()] }))] })), toolCall.startedAt && (_jsxs("div", { className: "flex gap-3 ml-auto", children: [_jsxs("span", { children: ["Started: ", new Date(toolCall.startedAt).toLocaleTimeString()] }), toolCall.completedAt && (_jsxs("span", { children: ["Completed:", " ", new Date(toolCall.completedAt).toLocaleTimeString(), " (", Math.round((toolCall.completedAt - toolCall.startedAt) / 1000), "s)"] }))] }))] }))] }))] }));
|
|
100
97
|
}
|
|
@@ -15,7 +15,7 @@ export function ToolCallList({ toolCalls, groupBy = "chronological", }) {
|
|
|
15
15
|
completed: toolCalls.filter((tc) => tc.status === "completed"),
|
|
16
16
|
failed: toolCalls.filter((tc) => tc.status === "failed"),
|
|
17
17
|
};
|
|
18
|
-
return (_jsxs("div", { className: "space-y-4", children: [grouped.in_progress.length > 0 && (_jsxs("div", { children: [_jsx("h4", { className: "text-
|
|
18
|
+
return (_jsxs("div", { className: "space-y-4", children: [grouped.in_progress.length > 0 && (_jsxs("div", { children: [_jsx("h4", { className: "text-[10px] font-bold text-zinc-400 uppercase tracking-wider mb-2 pl-1", children: "In Progress" }), grouped.in_progress.map((tc) => (_jsx(ToolCall, { toolCall: tc }, tc.id)))] })), grouped.pending.length > 0 && (_jsxs("div", { children: [_jsx("h4", { className: "text-[10px] font-bold text-zinc-400 uppercase tracking-wider mb-2 pl-1", children: "Pending" }), grouped.pending.map((tc) => (_jsx(ToolCall, { toolCall: tc }, tc.id)))] })), grouped.completed.length > 0 && (_jsxs("div", { children: [_jsx("h4", { className: "text-[10px] font-bold text-zinc-400 uppercase tracking-wider mb-2 pl-1", children: "Completed" }), grouped.completed.map((tc) => (_jsx(ToolCall, { toolCall: tc }, tc.id)))] })), grouped.failed.length > 0 && (_jsxs("div", { children: [_jsx("h4", { className: "text-[10px] font-bold text-zinc-400 uppercase tracking-wider mb-2 pl-1", children: "Failed" }), grouped.failed.map((tc) => (_jsx(ToolCall, { toolCall: tc }, tc.id)))] }))] }));
|
|
19
19
|
}
|
|
20
20
|
// Default: chronological order
|
|
21
21
|
return (_jsx("div", { className: "space-y-2", children: toolCalls.map((tc) => (_jsx(ToolCall, { toolCall: tc }, tc.id))) }));
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { toast } from "sonner";
|
|
2
|
+
export { MockFileSystemProvider, mockFileSystemData, } from "../data/mockFileSystemData.js";
|
|
3
|
+
export type { FileSystemData, FileSystemItem as FileSystemItemData, FileSystemItemType, FileSystemProvider, } from "../types/filesystem.js";
|
|
2
4
|
export { Button, type ButtonProps, buttonVariants } from "./Button.js";
|
|
3
5
|
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, } from "./Card.js";
|
|
4
6
|
export { ChatEmptyState, type ChatEmptyStateProps } from "./ChatEmptyState.js";
|
|
@@ -14,6 +16,8 @@ export { ChatView, type ChatViewProps } from "./ChatView.js";
|
|
|
14
16
|
export { Conversation, type ConversationProps } from "./Conversation.js";
|
|
15
17
|
export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, } from "./Dialog.js";
|
|
16
18
|
export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from "./DropdownMenu.js";
|
|
19
|
+
export { FileSystemItem, type FileSystemItemProps, } from "./FileSystemItem.js";
|
|
20
|
+
export { FileSystemView, type FileSystemViewProps, } from "./FileSystemView.js";
|
|
17
21
|
export { HeightTransition } from "./HeightTransition.js";
|
|
18
22
|
export { Input, type InputProps, inputVariants } from "./Input.js";
|
|
19
23
|
export { Label } from "./Label.js";
|