@brainpilot/web 0.0.4 → 0.0.6
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/assets/index-Br55rkHb.css +1 -0
- package/dist/assets/index-CeUzk-ej.js +445 -0
- package/dist/index.html +2 -2
- package/index.html +13 -0
- package/package.json +12 -3
- package/src/App.tsx +10 -0
- package/src/__tests__/agentsReducer.test.ts +67 -0
- package/src/__tests__/api.test.ts +221 -0
- package/src/__tests__/chatScrollMemory.test.ts +49 -0
- package/src/__tests__/demoConversation.test.ts +73 -0
- package/src/__tests__/demoReset.test.ts +24 -0
- package/src/__tests__/messageGroups.test.ts +80 -0
- package/src/__tests__/newUiComponents.test.tsx +101 -0
- package/src/__tests__/newUiEvents.test.ts +236 -0
- package/src/__tests__/runningToast.test.ts +29 -0
- package/src/__tests__/tokenUsage.test.ts +48 -0
- package/src/__tests__/toolDisplay.test.ts +55 -0
- package/src/__tests__/traceReducer.test.ts +62 -0
- package/src/components/chat/AskUserCard.tsx +123 -0
- package/src/components/chat/AutoRetryIndicator.tsx +71 -0
- package/src/components/chat/ComposerInput.tsx +73 -0
- package/src/components/chat/ComposerSendButton.tsx +26 -0
- package/src/components/chat/MarkdownMessage.tsx +24 -0
- package/src/components/chat/MessageStream.tsx +505 -0
- package/src/components/chat/PromptComposer.tsx +489 -0
- package/src/components/chat/SystemMessageBubble.tsx +46 -0
- package/src/components/chat/chatScrollMemory.ts +49 -0
- package/src/components/demo/DemoFileTree.tsx +146 -0
- package/src/components/demo/DemoView.tsx +730 -0
- package/src/components/demo/TraceNodeModal.tsx +80 -0
- package/src/components/demo/demoBundle.ts +223 -0
- package/src/components/demo/demoCache.ts +42 -0
- package/src/components/demo/demoReset.ts +16 -0
- package/src/components/files/FilePreviewView.tsx +153 -0
- package/src/components/files/FileSidebar.tsx +664 -0
- package/src/components/files/filePreview.ts +113 -0
- package/src/components/primitives/CustomSelect.tsx +200 -0
- package/src/components/primitives/IconButton.tsx +27 -0
- package/src/components/quota/DiskQuotaCriticalDialog.tsx +56 -0
- package/src/components/quota/DiskQuotaWarningDialog.tsx +65 -0
- package/src/components/quota/QuotaFileManager.tsx +197 -0
- package/src/components/search/SearchDialog.tsx +101 -0
- package/src/components/session/AgentNetwork.tsx +1233 -0
- package/src/components/session/AgentTraceViews.tsx +346 -0
- package/src/components/session/AnalyticsTab.tsx +220 -0
- package/src/components/session/GlobalOverview.tsx +108 -0
- package/src/components/session/NodeTooltip.tsx +127 -0
- package/src/components/session/TimelineTab.tsx +320 -0
- package/src/components/session/TraceGraphView.tsx +307 -0
- package/src/components/session/TraceNodeDetail.tsx +179 -0
- package/src/components/session/agentAnalytics.ts +397 -0
- package/src/components/session/agentNetworkShared.ts +339 -0
- package/src/components/session/traceLayout.ts +182 -0
- package/src/components/settings/SettingsDialog.tsx +737 -0
- package/src/components/shell/DesktopShell.tsx +261 -0
- package/src/components/shell/SandboxBuildingOverlay.tsx +73 -0
- package/src/components/shell/SandboxStatus.tsx +287 -0
- package/src/components/shell/TerminalDrawer.tsx +387 -0
- package/src/components/sidebar/Sidebar.tsx +191 -0
- package/src/config.ts +10 -0
- package/src/contexts/AppProviders.tsx +20 -0
- package/src/contexts/AuthContext.tsx +61 -0
- package/src/contexts/PreferencesContext.tsx +125 -0
- package/src/contexts/SSEContext.tsx +264 -0
- package/src/contexts/SandboxContext.tsx +310 -0
- package/src/contexts/SessionContext.tsx +919 -0
- package/src/contexts/agentsReducer.ts +49 -0
- package/src/contexts/draftStore.ts +103 -0
- package/src/contexts/messageFilters.ts +29 -0
- package/src/contexts/messageGroups.ts +77 -0
- package/src/contexts/messageReducer.ts +401 -0
- package/src/contexts/newUiEvents.ts +190 -0
- package/src/contexts/runningToast.ts +33 -0
- package/src/contexts/traceReducer.ts +62 -0
- package/src/contexts/turnTimer.test.ts +97 -0
- package/src/contexts/turnTimer.ts +108 -0
- package/src/contexts/useTurnTimer.ts +104 -0
- package/src/contracts/backend.ts +897 -0
- package/src/contracts/demoBundle.ts +83 -0
- package/src/i18n/messages/analytics.ts +106 -0
- package/src/i18n/messages/chat.ts +130 -0
- package/src/i18n/messages/contexts.ts +42 -0
- package/src/i18n/messages/demo.ts +80 -0
- package/src/i18n/messages/files.ts +82 -0
- package/src/i18n/messages/network.ts +190 -0
- package/src/i18n/messages/profile.ts +44 -0
- package/src/i18n/messages/quota.ts +36 -0
- package/src/i18n/messages/sandbox.ts +116 -0
- package/src/i18n/messages/search.ts +16 -0
- package/src/i18n/messages/settings.ts +188 -0
- package/src/i18n/messages/shell.ts +38 -0
- package/src/i18n/messages/sidebar.ts +52 -0
- package/src/i18n/messages/terminal.ts +22 -0
- package/src/i18n/messages/trace.ts +136 -0
- package/src/i18n/messages.ts +32 -0
- package/src/i18n/translate.ts +46 -0
- package/src/i18n/types.ts +15 -0
- package/src/i18n/useT.ts +15 -0
- package/src/main.tsx +13 -0
- package/src/mocks/backend.ts +729 -0
- package/src/styles/global.css +7578 -0
- package/src/styles/tokens.css +161 -0
- package/src/utils/api.ts +724 -0
- package/src/utils/download.ts +18 -0
- package/src/utils/format.ts +7 -0
- package/src/utils/toolDisplay.ts +74 -0
- package/src/utils/zip.ts +119 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.app.json +22 -0
- package/tsconfig.json +7 -0
- package/tsconfig.node.json +13 -0
- package/vite.config.ts +13 -0
- package/dist/assets/index-Cd0Mi_WU.css +0 -1
- package/dist/assets/index-FGg-DeYR.js +0 -448
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { useMemo, useState } from "react";
|
|
2
|
+
import { ChevronRight, File, FileImage, FileText, Folder } from "lucide-react";
|
|
3
|
+
import type { DemoFile } from "../../contracts/demoBundle";
|
|
4
|
+
import { getPreviewKind } from "../files/filePreview";
|
|
5
|
+
|
|
6
|
+
interface TreeNode {
|
|
7
|
+
name: string;
|
|
8
|
+
path: string;
|
|
9
|
+
isDir: boolean;
|
|
10
|
+
children: TreeNode[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Build a nested tree from a flat list of file paths. Folders first, alpha. */
|
|
14
|
+
export function buildFileTree(paths: string[]): TreeNode[] {
|
|
15
|
+
const root: TreeNode = { name: "", path: "", isDir: true, children: [] };
|
|
16
|
+
for (const raw of paths) {
|
|
17
|
+
const norm = raw.replace(/^\/+/, "");
|
|
18
|
+
const parts = norm.split("/").filter(Boolean);
|
|
19
|
+
let cursor = root;
|
|
20
|
+
let acc = "";
|
|
21
|
+
parts.forEach((part, idx) => {
|
|
22
|
+
acc = acc ? `${acc}/${part}` : part;
|
|
23
|
+
const isLeaf = idx === parts.length - 1;
|
|
24
|
+
let child = cursor.children.find((c) => c.name === part);
|
|
25
|
+
if (!child) {
|
|
26
|
+
// Preserve the original (possibly leading-slash) path on the leaf so it
|
|
27
|
+
// matches DemoFile.path / artifact paths exactly.
|
|
28
|
+
child = { name: part, path: isLeaf ? raw : acc, isDir: !isLeaf, children: [] };
|
|
29
|
+
cursor.children.push(child);
|
|
30
|
+
}
|
|
31
|
+
if (!isLeaf) {
|
|
32
|
+
child.isDir = true;
|
|
33
|
+
}
|
|
34
|
+
cursor = child;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
sortTree(root);
|
|
38
|
+
return root.children;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function sortTree(node: TreeNode) {
|
|
42
|
+
node.children.sort((a, b) => {
|
|
43
|
+
if (a.isDir !== b.isDir) {
|
|
44
|
+
return a.isDir ? -1 : 1;
|
|
45
|
+
}
|
|
46
|
+
return a.name.localeCompare(b.name);
|
|
47
|
+
});
|
|
48
|
+
node.children.forEach(sortTree);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function leafIcon(name: string) {
|
|
52
|
+
const kind = getPreviewKind(name);
|
|
53
|
+
if (kind === "image") {
|
|
54
|
+
return <FileImage size={14} />;
|
|
55
|
+
}
|
|
56
|
+
if (kind === "text") {
|
|
57
|
+
return <FileText size={14} />;
|
|
58
|
+
}
|
|
59
|
+
return <File size={14} />;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
interface DemoFileTreeProps {
|
|
63
|
+
files: DemoFile[];
|
|
64
|
+
highlightedPaths: Set<string>;
|
|
65
|
+
activePath: string | null;
|
|
66
|
+
onSelect: (path: string) => void;
|
|
67
|
+
emptyLabel: string;
|
|
68
|
+
skippedLabel: string;
|
|
69
|
+
unreadableLabel: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function DemoFileTree({ files, highlightedPaths, activePath, onSelect, emptyLabel, skippedLabel, unreadableLabel }: DemoFileTreeProps) {
|
|
73
|
+
const tree = useMemo(() => buildFileTree(files.map((f) => f.path)), [files]);
|
|
74
|
+
const truncated = useMemo(() => new Set(files.filter((f) => f.truncated).map((f) => f.path)), [files]);
|
|
75
|
+
const unreadable = useMemo(
|
|
76
|
+
() => new Set(files.filter((f) => f.reason === "unreadable").map((f) => f.path)),
|
|
77
|
+
[files],
|
|
78
|
+
);
|
|
79
|
+
const [collapsed, setCollapsed] = useState<Set<string>>(() => new Set());
|
|
80
|
+
|
|
81
|
+
if (files.length === 0) {
|
|
82
|
+
return <p className="demo-panel__empty">{emptyLabel}</p>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const toggle = (path: string) => {
|
|
86
|
+
setCollapsed((current) => {
|
|
87
|
+
const next = new Set(current);
|
|
88
|
+
if (next.has(path)) {
|
|
89
|
+
next.delete(path);
|
|
90
|
+
} else {
|
|
91
|
+
next.add(path);
|
|
92
|
+
}
|
|
93
|
+
return next;
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const renderNode = (node: TreeNode, depth: number) => {
|
|
98
|
+
const pad = 8 + depth * 14;
|
|
99
|
+
if (node.isDir) {
|
|
100
|
+
const isOpen = !collapsed.has(node.path);
|
|
101
|
+
return (
|
|
102
|
+
<div key={node.path || node.name} className="demo-tree-node">
|
|
103
|
+
<button
|
|
104
|
+
className="demo-tree-row demo-tree-row--dir"
|
|
105
|
+
style={{ paddingLeft: pad }}
|
|
106
|
+
onClick={() => toggle(node.path)}
|
|
107
|
+
type="button"
|
|
108
|
+
>
|
|
109
|
+
<span className={`demo-tree-chevron ${isOpen ? "is-open" : ""}`}>
|
|
110
|
+
<ChevronRight size={13} />
|
|
111
|
+
</span>
|
|
112
|
+
<Folder size={14} />
|
|
113
|
+
<span className="demo-tree-name">{node.name}</span>
|
|
114
|
+
</button>
|
|
115
|
+
{isOpen ? node.children.map((child) => renderNode(child, depth + 1)) : null}
|
|
116
|
+
</div>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
const isSkipped = truncated.has(node.path);
|
|
120
|
+
const isUnreadable = unreadable.has(node.path);
|
|
121
|
+
const isProduced = highlightedPaths.has(node.path);
|
|
122
|
+
const isActive = activePath === node.path;
|
|
123
|
+
return (
|
|
124
|
+
<div key={node.path} className="demo-tree-node">
|
|
125
|
+
<button
|
|
126
|
+
className={`demo-tree-row ${isActive ? "is-active" : ""} ${isProduced ? "is-produced" : ""} ${isSkipped ? "is-skipped" : ""}`}
|
|
127
|
+
style={{ paddingLeft: pad + 13 }}
|
|
128
|
+
disabled={isSkipped && !isUnreadable}
|
|
129
|
+
onClick={() => onSelect(node.path)}
|
|
130
|
+
title={node.path}
|
|
131
|
+
type="button"
|
|
132
|
+
>
|
|
133
|
+
{leafIcon(node.name)}
|
|
134
|
+
<span className="demo-tree-name">{node.name}</span>
|
|
135
|
+
{isUnreadable ? (
|
|
136
|
+
<small className="demo-tree-skip">{unreadableLabel}</small>
|
|
137
|
+
) : isSkipped ? (
|
|
138
|
+
<small className="demo-tree-skip">{skippedLabel}</small>
|
|
139
|
+
) : null}
|
|
140
|
+
</button>
|
|
141
|
+
</div>
|
|
142
|
+
);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
return <div className="demo-file-tree">{tree.map((node) => renderNode(node, 0))}</div>;
|
|
146
|
+
}
|