ai-design-system 0.1.53 → 0.1.54
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/components/blocks/AIConversation/AIConversation.tsx +6 -1
- package/components/composites/FileTreeExplorer/FileTreeExplorer.tsx +52 -2
- package/components/composites/ToolCallDisplay/ToolCallDisplay.tsx +29 -1
- package/components/features/AIDocEditor/AIDocEditor.tsx +56 -44
- package/components/features/AIDocEditor/useAIDocEditor.mock.ts +6 -11
- package/components/features/RefinementPanel/RefinementPanel.tsx +6 -0
- package/components/features/RefinementPanel/useRefinementPanel.d.ts +4 -0
- package/components/features/RefinementPanel/useRefinementPanel.mock.ts +3 -0
- package/dist/index.cjs +115 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +8 -0
- package/dist/index.d.ts +30 -14
- package/dist/index.js +115 -44
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -61,6 +61,10 @@ export interface AIConversationProps
|
|
|
61
61
|
description?: string
|
|
62
62
|
icon?: React.ReactNode
|
|
63
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Callback fired when a tool action (like a link click) is triggered
|
|
66
|
+
*/
|
|
67
|
+
onToolAction?: (toolCall: ToolCall, action: string) => void
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
/**
|
|
@@ -73,6 +77,7 @@ export const AIConversation = React.memo<AIConversationProps>(
|
|
|
73
77
|
onSelectSubAgent,
|
|
74
78
|
selectedSubAgent,
|
|
75
79
|
emptyState,
|
|
80
|
+
onToolAction,
|
|
76
81
|
...conversationProps
|
|
77
82
|
}) => {
|
|
78
83
|
const isEmpty = React.useMemo(
|
|
@@ -146,7 +151,7 @@ export const AIConversation = React.memo<AIConversationProps>(
|
|
|
146
151
|
>
|
|
147
152
|
{/* Render direct tool calls */}
|
|
148
153
|
{directToolCalls.map((tc) => (
|
|
149
|
-
<ToolCallDisplay key={tc.id} toolCall={tc} />
|
|
154
|
+
<ToolCallDisplay key={tc.id} toolCall={tc} onToolAction={onToolAction} />
|
|
150
155
|
))}
|
|
151
156
|
|
|
152
157
|
{/* Render specialist sub-agents */}
|
|
@@ -41,6 +41,40 @@ function renderTree(nodes: FileTreeNode[]): React.ReactNode {
|
|
|
41
41
|
})
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
function filterTree(nodes: FileTreeNode[], query: string): FileTreeNode[] {
|
|
45
|
+
if (!query) return nodes;
|
|
46
|
+
const lowerQuery = query.toLowerCase();
|
|
47
|
+
|
|
48
|
+
return nodes.reduce<FileTreeNode[]>((acc, node) => {
|
|
49
|
+
if (node.type === 'file') {
|
|
50
|
+
if (node.name.toLowerCase().includes(lowerQuery)) {
|
|
51
|
+
acc.push(node);
|
|
52
|
+
}
|
|
53
|
+
} else if (node.type === 'folder' && node.children) {
|
|
54
|
+
const filteredChildren = filterTree(node.children, query);
|
|
55
|
+
// Keep the folder if it matches the query itself, or if any of its children match
|
|
56
|
+
if (node.name.toLowerCase().includes(lowerQuery) || filteredChildren.length > 0) {
|
|
57
|
+
acc.push({ ...node, children: filteredChildren });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return acc;
|
|
61
|
+
}, []);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function getAllFolderPaths(nodes: FileTreeNode[]): Set<string> {
|
|
65
|
+
const paths = new Set<string>();
|
|
66
|
+
function traverse(n: FileTreeNode[]) {
|
|
67
|
+
for (const node of n) {
|
|
68
|
+
if (node.type === 'folder') {
|
|
69
|
+
paths.add(node.path);
|
|
70
|
+
if (node.children) traverse(node.children);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
traverse(nodes);
|
|
75
|
+
return paths;
|
|
76
|
+
}
|
|
77
|
+
|
|
44
78
|
export const FileTreeExplorer = React.memo<FileTreeExplorerProps>(
|
|
45
79
|
({
|
|
46
80
|
tree,
|
|
@@ -53,6 +87,19 @@ export const FileTreeExplorer = React.memo<FileTreeExplorerProps>(
|
|
|
53
87
|
headerClassName,
|
|
54
88
|
className,
|
|
55
89
|
}) => {
|
|
90
|
+
const [searchQuery, setSearchQuery] = React.useState("")
|
|
91
|
+
|
|
92
|
+
const filteredTree = React.useMemo(() => {
|
|
93
|
+
return filterTree(tree, searchQuery)
|
|
94
|
+
}, [tree, searchQuery])
|
|
95
|
+
|
|
96
|
+
const expandedPaths = React.useMemo(() => {
|
|
97
|
+
if (searchQuery) {
|
|
98
|
+
return getAllFolderPaths(filteredTree)
|
|
99
|
+
}
|
|
100
|
+
return defaultExpanded
|
|
101
|
+
}, [searchQuery, filteredTree, defaultExpanded])
|
|
102
|
+
|
|
56
103
|
return (
|
|
57
104
|
<div className={cn("flex flex-col rounded-lg border bg-background", className)}>
|
|
58
105
|
<div className={cn("flex items-center gap-2 border-b px-3 py-2", headerClassName)}>
|
|
@@ -64,6 +111,8 @@ export const FileTreeExplorer = React.memo<FileTreeExplorerProps>(
|
|
|
64
111
|
/>
|
|
65
112
|
<Input
|
|
66
113
|
placeholder={searchPlaceholder}
|
|
114
|
+
value={searchQuery}
|
|
115
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
67
116
|
className="pl-8"
|
|
68
117
|
/>
|
|
69
118
|
</div>
|
|
@@ -80,11 +129,12 @@ export const FileTreeExplorer = React.memo<FileTreeExplorerProps>(
|
|
|
80
129
|
</div>
|
|
81
130
|
<div className="p-2">
|
|
82
131
|
<FileTree
|
|
83
|
-
|
|
132
|
+
className="border-none bg-transparent"
|
|
133
|
+
defaultExpanded={expandedPaths}
|
|
84
134
|
selectedPath={selectedPath}
|
|
85
135
|
onSelect={onSelect}
|
|
86
136
|
>
|
|
87
|
-
{renderTree(
|
|
137
|
+
{renderTree(filteredTree)}
|
|
88
138
|
</FileTree>
|
|
89
139
|
</div>
|
|
90
140
|
</div>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from "react"
|
|
2
|
+
import { Icon } from "@/components/primitives/Icon"
|
|
2
3
|
import {
|
|
3
4
|
Tool,
|
|
4
5
|
ToolHeader,
|
|
@@ -20,6 +21,9 @@ export interface ToolCall {
|
|
|
20
21
|
args: Record<string, unknown>
|
|
21
22
|
result?: string
|
|
22
23
|
status: "pending" | "completed" | "error"
|
|
24
|
+
uiVariant?: "default" | "link"
|
|
25
|
+
linkText?: string
|
|
26
|
+
linkAction?: string
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
export interface ToolCallDisplayProps {
|
|
@@ -31,13 +35,17 @@ export interface ToolCallDisplayProps {
|
|
|
31
35
|
* Whether the tool call is initially expanded
|
|
32
36
|
*/
|
|
33
37
|
defaultExpanded?: boolean
|
|
38
|
+
/**
|
|
39
|
+
* Callback fired when a tool action (like a link click) is triggered
|
|
40
|
+
*/
|
|
41
|
+
onToolAction?: (toolCall: ToolCall, action: string) => void
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
/**
|
|
37
45
|
* ToolCallDisplay component - displays tool execution with expandable details
|
|
38
46
|
*/
|
|
39
47
|
export const ToolCallDisplay = React.memo<ToolCallDisplayProps>(
|
|
40
|
-
({ toolCall, defaultExpanded = false }) => {
|
|
48
|
+
({ toolCall, defaultExpanded = false, onToolAction }) => {
|
|
41
49
|
const [isExpanded, setIsExpanded] = React.useState(defaultExpanded)
|
|
42
50
|
|
|
43
51
|
const { name, args, result, status } = React.useMemo(() => {
|
|
@@ -78,6 +86,26 @@ export const ToolCallDisplay = React.memo<ToolCallDisplayProps>(
|
|
|
78
86
|
}
|
|
79
87
|
}, [status])
|
|
80
88
|
|
|
89
|
+
if (toolCall.uiVariant === "link") {
|
|
90
|
+
return (
|
|
91
|
+
<div
|
|
92
|
+
className="flex items-center gap-2 p-3 my-2 rounded-md border bg-muted/30 cursor-pointer hover:bg-muted/50 transition-colors"
|
|
93
|
+
onClick={(e) => {
|
|
94
|
+
e.preventDefault();
|
|
95
|
+
e.stopPropagation();
|
|
96
|
+
if (toolCall.linkAction && onToolAction) {
|
|
97
|
+
onToolAction(toolCall, toolCall.linkAction);
|
|
98
|
+
}
|
|
99
|
+
}}
|
|
100
|
+
>
|
|
101
|
+
<Icon name="external-link" className="size-4 text-blue-500" />
|
|
102
|
+
<span className="font-medium text-sm text-blue-500 hover:underline">
|
|
103
|
+
{toolCall.linkText || `${name} Action`}
|
|
104
|
+
</span>
|
|
105
|
+
</div>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
|
|
81
109
|
return (
|
|
82
110
|
<Tool open={isExpanded} onOpenChange={setIsExpanded}>
|
|
83
111
|
<ToolHeader
|
|
@@ -103,6 +103,8 @@ export interface AIDocEditorMultiTabProps {
|
|
|
103
103
|
onTabClose?: (documentId: string) => void
|
|
104
104
|
/** Optional completely separate file tree to show all available files in the explorer (even closed ones). If not provided, it falls back to showing only the currently open documents. */
|
|
105
105
|
fileTree?: FileTreeNode[]
|
|
106
|
+
/** When true, hides the document tab bar — useful for single-file mode where the file tree provides navigation. */
|
|
107
|
+
hideTabBar?: boolean
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
/**
|
|
@@ -273,60 +275,70 @@ export const AIDocEditor = React.memo<AIDocEditorProps>(
|
|
|
273
275
|
/**
|
|
274
276
|
* Multi-tab mode
|
|
275
277
|
*/
|
|
278
|
+
const { hideTabBar } = props as AIDocEditorMultiTabProps
|
|
279
|
+
|
|
280
|
+
let editorPane: React.ReactNode
|
|
281
|
+
|
|
276
282
|
if (!currentDocument) {
|
|
277
|
-
|
|
278
|
-
<div className=
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
283
|
+
editorPane = (
|
|
284
|
+
<div className="ai-doc-editor flex flex-col h-full w-full">
|
|
285
|
+
{!hideTabBar && (
|
|
286
|
+
<DocumentTabBar
|
|
287
|
+
className="w-full"
|
|
288
|
+
tabs={props.documents?.map((doc) => doc.file) || []}
|
|
289
|
+
activeTabId={props.activeDocumentId}
|
|
290
|
+
onTabSelect={props.onTabSelect}
|
|
291
|
+
onTabClose={props.onTabClose}
|
|
292
|
+
/>
|
|
293
|
+
)}
|
|
285
294
|
<div className="flex-1 flex items-center justify-center p-6 text-muted-foreground">
|
|
286
295
|
No documents open
|
|
287
296
|
</div>
|
|
288
297
|
</div>
|
|
289
298
|
)
|
|
290
|
-
}
|
|
299
|
+
} else {
|
|
300
|
+
const isMarkdownMulti = currentDocument.file.format === 'markdown'
|
|
291
301
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
onTabClose={props.onTabClose}
|
|
302
|
-
/>
|
|
303
|
-
<div className="flex-1 overflow-auto">
|
|
304
|
-
{isMarkdownMulti ? (
|
|
305
|
-
<div className="p-6">
|
|
306
|
-
<Streamdown
|
|
307
|
-
mode="streaming"
|
|
308
|
-
isAnimating
|
|
309
|
-
className="[&>*:first-child]:mt-0 [&>*:last-child]:mb-0"
|
|
310
|
-
>
|
|
311
|
-
{currentDocument.content as string}
|
|
312
|
-
</Streamdown>
|
|
313
|
-
</div>
|
|
314
|
-
) : (
|
|
315
|
-
<DocumentEditorWithComments
|
|
316
|
-
content={currentDocument.content}
|
|
317
|
-
format={currentDocument.file.format as 'json' | 'markdown' | undefined}
|
|
318
|
-
annotations={currentDocument.annotations}
|
|
319
|
-
currentUserId={currentUser.id}
|
|
320
|
-
currentUserName={currentUser.name}
|
|
321
|
-
readOnly={mode === 'readonly'}
|
|
322
|
-
onAnnotationAdd={handleAnnotationAdd}
|
|
323
|
-
onAnnotationUpdate={handleAnnotationUpdate}
|
|
324
|
-
className="p-6 h-full flex flex-col"
|
|
302
|
+
editorPane = (
|
|
303
|
+
<div className="ai-doc-editor flex flex-col h-full w-full">
|
|
304
|
+
{!hideTabBar && (
|
|
305
|
+
<DocumentTabBar
|
|
306
|
+
className="w-full"
|
|
307
|
+
tabs={props.documents?.map((doc) => doc.file) || []}
|
|
308
|
+
activeTabId={props.activeDocumentId}
|
|
309
|
+
onTabSelect={props.onTabSelect}
|
|
310
|
+
onTabClose={props.onTabClose}
|
|
325
311
|
/>
|
|
326
312
|
)}
|
|
313
|
+
<div className="flex-1 overflow-auto">
|
|
314
|
+
{isMarkdownMulti ? (
|
|
315
|
+
<div className="p-6">
|
|
316
|
+
<Streamdown
|
|
317
|
+
mode="streaming"
|
|
318
|
+
isAnimating
|
|
319
|
+
className="[&>*:first-child]:mt-0 [&>*:last-child]:mb-0"
|
|
320
|
+
>
|
|
321
|
+
{currentDocument.content as string}
|
|
322
|
+
</Streamdown>
|
|
323
|
+
</div>
|
|
324
|
+
) : (
|
|
325
|
+
<DocumentEditorWithComments
|
|
326
|
+
content={currentDocument.content}
|
|
327
|
+
format={currentDocument.file.format as 'json' | 'markdown' | undefined}
|
|
328
|
+
annotations={currentDocument.annotations}
|
|
329
|
+
selectedAnnotationId={props.selectedAnnotationId}
|
|
330
|
+
currentUserId={currentUser.id}
|
|
331
|
+
currentUserName={currentUser.name}
|
|
332
|
+
readOnly={mode === 'readonly'}
|
|
333
|
+
onAnnotationAdd={handleAnnotationAdd}
|
|
334
|
+
onAnnotationUpdate={handleAnnotationUpdate}
|
|
335
|
+
className="ai-doc-editor p-6 min-h-full"
|
|
336
|
+
/>
|
|
337
|
+
)}
|
|
338
|
+
</div>
|
|
327
339
|
</div>
|
|
328
|
-
|
|
329
|
-
|
|
340
|
+
)
|
|
341
|
+
}
|
|
330
342
|
|
|
331
343
|
return (
|
|
332
344
|
<AdjustableLayout
|
|
@@ -127,17 +127,12 @@ function useMultiTabDocEditorMockState(
|
|
|
127
127
|
|
|
128
128
|
const closeDocument = useCallback((documentId: string) => {
|
|
129
129
|
console.log('[Multi-Tab Mock] Closing document:', documentId)
|
|
130
|
-
setDocuments(prev =>
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
setActiveDocumentId(undefined)
|
|
137
|
-
}
|
|
138
|
-
return filtered
|
|
139
|
-
})
|
|
140
|
-
}, [activeDocumentId])
|
|
130
|
+
setDocuments(prev => prev.filter(doc => doc.file.id !== documentId))
|
|
131
|
+
if (activeDocumentId === documentId) {
|
|
132
|
+
const filtered = documents.filter(doc => doc.file.id !== documentId)
|
|
133
|
+
setActiveDocumentId(filtered.length > 0 ? filtered[0].file.id : undefined)
|
|
134
|
+
}
|
|
135
|
+
}, [activeDocumentId, documents])
|
|
141
136
|
|
|
142
137
|
const switchDocument = useCallback((documentId: string) => {
|
|
143
138
|
console.log('[Multi-Tab Mock] Switching to document:', documentId)
|
|
@@ -101,6 +101,10 @@ export interface RefinementPanelProps {
|
|
|
101
101
|
* Additional CSS classes
|
|
102
102
|
*/
|
|
103
103
|
className?: string;
|
|
104
|
+
/**
|
|
105
|
+
* Action handler for tool interactions
|
|
106
|
+
*/
|
|
107
|
+
onToolAction?: (toolCall: ToolCall, action: string) => void;
|
|
104
108
|
}
|
|
105
109
|
|
|
106
110
|
/**
|
|
@@ -122,6 +126,7 @@ export const RefinementPanel = React.memo<RefinementPanelProps>(
|
|
|
122
126
|
loading = false,
|
|
123
127
|
placeholder = "Ask a question or describe a task...",
|
|
124
128
|
className,
|
|
129
|
+
onToolAction,
|
|
125
130
|
}) => {
|
|
126
131
|
// File change queue state
|
|
127
132
|
const [fileChangeState, setFileChangeState] = React.useState<
|
|
@@ -262,6 +267,7 @@ export const RefinementPanel = React.memo<RefinementPanelProps>(
|
|
|
262
267
|
<AIConversation
|
|
263
268
|
messages={messages}
|
|
264
269
|
showAvatars={true}
|
|
270
|
+
onToolAction={onToolAction}
|
|
265
271
|
className="flex-1 min-h-0"
|
|
266
272
|
/>
|
|
267
273
|
<div className="sticky bottom-0 z-10 p-4 bg-gradient-to-t from-card via-card to-transparent pt-6">
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import type { RefinementMessage } from "./RefinementPanel";
|
|
12
12
|
import type { FileChangeData } from "@/components/composites/FileQueue";
|
|
13
13
|
import type { ActionRequest, ReviewConfig } from "@/components/composites/ApprovalCard";
|
|
14
|
+
import type { ToolCall } from "@/components/composites/ToolCallDisplay";
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Return type for the refinement panel hook
|
|
@@ -51,6 +52,9 @@ export interface UseRefinementPanelReturn {
|
|
|
51
52
|
|
|
52
53
|
/** Processing state for HITL approval */
|
|
53
54
|
isApprovalProcessing?: boolean;
|
|
55
|
+
|
|
56
|
+
/** Action handler for tool interactions */
|
|
57
|
+
handleToolAction?: (toolCall: ToolCall, action: string) => void;
|
|
54
58
|
}
|
|
55
59
|
|
|
56
60
|
/**
|
|
@@ -3,6 +3,7 @@ import type { RefinementMessage } from "./RefinementPanel";
|
|
|
3
3
|
import type { FileChangeData } from "@/components/composites/FileQueue";
|
|
4
4
|
import type { PromptInputMessage } from "@/components/ai-elements/prompt-input";
|
|
5
5
|
import type { ActionRequest, ReviewConfig } from "@/components/composites/ApprovalCard";
|
|
6
|
+
import type { ToolCall } from "@/components/composites/ToolCallDisplay";
|
|
6
7
|
import type { FormEvent } from "react";
|
|
7
8
|
|
|
8
9
|
export interface UseRefinementPanelReturn {
|
|
@@ -19,6 +20,7 @@ export interface UseRefinementPanelReturn {
|
|
|
19
20
|
handleApprovalReject?: (reason: string) => Promise<void>;
|
|
20
21
|
handleApprovalEdit?: (editedArgs: Record<string, unknown>) => Promise<void>;
|
|
21
22
|
isApprovalProcessing?: boolean;
|
|
23
|
+
handleToolAction?: (toolCall: ToolCall, action: string) => void;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
export interface UseRefinementPanelOptions {
|
|
@@ -173,5 +175,6 @@ export function useRefinementPanelMock(
|
|
|
173
175
|
handleApprovalReject: initialApprovalRequest ? handleApprovalReject : undefined,
|
|
174
176
|
handleApprovalEdit: initialApprovalRequest ? handleApprovalEdit : undefined,
|
|
175
177
|
isApprovalProcessing,
|
|
178
|
+
handleToolAction: (toolCall, action) => console.log(`[Mock Tool Action] ${action} on tool:`, toolCall),
|
|
176
179
|
};
|
|
177
180
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -3242,7 +3242,7 @@ var ToolOutput = (_a) => {
|
|
|
3242
3242
|
] }));
|
|
3243
3243
|
};
|
|
3244
3244
|
var ToolCallDisplay = React3__namespace.memo(
|
|
3245
|
-
({ toolCall, defaultExpanded = false }) => {
|
|
3245
|
+
({ toolCall, defaultExpanded = false, onToolAction }) => {
|
|
3246
3246
|
const [isExpanded, setIsExpanded] = React3__namespace.useState(defaultExpanded);
|
|
3247
3247
|
const { name, args, result, status } = React3__namespace.useMemo(() => {
|
|
3248
3248
|
const toolName = toolCall.name || "Unknown Tool";
|
|
@@ -3277,6 +3277,25 @@ var ToolCallDisplay = React3__namespace.memo(
|
|
|
3277
3277
|
return "output-available";
|
|
3278
3278
|
}
|
|
3279
3279
|
}, [status]);
|
|
3280
|
+
if (toolCall.uiVariant === "link") {
|
|
3281
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3282
|
+
"div",
|
|
3283
|
+
{
|
|
3284
|
+
className: "flex items-center gap-2 p-3 my-2 rounded-md border bg-muted/30 cursor-pointer hover:bg-muted/50 transition-colors",
|
|
3285
|
+
onClick: (e) => {
|
|
3286
|
+
e.preventDefault();
|
|
3287
|
+
e.stopPropagation();
|
|
3288
|
+
if (toolCall.linkAction && onToolAction) {
|
|
3289
|
+
onToolAction(toolCall, toolCall.linkAction);
|
|
3290
|
+
}
|
|
3291
|
+
},
|
|
3292
|
+
children: [
|
|
3293
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "external-link", className: "size-4 text-blue-500" }),
|
|
3294
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-sm text-blue-500 hover:underline", children: toolCall.linkText || `${name} Action` })
|
|
3295
|
+
]
|
|
3296
|
+
}
|
|
3297
|
+
);
|
|
3298
|
+
}
|
|
3280
3299
|
return /* @__PURE__ */ jsxRuntime.jsxs(Tool, { open: isExpanded, onOpenChange: setIsExpanded, children: [
|
|
3281
3300
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3282
3301
|
ToolHeader,
|
|
@@ -3395,13 +3414,15 @@ var AIConversation = React3__namespace.memo(
|
|
|
3395
3414
|
showAvatars = true,
|
|
3396
3415
|
onSelectSubAgent,
|
|
3397
3416
|
selectedSubAgent,
|
|
3398
|
-
emptyState
|
|
3417
|
+
emptyState,
|
|
3418
|
+
onToolAction
|
|
3399
3419
|
} = _b, conversationProps = __objRest(_b, [
|
|
3400
3420
|
"messages",
|
|
3401
3421
|
"showAvatars",
|
|
3402
3422
|
"onSelectSubAgent",
|
|
3403
3423
|
"selectedSubAgent",
|
|
3404
|
-
"emptyState"
|
|
3424
|
+
"emptyState",
|
|
3425
|
+
"onToolAction"
|
|
3405
3426
|
]);
|
|
3406
3427
|
const isEmpty = React3__namespace.useMemo(
|
|
3407
3428
|
() => messages.length === 0,
|
|
@@ -3456,7 +3477,7 @@ var AIConversation = React3__namespace.memo(
|
|
|
3456
3477
|
},
|
|
3457
3478
|
showAvatar: showAvatars,
|
|
3458
3479
|
children: [
|
|
3459
|
-
directToolCalls.map((tc) => /* @__PURE__ */ jsxRuntime.jsx(ToolCallDisplay, { toolCall: tc }, tc.id)),
|
|
3480
|
+
directToolCalls.map((tc) => /* @__PURE__ */ jsxRuntime.jsx(ToolCallDisplay, { toolCall: tc, onToolAction }, tc.id)),
|
|
3460
3481
|
subAgents.map((subAgent) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3461
3482
|
SpecialistMessage,
|
|
3462
3483
|
{
|
|
@@ -5521,7 +5542,8 @@ var RefinementPanel = React3__namespace.memo(
|
|
|
5521
5542
|
isApprovalProcessing = false,
|
|
5522
5543
|
loading = false,
|
|
5523
5544
|
placeholder = "Ask a question or describe a task...",
|
|
5524
|
-
className
|
|
5545
|
+
className,
|
|
5546
|
+
onToolAction
|
|
5525
5547
|
}) => {
|
|
5526
5548
|
const [fileChangeState, setFileChangeState] = React3__namespace.useState("approval-requested");
|
|
5527
5549
|
const [approval, setApproval] = React3__namespace.useState({});
|
|
@@ -5632,6 +5654,7 @@ var RefinementPanel = React3__namespace.memo(
|
|
|
5632
5654
|
{
|
|
5633
5655
|
messages,
|
|
5634
5656
|
showAvatars: true,
|
|
5657
|
+
onToolAction,
|
|
5635
5658
|
className: "flex-1 min-h-0"
|
|
5636
5659
|
}
|
|
5637
5660
|
),
|
|
@@ -10758,6 +10781,36 @@ function renderTree(nodes) {
|
|
|
10758
10781
|
return /* @__PURE__ */ jsxRuntime.jsx(FileTreeFile, { name: node.name, path: node.path }, node.path);
|
|
10759
10782
|
});
|
|
10760
10783
|
}
|
|
10784
|
+
function filterTree(nodes, query) {
|
|
10785
|
+
if (!query) return nodes;
|
|
10786
|
+
const lowerQuery = query.toLowerCase();
|
|
10787
|
+
return nodes.reduce((acc, node) => {
|
|
10788
|
+
if (node.type === "file") {
|
|
10789
|
+
if (node.name.toLowerCase().includes(lowerQuery)) {
|
|
10790
|
+
acc.push(node);
|
|
10791
|
+
}
|
|
10792
|
+
} else if (node.type === "folder" && node.children) {
|
|
10793
|
+
const filteredChildren = filterTree(node.children, query);
|
|
10794
|
+
if (node.name.toLowerCase().includes(lowerQuery) || filteredChildren.length > 0) {
|
|
10795
|
+
acc.push(__spreadProps(__spreadValues({}, node), { children: filteredChildren }));
|
|
10796
|
+
}
|
|
10797
|
+
}
|
|
10798
|
+
return acc;
|
|
10799
|
+
}, []);
|
|
10800
|
+
}
|
|
10801
|
+
function getAllFolderPaths(nodes) {
|
|
10802
|
+
const paths = /* @__PURE__ */ new Set();
|
|
10803
|
+
function traverse(n) {
|
|
10804
|
+
for (const node of n) {
|
|
10805
|
+
if (node.type === "folder") {
|
|
10806
|
+
paths.add(node.path);
|
|
10807
|
+
if (node.children) traverse(node.children);
|
|
10808
|
+
}
|
|
10809
|
+
}
|
|
10810
|
+
}
|
|
10811
|
+
traverse(nodes);
|
|
10812
|
+
return paths;
|
|
10813
|
+
}
|
|
10761
10814
|
var FileTreeExplorer = React3__namespace.memo(
|
|
10762
10815
|
({
|
|
10763
10816
|
tree,
|
|
@@ -10770,6 +10823,16 @@ var FileTreeExplorer = React3__namespace.memo(
|
|
|
10770
10823
|
headerClassName,
|
|
10771
10824
|
className
|
|
10772
10825
|
}) => {
|
|
10826
|
+
const [searchQuery, setSearchQuery] = React3__namespace.useState("");
|
|
10827
|
+
const filteredTree = React3__namespace.useMemo(() => {
|
|
10828
|
+
return filterTree(tree, searchQuery);
|
|
10829
|
+
}, [tree, searchQuery]);
|
|
10830
|
+
const expandedPaths = React3__namespace.useMemo(() => {
|
|
10831
|
+
if (searchQuery) {
|
|
10832
|
+
return getAllFolderPaths(filteredTree);
|
|
10833
|
+
}
|
|
10834
|
+
return defaultExpanded;
|
|
10835
|
+
}, [searchQuery, filteredTree, defaultExpanded]);
|
|
10773
10836
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col rounded-lg border bg-background", className), children: [
|
|
10774
10837
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-center gap-2 border-b px-3 py-2", headerClassName), children: [
|
|
10775
10838
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1", children: [
|
|
@@ -10785,6 +10848,8 @@ var FileTreeExplorer = React3__namespace.memo(
|
|
|
10785
10848
|
Input2,
|
|
10786
10849
|
{
|
|
10787
10850
|
placeholder: searchPlaceholder,
|
|
10851
|
+
value: searchQuery,
|
|
10852
|
+
onChange: (e) => setSearchQuery(e.target.value),
|
|
10788
10853
|
className: "pl-8"
|
|
10789
10854
|
}
|
|
10790
10855
|
)
|
|
@@ -10805,10 +10870,11 @@ var FileTreeExplorer = React3__namespace.memo(
|
|
|
10805
10870
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10806
10871
|
FileTree,
|
|
10807
10872
|
{
|
|
10808
|
-
|
|
10873
|
+
className: "border-none bg-transparent",
|
|
10874
|
+
defaultExpanded: expandedPaths,
|
|
10809
10875
|
selectedPath,
|
|
10810
10876
|
onSelect,
|
|
10811
|
-
children: renderTree(
|
|
10877
|
+
children: renderTree(filteredTree)
|
|
10812
10878
|
}
|
|
10813
10879
|
) })
|
|
10814
10880
|
] });
|
|
@@ -10901,11 +10967,14 @@ var AIDocEditor = React3__namespace.default.memo(
|
|
|
10901
10967
|
}
|
|
10902
10968
|
) });
|
|
10903
10969
|
}
|
|
10970
|
+
const { hideTabBar } = props;
|
|
10971
|
+
let editorPane;
|
|
10904
10972
|
if (!currentDocument) {
|
|
10905
|
-
|
|
10906
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10973
|
+
editorPane = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ai-doc-editor flex flex-col h-full w-full", children: [
|
|
10974
|
+
!hideTabBar && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10907
10975
|
DocumentTabBar,
|
|
10908
10976
|
{
|
|
10977
|
+
className: "w-full",
|
|
10909
10978
|
tabs: ((_a = props.documents) == null ? void 0 : _a.map((doc) => doc.file)) || [],
|
|
10910
10979
|
activeTabId: props.activeDocumentId,
|
|
10911
10980
|
onTabSelect: props.onTabSelect,
|
|
@@ -10914,42 +10983,44 @@ var AIDocEditor = React3__namespace.default.memo(
|
|
|
10914
10983
|
),
|
|
10915
10984
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex items-center justify-center p-6 text-muted-foreground", children: "No documents open" })
|
|
10916
10985
|
] });
|
|
10986
|
+
} else {
|
|
10987
|
+
const isMarkdownMulti = currentDocument.file.format === "markdown";
|
|
10988
|
+
editorPane = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ai-doc-editor flex flex-col h-full w-full", children: [
|
|
10989
|
+
!hideTabBar && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10990
|
+
DocumentTabBar,
|
|
10991
|
+
{
|
|
10992
|
+
className: "w-full",
|
|
10993
|
+
tabs: ((_b = props.documents) == null ? void 0 : _b.map((doc) => doc.file)) || [],
|
|
10994
|
+
activeTabId: props.activeDocumentId,
|
|
10995
|
+
onTabSelect: props.onTabSelect,
|
|
10996
|
+
onTabClose: props.onTabClose
|
|
10997
|
+
}
|
|
10998
|
+
),
|
|
10999
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto", children: isMarkdownMulti ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11000
|
+
streamdown.Streamdown,
|
|
11001
|
+
{
|
|
11002
|
+
mode: "streaming",
|
|
11003
|
+
isAnimating: true,
|
|
11004
|
+
className: "[&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
|
|
11005
|
+
children: currentDocument.content
|
|
11006
|
+
}
|
|
11007
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
11008
|
+
DocumentEditorWithComments,
|
|
11009
|
+
{
|
|
11010
|
+
content: currentDocument.content,
|
|
11011
|
+
format: currentDocument.file.format,
|
|
11012
|
+
annotations: currentDocument.annotations,
|
|
11013
|
+
selectedAnnotationId: props.selectedAnnotationId,
|
|
11014
|
+
currentUserId: currentUser2.id,
|
|
11015
|
+
currentUserName: currentUser2.name,
|
|
11016
|
+
readOnly: mode === "readonly",
|
|
11017
|
+
onAnnotationAdd: handleAnnotationAdd,
|
|
11018
|
+
onAnnotationUpdate: handleAnnotationUpdate,
|
|
11019
|
+
className: "ai-doc-editor p-6 min-h-full"
|
|
11020
|
+
}
|
|
11021
|
+
) })
|
|
11022
|
+
] });
|
|
10917
11023
|
}
|
|
10918
|
-
const isMarkdownMulti = currentDocument.file.format === "markdown";
|
|
10919
|
-
const editorPane = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ai-doc-editor flex flex-col h-full w-full", children: [
|
|
10920
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10921
|
-
DocumentTabBar,
|
|
10922
|
-
{
|
|
10923
|
-
className: "w-full",
|
|
10924
|
-
tabs: ((_b = props.documents) == null ? void 0 : _b.map((doc) => doc.file)) || [],
|
|
10925
|
-
activeTabId: props.activeDocumentId,
|
|
10926
|
-
onTabSelect: props.onTabSelect,
|
|
10927
|
-
onTabClose: props.onTabClose
|
|
10928
|
-
}
|
|
10929
|
-
),
|
|
10930
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto", children: isMarkdownMulti ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10931
|
-
streamdown.Streamdown,
|
|
10932
|
-
{
|
|
10933
|
-
mode: "streaming",
|
|
10934
|
-
isAnimating: true,
|
|
10935
|
-
className: "[&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
|
|
10936
|
-
children: currentDocument.content
|
|
10937
|
-
}
|
|
10938
|
-
) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
10939
|
-
DocumentEditorWithComments,
|
|
10940
|
-
{
|
|
10941
|
-
content: currentDocument.content,
|
|
10942
|
-
format: currentDocument.file.format,
|
|
10943
|
-
annotations: currentDocument.annotations,
|
|
10944
|
-
currentUserId: currentUser2.id,
|
|
10945
|
-
currentUserName: currentUser2.name,
|
|
10946
|
-
readOnly: mode === "readonly",
|
|
10947
|
-
onAnnotationAdd: handleAnnotationAdd,
|
|
10948
|
-
onAnnotationUpdate: handleAnnotationUpdate,
|
|
10949
|
-
className: "p-6 h-full flex flex-col"
|
|
10950
|
-
}
|
|
10951
|
-
) })
|
|
10952
|
-
] });
|
|
10953
11024
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10954
11025
|
AdjustableLayout,
|
|
10955
11026
|
{
|