@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.
Files changed (114) hide show
  1. package/dist/assets/index-Br55rkHb.css +1 -0
  2. package/dist/assets/index-CeUzk-ej.js +445 -0
  3. package/dist/index.html +2 -2
  4. package/index.html +13 -0
  5. package/package.json +12 -3
  6. package/src/App.tsx +10 -0
  7. package/src/__tests__/agentsReducer.test.ts +67 -0
  8. package/src/__tests__/api.test.ts +221 -0
  9. package/src/__tests__/chatScrollMemory.test.ts +49 -0
  10. package/src/__tests__/demoConversation.test.ts +73 -0
  11. package/src/__tests__/demoReset.test.ts +24 -0
  12. package/src/__tests__/messageGroups.test.ts +80 -0
  13. package/src/__tests__/newUiComponents.test.tsx +101 -0
  14. package/src/__tests__/newUiEvents.test.ts +236 -0
  15. package/src/__tests__/runningToast.test.ts +29 -0
  16. package/src/__tests__/tokenUsage.test.ts +48 -0
  17. package/src/__tests__/toolDisplay.test.ts +55 -0
  18. package/src/__tests__/traceReducer.test.ts +62 -0
  19. package/src/components/chat/AskUserCard.tsx +123 -0
  20. package/src/components/chat/AutoRetryIndicator.tsx +71 -0
  21. package/src/components/chat/ComposerInput.tsx +73 -0
  22. package/src/components/chat/ComposerSendButton.tsx +26 -0
  23. package/src/components/chat/MarkdownMessage.tsx +24 -0
  24. package/src/components/chat/MessageStream.tsx +505 -0
  25. package/src/components/chat/PromptComposer.tsx +489 -0
  26. package/src/components/chat/SystemMessageBubble.tsx +46 -0
  27. package/src/components/chat/chatScrollMemory.ts +49 -0
  28. package/src/components/demo/DemoFileTree.tsx +146 -0
  29. package/src/components/demo/DemoView.tsx +730 -0
  30. package/src/components/demo/TraceNodeModal.tsx +80 -0
  31. package/src/components/demo/demoBundle.ts +223 -0
  32. package/src/components/demo/demoCache.ts +42 -0
  33. package/src/components/demo/demoReset.ts +16 -0
  34. package/src/components/files/FilePreviewView.tsx +153 -0
  35. package/src/components/files/FileSidebar.tsx +664 -0
  36. package/src/components/files/filePreview.ts +113 -0
  37. package/src/components/primitives/CustomSelect.tsx +200 -0
  38. package/src/components/primitives/IconButton.tsx +27 -0
  39. package/src/components/quota/DiskQuotaCriticalDialog.tsx +56 -0
  40. package/src/components/quota/DiskQuotaWarningDialog.tsx +65 -0
  41. package/src/components/quota/QuotaFileManager.tsx +197 -0
  42. package/src/components/search/SearchDialog.tsx +101 -0
  43. package/src/components/session/AgentNetwork.tsx +1233 -0
  44. package/src/components/session/AgentTraceViews.tsx +346 -0
  45. package/src/components/session/AnalyticsTab.tsx +220 -0
  46. package/src/components/session/GlobalOverview.tsx +108 -0
  47. package/src/components/session/NodeTooltip.tsx +127 -0
  48. package/src/components/session/TimelineTab.tsx +320 -0
  49. package/src/components/session/TraceGraphView.tsx +307 -0
  50. package/src/components/session/TraceNodeDetail.tsx +179 -0
  51. package/src/components/session/agentAnalytics.ts +397 -0
  52. package/src/components/session/agentNetworkShared.ts +339 -0
  53. package/src/components/session/traceLayout.ts +182 -0
  54. package/src/components/settings/SettingsDialog.tsx +737 -0
  55. package/src/components/shell/DesktopShell.tsx +261 -0
  56. package/src/components/shell/SandboxBuildingOverlay.tsx +73 -0
  57. package/src/components/shell/SandboxStatus.tsx +287 -0
  58. package/src/components/shell/TerminalDrawer.tsx +387 -0
  59. package/src/components/sidebar/Sidebar.tsx +191 -0
  60. package/src/config.ts +10 -0
  61. package/src/contexts/AppProviders.tsx +20 -0
  62. package/src/contexts/AuthContext.tsx +61 -0
  63. package/src/contexts/PreferencesContext.tsx +125 -0
  64. package/src/contexts/SSEContext.tsx +264 -0
  65. package/src/contexts/SandboxContext.tsx +310 -0
  66. package/src/contexts/SessionContext.tsx +919 -0
  67. package/src/contexts/agentsReducer.ts +49 -0
  68. package/src/contexts/draftStore.ts +103 -0
  69. package/src/contexts/messageFilters.ts +29 -0
  70. package/src/contexts/messageGroups.ts +77 -0
  71. package/src/contexts/messageReducer.ts +401 -0
  72. package/src/contexts/newUiEvents.ts +190 -0
  73. package/src/contexts/runningToast.ts +33 -0
  74. package/src/contexts/traceReducer.ts +62 -0
  75. package/src/contexts/turnTimer.test.ts +97 -0
  76. package/src/contexts/turnTimer.ts +108 -0
  77. package/src/contexts/useTurnTimer.ts +104 -0
  78. package/src/contracts/backend.ts +897 -0
  79. package/src/contracts/demoBundle.ts +83 -0
  80. package/src/i18n/messages/analytics.ts +106 -0
  81. package/src/i18n/messages/chat.ts +130 -0
  82. package/src/i18n/messages/contexts.ts +42 -0
  83. package/src/i18n/messages/demo.ts +80 -0
  84. package/src/i18n/messages/files.ts +82 -0
  85. package/src/i18n/messages/network.ts +190 -0
  86. package/src/i18n/messages/profile.ts +44 -0
  87. package/src/i18n/messages/quota.ts +36 -0
  88. package/src/i18n/messages/sandbox.ts +116 -0
  89. package/src/i18n/messages/search.ts +16 -0
  90. package/src/i18n/messages/settings.ts +188 -0
  91. package/src/i18n/messages/shell.ts +38 -0
  92. package/src/i18n/messages/sidebar.ts +52 -0
  93. package/src/i18n/messages/terminal.ts +22 -0
  94. package/src/i18n/messages/trace.ts +136 -0
  95. package/src/i18n/messages.ts +32 -0
  96. package/src/i18n/translate.ts +46 -0
  97. package/src/i18n/types.ts +15 -0
  98. package/src/i18n/useT.ts +15 -0
  99. package/src/main.tsx +13 -0
  100. package/src/mocks/backend.ts +729 -0
  101. package/src/styles/global.css +7578 -0
  102. package/src/styles/tokens.css +161 -0
  103. package/src/utils/api.ts +724 -0
  104. package/src/utils/download.ts +18 -0
  105. package/src/utils/format.ts +7 -0
  106. package/src/utils/toolDisplay.ts +74 -0
  107. package/src/utils/zip.ts +119 -0
  108. package/src/vite-env.d.ts +1 -0
  109. package/tsconfig.app.json +22 -0
  110. package/tsconfig.json +7 -0
  111. package/tsconfig.node.json +13 -0
  112. package/vite.config.ts +13 -0
  113. package/dist/assets/index-Cd0Mi_WU.css +0 -1
  114. 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
+ }