@openviking/react 0.1.2 → 0.1.3

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 (98) hide show
  1. package/dist/1~0.js +506 -0
  2. package/dist/2~0.js +122 -0
  3. package/dist/{g~0.js → 30~0.js} +292 -167
  4. package/dist/client/index.d.ts +2 -1
  5. package/dist/client/paths.d.ts +64 -0
  6. package/dist/client/response.d.ts +31 -0
  7. package/dist/client/sse.d.ts +39 -0
  8. package/dist/client/stream.d.ts +26 -0
  9. package/dist/client/types.d.ts +104 -0
  10. package/dist/client.js +1 -239
  11. package/dist/components/agent-connect/style.css +2 -2
  12. package/dist/components/file-browser-entries/file-browser-entries-icons.d.ts +18 -0
  13. package/dist/components/file-browser-entries/file-browser-entries.d.ts +14 -0
  14. package/dist/components/file-browser-entries/index.d.ts +1 -0
  15. package/dist/components/file-browser-entries/style.css +155 -0
  16. package/dist/components/file-browser-entries/style.js +0 -0
  17. package/dist/components/file-browser-entries/types.d.ts +45 -0
  18. package/dist/components/file-browser-entries.js +1 -0
  19. package/dist/components/file-preview/file-preview-directory.d.ts +32 -0
  20. package/dist/components/file-preview/file-preview-header.d.ts +21 -3
  21. package/dist/components/file-preview/file-preview-panels.d.ts +41 -0
  22. package/dist/components/file-preview/file-preview-state.d.ts +10 -3
  23. package/dist/components/file-preview/file-preview.d.ts +2 -1
  24. package/dist/components/file-preview/level-selection.d.ts +25 -0
  25. package/dist/components/file-preview/style.css +76 -3
  26. package/dist/components/file-preview/types.d.ts +100 -1
  27. package/dist/components/file-preview/use-directory-level.d.ts +30 -0
  28. package/dist/components/file-preview/use-file-preview-actions-context.d.ts +6 -2
  29. package/dist/components/file-preview/use-file-preview-actions.d.ts +1 -1
  30. package/dist/components/file-preview.js +1 -1
  31. package/dist/components/file-tree/file-tree-info-tooltip.d.ts +7 -7
  32. package/dist/components/file-tree/file-tree-row-context.d.ts +0 -5
  33. package/dist/components/file-tree/file-tree-row-shared.d.ts +9 -2
  34. package/dist/components/file-tree/file-tree-tooltip-surface.d.ts +8 -8
  35. package/dist/components/file-tree/style.css +71 -34
  36. package/dist/components/file-tree/types.d.ts +20 -0
  37. package/dist/components/scope-switcher/style.css +2 -2
  38. package/dist/components/style.css +312 -47
  39. package/dist/components/tui/style.css +2 -2
  40. package/dist/components/viking-bot/style.css +2 -2
  41. package/dist/file-preview-viewer~0.js +1 -1
  42. package/dist/index.d.ts +2 -0
  43. package/dist/index.js +1 -0
  44. package/dist/l~0.js +1464 -25
  45. package/dist/modules/console/style.css +2 -2
  46. package/dist/modules/file-browser/file-browser-detail-icons.d.ts +10 -0
  47. package/dist/modules/file-browser/file-browser-detail.d.ts +33 -0
  48. package/dist/modules/file-browser/file-browser-empty.d.ts +3 -0
  49. package/dist/modules/file-browser/file-browser-failure.d.ts +22 -0
  50. package/dist/modules/file-browser/file-browser-icons.d.ts +18 -0
  51. package/dist/modules/file-browser/file-browser-labels.d.ts +28 -0
  52. package/dist/modules/file-browser/file-browser-layout.d.ts +27 -0
  53. package/dist/modules/file-browser/file-browser-toolbar.d.ts +18 -0
  54. package/dist/modules/file-browser/file-browser-tree-pane.d.ts +30 -0
  55. package/dist/modules/file-browser/file-browser.d.ts +14 -5
  56. package/dist/modules/file-browser/find-result.d.ts +24 -0
  57. package/dist/modules/file-browser/fs-directories.d.ts +33 -0
  58. package/dist/modules/file-browser/fs-file-kind.d.ts +19 -0
  59. package/dist/modules/file-browser/fs-icon.d.ts +17 -0
  60. package/dist/modules/file-browser/fs-model.d.ts +106 -0
  61. package/dist/modules/file-browser/fs-page.d.ts +16 -0
  62. package/dist/modules/file-browser/fs-path.d.ts +16 -0
  63. package/dist/modules/file-browser/fs-read-directory.d.ts +20 -0
  64. package/dist/modules/file-browser/fs-scope.d.ts +22 -0
  65. package/dist/modules/file-browser/fs-stat.d.ts +25 -0
  66. package/dist/modules/file-browser/index.d.ts +3 -1
  67. package/dist/modules/file-browser/style.css +4927 -35
  68. package/dist/modules/file-browser/tree-info-copy.d.ts +15 -0
  69. package/dist/modules/file-browser/tree-info-copy.zh-CN.d.ts +15 -0
  70. package/dist/modules/file-browser/types.d.ts +189 -44
  71. package/dist/modules/file-browser/use-container-width.d.ts +17 -0
  72. package/dist/modules/file-browser/use-file-browser.d.ts +49 -0
  73. package/dist/modules/file-browser/use-fs-preview.d.ts +51 -0
  74. package/dist/modules/file-browser/use-fs-search.d.ts +35 -0
  75. package/dist/modules/file-browser/use-fs-tree.d.ts +43 -0
  76. package/dist/modules/file-browser/use-request-scope.d.ts +39 -0
  77. package/dist/modules/file-browser.js +1 -1
  78. package/dist/modules/scope-cascade/style.css +2 -2
  79. package/dist/modules/style.css +4933 -41
  80. package/dist/n~0.js +178 -74
  81. package/dist/o~0.js +103 -0
  82. package/dist/shared/components/divider/divider.d.ts +18 -0
  83. package/dist/shared/components/divider/index.d.ts +1 -0
  84. package/dist/shared/components/divider/types.d.ts +35 -0
  85. package/dist/shared/components/overlay/types.d.ts +7 -0
  86. package/dist/shared/components/{tooltip/use-tooltip-position.d.ts → overlay/use-overlay-position.d.ts} +6 -6
  87. package/dist/shared/components/popover/index.d.ts +1 -0
  88. package/dist/shared/components/popover/popover.d.ts +23 -0
  89. package/dist/shared/components/popover/types.d.ts +50 -0
  90. package/dist/shared/components/resizable/clamp.d.ts +13 -0
  91. package/dist/shared/components/resizable/index.d.ts +2 -0
  92. package/dist/shared/components/resizable/resizable-handle.d.ts +25 -0
  93. package/dist/shared/components/resizable/types.d.ts +48 -0
  94. package/dist/shared/components/tooltip/types.d.ts +5 -5
  95. package/dist/style.css +5345 -188
  96. package/package.json +6 -1
  97. package/dist/components/file-tree/file-tree-tooltip.d.ts +0 -17
  98. package/dist/modules/file-browser/file-browser-toolbar-button.d.ts +0 -10
package/dist/l~0.js CHANGED
@@ -1,44 +1,1483 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
2
- function FileBrowserToolbarButton({ icon, children, onClick, disabled, className, ...rest }) {
3
- return /*#__PURE__*/ jsxs("button", {
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
3
+ import { Tooltip, FilePreview as file_preview_FilePreview } from "./30~0.js";
4
+ import { getFileTypeColor, resolveFileTypeIconKey, FolderIcon, getFileTypeIcon } from "./k~0.js";
5
+ import { FileTree as file_tree_FileTree } from "./n~0.js";
6
+ import { OV_PATHS, useOvClient } from "./1~0.js";
7
+ function clampResizableWidth(width, min, max) {
8
+ const rounded = Math.round(width);
9
+ const lower = Math.max(min, rounded);
10
+ return Math.min(Math.max(min, max), lower);
11
+ }
12
+ function ResizableHandle({ label, min, max, value, step = 16, direction = 1, onResize, className, ...rest }) {
13
+ const dragRef = useRef(null);
14
+ const [dragging, setDragging] = useState(false);
15
+ const endDrag = (event)=>{
16
+ if (!dragRef.current) return;
17
+ dragRef.current = null;
18
+ setDragging(false);
19
+ if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
20
+ };
21
+ const handlePointerDown = (event)=>{
22
+ if (!onResize) return;
23
+ if (0 !== event.button) return;
24
+ event.preventDefault();
25
+ event.currentTarget.setPointerCapture(event.pointerId);
26
+ dragRef.current = {
27
+ pointerId: event.pointerId,
28
+ x: event.clientX,
29
+ width: value
30
+ };
31
+ setDragging(true);
32
+ };
33
+ const handlePointerMove = (event)=>{
34
+ const drag = dragRef.current;
35
+ if (!drag || !onResize || drag.pointerId !== event.pointerId) return;
36
+ onResize(clampResizableWidth(drag.width + (event.clientX - drag.x) * direction, min, max));
37
+ };
38
+ const handleKeyDown = (event)=>{
39
+ if (!onResize) return;
40
+ if ('ArrowLeft' !== event.key && 'ArrowRight' !== event.key) return;
41
+ event.preventDefault();
42
+ const delta = ('ArrowRight' === event.key ? step : -step) * direction;
43
+ onResize(clampResizableWidth(value + delta, min, max));
44
+ };
45
+ return /*#__PURE__*/ jsx("div", {
4
46
  ...rest,
5
- type: "button",
6
- disabled: disabled,
47
+ role: "separator",
48
+ tabIndex: onResize ? 0 : void 0,
49
+ "aria-label": label,
50
+ "aria-orientation": "vertical",
51
+ "aria-valuemin": min,
52
+ "aria-valuemax": max,
53
+ "aria-valuenow": Math.round(value),
54
+ "data-dragging": dragging || void 0,
7
55
  className: [
8
- 'ov-file-browser__toolbar-button',
56
+ 'ov-resizable-handle',
9
57
  className
10
58
  ].filter(Boolean).join(' '),
11
- onClick: onClick,
59
+ onPointerDown: handlePointerDown,
60
+ onPointerMove: handlePointerMove,
61
+ onPointerUp: endDrag,
62
+ onPointerCancel: endDrag,
63
+ onKeyDown: handleKeyDown,
64
+ children: /*#__PURE__*/ jsx("span", {
65
+ "aria-hidden": "true",
66
+ className: "ov-resizable-handle__line"
67
+ })
68
+ });
69
+ }
70
+ const SIZE = 14;
71
+ function iconProps(size = SIZE) {
72
+ return {
73
+ width: size,
74
+ height: size,
75
+ viewBox: '0 0 16 16',
76
+ fill: 'none',
77
+ stroke: 'currentColor',
78
+ strokeWidth: 1.4,
79
+ strokeLinecap: 'round',
80
+ strokeLinejoin: 'round',
81
+ 'aria-hidden': true,
82
+ focusable: 'false'
83
+ };
84
+ }
85
+ function CopyIcon({ size = 12 }) {
86
+ return /*#__PURE__*/ jsxs("svg", {
87
+ ...iconProps(size),
88
+ children: [
89
+ /*#__PURE__*/ jsx("rect", {
90
+ x: "5.5",
91
+ y: "5.5",
92
+ width: "8",
93
+ height: "8",
94
+ rx: "1.5"
95
+ }),
96
+ /*#__PURE__*/ jsx("path", {
97
+ d: "M10.5 5.5v-1a1.5 1.5 0 0 0-1.5-1.5H4a1.5 1.5 0 0 0-1.5 1.5v5A1.5 1.5 0 0 0 4 11h1"
98
+ })
99
+ ]
100
+ });
101
+ }
102
+ function DownloadIcon() {
103
+ return /*#__PURE__*/ jsxs("svg", {
104
+ ...iconProps(),
105
+ children: [
106
+ /*#__PURE__*/ jsx("path", {
107
+ d: "M8 2.5v8"
108
+ }),
109
+ /*#__PURE__*/ jsx("path", {
110
+ d: "M5 7.5 8 10.5l3-3"
111
+ }),
112
+ /*#__PURE__*/ jsx("path", {
113
+ d: "M2.5 12.5h11"
114
+ })
115
+ ]
116
+ });
117
+ }
118
+ function FileBrowserDetail({ tabs, activeKey, locale, labels, footer, viewLabels, onActiveKeyChange }) {
119
+ return /*#__PURE__*/ jsx("div", {
120
+ className: "ov-file-browser__detail",
121
+ children: /*#__PURE__*/ jsx(file_preview_FilePreview, {
122
+ tabs: decorateTabs(tabs, viewLabels, footer),
123
+ activeKey: activeKey ?? void 0,
124
+ locale: locale,
125
+ labels: labels,
126
+ onActiveKeyChange: onActiveKeyChange
127
+ })
128
+ });
129
+ }
130
+ function decorateTabs(tabs, viewLabels, footer) {
131
+ return tabs.map((tab)=>{
132
+ if ('content' === tab.kind) return tab;
133
+ return {
134
+ ...tab,
135
+ slots: {
136
+ ...tab.slots,
137
+ footer,
138
+ actions: (actions)=>/*#__PURE__*/ jsxs("div", {
139
+ className: "ov-file-browser__detail-actions",
140
+ children: [
141
+ actions.canSwitchView ? /*#__PURE__*/ jsxs("div", {
142
+ className: "ov-file-browser__segmented",
143
+ role: "group",
144
+ "aria-label": viewLabels.viewSwitch,
145
+ children: [
146
+ /*#__PURE__*/ jsx("button", {
147
+ type: "button",
148
+ className: "ov-file-browser__segment",
149
+ "data-active": 'preview' === actions.viewMode || void 0,
150
+ onClick: ()=>actions.setViewMode('preview'),
151
+ children: viewLabels.preview
152
+ }),
153
+ /*#__PURE__*/ jsx("button", {
154
+ type: "button",
155
+ className: "ov-file-browser__segment",
156
+ "data-active": 'source' === actions.viewMode || void 0,
157
+ onClick: ()=>actions.setViewMode('source'),
158
+ children: viewLabels.source
159
+ })
160
+ ]
161
+ }) : null,
162
+ actions.canCopyContent || actions.canDownload ? /*#__PURE__*/ jsx("span", {
163
+ "aria-hidden": "true",
164
+ className: "ov-file-browser__detail-sep"
165
+ }) : null,
166
+ actions.canCopyContent ? /*#__PURE__*/ jsx("button", {
167
+ type: "button",
168
+ className: "ov-file-browser__detail-icon",
169
+ "aria-label": viewLabels.copyContent,
170
+ title: viewLabels.copyContent,
171
+ onClick: ()=>void actions.copyContent(),
172
+ children: /*#__PURE__*/ jsx(CopyIcon, {})
173
+ }) : null,
174
+ actions.canDownload ? /*#__PURE__*/ jsx("button", {
175
+ type: "button",
176
+ className: "ov-file-browser__detail-icon",
177
+ "aria-label": viewLabels.download,
178
+ title: viewLabels.download,
179
+ onClick: ()=>actions.download(),
180
+ children: /*#__PURE__*/ jsx(DownloadIcon, {})
181
+ }) : null
182
+ ]
183
+ })
184
+ }
185
+ };
186
+ });
187
+ }
188
+ const empty_state_namespaceObject = "data:image/png;base64,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";
189
+ function FileBrowserEmpty({ label }) {
190
+ return /*#__PURE__*/ jsxs("div", {
191
+ className: "ov-file-browser__empty",
192
+ children: [
193
+ /*#__PURE__*/ jsx("img", {
194
+ className: "ov-file-browser__empty-art",
195
+ src: empty_state_namespaceObject,
196
+ alt: "",
197
+ "aria-hidden": "true"
198
+ }),
199
+ /*#__PURE__*/ jsx("p", {
200
+ className: "ov-file-browser__empty-label",
201
+ children: label
202
+ })
203
+ ]
204
+ });
205
+ }
206
+ function FileBrowserFailure({ message, detail, retryLabel, onRetry }) {
207
+ return /*#__PURE__*/ jsxs("div", {
208
+ className: "ov-file-browser__failure",
209
+ role: "alert",
210
+ children: [
211
+ /*#__PURE__*/ jsx("p", {
212
+ className: "ov-file-browser__failure-title",
213
+ children: message
214
+ }),
215
+ detail ? /*#__PURE__*/ jsx("p", {
216
+ className: "ov-file-browser__failure-detail",
217
+ children: detail
218
+ }) : null,
219
+ /*#__PURE__*/ jsx("button", {
220
+ type: "button",
221
+ className: "ov-file-browser__failure-retry",
222
+ onClick: onRetry,
223
+ children: retryLabel
224
+ })
225
+ ]
226
+ });
227
+ }
228
+ const TREE_MIN_WIDTH = 200;
229
+ const DETAIL_MIN_WIDTH = 320;
230
+ const RESIZE_FOOTPRINT = 24;
231
+ const TREE_MAX_WIDTH = 520;
232
+ function resolveTreeMaxWidth(containerWidth) {
233
+ if (!containerWidth) return TREE_MAX_WIDTH;
234
+ return Math.max(TREE_MIN_WIDTH, Math.min(TREE_MAX_WIDTH, containerWidth - DETAIL_MIN_WIDTH - RESIZE_FOOTPRINT));
235
+ }
236
+ const file_browser_icons_SIZE = 16;
237
+ const strokeProps = {
238
+ width: file_browser_icons_SIZE,
239
+ height: file_browser_icons_SIZE,
240
+ viewBox: '0 0 48 48',
241
+ fill: 'none',
242
+ stroke: 'currentColor',
243
+ strokeWidth: 4,
244
+ 'aria-hidden': true,
245
+ focusable: 'false'
246
+ };
247
+ function SearchIcon() {
248
+ return /*#__PURE__*/ jsx("svg", {
249
+ ...strokeProps,
250
+ children: /*#__PURE__*/ jsx("path", {
251
+ d: "M33.072 33.071c6.248-6.248 6.248-16.379 0-22.627-6.249-6.249-16.38-6.249-22.628 0-6.248 6.248-6.248 16.379 0 22.627 6.248 6.248 16.38 6.248 22.628 0Zm0 0 8.485 8.485"
252
+ })
253
+ });
254
+ }
255
+ function RefreshIcon() {
256
+ return /*#__PURE__*/ jsx("svg", {
257
+ ...strokeProps,
258
+ children: /*#__PURE__*/ jsx("path", {
259
+ d: "M38.837 18C36.463 12.136 30.715 8 24 8 15.163 8 8 15.163 8 24s7.163 16 16 16c7.455 0 13.72-5.1 15.496-12M40 8v10H30"
260
+ })
261
+ });
262
+ }
263
+ function FileBrowserToolbar({ searchId, query, refreshing, canRefresh, placeholder, refreshLabel, onQueryChange, onRefresh }) {
264
+ return /*#__PURE__*/ jsxs("div", {
265
+ className: "ov-file-browser__toolbar",
266
+ children: [
267
+ /*#__PURE__*/ jsxs("label", {
268
+ className: "ov-file-browser__search",
269
+ htmlFor: searchId,
270
+ children: [
271
+ /*#__PURE__*/ jsx("span", {
272
+ className: "ov-file-browser__search-icon",
273
+ children: /*#__PURE__*/ jsx(SearchIcon, {})
274
+ }),
275
+ /*#__PURE__*/ jsx("input", {
276
+ id: searchId,
277
+ type: "search",
278
+ className: "ov-file-browser__search-input",
279
+ placeholder: placeholder,
280
+ value: query,
281
+ onChange: (event)=>onQueryChange(event.target.value)
282
+ })
283
+ ]
284
+ }),
285
+ /*#__PURE__*/ jsx(Tooltip, {
286
+ content: refreshLabel,
287
+ children: /*#__PURE__*/ jsx("button", {
288
+ type: "button",
289
+ className: [
290
+ 'ov-file-browser__refresh',
291
+ refreshing ? 'ov-file-browser__refresh--spinning' : ''
292
+ ].filter(Boolean).join(' '),
293
+ "aria-label": refreshLabel,
294
+ disabled: !canRefresh,
295
+ onClick: onRefresh,
296
+ children: /*#__PURE__*/ jsx(RefreshIcon, {})
297
+ })
298
+ })
299
+ ]
300
+ });
301
+ }
302
+ function fileTypeIcon(name) {
303
+ const Icon = getFileTypeIcon(name);
304
+ const key = resolveFileTypeIconKey(name);
305
+ return /*#__PURE__*/ jsx(Icon, {
306
+ className: "ov-file-tree__file-type-icon",
307
+ style: {
308
+ '--ov-file-tree-icon-light': getFileTypeColor(key, 'light'),
309
+ '--ov-file-tree-icon-dark': getFileTypeColor(key, 'dark')
310
+ }
311
+ });
312
+ }
313
+ function directoryIcon() {
314
+ return /*#__PURE__*/ jsx(FolderIcon, {
315
+ className: "ov-file-tree__file-type-icon"
316
+ });
317
+ }
318
+ function FileBrowserTreePane({ toolbarActions, searchId, browser, treeLabels, searchPlaceholder, refreshLabel, searchLoading, searchEmpty, searchErrorLabel, retryLabel }) {
319
+ return /*#__PURE__*/ jsxs(Fragment, {
12
320
  children: [
13
- /*#__PURE__*/ jsx("span", {
14
- className: "ov-file-browser__toolbar-button-icon",
15
- "aria-hidden": "true",
16
- children: icon
17
- }),
18
- /*#__PURE__*/ jsx("span", {
19
- className: "ov-file-browser__toolbar-button-label",
20
- children: children
321
+ toolbarActions ? /*#__PURE__*/ jsx("div", {
322
+ className: "ov-file-browser__entries",
323
+ children: toolbarActions
324
+ }) : null,
325
+ /*#__PURE__*/ jsx(FileBrowserToolbar, {
326
+ searchId: searchId,
327
+ query: browser.query,
328
+ refreshing: browser.refreshing,
329
+ canRefresh: browser.isReady,
330
+ placeholder: searchPlaceholder,
331
+ refreshLabel: refreshLabel,
332
+ onQueryChange: browser.actions.setQuery,
333
+ onRefresh: ()=>void browser.actions.refresh()
334
+ }),
335
+ /*#__PURE__*/ jsx("div", {
336
+ className: "ov-file-browser__tree-scroll",
337
+ children: /*#__PURE__*/ jsx(file_tree_FileTree, {
338
+ rows: browser.rows,
339
+ selectedId: browser.selectedId,
340
+ isReady: browser.isReady,
341
+ labels: treeLabels,
342
+ emptyFallback: browser.searching ? browser.searchError ? /*#__PURE__*/ jsxs("div", {
343
+ className: "ov-file-browser__hint ov-file-browser__hint--error",
344
+ children: [
345
+ /*#__PURE__*/ jsx("p", {
346
+ className: "ov-file-browser__failure-title",
347
+ children: searchErrorLabel
348
+ }),
349
+ /*#__PURE__*/ jsx("p", {
350
+ className: "ov-file-browser__failure-detail",
351
+ children: browser.searchError.message
352
+ }),
353
+ /*#__PURE__*/ jsx("button", {
354
+ type: "button",
355
+ className: "ov-file-browser__retry",
356
+ onClick: ()=>void browser.actions.refresh(),
357
+ children: retryLabel
358
+ })
359
+ ]
360
+ }) : /*#__PURE__*/ jsx("p", {
361
+ className: "ov-file-browser__hint",
362
+ children: browser.searchLoading ? searchLoading : searchEmpty
363
+ }) : void 0,
364
+ renderRowIcon: (row)=>fileTypeIcon(row.name),
365
+ operations: {
366
+ select: browser.actions.select,
367
+ toggleExpand: browser.actions.toggleExpand,
368
+ loadMore: browser.actions.loadMore,
369
+ retry: browser.actions.retry
370
+ }
371
+ })
21
372
  })
22
373
  ]
23
374
  });
24
375
  }
25
- function FileBrowser({ className, style, labels }) {
376
+ const DEFAULT_LABELS = {
377
+ empty: 'Select a file to preview',
378
+ error: 'Failed to load the directory',
379
+ retry: 'Retry',
380
+ refresh: 'Refresh',
381
+ searchPlaceholder: 'Search files ⌘+K...',
382
+ searchEmpty: 'No matching resources',
383
+ searchFailed: 'Failed to run the search',
384
+ loading: 'Loading…',
385
+ searchLoading: 'Searching…',
386
+ previewMode: 'Preview',
387
+ sourceMode: 'Source',
388
+ copyPath: 'Copy path',
389
+ copyContent: 'Copy content',
390
+ download: 'Download',
391
+ history: 'Version history',
392
+ viewSwitch: 'Switch view',
393
+ resizeTree: 'Resize the directory tree',
394
+ l0Summary: 'L0 Summary',
395
+ l1Overview: 'L1 Overview',
396
+ summaryEmpty: 'No summary generated yet',
397
+ summaryFailed: 'The summary could not be loaded.'
398
+ };
399
+ function resolveLabels(labels) {
400
+ return {
401
+ ...DEFAULT_LABELS,
402
+ ...labels,
403
+ tree: labels?.tree,
404
+ previewLabels: labels?.preview
405
+ };
406
+ }
407
+ function resolvePreviewLabels(text) {
408
+ return {
409
+ loading: text.loading,
410
+ copyPath: text.copyPath,
411
+ download: text.download,
412
+ ...text.previewLabels
413
+ };
414
+ }
415
+ const TREE_INFO_LABELS_ZH_CN = {
416
+ description: {
417
+ userRoot: '当前用户的上下文数据',
418
+ memories: '跨会话沉淀的长期记忆',
419
+ peers: '按应用或工作区隔离的上下文',
420
+ privacy: '密钥等敏感配置',
421
+ userResources: '该用户的私有知识资料',
422
+ sessions: '对话与任务运行记录',
423
+ skills: 'Agent 可用的技能与工具',
424
+ profile: '用户身份与背景',
425
+ preferences: '个性化偏好',
426
+ entities: '人物、项目、组织等实体',
427
+ events: '按日期归档的关键事件',
428
+ identity: 'Agent 名称与人设',
429
+ soul: 'Agent 行为准则与边界',
430
+ cases: '用于训练经验的交互案例',
431
+ trajectories: '可复用的任务执行轨迹',
432
+ experiences: '自动提炼的执行经验',
433
+ sharedResources: 'Agent 可引用的外部资料',
434
+ agentRoot: 'Agent 的能力、工具与经验',
435
+ agentEndpoints: '账号内共享的通信端点配置',
436
+ agentPayments: '账号内共享的支付能力配置',
437
+ agentSkills: '账号内可调用的技能定义',
438
+ agentTools: '账号内共享的工具配置',
439
+ memoryRoot: '长期记忆与累积信息',
440
+ resourceRoot: 'Agent 可引用的外部知识',
441
+ sessionRoot: '用户的原始会话记录',
442
+ systemRoot: '系统内置资源'
443
+ },
444
+ triggerBehavior: {
445
+ userRoot: '根据当前用户身份自动建立,无需手动创建',
446
+ memories: '提交会话、主动要求记住信息,或从会话中持续抽取',
447
+ peers: '以特定 peer 身份连接时建立,按 peer_id 隔离记忆与资料',
448
+ userResources: '导入资料时上传到该用户的私有资源目录',
449
+ sessions: '会话调用 OpenViking 时建立,消息、工具调用与归档持续写入',
450
+ skills: '作为个人技能被创建、安装或导入',
451
+ profile: '对话中出现稳定、明确的用户背景或工作方式',
452
+ preferences: '用户明确表达某个偏好、习惯或风格',
453
+ entities: '对话中出现值得保留的人物、项目或组织',
454
+ events: '对话中出现重要决定、承诺、安排、进展或结果',
455
+ identity: '首次记忆抽取时初始化,之后由写入操作更新',
456
+ soul: '首次记忆抽取时初始化,之后由写入操作调整',
457
+ cases: '提交了任务明确、执行结果可评估的会话',
458
+ trajectories: '提交了包含决策、工具调用或多步执行的任务',
459
+ experiences: '从任务案例与执行轨迹中提炼',
460
+ sharedResources: '导入资料时上传到共享资源空间',
461
+ agentEndpoints: '为账号注册集成端点时配置',
462
+ agentPayments: '为账号开通支付能力时配置',
463
+ agentSkills: '作为共享技能安装或导入,供所有 Agent 使用',
464
+ agentTools: '为账号注册工具时配置'
465
+ },
466
+ field: {
467
+ description: '说明',
468
+ triggerBehavior: '触发行为',
469
+ path: '路径'
470
+ }
471
+ };
472
+ function resolveTreeLabels(locale, hostLabels) {
473
+ if ('zh-CN' !== locale) return hostLabels;
474
+ const hostInfo = hostLabels?.info;
475
+ return {
476
+ ...hostLabels,
477
+ info: {
478
+ ...TREE_INFO_LABELS_ZH_CN,
479
+ ...hostInfo,
480
+ description: {
481
+ ...TREE_INFO_LABELS_ZH_CN.description,
482
+ ...hostInfo?.description
483
+ },
484
+ triggerBehavior: {
485
+ ...TREE_INFO_LABELS_ZH_CN.triggerBehavior,
486
+ ...hostInfo?.triggerBehavior
487
+ },
488
+ field: {
489
+ ...TREE_INFO_LABELS_ZH_CN.field,
490
+ ...hostInfo?.field
491
+ }
492
+ }
493
+ };
494
+ }
495
+ function useContainerWidth() {
496
+ const ref = useRef(null);
497
+ const [width, setWidth] = useState(0);
498
+ useEffect(()=>{
499
+ const element = ref.current;
500
+ if (!element) return;
501
+ const update = (next)=>setWidth((current)=>current === next ? current : next);
502
+ update(Math.round(element.getBoundingClientRect().width));
503
+ const observer = new ResizeObserver(([entry])=>{
504
+ if (entry) update(Math.round(entry.contentRect.width));
505
+ });
506
+ observer.observe(element);
507
+ return ()=>observer.disconnect();
508
+ }, []);
509
+ return {
510
+ ref,
511
+ width
512
+ };
513
+ }
514
+ const emptyDir = ()=>({
515
+ entries: [],
516
+ hasMore: false,
517
+ loading: false,
518
+ error: null
519
+ });
520
+ function mergePage(current, page, offset) {
521
+ const previous = current ?? emptyDir();
522
+ return {
523
+ entries: 0 === offset ? page.entries : [
524
+ ...previous.entries,
525
+ ...page.entries
526
+ ],
527
+ hasMore: page.hasMore,
528
+ loading: false,
529
+ error: null
530
+ };
531
+ }
532
+ function nameFromUri(uri) {
533
+ const trimmed = uri.replace(/\/+$/, '');
534
+ const index = trimmed.lastIndexOf('/');
535
+ const name = index < 0 ? trimmed : trimmed.slice(index + 1);
536
+ return name || trimmed;
537
+ }
538
+ function toEntryRow(entry, depth, expanded, index, busy) {
539
+ const isDir = true === entry.isDir;
540
+ return {
541
+ kind: 'entry',
542
+ id: void 0 === index ? entry.uri : `${entry.uri}#${index}`,
543
+ depth,
544
+ uri: entry.uri,
545
+ name: nameFromUri(entry.uri),
546
+ type: isDir ? 'directory' : 'file',
547
+ expanded: isDir ? expanded : void 0,
548
+ busy: busy || void 0
549
+ };
550
+ }
551
+ function toFileTab(entry, content, maxLines, icon, openParent) {
552
+ const name = nameFromUri(entry.uri);
553
+ return {
554
+ kind: 'file',
555
+ key: entry.uri,
556
+ title: name,
557
+ icon,
558
+ operations: {
559
+ openParent
560
+ },
561
+ source: {
562
+ content,
563
+ fileName: name,
564
+ path: entry.uri,
565
+ truncated: content.split('\n').length >= maxLines
566
+ }
567
+ };
568
+ }
569
+ function toDirectoryTab(uri, summary, labels, openParent, icon) {
570
+ const name = nameFromUri(uri);
571
+ const levelBody = (body, failure)=>void 0 === failure ? body : `> ${failure || labels.failure}`;
572
+ return {
573
+ kind: 'directory',
574
+ key: uri,
575
+ title: name,
576
+ icon,
577
+ levels: [
578
+ {
579
+ key: 'l0',
580
+ label: labels.l0,
581
+ source: {
582
+ content: levelBody(summary.abstract, summary.abstractError),
583
+ fileName: `${name}.md`,
584
+ path: uri,
585
+ fileType: 'markdown'
586
+ }
587
+ },
588
+ {
589
+ key: 'l1',
590
+ label: labels.l1,
591
+ source: {
592
+ content: levelBody(summary.overview, summary.overviewError),
593
+ fileName: `${name}.md`,
594
+ path: uri,
595
+ fileType: 'markdown'
596
+ }
597
+ }
598
+ ],
599
+ operations: {
600
+ openParent
601
+ }
602
+ };
603
+ }
604
+ function flattenTree(uri, depth, dirs, expanded) {
605
+ const dir = dirs[uri];
606
+ if (!dir) return [];
607
+ const rows = [];
608
+ for (const entry of dir.entries){
609
+ const isOpen = expanded.has(entry.uri);
610
+ const loadingChildren = isOpen && dirs[entry.uri]?.loading === true;
611
+ rows.push(toEntryRow(entry, depth, isOpen, void 0, loadingChildren));
612
+ if (isOpen) {
613
+ const children = flattenTree(entry.uri, depth + 1, dirs, expanded);
614
+ if (children.length > 0) rows.push(...children);
615
+ else if (loadingChildren) rows.push({
616
+ kind: 'loading',
617
+ id: `${entry.uri}::loading`,
618
+ depth: depth + 1,
619
+ parentId: entry.uri
620
+ });
621
+ else rows.push({
622
+ kind: 'empty',
623
+ id: `${entry.uri}::empty`,
624
+ depth: depth + 1,
625
+ parentId: entry.uri
626
+ });
627
+ }
628
+ }
629
+ if (dir.error) rows.push({
630
+ kind: 'error',
631
+ id: `${uri}::error`,
632
+ depth,
633
+ parentId: uri
634
+ });
635
+ else if (dir.hasMore) rows.push({
636
+ kind: 'load-more',
637
+ id: `${uri}::more`,
638
+ depth,
639
+ parentId: uri,
640
+ loading: dir.loading
641
+ });
642
+ return rows;
643
+ }
644
+ function isAbort(error) {
645
+ return 'object' == typeof error && null !== error && 'AbortError' === error.name;
646
+ }
647
+ function toError(cause) {
648
+ return cause instanceof Error ? cause : new Error(String(cause));
649
+ }
650
+ const BINARY_EXTENSIONS = new Set([
651
+ 'png',
652
+ 'jpg',
653
+ 'jpeg',
654
+ 'gif',
655
+ 'webp',
656
+ 'avif',
657
+ 'bmp',
658
+ 'ico',
659
+ 'svg',
660
+ 'pdf',
661
+ 'doc',
662
+ 'docx',
663
+ 'ppt',
664
+ 'pptx',
665
+ 'xls',
666
+ 'xlsx',
667
+ 'mp4',
668
+ 'webm',
669
+ 'mov',
670
+ 'mp3',
671
+ 'wav',
672
+ 'ogg',
673
+ 'm4a',
674
+ 'zip',
675
+ 'gz',
676
+ 'tar',
677
+ 'ovpack'
678
+ ]);
679
+ function isBinaryFile(name) {
680
+ const dot = name.lastIndexOf('.');
681
+ if (dot < 0 || dot === name.length - 1) return false;
682
+ return BINARY_EXTENSIONS.has(name.slice(dot + 1).toLowerCase());
683
+ }
684
+ const MIME_BY_EXTENSION = {
685
+ png: 'image/png',
686
+ jpg: 'image/jpeg',
687
+ jpeg: 'image/jpeg',
688
+ gif: 'image/gif',
689
+ webp: 'image/webp',
690
+ avif: 'image/avif',
691
+ bmp: 'image/bmp',
692
+ ico: 'image/x-icon',
693
+ svg: 'image/svg+xml',
694
+ pdf: 'application/pdf',
695
+ doc: 'application/msword',
696
+ docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
697
+ ppt: 'application/vnd.ms-powerpoint',
698
+ pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
699
+ xls: 'application/vnd.ms-excel',
700
+ xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
701
+ mp4: 'video/mp4',
702
+ webm: 'video/webm',
703
+ mov: 'video/quicktime',
704
+ mp3: 'audio/mpeg',
705
+ wav: 'audio/wav',
706
+ ogg: 'audio/ogg',
707
+ m4a: 'audio/mp4',
708
+ zip: 'application/zip',
709
+ gz: 'application/gzip',
710
+ tar: 'application/x-tar'
711
+ };
712
+ function mimeTypeOf(name) {
713
+ const dot = name.lastIndexOf('.');
714
+ if (dot < 0) return 'application/octet-stream';
715
+ return MIME_BY_EXTENSION[name.slice(dot + 1).toLowerCase()] ?? 'application/octet-stream';
716
+ }
717
+ function toBinaryTab(uri, name, file, icon, openParent) {
718
+ return {
719
+ kind: 'file',
720
+ key: uri,
721
+ title: name,
722
+ icon,
723
+ operations: {
724
+ openParent
725
+ },
726
+ source: {
727
+ file,
728
+ fileName: name,
729
+ path: uri
730
+ }
731
+ };
732
+ }
733
+ async function readDirectory(client, uri, options, labels, openParent) {
734
+ const read = (path)=>client.request({
735
+ method: 'GET',
736
+ path,
737
+ query: {
738
+ uri
739
+ },
740
+ options
741
+ }).then((value)=>({
742
+ ok: true,
743
+ text: 'string' == typeof value ? value : ''
744
+ })).catch((cause)=>({
745
+ ok: false,
746
+ cause
747
+ }));
748
+ const [abstractResult, overviewResult] = await Promise.all([
749
+ read(OV_PATHS.contentAbstract),
750
+ read(OV_PATHS.contentOverview)
751
+ ]);
752
+ const aborted = [
753
+ abstractResult,
754
+ overviewResult
755
+ ].find((result)=>!result.ok && isAbort(result.cause));
756
+ if (aborted && !aborted.ok) throw aborted.cause;
757
+ if (!abstractResult.ok && !overviewResult.ok) throw abstractResult.cause;
758
+ const reason = (result)=>result.ok ? void 0 : result.cause instanceof Error ? result.cause.message : String(result.cause);
759
+ return toDirectoryTab(uri, {
760
+ abstract: abstractResult.ok ? abstractResult.text : '',
761
+ overview: overviewResult.ok ? overviewResult.text : '',
762
+ abstractError: reason(abstractResult),
763
+ overviewError: reason(overviewResult)
764
+ }, labels, openParent, directoryIcon());
765
+ }
766
+ async function resolveIsDirectory(client, uri, options) {
767
+ try {
768
+ const result = await client.request({
769
+ method: 'GET',
770
+ path: OV_PATHS.fsStat,
771
+ query: {
772
+ uri
773
+ },
774
+ options
775
+ });
776
+ return result?.isDir === true || result?.is_dir === true;
777
+ } catch {
778
+ return false;
779
+ }
780
+ }
781
+ function abortError() {
782
+ const error = new Error('Aborted');
783
+ error.name = 'AbortError';
784
+ return error;
785
+ }
786
+ const MAX_LINES = 2000;
787
+ const DEFAULT_SUMMARY_LABELS = {
788
+ l0: 'L0 Summary',
789
+ l1: 'L1 Overview',
790
+ failure: 'The summary could not be loaded.'
791
+ };
792
+ function useFsPreview({ client, uri, resourceType = 'file', labels = DEFAULT_SUMMARY_LABELS, openParent, generation = 0, requestOptions }) {
793
+ const [tabs, setTabs] = useState(null);
794
+ const [activeKey, setActiveKey] = useState(null);
795
+ const [error, setError] = useState(null);
796
+ const [footer, setFooter] = useState(void 0);
797
+ useEffect(()=>{
798
+ if (!client || !uri) {
799
+ setTabs(null);
800
+ setActiveKey(null);
801
+ setError(null);
802
+ setFooter(void 0);
803
+ return;
804
+ }
805
+ const controller = new AbortController();
806
+ setTabs([
807
+ loadingTab(uri, 'file' !== resourceType)
808
+ ]);
809
+ setActiveKey(uri);
810
+ setActiveKey(null);
811
+ setError(null);
812
+ setFooter(void 0);
813
+ const options = {
814
+ ...requestOptions,
815
+ signal: controller.signal
816
+ };
817
+ const read = (async ()=>{
818
+ const isDir = 'unknown' === resourceType ? await resolveIsDirectory(client, uri, options) : 'directory' === resourceType;
819
+ if (controller.signal.aborted) throw abortError();
820
+ return isDir ? readDirectory(client, uri, options, labels, openParent) : readFile(client, uri, options, openParent);
821
+ })();
822
+ read.then((tab)=>{
823
+ if (controller.signal.aborted) return;
824
+ setTabs([
825
+ tab
826
+ ]);
827
+ setActiveKey(tab.key);
828
+ const body = 'directory' === tab.kind ? tab.levels[0].source.content ?? '' : 'file' === tab.kind ? tab.source.content ?? '' : '';
829
+ setFooter(`${body.length} characters`);
830
+ }, (cause)=>{
831
+ if (isAbort(cause) || controller.signal.aborted) return;
832
+ setTabs([]);
833
+ setError(cause instanceof Error ? cause : new Error(String(cause)));
834
+ });
835
+ return ()=>controller.abort();
836
+ }, [
837
+ client,
838
+ uri,
839
+ resourceType,
840
+ labels,
841
+ openParent,
842
+ generation,
843
+ requestOptions
844
+ ]);
845
+ return {
846
+ tabs,
847
+ activeKey,
848
+ error,
849
+ footer,
850
+ setActiveKey
851
+ };
852
+ }
853
+ function loadingTab(uri, isDirectory) {
854
+ if (isDirectory) return {
855
+ kind: 'directory',
856
+ key: uri,
857
+ loading: true,
858
+ levels: [
859
+ {
860
+ key: 'l0',
861
+ label: '',
862
+ source: {
863
+ fileName: `${nameFromUri(uri)}.md`,
864
+ path: uri,
865
+ fileType: 'markdown',
866
+ content: ''
867
+ }
868
+ },
869
+ {
870
+ key: 'l1',
871
+ label: '',
872
+ source: {
873
+ fileName: `${nameFromUri(uri)}.md`,
874
+ path: uri,
875
+ fileType: 'markdown',
876
+ content: ''
877
+ }
878
+ }
879
+ ]
880
+ };
881
+ return {
882
+ kind: 'file',
883
+ key: uri,
884
+ loading: true,
885
+ source: {
886
+ fileName: nameFromUri(uri),
887
+ path: uri,
888
+ content: ''
889
+ }
890
+ };
891
+ }
892
+ async function readFile(client, uri, options, openParent) {
893
+ const name = nameFromUri(uri);
894
+ const icon = fileTypeIcon(name);
895
+ if (isBinaryFile(name)) {
896
+ const blob = await client.request({
897
+ method: 'GET',
898
+ path: OV_PATHS.contentDownload,
899
+ query: {
900
+ uri
901
+ },
902
+ responseType: 'blob',
903
+ options
904
+ });
905
+ const typed = new Blob([
906
+ blob
907
+ ], {
908
+ type: mimeTypeOf(name)
909
+ });
910
+ return toBinaryTab(uri, name, typed, icon, openParent);
911
+ }
912
+ const content = await client.request({
913
+ method: 'GET',
914
+ path: OV_PATHS.contentRead,
915
+ query: {
916
+ uri,
917
+ limit: MAX_LINES
918
+ },
919
+ options
920
+ });
921
+ return toFileTab({
922
+ uri
923
+ }, 'string' == typeof content ? content : '', MAX_LINES, icon, openParent);
924
+ }
925
+ function mergeFindResult(result) {
926
+ const seen = new Set();
927
+ const entries = [];
928
+ for (const group of [
929
+ result?.memories,
930
+ result?.resources,
931
+ result?.skills
932
+ ])for (const item of group ?? []){
933
+ const uri = item?.uri;
934
+ if (!(!uri || seen.has(uri))) {
935
+ seen.add(uri);
936
+ entries.push({
937
+ uri,
938
+ isDir: false,
939
+ abstract: item.abstract?.trim() || void 0
940
+ });
941
+ }
942
+ }
943
+ return entries;
944
+ }
945
+ const LIMIT = 20;
946
+ function useFsSearch({ client, query, targetUri, generation = 0, requestOptions }) {
947
+ const [results, setResults] = useState(null);
948
+ const [loading, setLoading] = useState(false);
949
+ const [error, setError] = useState(null);
950
+ useEffect(()=>{
951
+ if (!client || !query) {
952
+ setResults(null);
953
+ setLoading(false);
954
+ setError(null);
955
+ return;
956
+ }
957
+ const controller = new AbortController();
958
+ setLoading(true);
959
+ setError(null);
960
+ client.request({
961
+ method: 'POST',
962
+ path: OV_PATHS.searchFind,
963
+ body: {
964
+ query,
965
+ target_uri: targetUri,
966
+ limit: LIMIT
967
+ },
968
+ options: {
969
+ ...requestOptions,
970
+ signal: controller.signal
971
+ }
972
+ }).then((result)=>{
973
+ if (controller.signal.aborted) return;
974
+ setResults(mergeFindResult(result));
975
+ setLoading(false);
976
+ }, (cause)=>{
977
+ if (isAbort(cause) || controller.signal.aborted) return;
978
+ setResults([]);
979
+ setError(toError(cause));
980
+ setLoading(false);
981
+ });
982
+ return ()=>controller.abort();
983
+ }, [
984
+ client,
985
+ query,
986
+ targetUri,
987
+ generation,
988
+ requestOptions
989
+ ]);
990
+ return {
991
+ results,
992
+ loading,
993
+ error
994
+ };
995
+ }
996
+ function knownDirectories(rootUri, dirs) {
997
+ const known = new Set([
998
+ rootUri
999
+ ]);
1000
+ for (const [parent, level] of Object.entries(dirs)){
1001
+ known.add(parent);
1002
+ for (const entry of level.entries)if (true === entry.isDir) known.add(entry.uri);
1003
+ }
1004
+ return known;
1005
+ }
1006
+ function knownFiles(dirs) {
1007
+ const known = new Set();
1008
+ for (const level of Object.values(dirs))for (const entry of level.entries)if (true !== entry.isDir) known.add(entry.uri);
1009
+ return known;
1010
+ }
1011
+ function useKnownFile(dirs) {
1012
+ const files = useMemo(()=>knownFiles(dirs), [
1013
+ dirs
1014
+ ]);
1015
+ return useCallback((uri)=>files.has(uri), [
1016
+ files
1017
+ ]);
1018
+ }
1019
+ const ids = new WeakMap();
1020
+ let nextId = 1;
1021
+ function idOf(value) {
1022
+ if (!value) return 0;
1023
+ const existing = ids.get(value);
1024
+ if (void 0 !== existing) return existing;
1025
+ const assigned = nextId++;
1026
+ ids.set(value, assigned);
1027
+ return assigned;
1028
+ }
1029
+ function fieldKey(value) {
1030
+ if (void 0 === value) return 'inherit';
1031
+ if ('function' == typeof value) return `fn#${idOf(value)}`;
1032
+ return `value:${value}`;
1033
+ }
1034
+ function scopeKeyOf(client, options, rootUri) {
1035
+ return JSON.stringify([
1036
+ idOf(client),
1037
+ void 0 === rootUri ? 'inherit-root' : `root:${rootUri}`,
1038
+ options?.baseURL === void 0 ? 'inherit-base' : `base:${options.baseURL}`,
1039
+ fieldKey(options?.apiKey),
1040
+ fieldKey(options?.accountId),
1041
+ fieldKey(options?.userId),
1042
+ fieldKey(options?.resourceId)
1043
+ ]);
1044
+ }
1045
+ function useRequestScope(client, requestOptions, rootUri) {
1046
+ const scopeKey = scopeKeyOf(client, requestOptions, rootUri);
1047
+ const scopeRef = useRef({
1048
+ key: scopeKey,
1049
+ controller: new AbortController()
1050
+ });
1051
+ const handleRef = useRef({
1052
+ current: ()=>scopeRef.current
1053
+ });
1054
+ useEffect(()=>{
1055
+ const current = scopeRef.current;
1056
+ if (current.key === scopeKey) return;
1057
+ current.controller.abort();
1058
+ scopeRef.current = {
1059
+ key: scopeKey,
1060
+ controller: new AbortController()
1061
+ };
1062
+ }, [
1063
+ scopeKey
1064
+ ]);
1065
+ useEffect(()=>()=>{
1066
+ scopeRef.current.controller.abort();
1067
+ scopeRef.current = {
1068
+ key: scopeRef.current.key,
1069
+ controller: new AbortController()
1070
+ };
1071
+ }, []);
1072
+ return handleRef.current;
1073
+ }
1074
+ function expandChain(rootUri, targetUri) {
1075
+ if (!targetUri) return [];
1076
+ const base = rootUri.endsWith('/') ? rootUri : `${rootUri}/`;
1077
+ if (!targetUri.startsWith(base)) return [];
1078
+ const rest = targetUri.slice(base.length).split('/').filter(Boolean);
1079
+ return rest.map((_, index)=>`${base}${rest.slice(0, index + 1).join('/')}`);
1080
+ }
1081
+ const PAGE_SIZE = 200;
1082
+ async function loadPage(client, uri, offset, signal, requestOptions) {
1083
+ const envelope = await client.requestEnvelope({
1084
+ method: 'GET',
1085
+ path: OV_PATHS.fsLs,
1086
+ query: {
1087
+ uri,
1088
+ output: 'agent',
1089
+ node_limit: PAGE_SIZE,
1090
+ offset
1091
+ },
1092
+ options: {
1093
+ ...requestOptions,
1094
+ signal
1095
+ }
1096
+ });
1097
+ return {
1098
+ entries: envelope.result ?? [],
1099
+ hasMore: envelope.hasMore
1100
+ };
1101
+ }
1102
+ function useFsTree({ client, rootUri, defaultExpandedUri, requestOptions }) {
1103
+ const [dirs, setDirs] = useState({});
1104
+ const [expanded, setExpanded] = useState(()=>new Set([
1105
+ rootUri
1106
+ ]));
1107
+ const [isReady, setReady] = useState(false);
1108
+ const [error, setError] = useState(null);
1109
+ const dirsRef = useRef(dirs);
1110
+ dirsRef.current = dirs;
1111
+ const expandedRef = useRef(expanded);
1112
+ expandedRef.current = expanded;
1113
+ useEffect(()=>{
1114
+ if (!client) return;
1115
+ const controller = new AbortController();
1116
+ setReady(false);
1117
+ setError(null);
1118
+ setExpanded(new Set([
1119
+ rootUri
1120
+ ]));
1121
+ setDirs({
1122
+ [rootUri]: {
1123
+ ...emptyDir(),
1124
+ loading: true
1125
+ }
1126
+ });
1127
+ const run = async ()=>{
1128
+ const root = await loadPage(client, rootUri, 0, controller.signal, requestOptions);
1129
+ if (controller.signal.aborted) return;
1130
+ setDirs({
1131
+ [rootUri]: mergePage(void 0, root, 0)
1132
+ });
1133
+ const chain = expandChain(rootUri, defaultExpandedUri);
1134
+ for (const uri of chain){
1135
+ let page;
1136
+ try {
1137
+ page = await loadPage(client, uri, 0, controller.signal, requestOptions);
1138
+ } catch (cause) {
1139
+ if (isAbort(cause) || controller.signal.aborted) return;
1140
+ break;
1141
+ }
1142
+ if (controller.signal.aborted) return;
1143
+ setExpanded((prev)=>new Set(prev).add(uri));
1144
+ setDirs((prev)=>({
1145
+ ...prev,
1146
+ [uri]: mergePage(prev[uri], page, 0)
1147
+ }));
1148
+ }
1149
+ if (controller.signal.aborted) return;
1150
+ setReady(true);
1151
+ };
1152
+ run().catch((cause)=>{
1153
+ if (isAbort(cause) || controller.signal.aborted) return;
1154
+ const failure = toError(cause);
1155
+ setError(failure);
1156
+ setDirs({
1157
+ [rootUri]: {
1158
+ ...emptyDir(),
1159
+ loading: false,
1160
+ error: failure
1161
+ }
1162
+ });
1163
+ setReady(true);
1164
+ });
1165
+ return ()=>controller.abort();
1166
+ }, [
1167
+ client,
1168
+ rootUri,
1169
+ defaultExpandedUri,
1170
+ requestOptions
1171
+ ]);
1172
+ const scope = useRequestScope(client, requestOptions, rootUri);
1173
+ const state = useMemo(()=>{
1174
+ const fetchPage = async (uri, offset)=>{
1175
+ if (!client) return;
1176
+ const current = scope.current();
1177
+ const { signal } = current.controller;
1178
+ if (signal.aborted) return;
1179
+ if (uri === rootUri) setError(null);
1180
+ setDirs((prev)=>({
1181
+ ...prev,
1182
+ [uri]: {
1183
+ ...prev[uri] ?? emptyDir(),
1184
+ loading: true,
1185
+ error: null
1186
+ }
1187
+ }));
1188
+ try {
1189
+ const page = await loadPage(client, uri, offset, signal, requestOptions);
1190
+ if (signal.aborted || scope.current().key !== current.key) return;
1191
+ setDirs((prev)=>({
1192
+ ...prev,
1193
+ [uri]: mergePage(prev[uri], page, offset)
1194
+ }));
1195
+ } catch (cause) {
1196
+ if (isAbort(cause) || signal.aborted) return;
1197
+ const failure = toError(cause);
1198
+ if (uri === rootUri) setError(failure);
1199
+ setDirs((prev)=>({
1200
+ ...prev,
1201
+ [uri]: {
1202
+ ...prev[uri] ?? emptyDir(),
1203
+ loading: false,
1204
+ error: failure
1205
+ }
1206
+ }));
1207
+ }
1208
+ };
1209
+ return {
1210
+ open: async (uri)=>{
1211
+ setExpanded((prev)=>new Set(prev).add(uri));
1212
+ if (!dirsRef.current[uri]) await fetchPage(uri, 0);
1213
+ },
1214
+ toggleExpand: async (row)=>{
1215
+ const isOpen = expandedRef.current.has(row.uri);
1216
+ setExpanded((prev)=>{
1217
+ const next = new Set(prev);
1218
+ if (isOpen) next.delete(row.uri);
1219
+ else next.add(row.uri);
1220
+ return next;
1221
+ });
1222
+ if (!isOpen && !dirsRef.current[row.uri]) await fetchPage(row.uri, 0);
1223
+ },
1224
+ loadMore: (parentId)=>fetchPage(parentId, dirsRef.current[parentId]?.entries.length ?? 0),
1225
+ retry: (parentId)=>fetchPage(parentId, 0),
1226
+ refresh: async ()=>{
1227
+ if (!client) return;
1228
+ const current = scope.current();
1229
+ const open = [
1230
+ ...expandedRef.current
1231
+ ];
1232
+ setError(null);
1233
+ setDirs({});
1234
+ for (const uri of open){
1235
+ if (scope.current().key !== current.key) return;
1236
+ await fetchPage(uri, 0);
1237
+ }
1238
+ }
1239
+ };
1240
+ }, [
1241
+ client,
1242
+ rootUri,
1243
+ requestOptions,
1244
+ scope
1245
+ ]);
1246
+ const rows = useMemo(()=>flattenTree(rootUri, 0, dirs, expanded), [
1247
+ rootUri,
1248
+ dirs,
1249
+ expanded
1250
+ ]);
1251
+ const directoryUris = useMemo(()=>knownDirectories(rootUri, dirs), [
1252
+ rootUri,
1253
+ dirs
1254
+ ]);
1255
+ const isKnownFile = useKnownFile(dirs);
1256
+ return {
1257
+ rows,
1258
+ isReady,
1259
+ error,
1260
+ directoryUris,
1261
+ isKnownFile,
1262
+ ...state
1263
+ };
1264
+ }
1265
+ function useFileBrowser({ rootUri, controlled = false, summaryLabels, defaultExpandedUri, currentUri, requestOptions, onUriChange }) {
1266
+ const client = useOvClient();
1267
+ const [query, setQuery] = useState('');
1268
+ const [pendingUri, setPendingUri] = useState(currentUri);
1269
+ const [refreshing, setRefreshing] = useState(false);
1270
+ const [refreshGeneration, setRefreshGeneration] = useState(0);
1271
+ const tree = useFsTree({
1272
+ client,
1273
+ rootUri,
1274
+ defaultExpandedUri,
1275
+ requestOptions
1276
+ });
1277
+ const search = useFsSearch({
1278
+ client,
1279
+ query,
1280
+ targetUri: rootUri,
1281
+ generation: refreshGeneration,
1282
+ requestOptions
1283
+ });
1284
+ const activeUri = controlled ? currentUri : pendingUri;
1285
+ const resourceType = null === activeUri ? 'file' : tree.directoryUris.has(activeUri) ? 'directory' : tree.isKnownFile(activeUri) ? 'file' : 'unknown';
1286
+ const openTree = tree.open;
1287
+ const notifyUriChange = useRef(onUriChange);
1288
+ notifyUriChange.current = onUriChange;
1289
+ const openParent = useMemo(()=>async (uri)=>{
1290
+ setPendingUri(uri);
1291
+ notifyUriChange.current(uri);
1292
+ await openTree(uri);
1293
+ }, [
1294
+ openTree
1295
+ ]);
1296
+ const preview = useFsPreview({
1297
+ client,
1298
+ uri: activeUri,
1299
+ resourceType,
1300
+ labels: summaryLabels,
1301
+ openParent,
1302
+ generation: refreshGeneration,
1303
+ requestOptions
1304
+ });
1305
+ const rows = useMemo(()=>{
1306
+ if (null === search.results) return tree.rows;
1307
+ return search.results.map((entry, index)=>toEntryRow(entry, 0, false, index));
1308
+ }, [
1309
+ search.results,
1310
+ tree.rows
1311
+ ]);
1312
+ const selectedId = useMemo(()=>{
1313
+ if (!activeUri || null === search.results) return activeUri;
1314
+ const index = search.results.findIndex((entry)=>entry.uri === activeUri);
1315
+ return index < 0 ? activeUri : `${activeUri}#${index}`;
1316
+ }, [
1317
+ activeUri,
1318
+ search.results
1319
+ ]);
1320
+ const { open, toggleExpand, loadMore, retry, refresh } = tree;
1321
+ const actions = useMemo(()=>({
1322
+ select: async (row)=>{
1323
+ setPendingUri(row.uri);
1324
+ notifyUriChange.current(row.uri);
1325
+ if ('directory' === row.type) await open(row.uri);
1326
+ },
1327
+ toggleExpand,
1328
+ loadMore: async (row)=>{
1329
+ const parentId = 'parentId' in row ? row.parentId : void 0;
1330
+ if (parentId) await loadMore(parentId);
1331
+ },
1332
+ retry: async (row)=>{
1333
+ const parentId = 'parentId' in row ? row.parentId : void 0;
1334
+ if (parentId) await retry(parentId);
1335
+ },
1336
+ refresh: async ()=>{
1337
+ setRefreshing(true);
1338
+ try {
1339
+ setRefreshGeneration((generation)=>generation + 1);
1340
+ await refresh();
1341
+ } finally{
1342
+ setRefreshing(false);
1343
+ }
1344
+ },
1345
+ setPreviewKey: preview.setActiveKey,
1346
+ setQuery
1347
+ }), [
1348
+ preview.setActiveKey,
1349
+ open,
1350
+ toggleExpand,
1351
+ loadMore,
1352
+ retry,
1353
+ refresh
1354
+ ]);
1355
+ return {
1356
+ rows,
1357
+ selectedId,
1358
+ currentUri: activeUri,
1359
+ isReady: tree.isReady,
1360
+ error: tree.error ?? search.error ?? preview.error,
1361
+ treeError: tree.error,
1362
+ previewError: preview.error,
1363
+ searchError: search.error,
1364
+ previewTabs: preview.tabs,
1365
+ previewKey: preview.activeKey,
1366
+ previewFooter: preview.footer,
1367
+ query,
1368
+ searching: null !== search.results,
1369
+ searchLoading: search.loading,
1370
+ refreshing,
1371
+ actions
1372
+ };
1373
+ }
1374
+ function FileBrowser({ uri, defaultUri, rootUri = 'viking://', defaultExpandedUri, locale, toolbarActions, onUriChange, labels, requestOptions, className, style, ...rest }) {
1375
+ const [internalUri, setInternalUri] = useState(()=>defaultUri ?? null);
1376
+ const [preferredTreeWidth, setPreferredTreeWidth] = useState(352);
1377
+ const searchId = useId();
1378
+ const isControlled = void 0 !== uri;
1379
+ const currentUri = isControlled ? uri : internalUri;
1380
+ const text = resolveLabels(labels);
1381
+ const { ref: layoutRef, width: layoutWidth } = useContainerWidth();
1382
+ const treeMaxWidth = resolveTreeMaxWidth(layoutWidth);
1383
+ const treeWidth = Math.min(preferredTreeWidth, treeMaxWidth);
1384
+ const changeUri = useCallback((next)=>{
1385
+ if (!isControlled) setInternalUri(next);
1386
+ onUriChange?.(next);
1387
+ }, [
1388
+ isControlled,
1389
+ onUriChange
1390
+ ]);
1391
+ const summaryLabels = useMemo(()=>({
1392
+ l0: text.l0Summary,
1393
+ l1: text.l1Overview,
1394
+ failure: text.summaryFailed
1395
+ }), [
1396
+ text.l0Summary,
1397
+ text.l1Overview,
1398
+ text.summaryFailed
1399
+ ]);
1400
+ const previewLabels = useMemo(()=>resolvePreviewLabels(resolveLabels(labels)), [
1401
+ labels
1402
+ ]);
1403
+ const treeLabels = useMemo(()=>resolveTreeLabels(locale, text.tree), [
1404
+ locale,
1405
+ text.tree
1406
+ ]);
1407
+ const browser = useFileBrowser({
1408
+ rootUri,
1409
+ controlled: isControlled,
1410
+ summaryLabels,
1411
+ defaultExpandedUri,
1412
+ currentUri,
1413
+ requestOptions,
1414
+ onUriChange: changeUri
1415
+ });
26
1416
  return /*#__PURE__*/ jsxs("div", {
1417
+ ...rest,
1418
+ ref: layoutRef,
27
1419
  className: [
28
- 'ov-module-placeholder',
1420
+ 'ov-file-browser',
29
1421
  className
30
1422
  ].filter(Boolean).join(' '),
31
- style: style,
1423
+ style: {
1424
+ ...style,
1425
+ '--ov-file-browser-tree-width': `${treeWidth}px`
1426
+ },
32
1427
  children: [
33
- /*#__PURE__*/ jsx("p", {
34
- className: "ov-module-placeholder__title",
35
- children: labels?.title ?? 'File browser'
1428
+ /*#__PURE__*/ jsx("div", {
1429
+ className: "ov-file-browser__tree",
1430
+ children: /*#__PURE__*/ jsx(FileBrowserTreePane, {
1431
+ toolbarActions: toolbarActions,
1432
+ searchId: searchId,
1433
+ browser: browser,
1434
+ treeLabels: treeLabels,
1435
+ searchPlaceholder: text.searchPlaceholder,
1436
+ refreshLabel: text.refresh,
1437
+ searchLoading: text.searchLoading,
1438
+ searchEmpty: text.searchEmpty,
1439
+ searchErrorLabel: text.searchFailed,
1440
+ retryLabel: text.retry
1441
+ })
36
1442
  }),
37
- /*#__PURE__*/ jsx("p", {
38
- className: "ov-module-placeholder__description",
39
- children: labels?.description ?? 'Placeholder. Functionality is not available yet.'
1443
+ /*#__PURE__*/ jsx(ResizableHandle, {
1444
+ label: text.resizeTree,
1445
+ min: 200,
1446
+ max: treeMaxWidth,
1447
+ value: treeWidth,
1448
+ onResize: setPreferredTreeWidth,
1449
+ className: "ov-file-browser__resizer"
1450
+ }),
1451
+ browser.previewTabs && browser.previewTabs.length > 0 ? /*#__PURE__*/ jsx(FileBrowserDetail, {
1452
+ tabs: browser.previewTabs,
1453
+ activeKey: browser.previewKey,
1454
+ locale: locale,
1455
+ labels: previewLabels,
1456
+ footer: browser.previewFooter,
1457
+ viewLabels: {
1458
+ preview: text.previewMode,
1459
+ source: text.sourceMode,
1460
+ copyPath: text.copyPath,
1461
+ copyContent: text.copyContent,
1462
+ download: text.download,
1463
+ viewSwitch: text.viewSwitch
1464
+ },
1465
+ onActiveKeyChange: browser.actions.setPreviewKey
1466
+ }) : browser.currentUri && browser.previewError ? /*#__PURE__*/ jsx("div", {
1467
+ className: "ov-file-browser__detail",
1468
+ children: /*#__PURE__*/ jsx(FileBrowserFailure, {
1469
+ message: text.error,
1470
+ detail: browser.previewError.message,
1471
+ retryLabel: text.retry,
1472
+ onRetry: ()=>void browser.actions.refresh()
1473
+ })
1474
+ }) : /*#__PURE__*/ jsx("div", {
1475
+ className: "ov-file-browser__detail",
1476
+ children: /*#__PURE__*/ jsx(FileBrowserEmpty, {
1477
+ label: text.empty
1478
+ })
40
1479
  })
41
1480
  ]
42
1481
  });
43
1482
  }
44
- export { FileBrowser, FileBrowserToolbarButton };
1483
+ export { FileBrowser, useFileBrowser };