@townco/ui 0.1.22 → 0.1.24
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-input.js +5 -1
- package/dist/core/hooks/use-chat-messages.js +7 -3
- package/dist/core/hooks/use-chat-session.js +5 -1
- package/dist/core/index.d.ts +0 -1
- package/dist/core/index.js +0 -1
- package/dist/core/store/chat-store.d.ts +6 -0
- package/dist/core/store/chat-store.js +27 -13
- package/dist/gui/components/Button.d.ts +1 -1
- package/dist/gui/components/Button.js +5 -5
- package/dist/gui/components/ChatPanelTabContent.d.ts +5 -0
- package/dist/gui/components/ChatPanelTabContent.js +5 -0
- package/dist/gui/components/ChatSecondaryPanel.d.ts +1 -1
- package/dist/gui/components/ChatSecondaryPanel.js +8 -3
- package/dist/gui/components/Input.js +1 -1
- package/dist/gui/components/PanelTabsHeader.d.ts +1 -1
- package/dist/gui/components/PanelTabsHeader.js +6 -1
- package/dist/gui/components/SourceListItem.d.ts +15 -0
- package/dist/gui/components/SourceListItem.js +7 -0
- package/dist/gui/components/ToolCall.js +7 -7
- package/dist/gui/components/index.d.ts +2 -1
- package/dist/gui/components/index.js +3 -2
- package/dist/sdk/client/acp-client.js +11 -3
- package/dist/sdk/transports/http.js +1 -1
- package/dist/sdk/transports/stdio.js +1 -1
- package/dist/tui/components/ChatView.d.ts +3 -0
- package/dist/tui/components/ChatView.js +20 -8
- package/dist/tui/components/InputBox.js +22 -3
- package/dist/tui/components/MessageList.js +1 -1
- package/dist/tui/components/SimpleTextInput.d.ts +7 -0
- package/dist/tui/components/SimpleTextInput.js +208 -0
- package/dist/tui/components/StatusBar.js +3 -3
- package/dist/tui/components/index.d.ts +1 -0
- package/dist/tui/components/index.js +1 -0
- package/package.json +3 -3
- package/src/styles/global.css +138 -84
- package/dist/core/lib/logger.d.ts +0 -24
- package/dist/core/lib/logger.js +0 -108
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { createLogger } from "@townco/core";
|
|
1
2
|
import { useCallback } from "react";
|
|
2
3
|
import { useChatStore } from "../store/chat-store.js";
|
|
3
4
|
import { useChatMessages } from "./use-chat-messages.js";
|
|
5
|
+
const logger = createLogger("use-chat-input", "debug");
|
|
4
6
|
/**
|
|
5
7
|
* Hook for managing chat input
|
|
6
8
|
*/
|
|
@@ -33,7 +35,9 @@ export function useChatInput(client) {
|
|
|
33
35
|
}
|
|
34
36
|
catch (error) {
|
|
35
37
|
// Error is handled in useChatMessages
|
|
36
|
-
|
|
38
|
+
logger.error("Failed to send message", {
|
|
39
|
+
error: error instanceof Error ? error.message : String(error),
|
|
40
|
+
});
|
|
37
41
|
}
|
|
38
42
|
finally {
|
|
39
43
|
setInputSubmitting(false);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { createLogger } from "@townco/core";
|
|
1
2
|
import { useCallback } from "react";
|
|
2
3
|
import { useChatStore } from "../store/chat-store.js";
|
|
4
|
+
const logger = createLogger("use-chat-messages", "debug");
|
|
3
5
|
/**
|
|
4
6
|
* Hook for managing chat messages
|
|
5
7
|
*/
|
|
@@ -17,12 +19,12 @@ export function useChatMessages(client) {
|
|
|
17
19
|
*/
|
|
18
20
|
const sendMessage = useCallback(async (content) => {
|
|
19
21
|
if (!client) {
|
|
20
|
-
|
|
22
|
+
logger.error("No client available");
|
|
21
23
|
setError("No client available");
|
|
22
24
|
return;
|
|
23
25
|
}
|
|
24
26
|
if (!sessionId) {
|
|
25
|
-
|
|
27
|
+
logger.error("No active session");
|
|
26
28
|
setError("No active session");
|
|
27
29
|
return;
|
|
28
30
|
}
|
|
@@ -74,7 +76,9 @@ export function useChatMessages(client) {
|
|
|
74
76
|
let accumulatedContent = "";
|
|
75
77
|
for await (const chunk of messageStream) {
|
|
76
78
|
if (chunk.tokenUsage) {
|
|
77
|
-
|
|
79
|
+
logger.debug("chunk.tokenUsage", {
|
|
80
|
+
tokenUsage: chunk.tokenUsage,
|
|
81
|
+
});
|
|
78
82
|
}
|
|
79
83
|
if (chunk.isComplete) {
|
|
80
84
|
// Update final message
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { createLogger } from "@townco/core";
|
|
1
2
|
import { useCallback, useEffect } from "react";
|
|
2
3
|
import { useChatStore } from "../store/chat-store.js";
|
|
4
|
+
const logger = createLogger("use-chat-session", "debug");
|
|
3
5
|
/**
|
|
4
6
|
* Hook for managing chat session lifecycle
|
|
5
7
|
*/
|
|
@@ -26,7 +28,9 @@ export function useChatSession(client) {
|
|
|
26
28
|
setConnectionStatus("connected");
|
|
27
29
|
}
|
|
28
30
|
catch (error) {
|
|
29
|
-
|
|
31
|
+
logger.error("Failed to connect", {
|
|
32
|
+
error: error instanceof Error ? error.message : String(error),
|
|
33
|
+
});
|
|
30
34
|
const message = error instanceof Error ? error.message : String(error);
|
|
31
35
|
setError(message);
|
|
32
36
|
setConnectionStatus("error");
|
package/dist/core/index.d.ts
CHANGED
package/dist/core/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type LogEntry } from "@townco/core";
|
|
1
2
|
import type { ConnectionStatus, DisplayMessage, InputState } from "../schemas/index.js";
|
|
2
3
|
import type { ToolCall, ToolCallUpdate } from "../schemas/tool-call.js";
|
|
3
4
|
/**
|
|
@@ -23,6 +24,8 @@ export interface ChatStore {
|
|
|
23
24
|
};
|
|
24
25
|
currentModel: string | null;
|
|
25
26
|
tokenDisplayMode: "context" | "input" | "output";
|
|
27
|
+
logs: LogEntry[];
|
|
28
|
+
activeTab: "chat" | "logs";
|
|
26
29
|
input: InputState;
|
|
27
30
|
setConnectionStatus: (status: ConnectionStatus) => void;
|
|
28
31
|
setSessionId: (id: string | null) => void;
|
|
@@ -49,6 +52,9 @@ export interface ChatStore {
|
|
|
49
52
|
setCurrentModel: (model: string) => void;
|
|
50
53
|
resetTokens: () => void;
|
|
51
54
|
cycleTokenDisplayMode: () => void;
|
|
55
|
+
addLog: (log: LogEntry) => void;
|
|
56
|
+
clearLogs: () => void;
|
|
57
|
+
setActiveTab: (tab: "chat" | "logs") => void;
|
|
52
58
|
}
|
|
53
59
|
/**
|
|
54
60
|
* Create chat store
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { createLogger } from "@townco/core";
|
|
1
2
|
import { create } from "zustand";
|
|
2
3
|
import { mergeToolCallUpdate } from "../schemas/tool-call.js";
|
|
4
|
+
const logger = createLogger("chat-store", "debug");
|
|
3
5
|
/**
|
|
4
6
|
* Create chat store
|
|
5
7
|
*/
|
|
@@ -24,6 +26,8 @@ export const useChatStore = create((set) => ({
|
|
|
24
26
|
},
|
|
25
27
|
currentModel: "claude-sonnet-4-5-20250929", // Default model, TODO: get from server
|
|
26
28
|
tokenDisplayMode: "context", // Default to showing context (both billed and current)
|
|
29
|
+
logs: [],
|
|
30
|
+
activeTab: "chat",
|
|
27
31
|
input: {
|
|
28
32
|
value: "",
|
|
29
33
|
isSubmitting: false,
|
|
@@ -46,7 +50,10 @@ export const useChatStore = create((set) => ({
|
|
|
46
50
|
let finalUpdates = updates;
|
|
47
51
|
if (updates.tokenUsage) {
|
|
48
52
|
const existingTokenUsage = existingMessage?.tokenUsage;
|
|
49
|
-
|
|
53
|
+
logger.debug("updateMessage: incoming tokenUsage", {
|
|
54
|
+
incoming: updates.tokenUsage,
|
|
55
|
+
existing: existingTokenUsage,
|
|
56
|
+
});
|
|
50
57
|
// LangChain sends multiple token updates:
|
|
51
58
|
// 1. Early chunk: inputTokens (context) + outputTokens (estimate) + totalTokens
|
|
52
59
|
// 2. Later chunk: inputTokens=0 + outputTokens (final) + totalTokens (just output)
|
|
@@ -58,7 +65,9 @@ export const useChatStore = create((set) => ({
|
|
|
58
65
|
totalTokens: Math.max(updates.tokenUsage.inputTokens ?? 0, existingTokenUsage?.inputTokens ?? 0) +
|
|
59
66
|
Math.max(updates.tokenUsage.outputTokens ?? 0, existingTokenUsage?.outputTokens ?? 0),
|
|
60
67
|
};
|
|
61
|
-
|
|
68
|
+
logger.debug("updateMessage: merged tokenUsage", {
|
|
69
|
+
merged: messageMaxTokens,
|
|
70
|
+
});
|
|
62
71
|
// Replace the tokenUsage in updates with the max values
|
|
63
72
|
finalUpdates = {
|
|
64
73
|
...updates,
|
|
@@ -87,14 +96,14 @@ export const useChatStore = create((set) => ({
|
|
|
87
96
|
// Apply the updates (using finalUpdates which has the max tokenUsage)
|
|
88
97
|
const messages = state.messages.map((msg) => msg.id === id ? { ...msg, ...finalUpdates } : msg);
|
|
89
98
|
// Verification logging (only if tokenUsage was updated)
|
|
90
|
-
if (updates.tokenUsage) {
|
|
99
|
+
if (updates.tokenUsage && finalUpdates.tokenUsage) {
|
|
91
100
|
const existingTokenUsage = existingMessage?.tokenUsage;
|
|
92
|
-
const
|
|
93
|
-
const inputDelta = (
|
|
101
|
+
const messageTokens = finalUpdates.tokenUsage;
|
|
102
|
+
const inputDelta = (messageTokens.inputTokens ?? 0) -
|
|
94
103
|
(existingTokenUsage?.inputTokens ?? 0);
|
|
95
|
-
const outputDelta = (
|
|
104
|
+
const outputDelta = (messageTokens.outputTokens ?? 0) -
|
|
96
105
|
(existingTokenUsage?.outputTokens ?? 0);
|
|
97
|
-
const totalDelta = (
|
|
106
|
+
const totalDelta = (messageTokens.totalTokens ?? 0) -
|
|
98
107
|
(existingTokenUsage?.totalTokens ?? 0);
|
|
99
108
|
// Calculate actual sum from updated messages
|
|
100
109
|
const messageTokenBreakdown = messages
|
|
@@ -112,11 +121,11 @@ export const useChatStore = create((set) => ({
|
|
|
112
121
|
const isBilledCorrect = actualSum.inputTokens === newTotalBilled.inputTokens &&
|
|
113
122
|
actualSum.outputTokens === newTotalBilled.outputTokens &&
|
|
114
123
|
actualSum.totalTokens === newTotalBilled.totalTokens;
|
|
115
|
-
|
|
124
|
+
logger.debug("updateMessage: tokenUsage update", {
|
|
116
125
|
messageId: id,
|
|
117
126
|
updates: updates.tokenUsage,
|
|
118
127
|
existing: existingTokenUsage,
|
|
119
|
-
messageMax:
|
|
128
|
+
messageMax: messageTokens,
|
|
120
129
|
delta: { inputDelta, outputDelta, totalDelta },
|
|
121
130
|
totalBilled: newTotalBilled,
|
|
122
131
|
currentContext: newCurrentContext,
|
|
@@ -125,7 +134,7 @@ export const useChatStore = create((set) => ({
|
|
|
125
134
|
messageCount: messages.length,
|
|
126
135
|
messagesWithTokens: messageTokenBreakdown.length,
|
|
127
136
|
breakdown: messageTokenBreakdown,
|
|
128
|
-
})
|
|
137
|
+
});
|
|
129
138
|
}
|
|
130
139
|
return {
|
|
131
140
|
messages,
|
|
@@ -146,7 +155,7 @@ export const useChatStore = create((set) => ({
|
|
|
146
155
|
// Find the most recent assistant message (which should be streaming)
|
|
147
156
|
const lastAssistantIndex = state.messages.findLastIndex((msg) => msg.role === "assistant");
|
|
148
157
|
if (lastAssistantIndex === -1) {
|
|
149
|
-
|
|
158
|
+
logger.warn("No assistant message found to add tool call to");
|
|
150
159
|
return state;
|
|
151
160
|
}
|
|
152
161
|
const messages = [...state.messages];
|
|
@@ -163,7 +172,7 @@ export const useChatStore = create((set) => ({
|
|
|
163
172
|
// Find the most recent assistant message
|
|
164
173
|
const lastAssistantIndex = state.messages.findLastIndex((msg) => msg.role === "assistant");
|
|
165
174
|
if (lastAssistantIndex === -1) {
|
|
166
|
-
|
|
175
|
+
logger.warn("No assistant message found to update tool call in");
|
|
167
176
|
return state;
|
|
168
177
|
}
|
|
169
178
|
const messages = [...state.messages];
|
|
@@ -173,7 +182,7 @@ export const useChatStore = create((set) => ({
|
|
|
173
182
|
const toolCalls = lastAssistantMsg.toolCalls || [];
|
|
174
183
|
const existingIndex = toolCalls.findIndex((tc) => tc.id === update.id);
|
|
175
184
|
if (existingIndex === -1) {
|
|
176
|
-
|
|
185
|
+
logger.warn(`Tool call ${update.id} not found in message`);
|
|
177
186
|
return state;
|
|
178
187
|
}
|
|
179
188
|
const existing = toolCalls[existingIndex];
|
|
@@ -271,4 +280,9 @@ export const useChatStore = create((set) => ({
|
|
|
271
280
|
return state; // Should never happen, but satisfies TypeScript
|
|
272
281
|
return { tokenDisplayMode: nextMode };
|
|
273
282
|
}),
|
|
283
|
+
addLog: (log) => set((state) => ({
|
|
284
|
+
logs: [...state.logs, log],
|
|
285
|
+
})),
|
|
286
|
+
clearLogs: () => set({ logs: [] }),
|
|
287
|
+
setActiveTab: (tab) => set({ activeTab: tab }),
|
|
274
288
|
}));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type VariantProps } from "class-variance-authority";
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
declare const buttonVariants: (props?: ({
|
|
4
|
-
variant?: "default" | "
|
|
4
|
+
variant?: "default" | "link" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
|
|
5
5
|
size?: "default" | "sm" | "lg" | "icon" | null | undefined;
|
|
6
6
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
7
|
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
@@ -6,11 +6,11 @@ import { cn } from "../lib/utils.js";
|
|
|
6
6
|
const buttonVariants = cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer", {
|
|
7
7
|
variants: {
|
|
8
8
|
variant: {
|
|
9
|
-
default: "bg-primary text-primary-foreground hover:bg-primary
|
|
10
|
-
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive
|
|
11
|
-
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
12
|
-
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary
|
|
13
|
-
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
9
|
+
default: "bg-primary text-primary-foreground hover:bg-primary-hover",
|
|
10
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive-hover",
|
|
11
|
+
outline: "border border-input bg-background hover:bg-accent-hover hover:text-accent-foreground",
|
|
12
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-hover",
|
|
13
|
+
ghost: "hover:bg-accent-hover hover:text-accent-foreground",
|
|
14
14
|
link: "text-primary underline-offset-4 hover:underline",
|
|
15
15
|
},
|
|
16
16
|
size: {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import { type SourceItem } from "./SourceListItem.js";
|
|
2
3
|
import type { TodoItem } from "./TodoListItem.js";
|
|
3
4
|
/**
|
|
4
5
|
* Shared tab content components for both mobile (ChatHeader) and desktop (Panel) views
|
|
@@ -12,6 +13,10 @@ export interface FilesTabContentProps extends React.HTMLAttributes<HTMLDivElemen
|
|
|
12
13
|
files?: string[];
|
|
13
14
|
}
|
|
14
15
|
export declare const FilesTabContent: React.ForwardRefExoticComponent<FilesTabContentProps & React.RefAttributes<HTMLDivElement>>;
|
|
16
|
+
export interface SourcesTabContentProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
17
|
+
sources?: SourceItem[];
|
|
18
|
+
}
|
|
19
|
+
export declare const SourcesTabContent: React.ForwardRefExoticComponent<SourcesTabContentProps & React.RefAttributes<HTMLDivElement>>;
|
|
15
20
|
export interface DatabaseTabContentProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
16
21
|
data?: unknown;
|
|
17
22
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
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
|
+
import { SourceListItem } from "./SourceListItem.js";
|
|
4
5
|
export const TodoTabContent = React.forwardRef(({ todos, className, ...props }, ref) => {
|
|
5
6
|
return (_jsx("div", { ref: ref, className: cn("space-y-2", className), ...props, children: todos.length === 0 ? (_jsx("div", { className: "flex items-center justify-center h-full min-h-[200px]", children: _jsx("p", { className: "text-sm text-muted-foreground", children: "No todos yet" }) })) : (todos.map((todo) => (_jsx("div", { className: "text-sm", children: todo.text }, todo.id)))) }));
|
|
6
7
|
});
|
|
@@ -9,6 +10,10 @@ export const FilesTabContent = React.forwardRef(({ files = [], className, ...pro
|
|
|
9
10
|
return (_jsx("div", { ref: ref, className: cn("space-y-2", className), ...props, children: files.length === 0 ? (_jsx("div", { className: "flex items-center justify-center h-full min-h-[200px]", children: _jsx("p", { className: "text-sm text-muted-foreground", children: "No files attached" }) })) : (files.map((file) => (_jsx("div", { className: "text-sm", children: file }, file)))) }));
|
|
10
11
|
});
|
|
11
12
|
FilesTabContent.displayName = "FilesTabContent";
|
|
13
|
+
export const SourcesTabContent = React.forwardRef(({ sources = [], className, ...props }, ref) => {
|
|
14
|
+
return (_jsx("div", { ref: ref, className: cn("space-y-2", className), ...props, children: sources.length === 0 ? (_jsx("div", { className: "flex items-center justify-center h-full min-h-[200px]", children: _jsx("p", { className: "text-sm text-muted-foreground", children: "No sources available" }) })) : (sources.map((source) => (_jsx(SourceListItem, { source: source }, source.id)))) }));
|
|
15
|
+
});
|
|
16
|
+
SourcesTabContent.displayName = "SourcesTabContent";
|
|
12
17
|
export const DatabaseTabContent = React.forwardRef(({ data, className, ...props }, ref) => {
|
|
13
18
|
return (_jsxs("div", { ref: ref, className: cn("space-y-4", className), ...props, children: [_jsx("h3", { className: "font-semibold text-lg", children: "Database" }), _jsxs("div", { className: "text-sm text-muted-foreground", children: [_jsx("p", { children: "Database viewer - panel automatically expanded to large size" }), _jsxs("div", { className: "mt-4 p-4 border border-border rounded", children: [_jsx("p", { children: "Your large data table would go here" }), data && typeof data === "object" ? (_jsx("pre", { className: "mt-2 text-xs overflow-auto", children: JSON.stringify(data, null, 2) })) : null] })] })] }));
|
|
14
19
|
});
|
|
@@ -29,6 +29,6 @@ export interface ChatSecondaryPanelProps extends React.HTMLAttributes<HTMLDivEle
|
|
|
29
29
|
/**
|
|
30
30
|
* Which tabs to show
|
|
31
31
|
*/
|
|
32
|
-
visibleTabs?: ("todo" | "files" | "database")[];
|
|
32
|
+
visibleTabs?: ("todo" | "files" | "database" | "sources")[];
|
|
33
33
|
}
|
|
34
34
|
export declare const ChatSecondaryPanel: React.ForwardRefExoticComponent<ChatSecondaryPanelProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { CheckSquare, Database, FileText } from "lucide-react";
|
|
2
|
+
import { CheckSquare, Database, FileText, Link2 } from "lucide-react";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { useEffect, useRef, useState } from "react";
|
|
5
5
|
import { cn } from "../lib/utils.js";
|
|
6
|
-
import { FilesTabContent, TodoTabContent } from "./ChatPanelTabContent.js";
|
|
6
|
+
import { FilesTabContent, SourcesTabContent, TodoTabContent, } from "./ChatPanelTabContent.js";
|
|
7
7
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "./Tabs.js";
|
|
8
8
|
import { TodoList } from "./TodoList.js";
|
|
9
9
|
export const ChatSecondaryPanel = React.forwardRef(({ client, todos, variant = "animated", showIcons = false, visibleTabs = ["todo", "files", "database"], className, ...props }, ref) => {
|
|
@@ -49,6 +49,11 @@ export const ChatSecondaryPanel = React.forwardRef(({ client, todos, variant = "
|
|
|
49
49
|
label: "Database",
|
|
50
50
|
icon: Database,
|
|
51
51
|
},
|
|
52
|
+
{
|
|
53
|
+
id: "sources",
|
|
54
|
+
label: "Sources",
|
|
55
|
+
icon: Link2,
|
|
56
|
+
},
|
|
52
57
|
];
|
|
53
58
|
const tabs = allTabs.filter((tab) => visibleTabs.includes(tab.id));
|
|
54
59
|
return (_jsx("div", { ref: ref, className: cn("select-none", className), ...props, children: _jsxs(Tabs, { value: activeTab, onValueChange: setActiveTab, className: "w-full", children: [variant === "pills" ? (
|
|
@@ -61,6 +66,6 @@ export const ChatSecondaryPanel = React.forwardRef(({ client, todos, variant = "
|
|
|
61
66
|
_jsxs("div", { className: "relative mb-4 border-border", children: [_jsx(TabsList, { className: "bg-transparent p-0 h-auto rounded-none w-full border-none", children: tabs.map((tab) => (_jsx(TabsTrigger, { value: tab.id, className: "px-3 py-1 text-sm font-[var(--font-family)] font-medium rounded-none text-foreground opacity-60 data-[state=active]:opacity-100 data-[state=active]:bg-transparent data-[state=active]:shadow-none", children: tab.label }, tab.id))) }), _jsx("div", { ref: containerRef, className: "absolute top-0 left-0 w-full overflow-hidden z-10 pointer-events-none", style: {
|
|
62
67
|
clipPath: "inset(0 100% 0 0% round 999px)",
|
|
63
68
|
transition: "clip-path 0.25s ease-out",
|
|
64
|
-
}, children: _jsx(TabsList, { className: "bg-secondary p-0 h-auto rounded-none w-full border-none", children: tabs.map((tab) => (_jsx(TabsTrigger, { value: tab.id, ref: activeTab === tab.id ? activeTabElementRef : null, className: "px-3 py-1 text-sm font-[var(--font-family)] font-medium rounded-none text-primary bg-transparent data-[state=active]:shadow-none shadow-none", tabIndex: -1, children: tab.label }, tab.id))) }) })] })), _jsx(TabsContent, { value: "todo", className: variant === "pills" ? "mt-0" : "", children: variant === "pills" ? (_jsx(TodoTabContent, { todos: todosToDisplay })) : (_jsx(TodoList, { todos: todosToDisplay })) }), _jsx(TabsContent, { value: "files", className: variant === "pills" ? "mt-0" : "", children: _jsx(FilesTabContent, {}) }), _jsx(TabsContent, { value: "database", className: variant === "pills" ? "mt-0" : "", children: _jsx("div", { className: "text-sm text-foreground opacity-60 italic", children: "Database tab coming soon..." }) })] }) }));
|
|
69
|
+
}, children: _jsx(TabsList, { className: "bg-secondary p-0 h-auto rounded-none w-full border-none", children: tabs.map((tab) => (_jsx(TabsTrigger, { value: tab.id, ref: activeTab === tab.id ? activeTabElementRef : null, className: "px-3 py-1 text-sm font-[var(--font-family)] font-medium rounded-none text-primary bg-transparent data-[state=active]:shadow-none shadow-none", tabIndex: -1, children: tab.label }, tab.id))) }) })] })), _jsx(TabsContent, { value: "todo", className: variant === "pills" ? "mt-0" : "", children: variant === "pills" ? (_jsx(TodoTabContent, { todos: todosToDisplay })) : (_jsx(TodoList, { todos: todosToDisplay })) }), _jsx(TabsContent, { value: "files", className: variant === "pills" ? "mt-0" : "", children: _jsx(FilesTabContent, {}) }), _jsx(TabsContent, { value: "database", className: variant === "pills" ? "mt-0" : "", children: _jsx("div", { className: "text-sm text-foreground opacity-60 italic", children: "Database tab coming soon..." }) }), _jsx(TabsContent, { value: "sources", className: variant === "pills" ? "mt-0" : "", children: _jsx(SourcesTabContent, {}) })] }) }));
|
|
65
70
|
});
|
|
66
71
|
ChatSecondaryPanel.displayName = "ChatSecondaryPanel";
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { cva } from "class-variance-authority";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { cn } from "../lib/utils.js";
|
|
5
|
-
const inputVariants = cva("flex h-10 w-full rounded-md border bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", {
|
|
5
|
+
const inputVariants = cva("flex h-10 w-full rounded-md border bg-input-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", {
|
|
6
6
|
variants: {
|
|
7
7
|
variant: {
|
|
8
8
|
default: "border-input focus-visible:ring-ring",
|
|
@@ -8,7 +8,7 @@ export interface PanelTabsHeaderProps extends Omit<React.ComponentPropsWithoutRe
|
|
|
8
8
|
/**
|
|
9
9
|
* Which tabs to show
|
|
10
10
|
*/
|
|
11
|
-
visibleTabs?: ("todo" | "files" | "database")[];
|
|
11
|
+
visibleTabs?: ("todo" | "files" | "database" | "sources")[];
|
|
12
12
|
/**
|
|
13
13
|
* Styling variant
|
|
14
14
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { CheckSquare, Database, FileText } from "lucide-react";
|
|
2
|
+
import { CheckSquare, Database, FileText, Link2 } from "lucide-react";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { cn } from "../lib/utils.js";
|
|
5
5
|
import { TabsList, TabsTrigger } from "./Tabs.js";
|
|
@@ -20,6 +20,11 @@ export const PanelTabsHeader = React.forwardRef(({ showIcons = true, visibleTabs
|
|
|
20
20
|
label: "Database",
|
|
21
21
|
icon: Database,
|
|
22
22
|
},
|
|
23
|
+
{
|
|
24
|
+
id: "sources",
|
|
25
|
+
label: "Sources",
|
|
26
|
+
icon: Link2,
|
|
27
|
+
},
|
|
23
28
|
];
|
|
24
29
|
const tabs = allTabs.filter((tab) => visibleTabs.includes(tab.id));
|
|
25
30
|
const gap = variant === "compact" ? "gap-[4px]" : "gap-3";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface SourceItem {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
url: string;
|
|
6
|
+
snippet: string;
|
|
7
|
+
sourceName: string;
|
|
8
|
+
favicon?: string;
|
|
9
|
+
timestamp?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface SourceListItemProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
12
|
+
source: SourceItem;
|
|
13
|
+
isSelected?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare const SourceListItem: React.ForwardRefExoticComponent<SourceListItemProps & React.RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1,7 @@
|
|
|
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
|
+
export const SourceListItem = React.forwardRef(({ source, isSelected, className, ...props }, ref) => {
|
|
5
|
+
return (_jsxs("button", { ref: ref, type: "button", className: cn("flex w-full text-left gap-2 items-start p-3 rounded-lg transition-colors cursor-pointer border border-transparent", "hover:bg-accent-hover hover:border-border/50", isSelected && "bg-accent-hover border-border/50", className), onClick: () => window.open(source.url, "_blank"), ...props, children: [_jsx("div", { className: "flex gap-2 items-center py-[2px] shrink-0", children: _jsx("div", { className: "relative rounded-[3px] shrink-0 size-4 overflow-hidden bg-muted", children: source.favicon ? (_jsx("img", { alt: source.sourceName, className: "size-full object-cover", src: source.favicon })) : (_jsx("div", { className: "size-full bg-muted" })) }) }), _jsxs("div", { className: "flex flex-1 flex-col gap-1 min-w-0", children: [_jsxs("div", { className: "text-xs leading-normal text-foreground", children: [_jsx("span", { className: "font-medium", children: source.sourceName }), _jsxs("span", { className: "text-muted-foreground", children: [" \u00B7 ", source.title] })] }), _jsx("p", { className: "text-xs leading-relaxed text-muted-foreground line-clamp-3", children: source.snippet })] })] }));
|
|
6
|
+
});
|
|
7
|
+
SourceListItem.displayName = "SourceListItem";
|
|
@@ -14,7 +14,7 @@ const statusStyles = {
|
|
|
14
14
|
/**
|
|
15
15
|
* Tool call kind icons (using emoji for simplicity)
|
|
16
16
|
*/
|
|
17
|
-
const
|
|
17
|
+
const _kindIcons = {
|
|
18
18
|
read: "\u{1F4C4}",
|
|
19
19
|
edit: "\u{270F}\u{FE0F}",
|
|
20
20
|
delete: "\u{1F5D1}\u{FE0F}",
|
|
@@ -31,9 +31,9 @@ const kindIcons = {
|
|
|
31
31
|
*/
|
|
32
32
|
export function ToolCall({ toolCall }) {
|
|
33
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-
|
|
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-muted-foreground 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-border rounded-md p-3 bg-card shadow-sm max-w-full", children: [toolCall.locations && toolCall.locations.length > 0 && (_jsxs("div", { children: [_jsx("div", { className: "text-xs font-semibold text-muted-foreground 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-foreground bg-muted px-2 py-1 rounded", children: [loc.path, loc.line !== null &&
|
|
35
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-
|
|
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-muted-foreground uppercase tracking-wide mb-1.5", children: "Input" }), _jsx("div", { className: "bg-muted p-2 rounded border border-border", 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-muted-foreground uppercase tracking-wide mb-1.5", children: "Output" }), _jsx("div", { className: "space-y-2", children: toolCall.content.map((block, idx) => {
|
|
37
37
|
// Generate a stable key based on content
|
|
38
38
|
const getBlockKey = () => {
|
|
39
39
|
if (block.type === "diff" && "path" in block) {
|
|
@@ -58,7 +58,7 @@ export function ToolCall({ toolCall }) {
|
|
|
58
58
|
const parsed = JSON.parse(text);
|
|
59
59
|
// If it's an object or array, render with JsonView
|
|
60
60
|
if (typeof parsed === "object" && parsed !== null) {
|
|
61
|
-
return (_jsx("div", { className: "bg-
|
|
61
|
+
return (_jsx("div", { className: "bg-muted p-2 rounded border border-border", children: _jsx(JsonView, { value: parsed, collapsed: false, displayDataTypes: false, displayObjectSize: false, enableClipboard: true, style: {
|
|
62
62
|
fontSize: "11px",
|
|
63
63
|
backgroundColor: "transparent",
|
|
64
64
|
} }) }, key));
|
|
@@ -68,7 +68,7 @@ export function ToolCall({ toolCall }) {
|
|
|
68
68
|
// Not valid JSON, render as plain text
|
|
69
69
|
}
|
|
70
70
|
// Render as plain text
|
|
71
|
-
return (_jsx("pre", { className: "bg-
|
|
71
|
+
return (_jsx("pre", { className: "bg-muted p-2.5 rounded border border-border text-xs overflow-x-auto font-mono text-foreground", children: text }, key));
|
|
72
72
|
};
|
|
73
73
|
// Handle nested content blocks (ACP format)
|
|
74
74
|
if (block.type === "content" && "content" in block) {
|
|
@@ -86,7 +86,7 @@ export function ToolCall({ toolCall }) {
|
|
|
86
86
|
"path" in block &&
|
|
87
87
|
"oldText" in block &&
|
|
88
88
|
"newText" in block) {
|
|
89
|
-
return (_jsxs("div", { className: "border rounded", children: [_jsxs("div", { className: "bg-
|
|
89
|
+
return (_jsxs("div", { className: "border rounded", children: [_jsxs("div", { className: "bg-muted px-2 py-1 text-xs font-mono", children: [block.path, "line" in block &&
|
|
90
90
|
block.line !== null &&
|
|
91
91
|
block.line !== undefined &&
|
|
92
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()));
|
|
@@ -96,5 +96,5 @@ export function ToolCall({ toolCall }) {
|
|
|
96
96
|
return (_jsxs("div", { className: "bg-black text-green-400 p-2 rounded text-xs font-mono", children: ["Terminal: ", block.terminalId] }, getBlockKey()));
|
|
97
97
|
}
|
|
98
98
|
return null;
|
|
99
|
-
}) })] })), toolCall.error && (_jsxs("div", { className: "bg-
|
|
99
|
+
}) })] })), toolCall.error && (_jsxs("div", { className: "bg-destructive/10 border border-destructive/20 rounded p-2.5 text-destructive", children: [_jsx("div", { className: "text-xs font-semibold text-destructive uppercase tracking-wide mb-1.5", children: "Error" }), _jsx("div", { className: "text-xs", children: toolCall.error })] })), toolCall.tokenUsage && (_jsxs("div", { className: "bg-muted border border-border rounded p-2.5", children: [_jsx("div", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide mb-2", children: "Token Usage" }), _jsxs("div", { className: "grid grid-cols-3 gap-3 text-xs text-foreground", children: [toolCall.tokenUsage.inputTokens !== undefined && (_jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground text-[10px] uppercase tracking-wide mb-0.5", children: "Input" }), _jsx("div", { className: "font-medium", children: toolCall.tokenUsage.inputTokens.toLocaleString() })] })), toolCall.tokenUsage.outputTokens !== undefined && (_jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground text-[10px] uppercase tracking-wide mb-0.5", children: "Output" }), _jsx("div", { className: "font-medium", children: toolCall.tokenUsage.outputTokens.toLocaleString() })] })), toolCall.tokenUsage.totalTokens !== undefined && (_jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground text-[10px] uppercase tracking-wide mb-0.5", children: "Total" }), _jsx("div", { className: "font-medium", children: toolCall.tokenUsage.totalTokens.toLocaleString() })] }))] })] })), toolCall.startedAt && (_jsxs("div", { className: "text-xs text-muted-foreground", children: ["Started: ", new Date(toolCall.startedAt).toLocaleTimeString(), toolCall.completedAt && (_jsxs(_Fragment, { children: [" ", "| Completed:", " ", new Date(toolCall.completedAt).toLocaleTimeString(), " (", Math.round((toolCall.completedAt - toolCall.startedAt) / 1000), "s)"] }))] }))] }))] }));
|
|
100
100
|
}
|
|
@@ -6,7 +6,7 @@ export type { ConnectionStatus } from "./ChatHeader.js";
|
|
|
6
6
|
export * as ChatHeader from "./ChatHeader.js";
|
|
7
7
|
export { Actions as ChatInputActions, Attachment as ChatInputAttachment, type ChatInputActionsProps, type ChatInputAttachmentProps, type ChatInputCommandMenuProps, type ChatInputFieldProps, type ChatInputRootProps, type ChatInputSubmitProps, type ChatInputToolbarProps, type ChatInputVoiceInputProps, CommandMenu as ChatInputCommandMenu, type CommandMenuItem, Field as ChatInputField, Root as ChatInputRoot, Submit as ChatInputSubmit, Toolbar as ChatInputToolbar, VoiceInput as ChatInputVoiceInput, } from "./ChatInput.js";
|
|
8
8
|
export * as ChatLayout from "./ChatLayout.js";
|
|
9
|
-
export { DatabaseTabContent, type DatabaseTabContentProps, FilesTabContent, type FilesTabContentProps, TodoTabContent, type TodoTabContentProps, } from "./ChatPanelTabContent.js";
|
|
9
|
+
export { DatabaseTabContent, type DatabaseTabContentProps, FilesTabContent, type FilesTabContentProps, SourcesTabContent, type SourcesTabContentProps, TodoTabContent, type TodoTabContentProps, } from "./ChatPanelTabContent.js";
|
|
10
10
|
export { ChatSecondaryPanel, type ChatSecondaryPanelProps, } from "./ChatSecondaryPanel.js";
|
|
11
11
|
export * as ChatSidebar from "./ChatSidebar.js";
|
|
12
12
|
export { ChatStatus, type ChatStatusProps } from "./ChatStatus.js";
|
|
@@ -25,6 +25,7 @@ export { Reasoning, type ReasoningProps } from "./Reasoning.js";
|
|
|
25
25
|
export { Response, type ResponseProps } from "./Response.js";
|
|
26
26
|
export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, } from "./Select.js";
|
|
27
27
|
export { Toaster } from "./Sonner.js";
|
|
28
|
+
export { type SourceItem, SourceListItem, type SourceListItemProps, } from "./SourceListItem.js";
|
|
28
29
|
export { Tabs, TabsContent, TabsList, TabsTrigger } from "./Tabs.js";
|
|
29
30
|
export { Task, type TaskItem, TaskList, type TaskListProps, type TaskProps, } from "./Task.js";
|
|
30
31
|
export { Textarea, type TextareaProps, textareaVariants } from "./Textarea.js";
|
|
@@ -8,7 +8,7 @@ export * as ChatHeader from "./ChatHeader.js";
|
|
|
8
8
|
export { Actions as ChatInputActions, Attachment as ChatInputAttachment, CommandMenu as ChatInputCommandMenu, Field as ChatInputField, Root as ChatInputRoot, Submit as ChatInputSubmit, Toolbar as ChatInputToolbar, VoiceInput as ChatInputVoiceInput, } from "./ChatInput.js";
|
|
9
9
|
// Chat layout components
|
|
10
10
|
export * as ChatLayout from "./ChatLayout.js";
|
|
11
|
-
export { DatabaseTabContent, FilesTabContent, TodoTabContent, } from "./ChatPanelTabContent.js";
|
|
11
|
+
export { DatabaseTabContent, FilesTabContent, SourcesTabContent, TodoTabContent, } from "./ChatPanelTabContent.js";
|
|
12
12
|
export { ChatSecondaryPanel, } from "./ChatSecondaryPanel.js";
|
|
13
13
|
export * as ChatSidebar from "./ChatSidebar.js";
|
|
14
14
|
export { ChatStatus } from "./ChatStatus.js";
|
|
@@ -29,8 +29,9 @@ export { PanelTabsHeader, } from "./PanelTabsHeader.js";
|
|
|
29
29
|
export { Reasoning } from "./Reasoning.js";
|
|
30
30
|
export { Response } from "./Response.js";
|
|
31
31
|
export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, } from "./Select.js";
|
|
32
|
-
// Toast components
|
|
33
32
|
export { Toaster } from "./Sonner.js";
|
|
33
|
+
// Toast components
|
|
34
|
+
export { SourceListItem, } from "./SourceListItem.js";
|
|
34
35
|
export { Tabs, TabsContent, TabsList, TabsTrigger } from "./Tabs.js";
|
|
35
36
|
// Task/Todo components
|
|
36
37
|
export { Task, TaskList, } from "./Task.js";
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { createLogger } from "@townco/core";
|
|
1
2
|
import { HttpTransport } from "../transports/http.js";
|
|
2
3
|
import { StdioTransport } from "../transports/stdio.js";
|
|
3
4
|
import { WebSocketTransport } from "../transports/websocket.js";
|
|
5
|
+
const logger = createLogger("acp-client", "debug");
|
|
4
6
|
/**
|
|
5
7
|
* Simplified ACP client with explicit transport selection
|
|
6
8
|
*/
|
|
@@ -17,7 +19,9 @@ export class AcpClient {
|
|
|
17
19
|
this.setupTransportListeners();
|
|
18
20
|
if (config.autoConnect) {
|
|
19
21
|
this.connect().catch((error) => {
|
|
20
|
-
|
|
22
|
+
logger.error("Failed to auto-connect", {
|
|
23
|
+
error: error instanceof Error ? error.message : String(error),
|
|
24
|
+
});
|
|
21
25
|
});
|
|
22
26
|
}
|
|
23
27
|
}
|
|
@@ -191,7 +195,9 @@ export class AcpClient {
|
|
|
191
195
|
handler(update);
|
|
192
196
|
}
|
|
193
197
|
catch (error) {
|
|
194
|
-
|
|
198
|
+
logger.error("Error in session update handler", {
|
|
199
|
+
error: error instanceof Error ? error.message : String(error),
|
|
200
|
+
});
|
|
195
201
|
}
|
|
196
202
|
}
|
|
197
203
|
}
|
|
@@ -202,7 +208,9 @@ export class AcpClient {
|
|
|
202
208
|
handler(error);
|
|
203
209
|
}
|
|
204
210
|
catch (err) {
|
|
205
|
-
|
|
211
|
+
logger.error("Error in error handler", {
|
|
212
|
+
error: err instanceof Error ? err.message : String(err),
|
|
213
|
+
});
|
|
206
214
|
}
|
|
207
215
|
}
|
|
208
216
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { Readable, Writable } from "node:stream";
|
|
3
3
|
import { ClientSideConnection, ndJsonStream, PROTOCOL_VERSION, } from "@agentclientprotocol/sdk";
|
|
4
|
-
import { createLogger } from "
|
|
4
|
+
import { createLogger } from "@townco/core";
|
|
5
5
|
const logger = createLogger("stdio-transport");
|
|
6
6
|
/**
|
|
7
7
|
* Stdio transport implementation using Agent Client Protocol SDK
|
|
@@ -3,3 +3,6 @@ export interface ChatViewProps {
|
|
|
3
3
|
client: AcpClient | null;
|
|
4
4
|
}
|
|
5
5
|
export declare function ChatView({ client }: ChatViewProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export declare function ChatViewStatus({ client }: {
|
|
7
|
+
client: AcpClient | null;
|
|
8
|
+
}): import("react/jsx-runtime").JSX.Element;
|