@invergent/agent-chat-react 1.4.3 → 1.4.4
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/index.cjs +828 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -1
- package/dist/index.d.ts +45 -1
- package/dist/index.js +829 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1711,6 +1711,28 @@ function DialogHeader({ className, ...props }) {
|
|
|
1711
1711
|
}
|
|
1712
1712
|
);
|
|
1713
1713
|
}
|
|
1714
|
+
function DialogFooter({
|
|
1715
|
+
className,
|
|
1716
|
+
showCloseButton = false,
|
|
1717
|
+
children,
|
|
1718
|
+
...props
|
|
1719
|
+
}) {
|
|
1720
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1721
|
+
"div",
|
|
1722
|
+
{
|
|
1723
|
+
"data-slot": "dialog-footer",
|
|
1724
|
+
className: cn(
|
|
1725
|
+
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
1726
|
+
className
|
|
1727
|
+
),
|
|
1728
|
+
...props,
|
|
1729
|
+
children: [
|
|
1730
|
+
children,
|
|
1731
|
+
showCloseButton && /* @__PURE__ */ jsxRuntime.jsx(radixUi.Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", children: "Close" }) })
|
|
1732
|
+
]
|
|
1733
|
+
}
|
|
1734
|
+
);
|
|
1735
|
+
}
|
|
1714
1736
|
function DialogTitle({
|
|
1715
1737
|
className,
|
|
1716
1738
|
...props
|
|
@@ -6075,6 +6097,777 @@ function ChatThread({
|
|
|
6075
6097
|
] })
|
|
6076
6098
|
] });
|
|
6077
6099
|
}
|
|
6100
|
+
var noop = () => {
|
|
6101
|
+
};
|
|
6102
|
+
var FileTreeContext = react.createContext({
|
|
6103
|
+
expandedPaths: /* @__PURE__ */ new Set(),
|
|
6104
|
+
togglePath: noop
|
|
6105
|
+
});
|
|
6106
|
+
function FileTree({
|
|
6107
|
+
expanded: controlledExpanded,
|
|
6108
|
+
defaultExpanded = /* @__PURE__ */ new Set(),
|
|
6109
|
+
selectedPath,
|
|
6110
|
+
onSelect,
|
|
6111
|
+
onExpandedChange,
|
|
6112
|
+
className,
|
|
6113
|
+
children,
|
|
6114
|
+
...props
|
|
6115
|
+
}) {
|
|
6116
|
+
const [internalExpanded, setInternalExpanded] = react.useState(defaultExpanded);
|
|
6117
|
+
const expandedPaths = controlledExpanded ?? internalExpanded;
|
|
6118
|
+
const togglePath = react.useCallback(
|
|
6119
|
+
(path) => {
|
|
6120
|
+
const next = new Set(expandedPaths);
|
|
6121
|
+
if (next.has(path)) {
|
|
6122
|
+
next.delete(path);
|
|
6123
|
+
} else {
|
|
6124
|
+
next.add(path);
|
|
6125
|
+
}
|
|
6126
|
+
setInternalExpanded(next);
|
|
6127
|
+
onExpandedChange?.(next);
|
|
6128
|
+
},
|
|
6129
|
+
[expandedPaths, onExpandedChange]
|
|
6130
|
+
);
|
|
6131
|
+
const contextValue = react.useMemo(
|
|
6132
|
+
() => ({
|
|
6133
|
+
expandedPaths,
|
|
6134
|
+
onSelect,
|
|
6135
|
+
selectedPath: selectedPath ?? void 0,
|
|
6136
|
+
togglePath
|
|
6137
|
+
}),
|
|
6138
|
+
[expandedPaths, onSelect, selectedPath, togglePath]
|
|
6139
|
+
);
|
|
6140
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FileTreeContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6141
|
+
"div",
|
|
6142
|
+
{
|
|
6143
|
+
className: cn("rounded-lg border bg-background text-sm", className),
|
|
6144
|
+
role: "tree",
|
|
6145
|
+
...props,
|
|
6146
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2", children })
|
|
6147
|
+
}
|
|
6148
|
+
) });
|
|
6149
|
+
}
|
|
6150
|
+
function FileTreeIcon({
|
|
6151
|
+
className,
|
|
6152
|
+
children,
|
|
6153
|
+
...props
|
|
6154
|
+
}) {
|
|
6155
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("shrink-0", className), ...props, children });
|
|
6156
|
+
}
|
|
6157
|
+
function FileTreeName({
|
|
6158
|
+
className,
|
|
6159
|
+
children,
|
|
6160
|
+
...props
|
|
6161
|
+
}) {
|
|
6162
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("truncate", className), ...props, children });
|
|
6163
|
+
}
|
|
6164
|
+
function FileTreeFolder({
|
|
6165
|
+
path,
|
|
6166
|
+
name,
|
|
6167
|
+
className,
|
|
6168
|
+
children,
|
|
6169
|
+
...props
|
|
6170
|
+
}) {
|
|
6171
|
+
const { expandedPaths, togglePath, selectedPath, onSelect } = react.useContext(FileTreeContext);
|
|
6172
|
+
const isExpanded = expandedPaths.has(path);
|
|
6173
|
+
const isSelected = selectedPath === path;
|
|
6174
|
+
const handleOpenChange = react.useCallback(() => {
|
|
6175
|
+
togglePath(path);
|
|
6176
|
+
}, [togglePath, path]);
|
|
6177
|
+
const handleSelect = react.useCallback(() => {
|
|
6178
|
+
onSelect?.(path);
|
|
6179
|
+
}, [onSelect, path]);
|
|
6180
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Collapsible, { onOpenChange: handleOpenChange, open: isExpanded, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("", className), role: "treeitem", tabIndex: 0, ...props, children: [
|
|
6181
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
6182
|
+
"div",
|
|
6183
|
+
{
|
|
6184
|
+
className: cn(
|
|
6185
|
+
"flex w-full items-center gap-1 rounded px-2 py-1 text-left transition-colors hover:bg-muted/50",
|
|
6186
|
+
isSelected && "bg-muted"
|
|
6187
|
+
),
|
|
6188
|
+
children: [
|
|
6189
|
+
/* @__PURE__ */ jsxRuntime.jsx(CollapsibleTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6190
|
+
"button",
|
|
6191
|
+
{
|
|
6192
|
+
className: "flex shrink-0 cursor-pointer items-center border-none bg-transparent p-0",
|
|
6193
|
+
type: "button",
|
|
6194
|
+
"aria-label": isExpanded ? `Collapse ${name}` : `Expand ${name}`,
|
|
6195
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6196
|
+
lucideReact.ChevronRightIcon,
|
|
6197
|
+
{
|
|
6198
|
+
className: cn(
|
|
6199
|
+
"size-4 shrink-0 text-muted-foreground transition-transform",
|
|
6200
|
+
isExpanded && "rotate-90"
|
|
6201
|
+
)
|
|
6202
|
+
}
|
|
6203
|
+
)
|
|
6204
|
+
}
|
|
6205
|
+
) }),
|
|
6206
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
6207
|
+
"button",
|
|
6208
|
+
{
|
|
6209
|
+
className: "flex min-w-0 flex-1 cursor-pointer items-center gap-1 border-none bg-transparent p-0 text-left",
|
|
6210
|
+
onClick: handleSelect,
|
|
6211
|
+
type: "button",
|
|
6212
|
+
children: [
|
|
6213
|
+
/* @__PURE__ */ jsxRuntime.jsx(FileTreeIcon, { children: isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderOpenIcon, { className: "size-4 text-blue-500" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderIcon, { className: "size-4 text-blue-500" }) }),
|
|
6214
|
+
/* @__PURE__ */ jsxRuntime.jsx(FileTreeName, { children: name })
|
|
6215
|
+
]
|
|
6216
|
+
}
|
|
6217
|
+
)
|
|
6218
|
+
]
|
|
6219
|
+
}
|
|
6220
|
+
),
|
|
6221
|
+
/* @__PURE__ */ jsxRuntime.jsx(CollapsibleContent, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-4 border-l border-muted-foreground/50 pl-2", children }) })
|
|
6222
|
+
] }) });
|
|
6223
|
+
}
|
|
6224
|
+
function FileTreeFile({
|
|
6225
|
+
path,
|
|
6226
|
+
name,
|
|
6227
|
+
icon,
|
|
6228
|
+
className,
|
|
6229
|
+
children,
|
|
6230
|
+
...props
|
|
6231
|
+
}) {
|
|
6232
|
+
const { selectedPath, onSelect } = react.useContext(FileTreeContext);
|
|
6233
|
+
const isSelected = selectedPath === path;
|
|
6234
|
+
const handleClick = react.useCallback(() => {
|
|
6235
|
+
onSelect?.(path);
|
|
6236
|
+
}, [onSelect, path]);
|
|
6237
|
+
const handleKeyDown = react.useCallback(
|
|
6238
|
+
(event) => {
|
|
6239
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
6240
|
+
onSelect?.(path);
|
|
6241
|
+
}
|
|
6242
|
+
},
|
|
6243
|
+
[onSelect, path]
|
|
6244
|
+
);
|
|
6245
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6246
|
+
"div",
|
|
6247
|
+
{
|
|
6248
|
+
className: cn(
|
|
6249
|
+
"group flex cursor-pointer items-center gap-1 rounded px-2 py-1 transition-colors hover:bg-muted/50",
|
|
6250
|
+
isSelected && "bg-muted",
|
|
6251
|
+
className
|
|
6252
|
+
),
|
|
6253
|
+
onClick: handleClick,
|
|
6254
|
+
onKeyDown: handleKeyDown,
|
|
6255
|
+
role: "treeitem",
|
|
6256
|
+
tabIndex: 0,
|
|
6257
|
+
...props,
|
|
6258
|
+
children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6259
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-4 shrink-0" }),
|
|
6260
|
+
/* @__PURE__ */ jsxRuntime.jsx(FileTreeIcon, { children: icon ?? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileIcon, { className: "size-4 text-muted-foreground" }) }),
|
|
6261
|
+
/* @__PURE__ */ jsxRuntime.jsx(FileTreeName, { children: name })
|
|
6262
|
+
] })
|
|
6263
|
+
}
|
|
6264
|
+
);
|
|
6265
|
+
}
|
|
6266
|
+
function Skeleton({ className, ...props }) {
|
|
6267
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6268
|
+
"div",
|
|
6269
|
+
{
|
|
6270
|
+
className: cn("animate-pulse rounded-md bg-muted", className),
|
|
6271
|
+
...props
|
|
6272
|
+
}
|
|
6273
|
+
);
|
|
6274
|
+
}
|
|
6275
|
+
|
|
6276
|
+
// src/lib/format.ts
|
|
6277
|
+
function formatFileSize(bytes) {
|
|
6278
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
6279
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
6280
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
6281
|
+
}
|
|
6282
|
+
function getLanguageHint(path) {
|
|
6283
|
+
const name = path.split("/").pop() ?? path;
|
|
6284
|
+
const dot = name.lastIndexOf(".");
|
|
6285
|
+
if (dot < 0) return "plaintext";
|
|
6286
|
+
const ext = name.slice(dot).toLowerCase();
|
|
6287
|
+
const map = {
|
|
6288
|
+
".py": "python",
|
|
6289
|
+
".js": "javascript",
|
|
6290
|
+
".ts": "typescript",
|
|
6291
|
+
".tsx": "tsx",
|
|
6292
|
+
".jsx": "jsx",
|
|
6293
|
+
".json": "json",
|
|
6294
|
+
".yaml": "yaml",
|
|
6295
|
+
".yml": "yaml",
|
|
6296
|
+
".toml": "toml",
|
|
6297
|
+
".sql": "sql",
|
|
6298
|
+
".sh": "bash",
|
|
6299
|
+
".css": "css",
|
|
6300
|
+
".html": "html",
|
|
6301
|
+
".md": "markdown",
|
|
6302
|
+
".rs": "rust",
|
|
6303
|
+
".go": "go",
|
|
6304
|
+
".java": "java",
|
|
6305
|
+
".rb": "ruby",
|
|
6306
|
+
".php": "php",
|
|
6307
|
+
".c": "c",
|
|
6308
|
+
".cpp": "cpp",
|
|
6309
|
+
".h": "c",
|
|
6310
|
+
".hpp": "cpp"
|
|
6311
|
+
};
|
|
6312
|
+
return map[ext] ?? "plaintext";
|
|
6313
|
+
}
|
|
6314
|
+
var SKELETON_WIDTHS = [70, 85, 55, 90, 60, 78, 45, 82, 65, 72];
|
|
6315
|
+
function FileViewer({
|
|
6316
|
+
file,
|
|
6317
|
+
loading,
|
|
6318
|
+
error,
|
|
6319
|
+
onClose
|
|
6320
|
+
}) {
|
|
6321
|
+
const visible = loading || file !== null || error !== null;
|
|
6322
|
+
if (!visible) return null;
|
|
6323
|
+
const fileName2 = file?.path.split("/").pop() ?? "File";
|
|
6324
|
+
const lang = file ? getLanguageHint(file.path) : "";
|
|
6325
|
+
const isImage = file?.encoding === "base64";
|
|
6326
|
+
const HeaderIcon = isImage ? lucideReact.ImageIcon : lucideReact.FileTextIcon;
|
|
6327
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1 flex-col border-t border-line", children: [
|
|
6328
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-2 border-b border-line px-3 py-2", children: [
|
|
6329
|
+
/* @__PURE__ */ jsxRuntime.jsx(HeaderIcon, { className: "size-3.5 shrink-0 text-muted-foreground" }),
|
|
6330
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
6331
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-xs font-medium", children: fileName2 }),
|
|
6332
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "truncate text-[10px] text-muted-foreground", children: [
|
|
6333
|
+
file?.path ?? "Loading...",
|
|
6334
|
+
file && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-1.5", children: [
|
|
6335
|
+
formatFileSize(file.size),
|
|
6336
|
+
file.truncated && " (truncated)"
|
|
6337
|
+
] })
|
|
6338
|
+
] })
|
|
6339
|
+
] }),
|
|
6340
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6341
|
+
"button",
|
|
6342
|
+
{
|
|
6343
|
+
type: "button",
|
|
6344
|
+
onClick: onClose,
|
|
6345
|
+
className: "shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
6346
|
+
"aria-label": "Close file",
|
|
6347
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { className: "size-3.5" })
|
|
6348
|
+
}
|
|
6349
|
+
)
|
|
6350
|
+
] }),
|
|
6351
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ScrollArea, { className: "min-h-0 flex-1", children: [
|
|
6352
|
+
loading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5 p-3", children: Array.from({ length: 10 }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
6353
|
+
Skeleton,
|
|
6354
|
+
{
|
|
6355
|
+
className: "h-3.5 rounded",
|
|
6356
|
+
style: {
|
|
6357
|
+
width: `${SKELETON_WIDTHS[index % SKELETON_WIDTHS.length]}%`
|
|
6358
|
+
}
|
|
6359
|
+
},
|
|
6360
|
+
index
|
|
6361
|
+
)) }),
|
|
6362
|
+
error && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 p-3 text-xs text-destructive", children: [
|
|
6363
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0" }),
|
|
6364
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: error })
|
|
6365
|
+
] }),
|
|
6366
|
+
file && isImage && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center p-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6367
|
+
"img",
|
|
6368
|
+
{
|
|
6369
|
+
src: `data:${file.mime_type ?? "image/png"};base64,${file.content}`,
|
|
6370
|
+
alt: fileName2,
|
|
6371
|
+
className: "max-h-[60vh] max-w-full rounded object-contain"
|
|
6372
|
+
}
|
|
6373
|
+
) }),
|
|
6374
|
+
file && !isImage && /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "wrap-break-word whitespace-pre-wrap p-3 text-[11px] leading-relaxed text-foreground", children: /* @__PURE__ */ jsxRuntime.jsx("code", { "data-language": lang, children: file.content }) })
|
|
6375
|
+
] })
|
|
6376
|
+
] });
|
|
6377
|
+
}
|
|
6378
|
+
var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
6379
|
+
".py",
|
|
6380
|
+
".js",
|
|
6381
|
+
".ts",
|
|
6382
|
+
".tsx",
|
|
6383
|
+
".jsx",
|
|
6384
|
+
".json",
|
|
6385
|
+
".md",
|
|
6386
|
+
".yaml",
|
|
6387
|
+
".yml",
|
|
6388
|
+
".toml",
|
|
6389
|
+
".sql",
|
|
6390
|
+
".sh",
|
|
6391
|
+
".css",
|
|
6392
|
+
".html",
|
|
6393
|
+
".txt",
|
|
6394
|
+
".csv",
|
|
6395
|
+
".rst",
|
|
6396
|
+
".cfg",
|
|
6397
|
+
".ini",
|
|
6398
|
+
".env",
|
|
6399
|
+
".rs",
|
|
6400
|
+
".go",
|
|
6401
|
+
".java",
|
|
6402
|
+
".rb",
|
|
6403
|
+
".php",
|
|
6404
|
+
".c",
|
|
6405
|
+
".cpp",
|
|
6406
|
+
".h",
|
|
6407
|
+
".lock",
|
|
6408
|
+
".gitignore",
|
|
6409
|
+
".dockerignore",
|
|
6410
|
+
".editorconfig"
|
|
6411
|
+
]);
|
|
6412
|
+
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
6413
|
+
".png",
|
|
6414
|
+
".jpg",
|
|
6415
|
+
".jpeg",
|
|
6416
|
+
".gif",
|
|
6417
|
+
".webp",
|
|
6418
|
+
".svg",
|
|
6419
|
+
".bmp",
|
|
6420
|
+
".ico",
|
|
6421
|
+
".avif",
|
|
6422
|
+
".tiff",
|
|
6423
|
+
".tif"
|
|
6424
|
+
]);
|
|
6425
|
+
var SKELETON_WIDTHS2 = [75, 60, 90, 65, 80, 70, 85, 55];
|
|
6426
|
+
var DEFAULT_WIDTH = 500;
|
|
6427
|
+
var MIN_WIDTH = 300;
|
|
6428
|
+
var MAX_WIDTH = 900;
|
|
6429
|
+
function isViewable(name) {
|
|
6430
|
+
const dot = name.lastIndexOf(".");
|
|
6431
|
+
const ext = dot >= 0 ? name.slice(dot).toLowerCase() : "";
|
|
6432
|
+
return TEXT_EXTENSIONS.has(ext) || IMAGE_EXTENSIONS.has(ext);
|
|
6433
|
+
}
|
|
6434
|
+
function collectExpandedPaths(entries, depth = 0) {
|
|
6435
|
+
const paths = [];
|
|
6436
|
+
for (const entry of entries) {
|
|
6437
|
+
if (entry.kind === "dir" && depth < 1) {
|
|
6438
|
+
paths.push(entry.path);
|
|
6439
|
+
if (entry.children) {
|
|
6440
|
+
paths.push(...collectExpandedPaths(entry.children, depth + 1));
|
|
6441
|
+
}
|
|
6442
|
+
}
|
|
6443
|
+
}
|
|
6444
|
+
return paths;
|
|
6445
|
+
}
|
|
6446
|
+
function findEntry(entries, path) {
|
|
6447
|
+
for (const entry of entries) {
|
|
6448
|
+
if (entry.path === path) return entry;
|
|
6449
|
+
if (entry.kind === "dir" && entry.children) {
|
|
6450
|
+
const found = findEntry(entry.children, path);
|
|
6451
|
+
if (found) return found;
|
|
6452
|
+
}
|
|
6453
|
+
}
|
|
6454
|
+
return null;
|
|
6455
|
+
}
|
|
6456
|
+
function RenderEntries({
|
|
6457
|
+
entries,
|
|
6458
|
+
onFileSelect,
|
|
6459
|
+
onDelete
|
|
6460
|
+
}) {
|
|
6461
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: entries.map((entry) => {
|
|
6462
|
+
if (entry.kind === "dir") {
|
|
6463
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FileTreeFolder, { name: entry.name, path: entry.path, children: entry.children && entry.children.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6464
|
+
RenderEntries,
|
|
6465
|
+
{
|
|
6466
|
+
entries: entry.children,
|
|
6467
|
+
onFileSelect,
|
|
6468
|
+
onDelete
|
|
6469
|
+
}
|
|
6470
|
+
) }, entry.path);
|
|
6471
|
+
}
|
|
6472
|
+
const viewable = isViewable(entry.name);
|
|
6473
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(FileTreeFile, { name: entry.name, path: entry.path, children: [
|
|
6474
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-4 shrink-0" }),
|
|
6475
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: entry.name }),
|
|
6476
|
+
entry.size != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 shrink-0 text-xs text-muted-foreground/60", children: formatFileSize(entry.size) }),
|
|
6477
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-1 flex shrink-0 items-center gap-0 opacity-0 transition-opacity group-hover:opacity-100", children: [
|
|
6478
|
+
viewable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6479
|
+
"button",
|
|
6480
|
+
{
|
|
6481
|
+
type: "button",
|
|
6482
|
+
className: "rounded p-0.5 text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
6483
|
+
onClick: (event) => {
|
|
6484
|
+
event.stopPropagation();
|
|
6485
|
+
onFileSelect(entry.path);
|
|
6486
|
+
},
|
|
6487
|
+
title: "View",
|
|
6488
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.DownloadIcon, { className: "size-3" })
|
|
6489
|
+
}
|
|
6490
|
+
),
|
|
6491
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6492
|
+
"button",
|
|
6493
|
+
{
|
|
6494
|
+
type: "button",
|
|
6495
|
+
className: "rounded p-0.5 text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
|
|
6496
|
+
onClick: (event) => {
|
|
6497
|
+
event.stopPropagation();
|
|
6498
|
+
onDelete(entry.path);
|
|
6499
|
+
},
|
|
6500
|
+
title: "Delete",
|
|
6501
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrashIcon, { className: "size-3" })
|
|
6502
|
+
}
|
|
6503
|
+
)
|
|
6504
|
+
] })
|
|
6505
|
+
] }, entry.path);
|
|
6506
|
+
}) });
|
|
6507
|
+
}
|
|
6508
|
+
function WorkspacePanel({
|
|
6509
|
+
adapter,
|
|
6510
|
+
sessionId,
|
|
6511
|
+
selectedPath,
|
|
6512
|
+
onSelectedPathChange
|
|
6513
|
+
}) {
|
|
6514
|
+
const fileInputRef = react.useRef(null);
|
|
6515
|
+
const [entries, setEntries] = react.useState([]);
|
|
6516
|
+
const [rootName, setRootName] = react.useState("workspace");
|
|
6517
|
+
const [treeLoading, setTreeLoading] = react.useState(false);
|
|
6518
|
+
const [treeError, setTreeError] = react.useState(null);
|
|
6519
|
+
const [file, setFile] = react.useState(null);
|
|
6520
|
+
const [fileLoading, setFileLoading] = react.useState(false);
|
|
6521
|
+
const [fileError, setFileError] = react.useState(null);
|
|
6522
|
+
const [notice, setNotice] = react.useState(null);
|
|
6523
|
+
const [uploading, setUploading] = react.useState(false);
|
|
6524
|
+
const [deleteTarget, setDeleteTarget] = react.useState(null);
|
|
6525
|
+
const [expandedPaths, setExpandedPaths] = react.useState(/* @__PURE__ */ new Set());
|
|
6526
|
+
const [width, setWidth] = react.useState(DEFAULT_WIDTH);
|
|
6527
|
+
const isResizing = react.useRef(false);
|
|
6528
|
+
const startX = react.useRef(0);
|
|
6529
|
+
const startWidth = react.useRef(DEFAULT_WIDTH);
|
|
6530
|
+
const fetchTree = react.useCallback(async () => {
|
|
6531
|
+
if (!sessionId) {
|
|
6532
|
+
setEntries([]);
|
|
6533
|
+
setRootName("workspace");
|
|
6534
|
+
setTreeError(null);
|
|
6535
|
+
return;
|
|
6536
|
+
}
|
|
6537
|
+
setTreeLoading(true);
|
|
6538
|
+
setTreeError(null);
|
|
6539
|
+
try {
|
|
6540
|
+
const tree = await adapter.getWorkspaceTree({ sessionId });
|
|
6541
|
+
setEntries(tree.entries);
|
|
6542
|
+
setRootName(tree.root || "workspace");
|
|
6543
|
+
setExpandedPaths(new Set(collectExpandedPaths(tree.entries)));
|
|
6544
|
+
} catch (error) {
|
|
6545
|
+
setEntries([]);
|
|
6546
|
+
setRootName("workspace");
|
|
6547
|
+
setTreeError(error.message);
|
|
6548
|
+
} finally {
|
|
6549
|
+
setTreeLoading(false);
|
|
6550
|
+
}
|
|
6551
|
+
}, [adapter, sessionId]);
|
|
6552
|
+
const fetchFile = react.useCallback(
|
|
6553
|
+
async (path) => {
|
|
6554
|
+
if (!sessionId) return;
|
|
6555
|
+
setFileLoading(true);
|
|
6556
|
+
setFileError(null);
|
|
6557
|
+
try {
|
|
6558
|
+
const nextFile = await adapter.getWorkspaceFile({ sessionId, path });
|
|
6559
|
+
setFile(nextFile);
|
|
6560
|
+
} catch (error) {
|
|
6561
|
+
setFile(null);
|
|
6562
|
+
setFileError(error.message);
|
|
6563
|
+
} finally {
|
|
6564
|
+
setFileLoading(false);
|
|
6565
|
+
}
|
|
6566
|
+
},
|
|
6567
|
+
[adapter, sessionId]
|
|
6568
|
+
);
|
|
6569
|
+
react.useEffect(() => {
|
|
6570
|
+
void fetchTree();
|
|
6571
|
+
}, [fetchTree]);
|
|
6572
|
+
react.useEffect(() => {
|
|
6573
|
+
if (!sessionId) {
|
|
6574
|
+
setFile(null);
|
|
6575
|
+
setFileError(null);
|
|
6576
|
+
onSelectedPathChange(null);
|
|
6577
|
+
}
|
|
6578
|
+
}, [onSelectedPathChange, sessionId]);
|
|
6579
|
+
react.useEffect(() => {
|
|
6580
|
+
if (!selectedPath) return;
|
|
6581
|
+
const parts = selectedPath.split("/");
|
|
6582
|
+
if (parts.length <= 1) return;
|
|
6583
|
+
setExpandedPaths((prev) => {
|
|
6584
|
+
const next = new Set(prev);
|
|
6585
|
+
let path = "";
|
|
6586
|
+
for (let index = 0; index < parts.length - 1; index += 1) {
|
|
6587
|
+
path = path ? `${path}/${parts[index]}` : parts[index];
|
|
6588
|
+
next.add(path);
|
|
6589
|
+
}
|
|
6590
|
+
return next;
|
|
6591
|
+
});
|
|
6592
|
+
}, [selectedPath]);
|
|
6593
|
+
react.useEffect(() => {
|
|
6594
|
+
if (!selectedPath || !sessionId || entries.length === 0) return;
|
|
6595
|
+
const entry = findEntry(entries, selectedPath);
|
|
6596
|
+
if (entry?.kind === "file" && file?.path !== selectedPath) {
|
|
6597
|
+
void fetchFile(selectedPath);
|
|
6598
|
+
}
|
|
6599
|
+
}, [entries, fetchFile, file?.path, selectedPath, sessionId]);
|
|
6600
|
+
const handleSelect = react.useCallback(
|
|
6601
|
+
(path) => {
|
|
6602
|
+
onSelectedPathChange(path);
|
|
6603
|
+
const entry = findEntry(entries, path);
|
|
6604
|
+
if (entry?.kind === "file") {
|
|
6605
|
+
void fetchFile(path);
|
|
6606
|
+
}
|
|
6607
|
+
},
|
|
6608
|
+
[entries, fetchFile, onSelectedPathChange]
|
|
6609
|
+
);
|
|
6610
|
+
const handleUpload = react.useCallback(
|
|
6611
|
+
async (files) => {
|
|
6612
|
+
if (!sessionId || files.length === 0) return;
|
|
6613
|
+
setUploading(true);
|
|
6614
|
+
setNotice(null);
|
|
6615
|
+
try {
|
|
6616
|
+
for (const uploadedFile of Array.from(files)) {
|
|
6617
|
+
await adapter.uploadWorkspaceFile({
|
|
6618
|
+
sessionId,
|
|
6619
|
+
file: uploadedFile
|
|
6620
|
+
});
|
|
6621
|
+
}
|
|
6622
|
+
setNotice(
|
|
6623
|
+
files.length === 1 ? `Uploaded ${files[0]?.name ?? "file"}` : `Uploaded ${files.length} files`
|
|
6624
|
+
);
|
|
6625
|
+
await fetchTree();
|
|
6626
|
+
} catch (error) {
|
|
6627
|
+
setNotice(error.message);
|
|
6628
|
+
} finally {
|
|
6629
|
+
setUploading(false);
|
|
6630
|
+
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
6631
|
+
}
|
|
6632
|
+
},
|
|
6633
|
+
[adapter, fetchTree, sessionId]
|
|
6634
|
+
);
|
|
6635
|
+
const handleDelete = react.useCallback(
|
|
6636
|
+
async (path) => {
|
|
6637
|
+
if (!sessionId) return;
|
|
6638
|
+
try {
|
|
6639
|
+
await adapter.deleteWorkspaceFile({ sessionId, path });
|
|
6640
|
+
if (selectedPath === path) {
|
|
6641
|
+
onSelectedPathChange(null);
|
|
6642
|
+
setFile(null);
|
|
6643
|
+
setFileError(null);
|
|
6644
|
+
}
|
|
6645
|
+
setNotice(`Deleted ${path.split("/").pop() ?? path}`);
|
|
6646
|
+
await fetchTree();
|
|
6647
|
+
} catch (error) {
|
|
6648
|
+
setNotice(error.message);
|
|
6649
|
+
} finally {
|
|
6650
|
+
setDeleteTarget(null);
|
|
6651
|
+
}
|
|
6652
|
+
},
|
|
6653
|
+
[adapter, fetchTree, onSelectedPathChange, selectedPath, sessionId]
|
|
6654
|
+
);
|
|
6655
|
+
const onResizeStart = react.useCallback(
|
|
6656
|
+
(event) => {
|
|
6657
|
+
event.preventDefault();
|
|
6658
|
+
isResizing.current = true;
|
|
6659
|
+
startX.current = event.clientX;
|
|
6660
|
+
startWidth.current = width;
|
|
6661
|
+
document.body.style.cursor = "col-resize";
|
|
6662
|
+
document.body.style.userSelect = "none";
|
|
6663
|
+
},
|
|
6664
|
+
[width]
|
|
6665
|
+
);
|
|
6666
|
+
react.useEffect(() => {
|
|
6667
|
+
const onMouseMove = (event) => {
|
|
6668
|
+
if (!isResizing.current) return;
|
|
6669
|
+
const delta = startX.current - event.clientX;
|
|
6670
|
+
setWidth(
|
|
6671
|
+
Math.min(MAX_WIDTH, Math.max(MIN_WIDTH, startWidth.current + delta))
|
|
6672
|
+
);
|
|
6673
|
+
};
|
|
6674
|
+
const onMouseUp = () => {
|
|
6675
|
+
if (!isResizing.current) return;
|
|
6676
|
+
isResizing.current = false;
|
|
6677
|
+
document.body.style.cursor = "";
|
|
6678
|
+
document.body.style.userSelect = "";
|
|
6679
|
+
};
|
|
6680
|
+
window.addEventListener("mousemove", onMouseMove);
|
|
6681
|
+
window.addEventListener("mouseup", onMouseUp);
|
|
6682
|
+
return () => {
|
|
6683
|
+
window.removeEventListener("mousemove", onMouseMove);
|
|
6684
|
+
window.removeEventListener("mouseup", onMouseUp);
|
|
6685
|
+
};
|
|
6686
|
+
}, []);
|
|
6687
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6688
|
+
"aside",
|
|
6689
|
+
{
|
|
6690
|
+
className: "relative z-10 flex min-h-0 flex-col overflow-hidden border-l border-muted-foreground/20 bg-card",
|
|
6691
|
+
style: { width, minWidth: MIN_WIDTH, maxWidth: MAX_WIDTH },
|
|
6692
|
+
children: [
|
|
6693
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6694
|
+
"div",
|
|
6695
|
+
{
|
|
6696
|
+
className: "absolute inset-y-0 left-0 z-20 w-1.5 cursor-col-resize transition-colors hover:bg-primary/20 active:bg-primary/30",
|
|
6697
|
+
onMouseDown: onResizeStart
|
|
6698
|
+
}
|
|
6699
|
+
),
|
|
6700
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6701
|
+
"input",
|
|
6702
|
+
{
|
|
6703
|
+
ref: fileInputRef,
|
|
6704
|
+
type: "file",
|
|
6705
|
+
multiple: true,
|
|
6706
|
+
className: "hidden",
|
|
6707
|
+
onChange: (event) => {
|
|
6708
|
+
if (event.target.files) void handleUpload(event.target.files);
|
|
6709
|
+
}
|
|
6710
|
+
}
|
|
6711
|
+
),
|
|
6712
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-14 items-center gap-2 border-b border-line px-3 py-3", children: [
|
|
6713
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderOpenIcon, { className: "size-4 shrink-0 text-amber-500" }),
|
|
6714
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
6715
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-sm font-medium text-foreground", children: rootName }),
|
|
6716
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-xs text-faint", children: "Workspace" })
|
|
6717
|
+
] }),
|
|
6718
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
|
|
6719
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6720
|
+
Button,
|
|
6721
|
+
{
|
|
6722
|
+
variant: "ghost",
|
|
6723
|
+
size: "icon-sm",
|
|
6724
|
+
onClick: () => fileInputRef.current?.click(),
|
|
6725
|
+
disabled: !sessionId || uploading,
|
|
6726
|
+
"aria-label": "Upload files",
|
|
6727
|
+
children: uploading ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2Icon, { className: "size-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.UploadIcon, { className: "size-4" })
|
|
6728
|
+
}
|
|
6729
|
+
) }),
|
|
6730
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "bottom", children: "Upload files" })
|
|
6731
|
+
] }),
|
|
6732
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
|
|
6733
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6734
|
+
Button,
|
|
6735
|
+
{
|
|
6736
|
+
variant: "ghost",
|
|
6737
|
+
size: "icon-sm",
|
|
6738
|
+
onClick: () => void fetchTree(),
|
|
6739
|
+
disabled: !sessionId || treeLoading,
|
|
6740
|
+
"aria-label": "Refresh workspace",
|
|
6741
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6742
|
+
lucideReact.RefreshCwIcon,
|
|
6743
|
+
{
|
|
6744
|
+
className: cn("size-4", treeLoading && "animate-spin")
|
|
6745
|
+
}
|
|
6746
|
+
)
|
|
6747
|
+
}
|
|
6748
|
+
) }),
|
|
6749
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "bottom", children: "Refresh" })
|
|
6750
|
+
] })
|
|
6751
|
+
] }),
|
|
6752
|
+
notice && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-line px-3 py-2 text-xs text-muted-foreground", children: notice }),
|
|
6753
|
+
/* @__PURE__ */ jsxRuntime.jsx(ScrollArea, { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-1 py-1", children: [
|
|
6754
|
+
treeLoading && entries.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1 p-2", children: Array.from({ length: 8 }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
6755
|
+
Skeleton,
|
|
6756
|
+
{
|
|
6757
|
+
className: "h-5 rounded",
|
|
6758
|
+
style: {
|
|
6759
|
+
width: `${SKELETON_WIDTHS2[index % SKELETON_WIDTHS2.length]}%`
|
|
6760
|
+
}
|
|
6761
|
+
},
|
|
6762
|
+
index
|
|
6763
|
+
)) }),
|
|
6764
|
+
treeError && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 p-3 text-sm text-destructive", children: [
|
|
6765
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircleIcon, { className: "mt-0.5 size-4 shrink-0" }),
|
|
6766
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: treeError })
|
|
6767
|
+
] }),
|
|
6768
|
+
!treeLoading && !treeError && entries.length === 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-8 text-center text-sm text-faint", children: [
|
|
6769
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { children: "No workspace files" }),
|
|
6770
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
6771
|
+
Button,
|
|
6772
|
+
{
|
|
6773
|
+
variant: "outline",
|
|
6774
|
+
size: "sm",
|
|
6775
|
+
className: "mt-3 gap-1.5",
|
|
6776
|
+
onClick: () => fileInputRef.current?.click(),
|
|
6777
|
+
disabled: !sessionId,
|
|
6778
|
+
children: [
|
|
6779
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.UploadIcon, { className: "size-3.5" }),
|
|
6780
|
+
"Upload files"
|
|
6781
|
+
]
|
|
6782
|
+
}
|
|
6783
|
+
)
|
|
6784
|
+
] }),
|
|
6785
|
+
entries.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6786
|
+
FileTree,
|
|
6787
|
+
{
|
|
6788
|
+
expanded: expandedPaths,
|
|
6789
|
+
onExpandedChange: setExpandedPaths,
|
|
6790
|
+
selectedPath,
|
|
6791
|
+
onSelect: handleSelect,
|
|
6792
|
+
className: "rounded-none border-0",
|
|
6793
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6794
|
+
RenderEntries,
|
|
6795
|
+
{
|
|
6796
|
+
entries,
|
|
6797
|
+
onFileSelect: handleSelect,
|
|
6798
|
+
onDelete: setDeleteTarget
|
|
6799
|
+
}
|
|
6800
|
+
)
|
|
6801
|
+
}
|
|
6802
|
+
)
|
|
6803
|
+
] }) }),
|
|
6804
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6805
|
+
FileViewer,
|
|
6806
|
+
{
|
|
6807
|
+
file,
|
|
6808
|
+
loading: fileLoading,
|
|
6809
|
+
error: fileError,
|
|
6810
|
+
onClose: () => {
|
|
6811
|
+
setFile(null);
|
|
6812
|
+
setFileError(null);
|
|
6813
|
+
}
|
|
6814
|
+
}
|
|
6815
|
+
),
|
|
6816
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6817
|
+
ConfirmDialog,
|
|
6818
|
+
{
|
|
6819
|
+
open: deleteTarget !== null,
|
|
6820
|
+
title: "Delete file?",
|
|
6821
|
+
description: `This will permanently delete ${deleteTarget?.split("/").pop() ?? "this file"} from the workspace.`,
|
|
6822
|
+
confirmLabel: "Delete",
|
|
6823
|
+
onConfirm: () => deleteTarget ? handleDelete(deleteTarget) : Promise.resolve(),
|
|
6824
|
+
onCancel: () => setDeleteTarget(null)
|
|
6825
|
+
}
|
|
6826
|
+
)
|
|
6827
|
+
]
|
|
6828
|
+
}
|
|
6829
|
+
);
|
|
6830
|
+
}
|
|
6831
|
+
function ConfirmDialog({
|
|
6832
|
+
open,
|
|
6833
|
+
title,
|
|
6834
|
+
description,
|
|
6835
|
+
confirmLabel,
|
|
6836
|
+
onConfirm,
|
|
6837
|
+
onCancel
|
|
6838
|
+
}) {
|
|
6839
|
+
const [loading, setLoading] = react.useState(false);
|
|
6840
|
+
const handleConfirm = async () => {
|
|
6841
|
+
setLoading(true);
|
|
6842
|
+
try {
|
|
6843
|
+
await onConfirm();
|
|
6844
|
+
} finally {
|
|
6845
|
+
setLoading(false);
|
|
6846
|
+
}
|
|
6847
|
+
};
|
|
6848
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6849
|
+
Dialog,
|
|
6850
|
+
{
|
|
6851
|
+
open,
|
|
6852
|
+
onOpenChange: (nextOpen) => {
|
|
6853
|
+
if (!nextOpen && !loading) onCancel();
|
|
6854
|
+
},
|
|
6855
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "sm:max-w-md", children: [
|
|
6856
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
|
|
6857
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: title }),
|
|
6858
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: description })
|
|
6859
|
+
] }),
|
|
6860
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogFooter, { children: [
|
|
6861
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", disabled: loading, onClick: onCancel, children: "Cancel" }),
|
|
6862
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "destructive", disabled: loading, onClick: handleConfirm, children: [
|
|
6863
|
+
loading && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2Icon, { className: "mr-1.5 size-3.5 animate-spin" }),
|
|
6864
|
+
confirmLabel
|
|
6865
|
+
] })
|
|
6866
|
+
] })
|
|
6867
|
+
] })
|
|
6868
|
+
}
|
|
6869
|
+
);
|
|
6870
|
+
}
|
|
6078
6871
|
|
|
6079
6872
|
// src/runtime/events.ts
|
|
6080
6873
|
var AGENT_CHAT_LISTENED_EVENTS = [
|
|
@@ -6885,6 +7678,7 @@ function AgentChat({
|
|
|
6885
7678
|
onMessagesChange,
|
|
6886
7679
|
disabled
|
|
6887
7680
|
}) {
|
|
7681
|
+
const [workspacePath, setWorkspacePath] = react.useState(null);
|
|
6888
7682
|
const runtime = useAgentChatRuntime({
|
|
6889
7683
|
adapter,
|
|
6890
7684
|
agentId,
|
|
@@ -6894,29 +7688,47 @@ function AgentChat({
|
|
|
6894
7688
|
react.useEffect(() => {
|
|
6895
7689
|
onMessagesChange?.(runtime.messages);
|
|
6896
7690
|
}, [onMessagesChange, runtime.messages]);
|
|
7691
|
+
const handleFileSelect = react.useCallback(
|
|
7692
|
+
(path) => {
|
|
7693
|
+
setWorkspacePath(path);
|
|
7694
|
+
onFileSelect?.(path);
|
|
7695
|
+
},
|
|
7696
|
+
[onFileSelect]
|
|
7697
|
+
);
|
|
6897
7698
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6898
7699
|
AgentChatAdapterProvider,
|
|
6899
7700
|
{
|
|
6900
7701
|
value: {
|
|
6901
7702
|
adapter,
|
|
6902
7703
|
sessionId,
|
|
6903
|
-
onFileSelect
|
|
7704
|
+
onFileSelect: handleFileSelect
|
|
6904
7705
|
},
|
|
6905
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("section", { className: "flex h-full min-h-0
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
|
|
6919
|
-
|
|
7706
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "flex h-full min-h-0 bg-card text-sm text-foreground", children: [
|
|
7707
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-w-0 flex-1 flex-col", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7708
|
+
ChatThread,
|
|
7709
|
+
{
|
|
7710
|
+
sessionId,
|
|
7711
|
+
messages: runtime.messages,
|
|
7712
|
+
isRunning: runtime.isRunning,
|
|
7713
|
+
onSend: (content) => void runtime.send(content),
|
|
7714
|
+
onStop: () => void runtime.stop(),
|
|
7715
|
+
onRetry: runtime.retry,
|
|
7716
|
+
onFileSelect: handleFileSelect,
|
|
7717
|
+
disabled,
|
|
7718
|
+
tokenUsage: runtime.tokenUsage,
|
|
7719
|
+
retryIndicator: runtime.retryIndicator
|
|
7720
|
+
}
|
|
7721
|
+
) }),
|
|
7722
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7723
|
+
WorkspacePanel,
|
|
7724
|
+
{
|
|
7725
|
+
adapter,
|
|
7726
|
+
sessionId,
|
|
7727
|
+
selectedPath: workspacePath,
|
|
7728
|
+
onSelectedPathChange: setWorkspacePath
|
|
7729
|
+
}
|
|
7730
|
+
)
|
|
7731
|
+
] }) })
|
|
6920
7732
|
}
|
|
6921
7733
|
);
|
|
6922
7734
|
}
|