@townco/ui 0.1.41 → 0.1.43
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/gui/components/ChatView.js +3 -3
- package/dist/gui/components/IconButton.d.ts +5 -0
- package/dist/gui/components/IconButton.js +8 -0
- package/dist/gui/components/PanelTabsHeader.js +1 -1
- package/dist/gui/components/ThemeProvider.d.ts +14 -0
- package/dist/gui/components/ThemeProvider.js +42 -0
- package/dist/gui/components/ThemeToggle.d.ts +1 -0
- package/dist/gui/components/ThemeToggle.js +9 -0
- package/dist/gui/components/ToolCall.js +42 -17
- package/dist/gui/components/ToolCallList.js +1 -1
- package/dist/gui/components/index.d.ts +3 -0
- package/dist/gui/components/index.js +3 -0
- package/package.json +3 -3
|
@@ -6,7 +6,7 @@ import { useChatMessages, useChatSession, useToolCalls, } from "../../core/hooks
|
|
|
6
6
|
import { useChatStore } from "../../core/store/chat-store.js";
|
|
7
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, ContextUsageButton, 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, IconButton, Message, MessageContent, PanelTabsHeader, SourcesTabContent, Tabs, TabsContent, ThemeToggle, TodoTabContent, } from "./index.js";
|
|
10
10
|
const logger = createLogger("gui");
|
|
11
11
|
// Helper component to provide openFiles callback
|
|
12
12
|
function OpenFilesButton({ children, }) {
|
|
@@ -25,12 +25,12 @@ function AsideTabs() {
|
|
|
25
25
|
// Mobile header component that uses ChatHeader context
|
|
26
26
|
function MobileHeader({ agentName, showHeader, }) {
|
|
27
27
|
const { isExpanded, setIsExpanded } = ChatHeader.useChatHeaderContext();
|
|
28
|
-
return (_jsxs("div", { className: "flex lg:hidden items-center
|
|
28
|
+
return (_jsxs("div", { className: "flex lg:hidden items-center flex-1", children: [showHeader && (_jsx("div", { className: "flex items-center gap-2 flex-1", children: _jsx("h1", { className: "text-heading-4 text-foreground", children: agentName }) })), !showHeader && _jsx("div", { className: "flex-1" }), _jsx(ThemeToggle, {}), _jsx(IconButton, { "aria-label": "Toggle menu", onClick: () => setIsExpanded(!isExpanded), children: _jsx(ChevronUp, { className: cn("size-4 text-muted-foreground transition-transform duration-200", isExpanded ? "" : "rotate-180") }) })] }));
|
|
29
29
|
}
|
|
30
30
|
// Header component that uses ChatLayout context (must be inside ChatLayout.Root)
|
|
31
31
|
function AppChatHeader({ agentName, todos, sources, showHeader, }) {
|
|
32
32
|
const { panelSize, setPanelSize } = ChatLayout.useChatLayoutContext();
|
|
33
|
-
return (_jsxs(ChatHeader.Root, { className: cn("border-b border-border bg-card relative lg:p-0", "[border-bottom-width:0.5px]"), children: [_jsxs("div", { className: "hidden lg:flex items-center
|
|
33
|
+
return (_jsxs(ChatHeader.Root, { className: cn("border-b border-border bg-card relative lg:p-0", "[border-bottom-width:0.5px]"), children: [_jsxs("div", { className: "hidden lg:flex items-center w-full h-16 py-5 pl-6 pr-4", children: [showHeader && (_jsx("div", { className: "flex items-center gap-2 flex-1", children: _jsx("h1", { className: "text-heading-4 text-foreground", children: agentName }) })), !showHeader && _jsx("div", { className: "flex-1" }), _jsx(ThemeToggle, {}), _jsx(IconButton, { "aria-label": "Toggle sidebar", onClick: () => {
|
|
34
34
|
setPanelSize(panelSize === "hidden" ? "small" : "hidden");
|
|
35
35
|
}, children: _jsx(PanelRight, { className: "size-4 text-muted-foreground" }) })] }), _jsx(MobileHeader, { agentName: agentName, showHeader: showHeader }), _jsx(ChatHeader.ExpandablePanel, { className: cn("pt-6 pb-8 px-6", "border-b border-border bg-card", "shadow-[0_4px_16px_0_rgba(0,0,0,0.04)]", "[border-bottom-width:0.5px]"), children: _jsxs(Tabs, { defaultValue: "todo", className: "w-full", children: [_jsx(PanelTabsHeader, { showIcons: true, visibleTabs: ["todo", "files", "sources"], variant: "default" }), _jsx(TabsContent, { value: "todo", className: "mt-4", children: _jsx(TodoTabContent, { todos: todos }) }), _jsx(TabsContent, { value: "files", className: "mt-4", children: _jsx(FilesTabContent, {}) }), _jsx(TabsContent, { value: "sources", className: "mt-4", children: _jsx(SourcesTabContent, { sources: sources }) })] }) })] }));
|
|
36
36
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
4
|
+
import { Button } from "./Button.js";
|
|
5
|
+
export const IconButton = React.forwardRef(({ className, ...props }, ref) => {
|
|
6
|
+
return (_jsx(Button, { ref: ref, variant: "ghost", size: "icon", className: cn("rounded-full", className), ...props }));
|
|
7
|
+
});
|
|
8
|
+
IconButton.displayName = "IconButton";
|
|
@@ -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-paragraph-sm font-medium", "data-[state=active]:bg-
|
|
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-muted data-[state=active]:text-foreground", "data-[state=inactive]:text-muted-foreground hover:text-foreground transition-colors"), children: [showIcons && Icon && _jsx(Icon, { className: "size-4" }), tab.label] }, tab.id));
|
|
34
34
|
}) }));
|
|
35
35
|
});
|
|
36
36
|
PanelTabsHeader.displayName = "PanelTabsHeader";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type Theme = "dark" | "light" | "system";
|
|
2
|
+
type ThemeProviderProps = {
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
defaultTheme?: Theme;
|
|
5
|
+
storageKey?: string;
|
|
6
|
+
};
|
|
7
|
+
type ThemeProviderState = {
|
|
8
|
+
theme: Theme;
|
|
9
|
+
setTheme: (theme: Theme) => void;
|
|
10
|
+
resolvedTheme: "dark" | "light";
|
|
11
|
+
};
|
|
12
|
+
export declare function ThemeProvider({ children, defaultTheme, storageKey, }: ThemeProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare const useTheme: () => ThemeProviderState;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useEffect, useState } from "react";
|
|
3
|
+
const initialState = {
|
|
4
|
+
theme: "system",
|
|
5
|
+
setTheme: () => null,
|
|
6
|
+
resolvedTheme: "light",
|
|
7
|
+
};
|
|
8
|
+
const ThemeProviderContext = createContext(initialState);
|
|
9
|
+
export function ThemeProvider({ children, defaultTheme = "system", storageKey = "vite-ui-theme", }) {
|
|
10
|
+
const [theme, setTheme] = useState(() => localStorage.getItem(storageKey) || defaultTheme);
|
|
11
|
+
const [resolvedTheme, setResolvedTheme] = useState("light");
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
const root = window.document.documentElement;
|
|
14
|
+
root.classList.remove("light", "dark");
|
|
15
|
+
if (theme === "system") {
|
|
16
|
+
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
|
|
17
|
+
.matches
|
|
18
|
+
? "dark"
|
|
19
|
+
: "light";
|
|
20
|
+
root.classList.add(systemTheme);
|
|
21
|
+
setResolvedTheme(systemTheme);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
root.classList.add(theme);
|
|
25
|
+
setResolvedTheme(theme);
|
|
26
|
+
}, [theme]);
|
|
27
|
+
const value = {
|
|
28
|
+
theme,
|
|
29
|
+
setTheme: (theme) => {
|
|
30
|
+
localStorage.setItem(storageKey, theme);
|
|
31
|
+
setTheme(theme);
|
|
32
|
+
},
|
|
33
|
+
resolvedTheme,
|
|
34
|
+
};
|
|
35
|
+
return (_jsx(ThemeProviderContext.Provider, { value: value, children: children }));
|
|
36
|
+
}
|
|
37
|
+
export const useTheme = () => {
|
|
38
|
+
const context = useContext(ThemeProviderContext);
|
|
39
|
+
if (context === undefined)
|
|
40
|
+
throw new Error("useTheme must be used within a ThemeProvider");
|
|
41
|
+
return context;
|
|
42
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function ThemeToggle(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Moon, Sun } from "lucide-react";
|
|
3
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "./DropdownMenu.js";
|
|
4
|
+
import { IconButton } from "./IconButton.js";
|
|
5
|
+
import { useTheme } from "./ThemeProvider.js";
|
|
6
|
+
export function ThemeToggle() {
|
|
7
|
+
const { setTheme } = useTheme();
|
|
8
|
+
return (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(IconButton, { children: [_jsx(Sun, { className: "size-4 text-muted-foreground rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" }), _jsx(Moon, { className: "absolute size-4 text-muted-foreground rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" }), _jsx("span", { className: "sr-only", children: "Toggle theme" })] }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsx(DropdownMenuItem, { onClick: () => setTheme("light"), children: "Light" }), _jsx(DropdownMenuItem, { onClick: () => setTheme("dark"), children: "Dark" }), _jsx(DropdownMenuItem, { onClick: () => setTheme("system"), children: "System" })] })] }));
|
|
9
|
+
}
|
|
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import JsonView from "@uiw/react-json-view";
|
|
3
3
|
import { CheckSquare, ChevronDown, Cloud, Edit, FileText, Globe, Link, Search, Wrench, } from "lucide-react";
|
|
4
4
|
import { useState } from "react";
|
|
5
|
+
import { useTheme } from "./ThemeProvider.js";
|
|
5
6
|
/**
|
|
6
7
|
* Map of icon names to Lucide components
|
|
7
8
|
*/
|
|
@@ -35,20 +36,48 @@ const _kindIcons = {
|
|
|
35
36
|
*/
|
|
36
37
|
export function ToolCall({ toolCall }) {
|
|
37
38
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
39
|
+
const { resolvedTheme } = useTheme();
|
|
38
40
|
// Determine which icon to show
|
|
39
41
|
const IconComponent = toolCall.icon && ICON_MAP[toolCall.icon]
|
|
40
42
|
? ICON_MAP[toolCall.icon]
|
|
41
43
|
: Wrench;
|
|
42
44
|
// Determine display name
|
|
43
45
|
const displayName = toolCall.prettyName || toolCall.title;
|
|
44
|
-
|
|
46
|
+
// JSON View style based on theme
|
|
47
|
+
const jsonStyle = {
|
|
48
|
+
fontSize: "11px",
|
|
49
|
+
backgroundColor: "transparent",
|
|
50
|
+
fontFamily: "inherit",
|
|
51
|
+
"--w-rjv-color": resolvedTheme === "dark" ? "#fafafa" : "#09090b",
|
|
52
|
+
"--w-rjv-key-string": resolvedTheme === "dark" ? "#fafafa" : "#09090b",
|
|
53
|
+
"--w-rjv-background-color": "transparent",
|
|
54
|
+
"--w-rjv-line-color": resolvedTheme === "dark" ? "#27272a" : "#e4e4e7",
|
|
55
|
+
"--w-rjv-arrow-color": resolvedTheme === "dark" ? "#a1a1aa" : "#71717a",
|
|
56
|
+
"--w-rjv-edit-color": resolvedTheme === "dark" ? "#fafafa" : "#09090b",
|
|
57
|
+
"--w-rjv-info-color": resolvedTheme === "dark" ? "#a1a1aa" : "#71717a",
|
|
58
|
+
"--w-rjv-update-color": resolvedTheme === "dark" ? "#fafafa" : "#09090b",
|
|
59
|
+
"--w-rjv-copied-color": resolvedTheme === "dark" ? "#fafafa" : "#09090b",
|
|
60
|
+
"--w-rjv-copied-success-color": resolvedTheme === "dark" ? "#22c55e" : "#16a34a",
|
|
61
|
+
"--w-rjv-curlybraces-color": resolvedTheme === "dark" ? "#a1a1aa" : "#71717a",
|
|
62
|
+
"--w-rjv-colon-color": resolvedTheme === "dark" ? "#a1a1aa" : "#71717a",
|
|
63
|
+
"--w-rjv-brackets-color": resolvedTheme === "dark" ? "#a1a1aa" : "#71717a",
|
|
64
|
+
"--w-rjv-quotes-color": resolvedTheme === "dark" ? "#a1a1aa" : "#71717a",
|
|
65
|
+
"--w-rjv-quotes-string-color": resolvedTheme === "dark" ? "#a1a1aa" : "#71717a",
|
|
66
|
+
"--w-rjv-type-string-color": resolvedTheme === "dark" ? "#22c55e" : "#16a34a",
|
|
67
|
+
"--w-rjv-type-int-color": resolvedTheme === "dark" ? "#f59e0b" : "#d97706",
|
|
68
|
+
"--w-rjv-type-float-color": resolvedTheme === "dark" ? "#f59e0b" : "#d97706",
|
|
69
|
+
"--w-rjv-type-bigint-color": resolvedTheme === "dark" ? "#f59e0b" : "#d97706",
|
|
70
|
+
"--w-rjv-type-boolean-color": resolvedTheme === "dark" ? "#3b82f6" : "#2563eb",
|
|
71
|
+
"--w-rjv-type-date-color": resolvedTheme === "dark" ? "#ec4899" : "#db2777",
|
|
72
|
+
"--w-rjv-type-url-color": resolvedTheme === "dark" ? "#3b82f6" : "#2563eb",
|
|
73
|
+
"--w-rjv-type-null-color": resolvedTheme === "dark" ? "#ef4444" : "#dc2626",
|
|
74
|
+
"--w-rjv-type-nan-color": resolvedTheme === "dark" ? "#ef4444" : "#dc2626",
|
|
75
|
+
"--w-rjv-type-undefined-color": resolvedTheme === "dark" ? "#ef4444" : "#dc2626",
|
|
76
|
+
};
|
|
77
|
+
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-muted-foreground", children: [_jsx("div", { className: "text-muted-foreground", children: _jsx(IconComponent, { className: "h-3 w-3" }) }), _jsx("span", { className: "text-paragraph-sm text-muted-foreground", children: displayName }), _jsx(ChevronDown, { className: `h-3 w-3 text-muted-foreground/70 transition-transform duration-200 ${isExpanded ? "rotate-180" : ""}` })] }) }), isExpanded && (_jsxs("div", { className: "mt-2 text-sm border border-border rounded-lg bg-card overflow-hidden w-full", children: [toolCall.locations && toolCall.locations.length > 0 && (_jsxs("div", { className: "p-3 border-b border-border", children: [_jsx("div", { className: "text-[10px] font-bold text-muted-foreground 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-foreground bg-muted px-1.5 py-0.5 rounded w-fit", children: [loc.path, loc.line !== null &&
|
|
45
78
|
loc.line !== undefined &&
|
|
46
|
-
`:${loc.line}`] }, `${loc.path}:${loc.line ?? ""}`))) })] })), toolCall.rawInput && Object.keys(toolCall.rawInput).length > 0 && (_jsxs("div", { className: "p-3 border-b border-
|
|
47
|
-
|
|
48
|
-
backgroundColor: "transparent",
|
|
49
|
-
fontFamily: "inherit",
|
|
50
|
-
} }) })] })), (toolCall.content && toolCall.content.length > 0) ||
|
|
51
|
-
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) => {
|
|
79
|
+
`:${loc.line}`] }, `${loc.path}:${loc.line ?? ""}`))) })] })), toolCall.rawInput && Object.keys(toolCall.rawInput).length > 0 && (_jsxs("div", { className: "p-3 border-b border-border", children: [_jsx("div", { className: "text-[10px] font-bold text-muted-foreground uppercase tracking-wider mb-1.5 font-sans", children: "Input" }), _jsx("div", { className: "text-[11px] font-mono text-foreground", children: _jsx(JsonView, { value: toolCall.rawInput, collapsed: false, displayDataTypes: false, displayObjectSize: false, enableClipboard: true, style: jsonStyle }) })] })), (toolCall.content && toolCall.content.length > 0) ||
|
|
80
|
+
toolCall.error ? (_jsxs("div", { className: "p-3 border-b border-border last:border-0", children: [_jsx("div", { className: "text-[10px] font-bold text-muted-foreground uppercase tracking-wider mb-1.5 font-sans", children: "Output" }), _jsxs("div", { className: "space-y-2 text-[11px] text-foreground", children: [toolCall.content?.map((block, idx) => {
|
|
52
81
|
// Generate a stable key based on content
|
|
53
82
|
const getBlockKey = () => {
|
|
54
83
|
if (block.type === "diff" && "path" in block) {
|
|
@@ -73,18 +102,14 @@ export function ToolCall({ toolCall }) {
|
|
|
73
102
|
const parsed = JSON.parse(text);
|
|
74
103
|
// If it's an object or array, render with JsonView
|
|
75
104
|
if (typeof parsed === "object" && parsed !== null) {
|
|
76
|
-
return (_jsx("div", { className: "text-[11px]", children: _jsx(JsonView, { value: parsed, collapsed: false, displayDataTypes: false, displayObjectSize: false, enableClipboard: true, style:
|
|
77
|
-
fontSize: "11px",
|
|
78
|
-
backgroundColor: "transparent",
|
|
79
|
-
fontFamily: "inherit",
|
|
80
|
-
} }) }, key));
|
|
105
|
+
return (_jsx("div", { className: "text-[11px]", children: _jsx(JsonView, { value: parsed, collapsed: false, displayDataTypes: false, displayObjectSize: false, enableClipboard: true, style: jsonStyle }) }, key));
|
|
81
106
|
}
|
|
82
107
|
}
|
|
83
108
|
catch {
|
|
84
109
|
// Not valid JSON, render as plain text
|
|
85
110
|
}
|
|
86
111
|
// Render as plain text
|
|
87
|
-
return (_jsx("pre", { className: "whitespace-pre-wrap font-mono text-[11px] text-
|
|
112
|
+
return (_jsx("pre", { className: "whitespace-pre-wrap font-mono text-[11px] text-foreground overflow-x-auto", children: text }, key));
|
|
88
113
|
};
|
|
89
114
|
// Handle nested content blocks (ACP format)
|
|
90
115
|
if (block.type === "content" && "content" in block) {
|
|
@@ -102,15 +127,15 @@ export function ToolCall({ toolCall }) {
|
|
|
102
127
|
"path" in block &&
|
|
103
128
|
"oldText" in block &&
|
|
104
129
|
"newText" in block) {
|
|
105
|
-
return (_jsxs("div", { className: "border border-
|
|
130
|
+
return (_jsxs("div", { className: "border border-border rounded bg-card", children: [_jsxs("div", { className: "bg-muted px-2 py-1 text-[10px] font-mono text-muted-foreground border-b border-border", children: [block.path, "line" in block &&
|
|
106
131
|
block.line !== null &&
|
|
107
132
|
block.line !== undefined &&
|
|
108
|
-
`:${block.line}`] }), _jsxs("div", { className: "p-2 font-mono text-[11px]", children: [_jsxs("div", { className: "text-red-
|
|
133
|
+
`:${block.line}`] }), _jsxs("div", { className: "p-2 font-mono text-[11px]", children: [_jsxs("div", { className: "text-red-500 dark:text-red-400", children: ["- ", block.oldText] }), _jsxs("div", { className: "text-green-500 dark:text-green-400", children: ["+ ", block.newText] })] })] }, getBlockKey()));
|
|
109
134
|
}
|
|
110
135
|
// Handle terminal blocks
|
|
111
136
|
if (block.type === "terminal" && "terminalId" in block) {
|
|
112
|
-
return (_jsxs("div", { className: "bg-
|
|
137
|
+
return (_jsxs("div", { className: "bg-neutral-900 text-neutral-100 p-2 rounded text-[11px] font-mono", children: ["Terminal: ", block.terminalId] }, getBlockKey()));
|
|
113
138
|
}
|
|
114
139
|
return null;
|
|
115
|
-
}), toolCall.error && (_jsxs("div", { className: "text-
|
|
140
|
+
}), toolCall.error && (_jsxs("div", { className: "text-destructive font-mono text-[11px] mt-2", children: ["Error: ", toolCall.error] }))] })] })) : null, (toolCall.tokenUsage || toolCall.startedAt) && (_jsxs("div", { className: "p-2 bg-muted/50 border-t border-border flex flex-wrap gap-4 text-[10px] text-muted-foreground 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)"] }))] }))] }))] }))] }));
|
|
116
141
|
}
|
|
@@ -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-[10px] font-bold 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-muted-foreground 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-muted-foreground 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-muted-foreground 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))) }));
|
|
@@ -22,6 +22,7 @@ export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMe
|
|
|
22
22
|
export { FileSystemItem, type FileSystemItemProps, } from "./FileSystemItem.js";
|
|
23
23
|
export { FileSystemView, type FileSystemViewProps, } from "./FileSystemView.js";
|
|
24
24
|
export { HeightTransition } from "./HeightTransition.js";
|
|
25
|
+
export { IconButton, type IconButtonProps } from "./IconButton.js";
|
|
25
26
|
export { Input, type InputProps, inputVariants } from "./Input.js";
|
|
26
27
|
export { Label } from "./Label.js";
|
|
27
28
|
export { MarkdownRenderer } from "./MarkdownRenderer.js";
|
|
@@ -37,6 +38,8 @@ export { type SourceItem, SourceListItem, type SourceListItemProps, } from "./So
|
|
|
37
38
|
export { Tabs, TabsContent, TabsList, TabsTrigger } from "./Tabs.js";
|
|
38
39
|
export { Task, type TaskItem, TaskList, type TaskListProps, type TaskProps, } from "./Task.js";
|
|
39
40
|
export { Textarea, type TextareaProps, textareaVariants } from "./Textarea.js";
|
|
41
|
+
export { ThemeProvider, useTheme } from "./ThemeProvider.js";
|
|
42
|
+
export { ThemeToggle } from "./ThemeToggle.js";
|
|
40
43
|
export { ThinkingBlock, type ThinkingBlockProps, } from "./ThinkingBlock.js";
|
|
41
44
|
export { TodoList, type TodoListProps } from "./TodoList.js";
|
|
42
45
|
export { type TodoItem, TodoListItem, type TodoListItemProps, } from "./TodoListItem.js";
|
|
@@ -28,6 +28,7 @@ export { FileSystemItem, } from "./FileSystemItem.js";
|
|
|
28
28
|
export { FileSystemView, } from "./FileSystemView.js";
|
|
29
29
|
// Utility components
|
|
30
30
|
export { HeightTransition } from "./HeightTransition.js";
|
|
31
|
+
export { IconButton } from "./IconButton.js";
|
|
31
32
|
export { Input, inputVariants } from "./Input.js";
|
|
32
33
|
export { Label } from "./Label.js";
|
|
33
34
|
export { MarkdownRenderer } from "./MarkdownRenderer.js";
|
|
@@ -44,6 +45,8 @@ export { Tabs, TabsContent, TabsList, TabsTrigger } from "./Tabs.js";
|
|
|
44
45
|
// Task/Todo components
|
|
45
46
|
export { Task, TaskList, } from "./Task.js";
|
|
46
47
|
export { Textarea, textareaVariants } from "./Textarea.js";
|
|
48
|
+
export { ThemeProvider, useTheme } from "./ThemeProvider.js";
|
|
49
|
+
export { ThemeToggle } from "./ThemeToggle.js";
|
|
47
50
|
export { ThinkingBlock, } from "./ThinkingBlock.js";
|
|
48
51
|
export { TodoList } from "./TodoList.js";
|
|
49
52
|
export { TodoListItem, } from "./TodoListItem.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@townco/ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.43",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@agentclientprotocol/sdk": "^0.5.1",
|
|
43
|
-
"@townco/core": "0.0.
|
|
43
|
+
"@townco/core": "0.0.21",
|
|
44
44
|
"@radix-ui/react-dialog": "^1.1.15",
|
|
45
45
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
46
46
|
"@radix-ui/react-label": "^2.1.8",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
65
|
"@tailwindcss/postcss": "^4.1.17",
|
|
66
|
-
"@townco/tsconfig": "0.1.
|
|
66
|
+
"@townco/tsconfig": "0.1.40",
|
|
67
67
|
"@types/node": "^24.10.0",
|
|
68
68
|
"@types/react": "^19.2.2",
|
|
69
69
|
"ink": "^6.4.0",
|