@townco/ui 0.1.67 → 0.1.69

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 (56) hide show
  1. package/dist/core/hooks/use-chat-messages.d.ts +5 -0
  2. package/dist/core/hooks/use-tool-calls.d.ts +5 -0
  3. package/dist/core/hooks/use-tool-calls.js +2 -1
  4. package/dist/core/schemas/chat.d.ts +10 -0
  5. package/dist/core/schemas/tool-call.d.ts +96 -0
  6. package/dist/core/schemas/tool-call.js +12 -0
  7. package/dist/core/utils/tool-call-state.d.ts +30 -0
  8. package/dist/core/utils/tool-call-state.js +73 -0
  9. package/dist/core/utils/tool-summary.d.ts +13 -0
  10. package/dist/core/utils/tool-summary.js +172 -0
  11. package/dist/core/utils/tool-verbiage.d.ts +28 -0
  12. package/dist/core/utils/tool-verbiage.js +185 -0
  13. package/dist/gui/components/AppSidebar.d.ts +22 -0
  14. package/dist/gui/components/AppSidebar.js +22 -0
  15. package/dist/gui/components/ChatLayout.d.ts +5 -0
  16. package/dist/gui/components/ChatLayout.js +239 -132
  17. package/dist/gui/components/ChatView.js +42 -118
  18. package/dist/gui/components/MessageContent.js +199 -49
  19. package/dist/gui/components/SessionHistory.d.ts +10 -0
  20. package/dist/gui/components/SessionHistory.js +101 -0
  21. package/dist/gui/components/SessionHistoryItem.d.ts +11 -0
  22. package/dist/gui/components/SessionHistoryItem.js +24 -0
  23. package/dist/gui/components/Sheet.d.ts +25 -0
  24. package/dist/gui/components/Sheet.js +36 -0
  25. package/dist/gui/components/Sidebar.d.ts +65 -0
  26. package/dist/gui/components/Sidebar.js +231 -0
  27. package/dist/gui/components/SidebarToggle.d.ts +3 -0
  28. package/dist/gui/components/SidebarToggle.js +9 -0
  29. package/dist/gui/components/SubAgentDetails.d.ts +13 -6
  30. package/dist/gui/components/SubAgentDetails.js +29 -14
  31. package/dist/gui/components/ToolCallList.js +3 -3
  32. package/dist/gui/components/ToolOperation.d.ts +11 -0
  33. package/dist/gui/components/ToolOperation.js +289 -0
  34. package/dist/gui/components/WorkProgress.d.ts +20 -0
  35. package/dist/gui/components/WorkProgress.js +79 -0
  36. package/dist/gui/components/index.d.ts +8 -1
  37. package/dist/gui/components/index.js +9 -1
  38. package/dist/gui/hooks/index.d.ts +1 -0
  39. package/dist/gui/hooks/index.js +1 -0
  40. package/dist/gui/hooks/use-mobile.d.ts +1 -0
  41. package/dist/gui/hooks/use-mobile.js +15 -0
  42. package/dist/gui/index.d.ts +1 -0
  43. package/dist/gui/index.js +2 -0
  44. package/dist/gui/lib/motion.d.ts +55 -0
  45. package/dist/gui/lib/motion.js +217 -0
  46. package/dist/sdk/schemas/session.d.ts +102 -6
  47. package/dist/sdk/transports/http.js +105 -37
  48. package/dist/sdk/transports/types.d.ts +5 -0
  49. package/package.json +8 -7
  50. package/src/styles/global.css +128 -1
  51. package/dist/gui/components/InvokingGroup.d.ts +0 -9
  52. package/dist/gui/components/InvokingGroup.js +0 -16
  53. package/dist/gui/components/ToolCall.d.ts +0 -8
  54. package/dist/gui/components/ToolCall.js +0 -226
  55. package/dist/gui/components/ToolCallGroup.d.ts +0 -8
  56. package/dist/gui/components/ToolCallGroup.js +0 -29
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Mapping of tool names to their verbiage templates
3
+ *
4
+ * NOTE: Built-in Town SDK tools now include verbiage metadata in their definitions.
5
+ * This map is kept as a fallback for:
6
+ * - Legacy/external tools (e.g., Cursor IDE tools)
7
+ * - Custom tools without verbiage metadata
8
+ * - Backward compatibility
9
+ */
10
+ export const TOOL_VERBIAGE_MAP = {
11
+ // Town SDK filesystem tools (actual names: "Grep", "Read", "Write")
12
+ Read: {
13
+ active: "Reading {file}",
14
+ past: "Read {file}",
15
+ paramKey: "file_path",
16
+ },
17
+ Write: {
18
+ active: "Writing {file}",
19
+ past: "Wrote {file}",
20
+ paramKey: "file_path",
21
+ },
22
+ Grep: {
23
+ active: "Searching for {query}",
24
+ past: "Searched for {query}",
25
+ paramKey: "pattern",
26
+ },
27
+ // Town SDK web tools (actual names: "WebSearch", "WebFetch")
28
+ WebSearch: {
29
+ active: "Searching the web for {query}",
30
+ past: "Searched the web for {query}",
31
+ paramKey: "query",
32
+ },
33
+ WebFetch: {
34
+ active: "Fetching {url}",
35
+ past: "Fetched {url}",
36
+ paramKey: "url",
37
+ },
38
+ // Legacy/external tool names (for backward compatibility)
39
+ read_file: {
40
+ active: "Reading {file}",
41
+ past: "Read {file}",
42
+ paramKey: "target_file",
43
+ },
44
+ write: {
45
+ active: "Writing {file}",
46
+ past: "Wrote {file}",
47
+ paramKey: "file_path",
48
+ },
49
+ grep: {
50
+ active: "Searching for {query}",
51
+ past: "Searched for {query}",
52
+ paramKey: "pattern",
53
+ },
54
+ web_search: {
55
+ active: "Searching the web for {query}",
56
+ past: "Searched the web for {query}",
57
+ paramKey: "search_term",
58
+ },
59
+ search_replace: {
60
+ active: "Editing {file}",
61
+ past: "Edited {file}",
62
+ paramKey: "file_path",
63
+ },
64
+ delete_file: {
65
+ active: "Deleting {file}",
66
+ past: "Deleted {file}",
67
+ paramKey: "target_file",
68
+ },
69
+ codebase_search: {
70
+ active: "Searching codebase for {query}",
71
+ past: "Searched codebase for {query}",
72
+ paramKey: "query",
73
+ },
74
+ glob_file_search: {
75
+ active: "Finding files matching {pattern}",
76
+ past: "Found files matching {pattern}",
77
+ paramKey: "glob_pattern",
78
+ },
79
+ run_terminal_cmd: {
80
+ active: "Running {command}",
81
+ past: "Ran {command}",
82
+ paramKey: "command",
83
+ },
84
+ list_dir: {
85
+ active: "Listing {directory}",
86
+ past: "Listed {directory}",
87
+ paramKey: "target_directory",
88
+ },
89
+ edit_notebook: {
90
+ active: "Editing notebook",
91
+ past: "Edited notebook",
92
+ },
93
+ read_lints: {
94
+ active: "Reading linter errors",
95
+ past: "Read linter errors",
96
+ },
97
+ // Town SDK todo tool
98
+ todo_write: {
99
+ active: "Updating to-do's",
100
+ past: "Updated to-do's",
101
+ },
102
+ };
103
+ /**
104
+ * Extract parameter value from tool call
105
+ */
106
+ function extractParameter(toolCall, paramKey) {
107
+ if (!paramKey || !toolCall.rawInput)
108
+ return null;
109
+ const value = toolCall.rawInput[paramKey];
110
+ if (typeof value === "string") {
111
+ return value;
112
+ }
113
+ return null;
114
+ }
115
+ /**
116
+ * Format verbiage template with parameter values
117
+ */
118
+ function formatVerbiage(template, params) {
119
+ let result = template;
120
+ for (const [key, value] of Object.entries(params)) {
121
+ result = result.replace(`{${key}}`, value);
122
+ }
123
+ return result;
124
+ }
125
+ /**
126
+ * Truncate text to a maximum length with ellipsis
127
+ */
128
+ function truncate(text, maxLength) {
129
+ if (text.length <= maxLength)
130
+ return text;
131
+ return text.substring(0, maxLength - 1) + "…";
132
+ }
133
+ /**
134
+ * Get display verbiage for a tool call
135
+ */
136
+ export function getToolCallVerbiage(toolCall, tense) {
137
+ // First check if the tool has verbiage metadata
138
+ const template = toolCall.verbiage || TOOL_VERBIAGE_MAP[toolCall.title];
139
+ // If no template, fall back to pretty name or title
140
+ if (!template) {
141
+ const baseName = toolCall.prettyName || toolCall.title;
142
+ return tense === "active" ? `Using ${baseName}` : `Used ${baseName}`;
143
+ }
144
+ const verbiageTemplate = tense === "active" ? template.active : template.past;
145
+ // Extract parameter if specified
146
+ if (template.paramKey) {
147
+ const paramValue = extractParameter(toolCall, template.paramKey);
148
+ if (paramValue) {
149
+ // Truncate long parameter values
150
+ const truncatedValue = truncate(paramValue, 50);
151
+ // Determine the placeholder name based on param key
152
+ let placeholderName = "value";
153
+ if (template.paramKey.includes("file") ||
154
+ template.paramKey.includes("path")) {
155
+ placeholderName = "file";
156
+ }
157
+ else if (template.paramKey.includes("query") ||
158
+ template.paramKey.includes("pattern")) {
159
+ placeholderName = "query";
160
+ }
161
+ else if (template.paramKey.includes("command")) {
162
+ placeholderName = "command";
163
+ }
164
+ else if (template.paramKey.includes("directory")) {
165
+ placeholderName = "directory";
166
+ }
167
+ return formatVerbiage(verbiageTemplate, {
168
+ [placeholderName]: truncatedValue,
169
+ });
170
+ }
171
+ }
172
+ // If subline exists, use it as context
173
+ if (toolCall.subline) {
174
+ const prefix = verbiageTemplate.split("{")[0];
175
+ return prefix ? `${prefix.trim()} ${toolCall.subline}` : toolCall.subline;
176
+ }
177
+ // Return template without parameters
178
+ return verbiageTemplate.replace(/\s*\{[^}]+\}/g, "");
179
+ }
180
+ /**
181
+ * Get a short display name for a tool (for grouping)
182
+ */
183
+ export function getToolDisplayName(toolCall) {
184
+ return toolCall.prettyName || toolCall.title;
185
+ }
@@ -0,0 +1,22 @@
1
+ import type { AcpClient } from "../../sdk/client/index.js";
2
+ export interface AppSidebarProps {
3
+ /** The ACP client for fetching sessions */
4
+ client: AcpClient | null;
5
+ /** The current session ID */
6
+ currentSessionId: string | null;
7
+ /** Callback when a session is selected */
8
+ onSessionSelect?: (sessionId: string) => void;
9
+ /** Callback when a new session is requested */
10
+ onNewSession?: () => void;
11
+ /** Callback when a session is renamed */
12
+ onRenameSession?: (sessionId: string) => void;
13
+ /** Callback when a session is archived */
14
+ onArchiveSession?: (sessionId: string) => void;
15
+ /** Callback when a session is deleted */
16
+ onDeleteSession?: (sessionId: string) => void;
17
+ /** Optional footer content */
18
+ footer?: React.ReactNode;
19
+ /** Additional className for the sidebar */
20
+ className?: string;
21
+ }
22
+ export declare function AppSidebar({ client, currentSessionId, onSessionSelect, onNewSession, onRenameSession, onArchiveSession, onDeleteSession, footer, className, }: AppSidebarProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Plus } from "lucide-react";
3
+ import { cn } from "../lib/utils.js";
4
+ import { IconButton } from "./IconButton.js";
5
+ import { SessionHistory } from "./SessionHistory.js";
6
+ import { Sidebar, SidebarContent, SidebarFooter, SidebarHeader, useSidebar, } from "./Sidebar.js";
7
+ export function AppSidebar({ client, currentSessionId, onSessionSelect, onNewSession, onRenameSession, onArchiveSession, onDeleteSession, footer, className, }) {
8
+ const { setOpenMobile } = useSidebar();
9
+ const handleNewSession = () => {
10
+ if (onNewSession) {
11
+ onNewSession();
12
+ }
13
+ else {
14
+ // Default behavior: clear session from URL and reload
15
+ const url = new URL(window.location.href);
16
+ url.searchParams.delete("session");
17
+ window.location.href = url.toString();
18
+ }
19
+ setOpenMobile(false);
20
+ };
21
+ return (_jsxs(Sidebar, { className: cn("group-data-[side=left]:border-r-0", className), children: [_jsx(SidebarHeader, { className: "h-16 py-5 pl-6 pr-4", children: _jsxs("div", { className: "flex flex-row items-center justify-between w-full", children: [_jsx("span", { className: "font-semibold text-lg", children: "Sessions" }), _jsx(IconButton, { onClick: handleNewSession, "aria-label": "New Chat", children: _jsx(Plus, { className: "size-4 text-muted-foreground" }) })] }) }), _jsx(SidebarContent, { children: _jsx(SessionHistory, { client: client, currentSessionId: currentSessionId, onSessionSelect: onSessionSelect, onRenameSession: onRenameSession, onArchiveSession: onArchiveSession, onDeleteSession: onDeleteSession }) }), footer && _jsx(SidebarFooter, { children: footer })] }));
22
+ }
@@ -8,6 +8,9 @@ interface ChatLayoutContextValue {
8
8
  setPanelSize: (size: PanelSize) => void;
9
9
  activeTab: PanelTabType;
10
10
  setActiveTab: (tab: PanelTabType) => void;
11
+ panelOpen: boolean;
12
+ setPanelOpen: (open: boolean) => void;
13
+ togglePanel: () => void;
11
14
  }
12
15
  declare const ChatLayoutContext: React.Context<ChatLayoutContextValue | undefined>;
13
16
  declare const useChatLayoutContext: () => ChatLayoutContextValue;
@@ -36,6 +39,8 @@ export interface ChatLayoutMessagesProps extends React.HTMLAttributes<HTMLDivEle
36
39
  onScrollChange?: (isAtBottom: boolean) => void;
37
40
  /** Whether to show scroll to bottom button */
38
41
  showScrollToBottom?: boolean;
42
+ /** Whether to scroll to bottom on initial mount (default: true) */
43
+ initialScrollToBottom?: boolean;
39
44
  }
40
45
  declare const ChatLayoutMessages: React.ForwardRefExoticComponent<ChatLayoutMessagesProps & React.RefAttributes<HTMLDivElement>>;
41
46
  export interface ChatLayoutFooterProps extends React.HTMLAttributes<HTMLDivElement> {