@townco/ui 0.1.37 → 0.1.38
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-messages.d.ts +2 -0
- package/dist/core/hooks/use-chat-messages.js +19 -1
- package/dist/core/hooks/use-tool-calls.d.ts +2 -0
- package/dist/core/lib/logger.d.ts +0 -35
- package/dist/core/lib/logger.js +25 -108
- package/dist/core/schemas/chat.d.ts +4 -0
- package/dist/core/schemas/tool-call.d.ts +2 -0
- package/dist/core/schemas/tool-call.js +4 -0
- package/dist/gui/components/ChatEmptyState.d.ts +6 -0
- package/dist/gui/components/ChatEmptyState.js +2 -2
- package/dist/gui/components/ChatInput.js +1 -1
- package/dist/gui/components/ChatLayout.js +102 -8
- package/dist/gui/components/ChatPanelTabContent.d.ts +1 -1
- package/dist/gui/components/ChatPanelTabContent.js +10 -3
- package/dist/gui/components/ChatView.js +37 -13
- package/dist/gui/components/ContextUsageButton.d.ts +7 -0
- package/dist/gui/components/ContextUsageButton.js +18 -0
- package/dist/gui/components/FileSystemItem.js +6 -7
- package/dist/gui/components/FileSystemView.js +3 -3
- package/dist/gui/components/InlineToolCallSummary.d.ts +14 -0
- package/dist/gui/components/InlineToolCallSummary.js +110 -0
- package/dist/gui/components/InlineToolCallSummaryACP.d.ts +15 -0
- package/dist/gui/components/InlineToolCallSummaryACP.js +90 -0
- package/dist/gui/components/Response.js +2 -2
- package/dist/gui/components/SourceListItem.js +9 -1
- package/dist/gui/components/TodoListItem.js +19 -2
- package/dist/gui/components/ToolCall.js +21 -2
- package/dist/gui/components/Tooltip.d.ts +7 -0
- package/dist/gui/components/Tooltip.js +10 -0
- package/dist/gui/components/index.d.ts +4 -0
- package/dist/gui/components/index.js +5 -0
- package/dist/gui/components/tool-call-summary.d.ts +44 -0
- package/dist/gui/components/tool-call-summary.js +67 -0
- package/dist/gui/data/mockSourceData.d.ts +10 -0
- package/dist/gui/data/mockSourceData.js +40 -0
- package/dist/gui/data/mockTodoData.d.ts +10 -0
- package/dist/gui/data/mockTodoData.js +35 -0
- package/dist/gui/examples/FileSystemDemo.d.ts +5 -0
- package/dist/gui/examples/FileSystemDemo.js +24 -0
- package/dist/gui/examples/FileSystemExample.d.ts +17 -0
- package/dist/gui/examples/FileSystemExample.js +94 -0
- package/dist/sdk/schemas/session.d.ts +2 -0
- package/dist/sdk/transports/http.js +12 -0
- package/dist/sdk/transports/stdio.js +13 -0
- package/package.json +3 -3
- package/dist/tui/components/LogsPanel.d.ts +0 -5
- package/dist/tui/components/LogsPanel.js +0 -29
|
@@ -1,13 +1,27 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { createLogger } from "@townco/core";
|
|
3
3
|
import { ArrowUp, ChevronUp, Code, PanelRight, Settings, Sparkles, } from "lucide-react";
|
|
4
4
|
import { useEffect, useState } from "react";
|
|
5
5
|
import { useChatMessages, useChatSession, useToolCalls, } from "../../core/hooks/index.js";
|
|
6
6
|
import { useChatStore } from "../../core/store/chat-store.js";
|
|
7
|
-
import { formatTokenPercentage } from "../../core/utils/model-context.js";
|
|
7
|
+
import { calculateTokenPercentage, formatTokenPercentage, } from "../../core/utils/model-context.js";
|
|
8
8
|
import { cn } from "../lib/utils.js";
|
|
9
|
-
import { ChatEmptyState, ChatHeader, ChatInputActions, ChatInputAttachment, ChatInputCommandMenu, ChatInputField, ChatInputRoot, ChatInputSubmit, ChatInputToolbar, ChatInputVoiceInput, ChatLayout, FilesTabContent, Message, MessageContent, PanelTabsHeader, SourcesTabContent, Tabs, TabsContent, TodoTabContent, } from "./index.js";
|
|
9
|
+
import { ChatEmptyState, ChatHeader, ChatInputActions, ChatInputAttachment, ChatInputCommandMenu, ChatInputField, ChatInputRoot, ChatInputSubmit, ChatInputToolbar, ChatInputVoiceInput, ChatLayout, ContextUsageButton, FilesTabContent, Message, MessageContent, PanelTabsHeader, SourcesTabContent, Tabs, TabsContent, TodoTabContent, } from "./index.js";
|
|
10
10
|
const logger = createLogger("gui");
|
|
11
|
+
// Helper component to provide openFiles callback
|
|
12
|
+
function OpenFilesButton({ children, }) {
|
|
13
|
+
const { setPanelSize, setActiveTab } = ChatLayout.useChatLayoutContext();
|
|
14
|
+
const openFiles = () => {
|
|
15
|
+
setPanelSize("small");
|
|
16
|
+
setActiveTab("files");
|
|
17
|
+
};
|
|
18
|
+
return _jsx(_Fragment, { children: children({ openFiles }) });
|
|
19
|
+
}
|
|
20
|
+
// Controlled Tabs component for the aside panel
|
|
21
|
+
function AsideTabs() {
|
|
22
|
+
const { activeTab, setActiveTab } = ChatLayout.useChatLayoutContext();
|
|
23
|
+
return (_jsxs(Tabs, { value: activeTab, onValueChange: (value) => setActiveTab(value), className: "flex flex-col h-full", children: [_jsx("div", { className: cn("border-b border-border bg-card", "px-6 py-2 h-16", "flex items-center", "[border-bottom-width:0.5px]"), children: _jsx(PanelTabsHeader, { showIcons: true, visibleTabs: ["todo", "files", "sources"], variant: "compact" }) }), _jsx(TabsContent, { value: "todo", className: "flex-1 p-4 mt-0", children: _jsx(TodoTabContent, {}) }), _jsx(TabsContent, { value: "files", className: "flex-1 p-4 mt-0", children: _jsx(FilesTabContent, {}) }), _jsx(TabsContent, { value: "sources", className: "flex-1 p-4 mt-0", children: _jsx(SourcesTabContent, {}) })] }));
|
|
24
|
+
}
|
|
11
25
|
// Mobile header component that uses ChatHeader context
|
|
12
26
|
function MobileHeader({ agentName, showHeader, }) {
|
|
13
27
|
const { isExpanded, setIsExpanded } = ChatHeader.useChatHeaderContext();
|
|
@@ -29,6 +43,7 @@ export function ChatView({ client, initialSessionId, error: initError, }) {
|
|
|
29
43
|
const currentModel = useChatStore((state) => state.currentModel);
|
|
30
44
|
const [agentName, setAgentName] = useState("Agent");
|
|
31
45
|
const [isLargeScreen, setIsLargeScreen] = useState(typeof window !== "undefined" ? window.innerWidth >= 1024 : true);
|
|
46
|
+
const [placeholder, setPlaceholder] = useState("Type a message or / for commands...");
|
|
32
47
|
// Log connection status changes
|
|
33
48
|
useEffect(() => {
|
|
34
49
|
logger.debug("Connection status changed", { status: connectionStatus });
|
|
@@ -59,6 +74,14 @@ export function ChatView({ client, initialSessionId, error: initError, }) {
|
|
|
59
74
|
mediaQuery.removeEventListener("change", handleChange);
|
|
60
75
|
};
|
|
61
76
|
}, []);
|
|
77
|
+
// Handle prompt hover - temporarily show the full prompt as placeholder
|
|
78
|
+
const handlePromptHover = (prompt) => {
|
|
79
|
+
setPlaceholder(prompt);
|
|
80
|
+
};
|
|
81
|
+
// Handle prompt leave - restore the default placeholder
|
|
82
|
+
const handlePromptLeave = () => {
|
|
83
|
+
setPlaceholder("Type a message or / for commands...");
|
|
84
|
+
};
|
|
62
85
|
// If there's an initialization error, show error UI (after all hooks have been called)
|
|
63
86
|
if (initError) {
|
|
64
87
|
return (_jsx("div", { className: "flex items-center justify-center h-screen bg-background", children: _jsxs("div", { className: "text-center p-8 max-w-md", children: [_jsx("h1", { className: "text-2xl font-bold text-destructive mb-4", children: "Initialization Error" }), _jsx("p", { className: "text-foreground mb-4", children: initError }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Failed to initialize the ACP client. Check the console for details." })] }) }));
|
|
@@ -148,15 +171,16 @@ export function ChatView({ client, initialSessionId, error: initError, }) {
|
|
|
148
171
|
},
|
|
149
172
|
},
|
|
150
173
|
];
|
|
151
|
-
return (_jsxs(ChatLayout.Root, { defaultPanelSize: "hidden", defaultActiveTab: "todo", children: [_jsxs(ChatLayout.Main, { children: [_jsx(AppChatHeader, { agentName: agentName, todos: todos, sources: sources, showHeader: messages.length > 0 }), connectionStatus === "error" && error && (_jsx("div", { className: "border-b border-destructive/20 bg-destructive/10 px-6 py-4", children: _jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { className: "flex-1", children: [_jsx("h3", { className: "mb-1 text-paragraph-sm font-semibold text-destructive", children: "Connection Error" }), _jsx("p", { className: "whitespace-pre-line text-paragraph-sm text-foreground", children: error })] }), _jsx("button", { type: "button", onClick: connect, className: "rounded-lg bg-destructive px-4 py-2 text-paragraph-sm font-medium text-destructive-foreground transition-colors hover:bg-destructive-hover", children: "Retry" })] }) })), _jsxs(ChatLayout.Body, { children: [_jsx(ChatLayout.Messages, { children: messages.length === 0 ? (_jsx("div", { className: "flex flex-1 items-center px-4", children: _jsx(ChatEmptyState, { title: agentName, description: "This agent can help you with your tasks. Start a conversation by typing a message below.", suggestedPrompts: [
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
174
|
+
return (_jsxs(ChatLayout.Root, { defaultPanelSize: "hidden", defaultActiveTab: "todo", children: [_jsxs(ChatLayout.Main, { children: [_jsx(AppChatHeader, { agentName: agentName, todos: todos, sources: sources, showHeader: messages.length > 0 }), connectionStatus === "error" && error && (_jsx("div", { className: "border-b border-destructive/20 bg-destructive/10 px-6 py-4", children: _jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { className: "flex-1", children: [_jsx("h3", { className: "mb-1 text-paragraph-sm font-semibold text-destructive", children: "Connection Error" }), _jsx("p", { className: "whitespace-pre-line text-paragraph-sm text-foreground", children: error })] }), _jsx("button", { type: "button", onClick: connect, className: "rounded-lg bg-destructive px-4 py-2 text-paragraph-sm font-medium text-destructive-foreground transition-colors hover:bg-destructive-hover", children: "Retry" })] }) })), _jsxs(ChatLayout.Body, { children: [_jsx(ChatLayout.Messages, { children: messages.length === 0 ? (_jsx(OpenFilesButton, { children: ({ openFiles }) => (_jsx("div", { className: "flex flex-1 items-center px-4", children: _jsx(ChatEmptyState, { title: agentName, description: "This agent can help you with your tasks. Start a conversation by typing a message below.", suggestedPrompts: [
|
|
175
|
+
"Search the web for the latest news on top tech company earnings, produce a summary for each company, and then a macro trend analysis of the tech industry. Use your todo list",
|
|
176
|
+
"Explain how this works",
|
|
177
|
+
"Create a new feature",
|
|
178
|
+
"Review my changes",
|
|
179
|
+
], onPromptClick: (prompt) => {
|
|
180
|
+
sendMessage(prompt);
|
|
181
|
+
setPlaceholder("Type a message or / for commands...");
|
|
182
|
+
logger.info("Prompt clicked", { prompt });
|
|
183
|
+
}, onPromptHover: handlePromptHover, onPromptLeave: handlePromptLeave, onOpenFiles: openFiles }) })) })) : (_jsx("div", { className: "flex flex-col px-4", children: messages.map((message, index) => {
|
|
160
184
|
// Calculate dynamic spacing based on message sequence
|
|
161
185
|
const isFirst = index === 0;
|
|
162
186
|
const previousMessage = isFirst ? null : messages[index - 1];
|
|
@@ -175,5 +199,5 @@ export function ChatView({ client, initialSessionId, error: initError, }) {
|
|
|
175
199
|
previousMessage?.role === "assistant" ? "mt-2" : "mt-6";
|
|
176
200
|
}
|
|
177
201
|
return (_jsx(Message, { message: message, className: spacingClass, isLastMessage: index === messages.length - 1, children: _jsx(MessageContent, { message: message, thinkingDisplayStyle: "collapsible" }) }, message.id));
|
|
178
|
-
}) })) }), _jsx(ChatLayout.Footer, { children: _jsxs(ChatInputRoot, { client: client, startSession: startSession, children: [_jsx(ChatInputCommandMenu, { commands: commandMenuItems }), _jsx(ChatInputField, { placeholder:
|
|
202
|
+
}) })) }), _jsx(ChatLayout.Footer, { children: _jsxs(ChatInputRoot, { client: client, startSession: startSession, children: [_jsx(ChatInputCommandMenu, { commands: commandMenuItems }), _jsx(ChatInputField, { placeholder: placeholder, autoFocus: true }), _jsxs(ChatInputToolbar, { children: [_jsxs("div", { className: "flex items-baseline gap-1", children: [_jsx(ChatInputActions, {}), _jsx(ChatInputAttachment, {}), latestTokenUsage && (_jsx(ContextUsageButton, { percentage: calculateTokenPercentage(latestTokenUsage.totalTokens ?? 0, currentModel ?? undefined), tokens: latestTokenUsage.totalTokens ?? 0, formattedPercentage: formatTokenPercentage(latestTokenUsage.totalTokens ?? 0, currentModel ?? undefined) }))] }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx(ChatInputVoiceInput, {}), _jsx(ChatInputSubmit, { children: _jsx(ArrowUp, { className: "size-4" }) })] })] })] }) })] })] }), isLargeScreen && (_jsx(ChatLayout.Aside, { breakpoint: "lg", children: _jsx(AsideTabs, {}) }))] }));
|
|
179
203
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface ContextUsageButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
3
|
+
percentage: number;
|
|
4
|
+
tokens: number;
|
|
5
|
+
formattedPercentage: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const ContextUsageButton: React.ForwardRefExoticComponent<ContextUsageButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
4
|
+
import { Button } from "./Button.js";
|
|
5
|
+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "./Tooltip.js";
|
|
6
|
+
export const ContextUsageButton = React.forwardRef(({ percentage, tokens, formattedPercentage, className, ...props }, ref) => {
|
|
7
|
+
// Clamp percentage between 0 and 100
|
|
8
|
+
const clampedPercentage = Math.min(100, Math.max(0, percentage));
|
|
9
|
+
// SVG parameters
|
|
10
|
+
const size = 16;
|
|
11
|
+
const strokeWidth = 2;
|
|
12
|
+
const radius = (size - strokeWidth) / 2;
|
|
13
|
+
const center = size / 2;
|
|
14
|
+
const circumference = 2 * Math.PI * radius;
|
|
15
|
+
const offset = circumference - (clampedPercentage / 100) * circumference;
|
|
16
|
+
return (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { ref: ref, type: "button", variant: "ghost", size: "icon", className: cn("rounded-full cursor-default", className), ...props, children: _jsxs("svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, className: "transform -rotate-90", children: [_jsx("circle", { cx: center, cy: center, r: radius, stroke: "currentColor", strokeWidth: strokeWidth, fill: "transparent", className: "opacity-20" }), _jsx("circle", { cx: center, cy: center, r: radius, stroke: "currentColor", strokeWidth: strokeWidth, fill: "transparent", strokeDasharray: circumference, strokeDashoffset: offset, strokeLinecap: "round", className: "transition-all duration-300 ease-in-out" })] }) }) }), _jsx(TooltipContent, { side: "top", align: "center", children: _jsxs("p", { children: ["Context: ", formattedPercentage, " (", tokens.toLocaleString(), " tokens)"] }) })] }) }));
|
|
17
|
+
});
|
|
18
|
+
ContextUsageButton.displayName = "ContextUsageButton";
|
|
@@ -10,7 +10,6 @@ import { cn } from "../lib/utils.js";
|
|
|
10
10
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "./DropdownMenu.js";
|
|
11
11
|
export function FileSystemItem({ item, level = 0, onSelect, selectedId, isDropTarget = false, onDownload, onRename, onDelete, }) {
|
|
12
12
|
const [isExpanded, setIsExpanded] = React.useState(true);
|
|
13
|
-
const [isFocused, setIsFocused] = React.useState(false);
|
|
14
13
|
const isSelected = selectedId === item.id;
|
|
15
14
|
const handleToggle = () => {
|
|
16
15
|
if (item.type === "folder") {
|
|
@@ -49,7 +48,7 @@ export function FileSystemItem({ item, level = 0, onSelect, selectedId, isDropTa
|
|
|
49
48
|
};
|
|
50
49
|
return (_jsxs("div", { className: "flex flex-col w-full", children: [_jsxs("div", { role: "button", tabIndex: 0, "aria-expanded": item.type === "folder" ? isExpanded : undefined, className: cn(
|
|
51
50
|
// Base styles with semantic typography
|
|
52
|
-
"group flex items-center gap-2 rounded-md cursor-pointer transition-colors text-paragraph-sm", getPaddingClass(),
|
|
51
|
+
"group/item flex items-center gap-2 rounded-md cursor-pointer transition-colors text-paragraph-sm", getPaddingClass(),
|
|
53
52
|
// State styles using semantic colors
|
|
54
53
|
// Default: transparent background
|
|
55
54
|
// Hover: accent-hover background
|
|
@@ -62,11 +61,11 @@ export function FileSystemItem({ item, level = 0, onSelect, selectedId, isDropTa
|
|
|
62
61
|
isDropTarget && [
|
|
63
62
|
"bg-accent",
|
|
64
63
|
"border border-dashed border-border-dark",
|
|
65
|
-
]), onClick: handleClick, onKeyDown: handleKeyDown,
|
|
66
|
-
// Hidden by default, shown on group hover
|
|
67
|
-
"opacity-0 group-hover:opacity-100",
|
|
68
|
-
//
|
|
69
|
-
|
|
64
|
+
]), onClick: handleClick, onKeyDown: handleKeyDown, children: [_jsx("div", { className: "shrink-0 size-4 flex items-center justify-center text-foreground", children: item.type === "folder" ? (isExpanded ? (_jsx(FolderOpen, { className: "size-4" })) : (_jsx(Folder, { className: "size-4" }))) : (_jsx(FileCode, { className: "size-4" })) }), _jsx("p", { className: "flex-1 text-foreground whitespace-nowrap overflow-hidden text-ellipsis", children: item.name }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { className: cn("shrink-0 size-4 transition-opacity text-muted-foreground hover:text-foreground",
|
|
65
|
+
// Hidden by default, shown on group hover only
|
|
66
|
+
"opacity-0 group-hover/item:opacity-100",
|
|
67
|
+
// Force visible when menu is open
|
|
68
|
+
"data-[state=open]:opacity-100"), onClick: (e) => {
|
|
70
69
|
e.stopPropagation();
|
|
71
70
|
}, "aria-label": "More options", type: "button", tabIndex: -1, children: _jsx(MoreVertical, { className: "size-4" }) }) }), _jsxs(DropdownMenuContent, { align: "end", side: "bottom", sideOffset: 5, alignOffset: 0, collisionPadding: 8, className: "w-40 z-[100]", onClick: (e) => e.stopPropagation(), children: [onDownload && (_jsx(DropdownMenuItem, { onClick: (e) => {
|
|
72
71
|
e.stopPropagation();
|
|
@@ -37,10 +37,10 @@ export function FileSystemView({ className, provider = defaultProvider, onItemSe
|
|
|
37
37
|
onItemSelect?.(item);
|
|
38
38
|
};
|
|
39
39
|
if (isLoading) {
|
|
40
|
-
return (_jsx("div", { className: cn("
|
|
40
|
+
return (_jsx("div", { className: cn("", className), children: _jsx("p", { className: "text-sm text-muted-foreground", children: "Loading..." }) }));
|
|
41
41
|
}
|
|
42
42
|
if (error) {
|
|
43
|
-
return (_jsx("div", { className: cn("
|
|
43
|
+
return (_jsx("div", { className: cn("", className), children: _jsxs("p", { className: "text-sm text-destructive", children: ["Error: ", error] }) }));
|
|
44
44
|
}
|
|
45
|
-
return (_jsx("div", { className: cn("flex flex-col
|
|
45
|
+
return (_jsx("div", { className: cn("flex flex-col", 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
46
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AcpClient } from "../../sdk/client/acp-client.js";
|
|
2
|
+
import type { ToolCall } from "../../core/schemas/tool-call.js";
|
|
3
|
+
export interface InlineToolCallSummaryProps {
|
|
4
|
+
/** The tool call to summarize */
|
|
5
|
+
toolCall: ToolCall;
|
|
6
|
+
/** ACP client for making requests */
|
|
7
|
+
client: AcpClient | null;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Inline tool call summary that appears beneath completed tool calls
|
|
11
|
+
* Shows a brief AI-generated summary of what the tool accomplished
|
|
12
|
+
* Uses the ACP client to make the request
|
|
13
|
+
*/
|
|
14
|
+
export declare function InlineToolCallSummary({ toolCall, client, }: InlineToolCallSummaryProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { CheckCircle, Sparkles } from "lucide-react";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
/**
|
|
5
|
+
* Inline tool call summary that appears beneath completed tool calls
|
|
6
|
+
* Shows a brief AI-generated summary of what the tool accomplished
|
|
7
|
+
* Uses the ACP client to make the request
|
|
8
|
+
*/
|
|
9
|
+
export function InlineToolCallSummary({ toolCall, client, }) {
|
|
10
|
+
const [summary, setSummary] = useState(null);
|
|
11
|
+
const [loading, setLoading] = useState(false);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
// Only generate summary for completed tool calls
|
|
14
|
+
if (toolCall.status !== "completed" || !client) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
// Don't fetch if we already have a summary
|
|
18
|
+
if (summary) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const fetchSummary = async () => {
|
|
22
|
+
setLoading(true);
|
|
23
|
+
try {
|
|
24
|
+
// Create a minimal Anthropic-format request with just this tool call
|
|
25
|
+
const request = {
|
|
26
|
+
messages: [
|
|
27
|
+
{
|
|
28
|
+
role: "assistant",
|
|
29
|
+
content: [
|
|
30
|
+
{
|
|
31
|
+
type: "tool_use",
|
|
32
|
+
id: toolCall.id,
|
|
33
|
+
name: toolCall.title.toLowerCase().replace(/\s+/g, "_"),
|
|
34
|
+
input: toolCall.rawInput || {},
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
role: "user",
|
|
40
|
+
content: [
|
|
41
|
+
{
|
|
42
|
+
type: "tool_result",
|
|
43
|
+
tool_use_id: toolCall.id,
|
|
44
|
+
content: extractToolOutput(toolCall),
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
// Make ACP RPC request to agent/summarize method
|
|
51
|
+
const response = await client.request("agent/summarize", request);
|
|
52
|
+
// Extract the description from the first tool call
|
|
53
|
+
if (response.toolCalls && response.toolCalls.length > 0) {
|
|
54
|
+
const firstToolCall = response.toolCalls[0];
|
|
55
|
+
if (firstToolCall) {
|
|
56
|
+
setSummary(firstToolCall.description);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
// Silently fail - summaries are optional enhancements
|
|
62
|
+
console.debug("Failed to fetch tool call summary via ACP:", error);
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
setLoading(false);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
fetchSummary();
|
|
69
|
+
}, [toolCall, client, summary]);
|
|
70
|
+
// Don't show anything if not completed or still loading
|
|
71
|
+
if (toolCall.status !== "completed" || loading) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
// Don't show if no summary
|
|
75
|
+
if (!summary) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
return (_jsxs("div", { className: "flex items-start gap-2 mt-2 px-3 py-2 rounded-lg bg-emerald-50/50 border border-emerald-100", children: [_jsx(CheckCircle, { className: "h-3.5 w-3.5 text-emerald-600 shrink-0 mt-0.5" }), _jsx("div", { className: "flex-1 min-w-0", children: _jsx("p", { className: "text-[11px] text-emerald-900 font-medium", children: summary }) }), _jsx(Sparkles, { className: "h-3 w-3 text-emerald-600/50 shrink-0 mt-0.5" })] }));
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Extract output text from a tool call for summarization
|
|
82
|
+
*/
|
|
83
|
+
function extractToolOutput(toolCall) {
|
|
84
|
+
// Try to extract text from content blocks
|
|
85
|
+
if (toolCall.content && toolCall.content.length > 0) {
|
|
86
|
+
const textBlocks = [];
|
|
87
|
+
for (const block of toolCall.content) {
|
|
88
|
+
if (block.type === "text" && "text" in block) {
|
|
89
|
+
textBlocks.push(block.text);
|
|
90
|
+
}
|
|
91
|
+
else if (block.type === "content" && "content" in block) {
|
|
92
|
+
const innerContent = block.content;
|
|
93
|
+
if (innerContent.type === "text" && innerContent.text) {
|
|
94
|
+
textBlocks.push(innerContent.text);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (textBlocks.length > 0) {
|
|
99
|
+
// Truncate very long outputs for summary purposes
|
|
100
|
+
const output = textBlocks.join("\n");
|
|
101
|
+
return output.length > 500 ? `${output.slice(0, 500)}...` : output;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Fallback to raw output
|
|
105
|
+
if (toolCall.rawOutput) {
|
|
106
|
+
const output = JSON.stringify(toolCall.rawOutput);
|
|
107
|
+
return output.length > 500 ? `${output.slice(0, 500)}...` : output;
|
|
108
|
+
}
|
|
109
|
+
return "No output";
|
|
110
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AcpClient } from "../../sdk/client/acp-client.js";
|
|
2
|
+
import type { ToolCall } from "../../core/schemas/tool-call.js";
|
|
3
|
+
export interface InlineToolCallSummaryACPProps {
|
|
4
|
+
/** The tool call to summarize */
|
|
5
|
+
toolCall: ToolCall;
|
|
6
|
+
/** ACP client for making requests */
|
|
7
|
+
client: AcpClient | null;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Inline tool call summary using ACP protocol
|
|
11
|
+
*
|
|
12
|
+
* This version uses the ACP client to make a custom method call
|
|
13
|
+
* instead of direct HTTP fetch
|
|
14
|
+
*/
|
|
15
|
+
export declare function InlineToolCallSummaryACP({ toolCall, client, }: InlineToolCallSummaryACPProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { CheckCircle, Sparkles } from "lucide-react";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
/**
|
|
5
|
+
* Inline tool call summary using ACP protocol
|
|
6
|
+
*
|
|
7
|
+
* This version uses the ACP client to make a custom method call
|
|
8
|
+
* instead of direct HTTP fetch
|
|
9
|
+
*/
|
|
10
|
+
export function InlineToolCallSummaryACP({ toolCall, client, }) {
|
|
11
|
+
const [summary, setSummary] = useState(null);
|
|
12
|
+
const [loading, setLoading] = useState(false);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (toolCall.status !== "completed" || !client || summary) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const fetchSummary = async () => {
|
|
18
|
+
setLoading(true);
|
|
19
|
+
try {
|
|
20
|
+
// This would require adding a custom ACP method to the server
|
|
21
|
+
// For now, this shows the concept - you'd need to implement
|
|
22
|
+
// the corresponding handler in the ACP adapter
|
|
23
|
+
// Example of what it might look like:
|
|
24
|
+
// const response = await client.request({
|
|
25
|
+
// method: "agent/summarize",
|
|
26
|
+
// params: {
|
|
27
|
+
// messages: [
|
|
28
|
+
// {
|
|
29
|
+
// role: "assistant",
|
|
30
|
+
// content: [{
|
|
31
|
+
// type: "tool_use",
|
|
32
|
+
// id: toolCall.id,
|
|
33
|
+
// name: toolCall.title,
|
|
34
|
+
// input: toolCall.rawInput || {}
|
|
35
|
+
// }]
|
|
36
|
+
// },
|
|
37
|
+
// {
|
|
38
|
+
// role: "user",
|
|
39
|
+
// content: [{
|
|
40
|
+
// type: "tool_result",
|
|
41
|
+
// tool_use_id: toolCall.id,
|
|
42
|
+
// content: extractToolOutput(toolCall)
|
|
43
|
+
// }]
|
|
44
|
+
// }
|
|
45
|
+
// ]
|
|
46
|
+
// }
|
|
47
|
+
// });
|
|
48
|
+
// For now, fall back to direct fetch since the ACP method
|
|
49
|
+
// isn't implemented
|
|
50
|
+
console.log("ACP-based summary not yet implemented");
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
console.debug("Failed to fetch tool call summary via ACP:", error);
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
setLoading(false);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
fetchSummary();
|
|
60
|
+
}, [toolCall, client, summary]);
|
|
61
|
+
if (toolCall.status !== "completed" || loading || !summary) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
return (_jsxs("div", { className: "flex items-start gap-2 mt-2 px-3 py-2 rounded-lg bg-emerald-50/50 border border-emerald-100", children: [_jsx(CheckCircle, { className: "h-3.5 w-3.5 text-emerald-600 shrink-0 mt-0.5" }), _jsx("div", { className: "flex-1 min-w-0", children: _jsx("p", { className: "text-[11px] text-emerald-900 font-medium", children: summary }) }), _jsx(Sparkles, { className: "h-3 w-3 text-emerald-600/50 shrink-0 mt-0.5" })] }));
|
|
65
|
+
}
|
|
66
|
+
function extractToolOutput(toolCall) {
|
|
67
|
+
if (toolCall.content && toolCall.content.length > 0) {
|
|
68
|
+
const textBlocks = [];
|
|
69
|
+
for (const block of toolCall.content) {
|
|
70
|
+
if (block.type === "text" && "text" in block) {
|
|
71
|
+
textBlocks.push(block.text);
|
|
72
|
+
}
|
|
73
|
+
else if (block.type === "content" && "content" in block) {
|
|
74
|
+
const innerContent = block.content;
|
|
75
|
+
if (innerContent.type === "text" && innerContent.text) {
|
|
76
|
+
textBlocks.push(innerContent.text);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (textBlocks.length > 0) {
|
|
81
|
+
const output = textBlocks.join("\n");
|
|
82
|
+
return output.length > 500 ? `${output.slice(0, 500)}...` : output;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (toolCall.rawOutput) {
|
|
86
|
+
const output = JSON.stringify(toolCall.rawOutput);
|
|
87
|
+
return output.length > 500 ? `${output.slice(0, 500)}...` : output;
|
|
88
|
+
}
|
|
89
|
+
return "No output";
|
|
90
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import ReactMarkdown from "react-markdown";
|
|
4
4
|
import remarkGfm from "remark-gfm";
|
|
@@ -92,6 +92,6 @@ export const Response = React.forwardRef(({ content, isStreaming = false, showEm
|
|
|
92
92
|
// Horizontal rule
|
|
93
93
|
hr: ({ node, ...props }) => (_jsx("hr", { className: "my-6 border-t border-border opacity-50", ...props })),
|
|
94
94
|
};
|
|
95
|
-
return (
|
|
95
|
+
return (_jsx("div", { ref: ref, className: cn("markdown-content prose prose-sm max-w-none dark:prose-invert", className), ...props, children: _jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], components: components, children: content }) }));
|
|
96
96
|
});
|
|
97
97
|
Response.displayName = "Response";
|
|
@@ -2,6 +2,14 @@ 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(
|
|
5
|
+
return (_jsxs("button", { ref: ref, type: "button", className: cn(
|
|
6
|
+
// Base styles matching FileSystemItem
|
|
7
|
+
"group flex w-full text-left gap-2 items-start p-2 rounded-md cursor-pointer transition-colors text-paragraph-sm",
|
|
8
|
+
// Hover state - matching FileSystemItem
|
|
9
|
+
"hover:bg-accent-hover",
|
|
10
|
+
// Focus state - matching FileSystemItem
|
|
11
|
+
"focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-border-dark",
|
|
12
|
+
// Selected state - matching FileSystemItem
|
|
13
|
+
isSelected && "bg-accent", className), onClick: () => window.open(source.url, "_blank"), ...props, children: [_jsx("div", { className: "shrink-0 flex items-center h-5", children: _jsx("div", { className: "relative rounded-[3px] 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-paragraph-sm 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-paragraph-sm text-muted-foreground line-clamp-3", children: source.snippet })] })] }));
|
|
6
14
|
});
|
|
7
15
|
SourceListItem.displayName = "SourceListItem";
|
|
@@ -1,7 +1,24 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Circle, CircleCheck } from "lucide-react";
|
|
2
3
|
import * as React from "react";
|
|
3
4
|
import { cn } from "../lib/utils.js";
|
|
4
5
|
export const TodoListItem = React.forwardRef(({ todo, className, ...props }, ref) => {
|
|
5
|
-
|
|
6
|
+
const isCompleted = todo.status === "completed";
|
|
7
|
+
const isSelected = false; // TODO: Add selection support later if needed
|
|
8
|
+
return (
|
|
9
|
+
/* biome-ignore lint/a11y/useSemanticElements: Keeping div for consistency with FileSystemItem pattern */
|
|
10
|
+
_jsxs("div", { ref: ref, className: cn(
|
|
11
|
+
// Base styles matching FileSystemItem
|
|
12
|
+
"group flex items-center gap-2 p-2 rounded-md cursor-pointer transition-colors text-paragraph-sm",
|
|
13
|
+
// Hover state - matching FileSystemItem
|
|
14
|
+
"hover:bg-accent-hover",
|
|
15
|
+
// Focus state - matching FileSystemItem
|
|
16
|
+
"focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-border-dark",
|
|
17
|
+
// Selected state (if needed later)
|
|
18
|
+
isSelected && "bg-accent", className), role: "button", tabIndex: 0, ...props, children: [_jsx("div", { className: "shrink-0 size-4 flex items-center justify-center text-foreground", children: isCompleted ? (_jsx(CircleCheck, { className: "size-4 text-muted-foreground" })) : (_jsx(Circle, { className: "size-4 text-foreground" })) }), _jsx("p", { className: cn("flex-1 text-foreground",
|
|
19
|
+
// Completed state: strikethrough + muted color
|
|
20
|
+
isCompleted && "line-through text-muted-foreground",
|
|
21
|
+
// In-progress state: medium weight for emphasis
|
|
22
|
+
todo.status === "in_progress" && "font-medium"), children: todo.text })] }));
|
|
6
23
|
});
|
|
7
24
|
TodoListItem.displayName = "TodoListItem";
|
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import JsonView from "@uiw/react-json-view";
|
|
3
|
-
import { ChevronDown, Wrench } from "lucide-react";
|
|
3
|
+
import { CheckSquare, ChevronDown, Cloud, Edit, FileText, Globe, Link, Search, Wrench, } from "lucide-react";
|
|
4
4
|
import { useState } from "react";
|
|
5
|
+
/**
|
|
6
|
+
* Map of icon names to Lucide components
|
|
7
|
+
*/
|
|
8
|
+
const ICON_MAP = {
|
|
9
|
+
Globe: Globe,
|
|
10
|
+
Link: Link,
|
|
11
|
+
Cloud: Cloud,
|
|
12
|
+
CheckSquare: CheckSquare,
|
|
13
|
+
Search: Search,
|
|
14
|
+
FileText: FileText,
|
|
15
|
+
Edit: Edit,
|
|
16
|
+
Wrench: Wrench,
|
|
17
|
+
};
|
|
5
18
|
/**
|
|
6
19
|
* Tool call kind icons (using emoji for simplicity)
|
|
7
20
|
*/
|
|
@@ -22,7 +35,13 @@ const _kindIcons = {
|
|
|
22
35
|
*/
|
|
23
36
|
export function ToolCall({ toolCall }) {
|
|
24
37
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
25
|
-
|
|
38
|
+
// Determine which icon to show
|
|
39
|
+
const IconComponent = toolCall.icon && ICON_MAP[toolCall.icon]
|
|
40
|
+
? ICON_MAP[toolCall.icon]
|
|
41
|
+
: Wrench;
|
|
42
|
+
// Determine display name
|
|
43
|
+
const displayName = toolCall.prettyName || toolCall.title;
|
|
44
|
+
return (_jsxs("div", { className: "flex flex-col my-4", 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(IconComponent, { className: "h-3 w-3" }) }), _jsx("span", { className: "text-paragraph-sm text-zinc-500", children: displayName }), _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 &&
|
|
26
45
|
loc.line !== undefined &&
|
|
27
46
|
`:${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
47
|
fontSize: "11px",
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
declare const TooltipProvider: React.FC<TooltipPrimitive.TooltipProviderProps>;
|
|
4
|
+
declare const Tooltip: React.FC<TooltipPrimitive.TooltipProps>;
|
|
5
|
+
declare const TooltipTrigger: React.ForwardRefExoticComponent<TooltipPrimitive.TooltipTriggerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
6
|
+
declare const TooltipContent: React.ForwardRefExoticComponent<Omit<TooltipPrimitive.TooltipContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
7
|
+
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cn } from "../lib/utils.js";
|
|
5
|
+
const TooltipProvider = TooltipPrimitive.Provider;
|
|
6
|
+
const Tooltip = TooltipPrimitive.Root;
|
|
7
|
+
const TooltipTrigger = TooltipPrimitive.Trigger;
|
|
8
|
+
const TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => (_jsx(TooltipPrimitive.Content, { ref: ref, sideOffset: sideOffset, className: cn("z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className), ...props })));
|
|
9
|
+
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
10
|
+
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { toast } from "sonner";
|
|
2
2
|
export { MockFileSystemProvider, mockFileSystemData, } from "../data/mockFileSystemData.js";
|
|
3
|
+
export { mockSourceData } from "../data/mockSourceData.js";
|
|
4
|
+
export { mockTodoData } from "../data/mockTodoData.js";
|
|
3
5
|
export type { FileSystemData, FileSystemItem as FileSystemItemData, FileSystemItemType, FileSystemProvider, } from "../types/filesystem.js";
|
|
4
6
|
export { Button, type ButtonProps, buttonVariants } from "./Button.js";
|
|
5
7
|
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, } from "./Card.js";
|
|
@@ -13,6 +15,7 @@ export { ChatSecondaryPanel, type ChatSecondaryPanelProps, } from "./ChatSeconda
|
|
|
13
15
|
export * as ChatSidebar from "./ChatSidebar.js";
|
|
14
16
|
export { ChatStatus, type ChatStatusProps } from "./ChatStatus.js";
|
|
15
17
|
export { ChatView, type ChatViewProps } from "./ChatView.js";
|
|
18
|
+
export { ContextUsageButton, type ContextUsageButtonProps, } from "./ContextUsageButton.js";
|
|
16
19
|
export { Conversation, type ConversationProps } from "./Conversation.js";
|
|
17
20
|
export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, } from "./Dialog.js";
|
|
18
21
|
export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from "./DropdownMenu.js";
|
|
@@ -39,3 +42,4 @@ export { TodoList, type TodoListProps } from "./TodoList.js";
|
|
|
39
42
|
export { type TodoItem, TodoListItem, type TodoListItemProps, } from "./TodoListItem.js";
|
|
40
43
|
export { ToolCall, type ToolCallProps } from "./ToolCall.js";
|
|
41
44
|
export { ToolCallList, type ToolCallListProps } from "./ToolCallList.js";
|
|
45
|
+
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "./Tooltip.js";
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Base UI components
|
|
2
2
|
export { toast } from "sonner";
|
|
3
3
|
export { MockFileSystemProvider, mockFileSystemData, } from "../data/mockFileSystemData.js";
|
|
4
|
+
export { mockSourceData } from "../data/mockSourceData.js";
|
|
5
|
+
export { mockTodoData } from "../data/mockTodoData.js";
|
|
4
6
|
export { Button, buttonVariants } from "./Button.js";
|
|
5
7
|
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, } from "./Card.js";
|
|
6
8
|
export { ChatEmptyState } from "./ChatEmptyState.js";
|
|
@@ -14,6 +16,7 @@ export { ChatSecondaryPanel, } from "./ChatSecondaryPanel.js";
|
|
|
14
16
|
export * as ChatSidebar from "./ChatSidebar.js";
|
|
15
17
|
export { ChatStatus } from "./ChatStatus.js";
|
|
16
18
|
export { ChatView } from "./ChatView.js";
|
|
19
|
+
export { ContextUsageButton, } from "./ContextUsageButton.js";
|
|
17
20
|
// Chat components - shadcn.io/ai inspired primitives
|
|
18
21
|
export { Conversation } from "./Conversation.js";
|
|
19
22
|
// Dialog components
|
|
@@ -46,3 +49,5 @@ export { TodoList } from "./TodoList.js";
|
|
|
46
49
|
export { TodoListItem, } from "./TodoListItem.js";
|
|
47
50
|
export { ToolCall } from "./ToolCall.js";
|
|
48
51
|
export { ToolCallList } from "./ToolCallList.js";
|
|
52
|
+
// Tooltip components
|
|
53
|
+
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "./Tooltip.js";
|