@townco/ui 0.1.15 → 0.1.17

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.
Files changed (42) hide show
  1. package/dist/core/hooks/index.d.ts +1 -0
  2. package/dist/core/hooks/index.js +1 -0
  3. package/dist/core/hooks/use-chat-messages.d.ts +50 -11
  4. package/dist/core/hooks/use-chat-session.d.ts +5 -5
  5. package/dist/core/hooks/use-tool-calls.d.ts +52 -0
  6. package/dist/core/hooks/use-tool-calls.js +61 -0
  7. package/dist/core/schemas/chat.d.ts +166 -83
  8. package/dist/core/schemas/chat.js +27 -27
  9. package/dist/core/schemas/index.d.ts +1 -0
  10. package/dist/core/schemas/index.js +1 -0
  11. package/dist/core/schemas/tool-call.d.ts +174 -0
  12. package/dist/core/schemas/tool-call.js +130 -0
  13. package/dist/core/store/chat-store.d.ts +28 -28
  14. package/dist/core/store/chat-store.js +123 -59
  15. package/dist/gui/components/ChatLayout.js +11 -10
  16. package/dist/gui/components/Dialog.js +8 -84
  17. package/dist/gui/components/Label.js +2 -12
  18. package/dist/gui/components/MessageContent.js +4 -1
  19. package/dist/gui/components/Select.js +12 -118
  20. package/dist/gui/components/Tabs.js +4 -32
  21. package/dist/gui/components/ToolCall.d.ts +8 -0
  22. package/dist/gui/components/ToolCall.js +100 -0
  23. package/dist/gui/components/ToolCallList.d.ts +9 -0
  24. package/dist/gui/components/ToolCallList.js +22 -0
  25. package/dist/gui/components/index.d.ts +2 -0
  26. package/dist/gui/components/index.js +2 -0
  27. package/dist/gui/components/resizable.d.ts +7 -0
  28. package/dist/gui/components/resizable.js +7 -0
  29. package/dist/sdk/schemas/session.d.ts +390 -220
  30. package/dist/sdk/schemas/session.js +74 -29
  31. package/dist/sdk/transports/http.js +705 -472
  32. package/dist/sdk/transports/stdio.js +187 -32
  33. package/dist/tui/components/ChatView.js +19 -51
  34. package/dist/tui/components/MessageList.d.ts +2 -4
  35. package/dist/tui/components/MessageList.js +13 -37
  36. package/dist/tui/components/ToolCall.d.ts +9 -0
  37. package/dist/tui/components/ToolCall.js +41 -0
  38. package/dist/tui/components/ToolCallList.d.ts +8 -0
  39. package/dist/tui/components/ToolCallList.js +17 -0
  40. package/dist/tui/components/index.d.ts +2 -0
  41. package/dist/tui/components/index.js +2 -0
  42. package/package.json +4 -2
@@ -1,98 +1,22 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
2
  import * as DialogPrimitive from "@radix-ui/react-dialog";
2
3
  import { X } from "lucide-react";
3
4
  import * as React from "react";
4
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
5
5
  import { cn } from "../lib/utils.js";
6
-
7
6
  const Dialog = DialogPrimitive.Root;
8
7
  const DialogTrigger = DialogPrimitive.Trigger;
9
8
  const DialogPortal = DialogPrimitive.Portal;
10
9
  const DialogClose = DialogPrimitive.Close;
11
- const DialogOverlay = React.forwardRef(({ className, ...props }, ref) =>
12
- _jsx(DialogPrimitive.Overlay, {
13
- ref: ref,
14
- className: cn(
15
- "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
16
- className,
17
- ),
18
- ...props,
19
- }),
20
- );
10
+ const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => (_jsx(DialogPrimitive.Overlay, { ref: ref, className: cn("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", className), ...props })));
21
11
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
22
- const DialogContent = React.forwardRef(
23
- ({ className, children, ...props }, ref) =>
24
- _jsxs(DialogPortal, {
25
- children: [
26
- _jsx(DialogOverlay, {}),
27
- _jsxs(DialogPrimitive.Content, {
28
- ref: ref,
29
- className: cn(
30
- "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
31
- className,
32
- ),
33
- ...props,
34
- children: [
35
- children,
36
- _jsxs(DialogPrimitive.Close, {
37
- className:
38
- "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground",
39
- children: [
40
- _jsx(X, { className: "h-4 w-4" }),
41
- _jsx("span", { className: "sr-only", children: "Close" }),
42
- ],
43
- }),
44
- ],
45
- }),
46
- ],
47
- }),
48
- );
12
+ const DialogContent = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { ref: ref, className: cn("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", className), ...props, children: [children, _jsxs(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [_jsx(X, { className: "h-4 w-4" }), _jsx("span", { className: "sr-only", children: "Close" })] })] })] })));
49
13
  DialogContent.displayName = DialogPrimitive.Content.displayName;
50
- const DialogHeader = ({ className, ...props }) =>
51
- _jsx("div", {
52
- className: cn(
53
- "flex flex-col space-y-1.5 text-center sm:text-left",
54
- className,
55
- ),
56
- ...props,
57
- });
14
+ const DialogHeader = ({ className, ...props }) => (_jsx("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props }));
58
15
  DialogHeader.displayName = "DialogHeader";
59
- const DialogFooter = ({ className, ...props }) =>
60
- _jsx("div", {
61
- className: cn(
62
- "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
63
- className,
64
- ),
65
- ...props,
66
- });
16
+ const DialogFooter = ({ className, ...props }) => (_jsx("div", { className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className), ...props }));
67
17
  DialogFooter.displayName = "DialogFooter";
68
- const DialogTitle = React.forwardRef(({ className, ...props }, ref) =>
69
- _jsx(DialogPrimitive.Title, {
70
- ref: ref,
71
- className: cn(
72
- "text-lg font-semibold leading-none tracking-tight",
73
- className,
74
- ),
75
- ...props,
76
- }),
77
- );
18
+ const DialogTitle = React.forwardRef(({ className, ...props }, ref) => (_jsx(DialogPrimitive.Title, { ref: ref, className: cn("text-lg font-semibold leading-none tracking-tight", className), ...props })));
78
19
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
79
- const DialogDescription = React.forwardRef(({ className, ...props }, ref) =>
80
- _jsx(DialogPrimitive.Description, {
81
- ref: ref,
82
- className: cn("text-sm text-muted-foreground", className),
83
- ...props,
84
- }),
85
- );
20
+ const DialogDescription = React.forwardRef(({ className, ...props }, ref) => (_jsx(DialogPrimitive.Description, { ref: ref, className: cn("text-sm text-muted-foreground", className), ...props })));
86
21
  DialogDescription.displayName = DialogPrimitive.Description.displayName;
87
- export {
88
- Dialog,
89
- DialogPortal,
90
- DialogOverlay,
91
- DialogClose,
92
- DialogTrigger,
93
- DialogContent,
94
- DialogHeader,
95
- DialogFooter,
96
- DialogTitle,
97
- DialogDescription,
98
- };
22
+ export { Dialog, DialogPortal, DialogOverlay, DialogClose, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, };
@@ -1,17 +1,7 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
1
2
  import * as LabelPrimitive from "@radix-ui/react-label";
2
3
  import * as React from "react";
3
- import { jsx as _jsx } from "react/jsx-runtime";
4
4
  import { cn } from "../lib/utils.js";
5
-
6
- const Label = React.forwardRef(({ className, ...props }, ref) =>
7
- _jsx(LabelPrimitive.Root, {
8
- ref: ref,
9
- className: cn(
10
- "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
11
- className,
12
- ),
13
- ...props,
14
- }),
15
- );
5
+ const Label = React.forwardRef(({ className, ...props }, ref) => (_jsx(LabelPrimitive.Root, { ref: ref, className: cn("text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", className), ...props })));
16
6
  Label.displayName = LabelPrimitive.Root.displayName;
17
7
  export { Label };
@@ -6,6 +6,7 @@ import { useChatStore } from "../../core/store/chat-store.js";
6
6
  import { cn } from "../lib/utils.js";
7
7
  import { Reasoning } from "./Reasoning.js";
8
8
  import { Response } from "./Response.js";
9
+ import { ToolCall } from "./ToolCall.js";
9
10
  /**
10
11
  * MessageContent component inspired by shadcn.io/ai
11
12
  * Provides the content container with role-based styling
@@ -97,7 +98,9 @@ export const MessageContent = React.forwardRef(({ role: roleProp, variant, isStr
97
98
  const hasThinking = !!thinking;
98
99
  // Check if waiting (streaming but no content yet)
99
100
  const isWaiting = message.isStreaming && !message.content && message.role === "assistant";
100
- content = (_jsxs(_Fragment, { children: [message.role === "assistant" && hasThinking && (_jsx(Reasoning, { content: thinking, isStreaming: message.isStreaming, mode: thinkingDisplayStyle, autoCollapse: true })), isWaiting && streamingStartTime && (_jsxs("div", { className: "flex items-center gap-2 opacity-50", children: [_jsx(Loader2Icon, { className: "size-4 animate-spin text-muted-foreground" }), _jsx(WaitingElapsedTime, { startTime: streamingStartTime })] })), message.role === "user" ? (_jsx("div", { className: "whitespace-pre-wrap", children: message.content })) : (_jsx(Response, { content: message.content, isStreaming: message.isStreaming, showEmpty: false }))] }));
101
+ content = (_jsxs(_Fragment, { children: [message.role === "assistant" && hasThinking && (_jsx(Reasoning, { content: thinking, isStreaming: message.isStreaming, mode: thinkingDisplayStyle, autoCollapse: true })), isWaiting && streamingStartTime && (_jsxs("div", { className: "flex items-center gap-2 opacity-50", children: [_jsx(Loader2Icon, { className: "size-4 animate-spin text-muted-foreground" }), _jsx(WaitingElapsedTime, { startTime: streamingStartTime })] })), message.role === "assistant" &&
102
+ message.toolCalls &&
103
+ message.toolCalls.length > 0 && (_jsx("div", { className: "flex flex-col gap-2 mb-3", children: message.toolCalls.map((toolCall) => (_jsx(ToolCall, { toolCall: toolCall }, toolCall.id))) })), message.role === "user" ? (_jsx("div", { className: "whitespace-pre-wrap", children: message.content })) : (_jsx(Response, { content: message.content, isStreaming: message.isStreaming, showEmpty: false }))] }));
101
104
  }
102
105
  return (_jsx("div", { ref: ref, className: cn(messageContentVariants({ role, variant }), isStreaming && "animate-pulse-subtle", className), ...props, children: content }));
103
106
  });
@@ -1,132 +1,26 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
2
  import * as SelectPrimitive from "@radix-ui/react-select";
2
3
  import { Check, ChevronDown, ChevronsUpDown, ChevronUp } from "lucide-react";
3
4
  import * as React from "react";
4
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
5
5
  import { cn } from "../lib/utils.js";
6
-
7
6
  const Select = SelectPrimitive.Root;
8
7
  const SelectGroup = SelectPrimitive.Group;
9
8
  const SelectValue = SelectPrimitive.Value;
10
- const SelectTrigger = React.forwardRef(
11
- ({ className, children, ...props }, ref) =>
12
- _jsxs(SelectPrimitive.Trigger, {
13
- ref: ref,
14
- className: cn(
15
- "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",
16
- className,
17
- ),
18
- ...props,
19
- children: [
20
- children,
21
- _jsx(SelectPrimitive.Icon, {
22
- asChild: true,
23
- children: _jsx(ChevronsUpDown, { className: "h-4 w-4 opacity-50" }),
24
- }),
25
- ],
26
- }),
27
- );
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" }) })] })));
28
10
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
29
- const SelectScrollUpButton = React.forwardRef(({ className, ...props }, ref) =>
30
- _jsx(SelectPrimitive.ScrollUpButton, {
31
- ref: ref,
32
- className: cn(
33
- "flex cursor-default items-center justify-center py-1",
34
- className,
35
- ),
36
- ...props,
37
- children: _jsx(ChevronUp, { className: "h-4 w-4" }),
38
- }),
39
- );
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" }) })));
40
12
  SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
41
- const SelectScrollDownButton = React.forwardRef(
42
- ({ className, ...props }, ref) =>
43
- _jsx(SelectPrimitive.ScrollDownButton, {
44
- ref: ref,
45
- className: cn(
46
- "flex cursor-default items-center justify-center py-1",
47
- className,
48
- ),
49
- ...props,
50
- children: _jsx(ChevronDown, { className: "h-4 w-4" }),
51
- }),
52
- );
13
+ const SelectScrollDownButton = React.forwardRef(({ className, ...props }, ref) => (_jsx(SelectPrimitive.ScrollDownButton, { ref: ref, className: cn("flex cursor-default items-center justify-center py-1", className), ...props, children: _jsx(ChevronDown, { className: "h-4 w-4" }) })));
53
14
  SelectScrollDownButton.displayName =
54
- SelectPrimitive.ScrollDownButton.displayName;
55
- const SelectContent = React.forwardRef(
56
- ({ className, children, position = "popper", ...props }, ref) =>
57
- _jsx(SelectPrimitive.Portal, {
58
- children: _jsxs(SelectPrimitive.Content, {
59
- ref: ref,
60
- className: cn(
61
- "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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",
62
- position === "popper" &&
63
- "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
64
- className,
65
- ),
66
- position: position,
67
- ...props,
68
- children: [
69
- _jsx(SelectScrollUpButton, {}),
70
- _jsx(SelectPrimitive.Viewport, {
71
- className: cn(
72
- "p-1",
73
- position === "popper" &&
74
- "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]",
75
- ),
76
- children: children,
77
- }),
78
- _jsx(SelectScrollDownButton, {}),
79
- ],
80
- }),
81
- }),
82
- );
15
+ SelectPrimitive.ScrollDownButton.displayName;
16
+ const SelectContent = React.forwardRef(({ className, children, position = "popper", ...props }, ref) => (_jsx(SelectPrimitive.Portal, { children: _jsxs(SelectPrimitive.Content, { ref: ref, className: cn("relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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", position === "popper" &&
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
+ "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"), children: children }), _jsx(SelectScrollDownButton, {})] }) })));
83
19
  SelectContent.displayName = SelectPrimitive.Content.displayName;
84
- const SelectLabel = React.forwardRef(({ className, ...props }, ref) =>
85
- _jsx(SelectPrimitive.Label, {
86
- ref: ref,
87
- className: cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className),
88
- ...props,
89
- }),
90
- );
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 })));
91
21
  SelectLabel.displayName = SelectPrimitive.Label.displayName;
92
- const SelectItem = React.forwardRef(({ className, children, ...props }, ref) =>
93
- _jsxs(SelectPrimitive.Item, {
94
- ref: ref,
95
- className: cn(
96
- "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",
97
- className,
98
- ),
99
- ...props,
100
- children: [
101
- _jsx("span", {
102
- className:
103
- "absolute left-2 flex h-3.5 w-3.5 items-center justify-center",
104
- children: _jsx(SelectPrimitive.ItemIndicator, {
105
- children: _jsx(Check, { className: "h-4 w-4" }),
106
- }),
107
- }),
108
- _jsx(SelectPrimitive.ItemText, { children: children }),
109
- ],
110
- }),
111
- );
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 })] })));
112
23
  SelectItem.displayName = SelectPrimitive.Item.displayName;
113
- const SelectSeparator = React.forwardRef(({ className, ...props }, ref) =>
114
- _jsx(SelectPrimitive.Separator, {
115
- ref: ref,
116
- className: cn("-mx-1 my-1 h-px bg-muted", className),
117
- ...props,
118
- }),
119
- );
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 })));
120
25
  SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
121
- export {
122
- Select,
123
- SelectGroup,
124
- SelectValue,
125
- SelectTrigger,
126
- SelectContent,
127
- SelectLabel,
128
- SelectItem,
129
- SelectSeparator,
130
- SelectScrollUpButton,
131
- SelectScrollDownButton,
132
- };
26
+ export { Select, SelectGroup, SelectValue, SelectTrigger, SelectContent, SelectLabel, SelectItem, SelectSeparator, SelectScrollUpButton, SelectScrollDownButton, };
@@ -1,40 +1,12 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
1
2
  import * as TabsPrimitive from "@radix-ui/react-tabs";
2
3
  import * as React from "react";
3
- import { jsx as _jsx } from "react/jsx-runtime";
4
4
  import { cn } from "../lib/utils.js";
5
-
6
5
  const Tabs = TabsPrimitive.Root;
7
- const TabsList = React.forwardRef(({ className, ...props }, ref) =>
8
- _jsx(TabsPrimitive.List, {
9
- ref: ref,
10
- className: cn(
11
- "inline-flex h-10 items-center rounded-md bg-muted p-1 text-muted-foreground gap-1",
12
- className,
13
- ),
14
- ...props,
15
- }),
16
- );
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 })));
17
7
  TabsList.displayName = TabsPrimitive.List.displayName;
18
- const TabsTrigger = React.forwardRef(({ className, ...props }, ref) =>
19
- _jsx(TabsPrimitive.Trigger, {
20
- ref: ref,
21
- className: cn(
22
- "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",
23
- className,
24
- ),
25
- ...props,
26
- }),
27
- );
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 })));
28
9
  TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
29
- const TabsContent = React.forwardRef(({ className, ...props }, ref) =>
30
- _jsx(TabsPrimitive.Content, {
31
- ref: ref,
32
- className: cn(
33
- "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
34
- className,
35
- ),
36
- ...props,
37
- }),
38
- );
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 })));
39
11
  TabsContent.displayName = TabsPrimitive.Content.displayName;
40
12
  export { Tabs, TabsList, TabsTrigger, TabsContent };
@@ -0,0 +1,8 @@
1
+ import type { ToolCall as ToolCallType } from "../../core/schemas/tool-call.js";
2
+ export interface ToolCallProps {
3
+ toolCall: ToolCallType;
4
+ }
5
+ /**
6
+ * ToolCall component - displays a single tool call with collapsible details
7
+ */
8
+ export declare function ToolCall({ toolCall }: ToolCallProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,100 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import JsonView from "@uiw/react-json-view";
3
+ import { Wrench } from "lucide-react";
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
+ /**
15
+ * Tool call kind icons (using emoji for simplicity)
16
+ */
17
+ const kindIcons = {
18
+ read: "\u{1F4C4}",
19
+ edit: "\u{270F}\u{FE0F}",
20
+ delete: "\u{1F5D1}\u{FE0F}",
21
+ move: "\u{1F4E6}",
22
+ search: "\u{1F50D}",
23
+ execute: "\u{2699}\u{FE0F}",
24
+ think: "\u{1F4AD}",
25
+ fetch: "\u{1F310}",
26
+ switch_mode: "\u{1F501}",
27
+ other: "\u{1F527}",
28
+ };
29
+ /**
30
+ * ToolCall component - displays a single tool call with collapsible details
31
+ */
32
+ export function ToolCall({ toolCall }) {
33
+ const [isExpanded, setIsExpanded] = useState(false);
34
+ return (_jsxs("div", { className: "flex flex-col", children: [_jsxs("button", { type: "button", className: "flex items-center gap-1.5 cursor-pointer bg-transparent border-none p-0 text-left group w-fit", onClick: () => setIsExpanded(!isExpanded), "aria-expanded": isExpanded, children: [_jsxs("span", { className: `inline-flex items-center gap-1.5 px-2 py-1 text-xs font-medium rounded ${statusStyles[toolCall.status]}`, children: [_jsx(Wrench, { className: "h-3 w-3" }), _jsx("span", { children: toolCall.title }), toolCall.status === "completed" && _jsx("span", { children: "\u2713" })] }), _jsx("span", { className: "text-gray-400 text-xs opacity-0 group-hover:opacity-100 transition-opacity", children: isExpanded ? "▲" : "▼" })] }), isExpanded && (_jsxs("div", { className: "mt-2 space-y-3 text-sm border border-gray-200 rounded-md p-3 bg-white shadow-sm max-w-full", children: [toolCall.locations && toolCall.locations.length > 0 && (_jsxs("div", { children: [_jsx("div", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5", children: "Files" }), _jsx("ul", { className: "space-y-1", children: toolCall.locations.map((loc) => (_jsxs("li", { className: "font-mono text-xs text-gray-700 bg-gray-50 px-2 py-1 rounded", children: [loc.path, loc.line !== null &&
35
+ 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-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5", children: "Input" }), _jsx("div", { className: "bg-gray-50 p-2 rounded border border-gray-200", children: _jsx(JsonView, { value: toolCall.rawInput, collapsed: false, displayDataTypes: false, displayObjectSize: false, enableClipboard: true, style: { fontSize: "11px", backgroundColor: "transparent" } }) })] })), toolCall.content && toolCall.content.length > 0 && (_jsxs("div", { children: [_jsx("div", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5", children: "Output" }), _jsx("div", { className: "space-y-2", children: toolCall.content.map((block, idx) => {
37
+ // Generate a stable key based on content
38
+ const getBlockKey = () => {
39
+ if (block.type === "diff" && "path" in block) {
40
+ return `diff-${block.path}-${idx}`;
41
+ }
42
+ if (block.type === "terminal" && "terminalId" in block) {
43
+ return `terminal-${block.terminalId}`;
44
+ }
45
+ if (block.type === "text" && "text" in block) {
46
+ return `text-${block.text.substring(0, 20)}-${idx}`;
47
+ }
48
+ if (block.type === "content" && "content" in block) {
49
+ const innerContent = block.content;
50
+ return `content-${innerContent.text?.substring(0, 20)}-${idx}`;
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-gray-50 p-2 rounded border border-gray-200", children: _jsx(JsonView, { value: parsed, collapsed: false, displayDataTypes: false, displayObjectSize: false, enableClipboard: true, style: {
62
+ fontSize: "11px",
63
+ backgroundColor: "transparent",
64
+ } }) }, key));
65
+ }
66
+ }
67
+ catch {
68
+ // Not valid JSON, render as plain text
69
+ }
70
+ // Render as plain text
71
+ return (_jsx("pre", { className: "bg-gray-50 p-2.5 rounded border border-gray-200 text-xs overflow-x-auto font-mono text-gray-800", children: text }, key));
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());
78
+ }
79
+ }
80
+ // Handle direct text blocks
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-gray-100 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-red-50 border border-red-200 rounded p-2.5 text-red-700", children: [_jsx("div", { className: "text-xs font-semibold text-red-600 uppercase tracking-wide mb-1.5", children: "Error" }), _jsx("div", { className: "text-xs", children: toolCall.error })] })), toolCall.tokenUsage && (_jsxs("div", { className: "bg-gray-50 border border-gray-200 rounded p-2.5", children: [_jsx("div", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wide mb-2", children: "Token Usage" }), _jsxs("div", { className: "grid grid-cols-3 gap-3 text-xs text-gray-700", children: [toolCall.tokenUsage.inputTokens !== undefined && (_jsxs("div", { children: [_jsx("div", { className: "text-gray-500 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-gray-500 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-gray-500 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-gray-500", 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)"] }))] }))] }))] }));
100
+ }
@@ -0,0 +1,9 @@
1
+ import type { ToolCall as ToolCallType } from "../../core/schemas/tool-call.js";
2
+ export interface ToolCallListProps {
3
+ toolCalls: ToolCallType[];
4
+ groupBy?: "status" | "chronological";
5
+ }
6
+ /**
7
+ * ToolCallList component - renders a list of tool calls, optionally grouped
8
+ */
9
+ export declare function ToolCallList({ toolCalls, groupBy, }: ToolCallListProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ToolCall } from "./ToolCall.js";
3
+ /**
4
+ * ToolCallList component - renders a list of tool calls, optionally grouped
5
+ */
6
+ export function ToolCallList({ toolCalls, groupBy = "chronological", }) {
7
+ if (!toolCalls || toolCalls.length === 0) {
8
+ return null;
9
+ }
10
+ // Group by status if requested
11
+ if (groupBy === "status") {
12
+ const grouped = {
13
+ in_progress: toolCalls.filter((tc) => tc.status === "in_progress"),
14
+ pending: toolCalls.filter((tc) => tc.status === "pending"),
15
+ completed: toolCalls.filter((tc) => tc.status === "completed"),
16
+ failed: toolCalls.filter((tc) => tc.status === "failed"),
17
+ };
18
+ return (_jsxs("div", { className: "space-y-4", children: [grouped.in_progress.length > 0 && (_jsxs("div", { children: [_jsx("h4", { className: "text-sm font-semibold text-gray-700 mb-2", 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-sm font-semibold text-gray-700 mb-2", children: "Pending" }), grouped.pending.map((tc) => (_jsx(ToolCall, { toolCall: tc }, tc.id)))] })), grouped.completed.length > 0 && (_jsxs("div", { children: [_jsx("h4", { className: "text-sm font-semibold text-gray-700 mb-2", children: "Completed" }), grouped.completed.map((tc) => (_jsx(ToolCall, { toolCall: tc }, tc.id)))] })), grouped.failed.length > 0 && (_jsxs("div", { children: [_jsx("h4", { className: "text-sm font-semibold text-gray-700 mb-2", children: "Failed" }), grouped.failed.map((tc) => (_jsx(ToolCall, { toolCall: tc }, tc.id)))] }))] }));
19
+ }
20
+ // Default: chronological order
21
+ return (_jsx("div", { className: "space-y-2", children: toolCalls.map((tc) => (_jsx(ToolCall, { toolCall: tc }, tc.id))) }));
22
+ }
@@ -29,3 +29,5 @@ export { Textarea, type TextareaProps, textareaVariants } from "./Textarea.js";
29
29
  export { ThinkingBlock, type ThinkingBlockProps, } from "./ThinkingBlock.js";
30
30
  export { TodoList, type TodoListProps } from "./TodoList.js";
31
31
  export { type TodoItem, TodoListItem, type TodoListItemProps, } from "./TodoListItem.js";
32
+ export { ToolCall, type ToolCallProps } from "./ToolCall.js";
33
+ export { ToolCallList, type ToolCallListProps } from "./ToolCallList.js";
@@ -36,3 +36,5 @@ export { Textarea, textareaVariants } from "./Textarea.js";
36
36
  export { ThinkingBlock, } from "./ThinkingBlock.js";
37
37
  export { TodoList } from "./TodoList.js";
38
38
  export { TodoListItem, } from "./TodoListItem.js";
39
+ export { ToolCall } from "./ToolCall.js";
40
+ export { ToolCallList } from "./ToolCallList.js";
@@ -0,0 +1,7 @@
1
+ import * as ResizablePrimitive from "react-resizable-panels";
2
+ declare const ResizablePanelGroup: ({ className, ...props }: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) => import("react/jsx-runtime").JSX.Element;
3
+ declare const ResizablePanel: ({ className, ...props }: React.ComponentProps<typeof ResizablePrimitive.Panel>) => import("react/jsx-runtime").JSX.Element;
4
+ declare const ResizableHandle: ({ withHandle, className, ...props }: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
5
+ withHandle?: boolean;
6
+ }) => import("react/jsx-runtime").JSX.Element;
7
+ export { ResizablePanelGroup, ResizablePanel, ResizableHandle };
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as ResizablePrimitive from "react-resizable-panels";
3
+ import { cn } from "../lib/utils.js";
4
+ const ResizablePanelGroup = ({ className, ...props }) => (_jsx(ResizablePrimitive.PanelGroup, { className: cn("flex h-full w-full data-[panel-group-direction=vertical]:flex-col", className), ...props }));
5
+ const ResizablePanel = ({ className, ...props }) => (_jsx(ResizablePrimitive.Panel, { className: cn(className), ...props }));
6
+ const ResizableHandle = ({ withHandle, className, ...props }) => (_jsx(ResizablePrimitive.PanelResizeHandle, { className: cn("relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90", className), ...props, children: withHandle && (_jsx("div", { className: "z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border", children: _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "h-2.5 w-2.5", children: [_jsx("title", { children: "Resize Handle" }), _jsx("circle", { cx: "9", cy: "12", r: "1" }), _jsx("circle", { cx: "9", cy: "5", r: "1" }), _jsx("circle", { cx: "9", cy: "19", r: "1" }), _jsx("circle", { cx: "15", cy: "12", r: "1" }), _jsx("circle", { cx: "15", cy: "5", r: "1" }), _jsx("circle", { cx: "15", cy: "19", r: "1" })] }) })) }));
7
+ export { ResizablePanelGroup, ResizablePanel, ResizableHandle };