@jaxzhou/dsh-file-explorer 0.1.0

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/lib/client.js ADDED
@@ -0,0 +1,1073 @@
1
+ window.__ModuleLoader__.load({ id: "@jaxzhou/dsh-file-explorer", factory: (require) => {
2
+ var module = { exports: {} }; var exports = module.exports;
3
+ "use strict";
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name2 in all)
10
+ __defProp(target, name2, { get: all[name2], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ // src/client/index.ts
23
+ var index_exports = {};
24
+ __export(index_exports, {
25
+ FILES_VIEW_ID: () => FILES_VIEW_ID,
26
+ apply: () => apply,
27
+ extensionOf: () => extensionOf,
28
+ hasSourceToggle: () => hasSourceToggle,
29
+ inject: () => inject,
30
+ name: () => name,
31
+ parseJsonDocument: () => parseJsonDocument,
32
+ previewFormatFor: () => previewFormatFor,
33
+ previewLines: () => previewLines
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+
37
+ // src/client/FilesView.tsx
38
+ var import_react = require("react");
39
+ var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
40
+
41
+ // src/client/format.ts
42
+ var IMAGE_MEDIA_TYPES = /* @__PURE__ */ new Map([
43
+ ["png", "image/png"],
44
+ ["apng", "image/apng"],
45
+ ["jpg", "image/jpeg"],
46
+ ["jpeg", "image/jpeg"],
47
+ ["jfif", "image/jpeg"],
48
+ ["gif", "image/gif"],
49
+ ["webp", "image/webp"],
50
+ ["avif", "image/avif"],
51
+ ["bmp", "image/bmp"],
52
+ ["ico", "image/x-icon"],
53
+ // An SVG draws as an image here; `<img>` neither runs its scripts nor lets it
54
+ // reach the application origin, so the markup stays inert.
55
+ ["svg", "image/svg+xml"]
56
+ ]);
57
+ var GRAMMAR_EXTENSIONS = {
58
+ typescript: ["ts", "tsx", "mts", "cts", "js", "jsx", "mjs", "cjs"],
59
+ shellscript: ["sh", "bash", "zsh", "ksh", "shell"],
60
+ json: ["json", "jsonc", "jsonl", "ndjson", "map", "webmanifest"],
61
+ python: ["py", "pyw", "pyi"],
62
+ ruby: ["rb", "rake", "gemspec", "ru"],
63
+ go: ["go"],
64
+ rust: ["rs"],
65
+ java: ["java"],
66
+ c: ["c", "h"],
67
+ cpp: ["cc", "cpp", "cxx", "hh", "hpp", "hxx", "ipp"],
68
+ csharp: ["cs", "csx"],
69
+ kotlin: ["kt", "kts"],
70
+ swift: ["swift"],
71
+ php: ["php", "phtml", "php3", "php4", "php5"],
72
+ yaml: ["yaml", "yml"],
73
+ toml: ["toml"],
74
+ ini: ["ini", "cfg", "conf", "properties", "desktop", "service"],
75
+ markdown: ["md", "markdown", "mkd", "mdown", "mdwn"],
76
+ mdx: ["mdx"],
77
+ html: ["html", "htm", "xhtml", "shtml"],
78
+ css: ["css"],
79
+ scss: ["scss"],
80
+ less: ["less"],
81
+ sql: ["sql", "ddl", "dml"],
82
+ xml: ["xml", "xsd", "xsl", "xslt", "rss", "atom", "plist"],
83
+ lua: ["lua"]
84
+ };
85
+ var GRAMMAR_BY_EXTENSION = new Map(Object.entries(GRAMMAR_EXTENSIONS).flatMap(([grammar, suffixes]) => suffixes.map((suffix) => [suffix, grammar])));
86
+ function extensionOf(path) {
87
+ const normalized = path.replaceAll("\\", "/");
88
+ const name2 = normalized.slice(normalized.lastIndexOf("/") + 1);
89
+ const at = name2.lastIndexOf(".");
90
+ if (at <= 0 || at === name2.length - 1) return void 0;
91
+ return name2.slice(at + 1).toLowerCase();
92
+ }
93
+ function previewFormatFor(path) {
94
+ const extension = extensionOf(path);
95
+ const mediaType = extension === void 0 ? void 0 : IMAGE_MEDIA_TYPES.get(extension);
96
+ if (mediaType !== void 0) return { kind: "image", lang: void 0, mediaType };
97
+ const lang = extension === void 0 ? void 0 : GRAMMAR_BY_EXTENSION.get(extension);
98
+ if (lang === void 0) return { kind: "text", lang: void 0, mediaType: void 0 };
99
+ if (lang === "json") return { kind: "json", lang, mediaType: void 0 };
100
+ if (lang === "markdown") return { kind: "markdown", lang, mediaType: void 0 };
101
+ return { kind: "code", lang, mediaType: void 0 };
102
+ }
103
+ function hasSourceToggle(format) {
104
+ return format.kind === "markdown" || format.kind === "json";
105
+ }
106
+
107
+ // src/client/FilesView.tsx
108
+ var import_jsx_runtime = require("react/jsx-runtime");
109
+ var byName = new Intl.Collator(void 0, { numeric: true, sensitivity: "base" });
110
+ function orderEntries(entries) {
111
+ return [...entries].sort((left, right) => {
112
+ const group = Number(right.type === "directory") - Number(left.type === "directory");
113
+ return group !== 0 ? group : byName.compare(left.name, right.name);
114
+ });
115
+ }
116
+ function childPath(parent, name2) {
117
+ return `${parent.replace(/[/\\]+$/, "")}/${name2}`;
118
+ }
119
+ function pathParts(path) {
120
+ const at = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
121
+ if (at < 0) return { directory: "", name: path };
122
+ return { directory: path.slice(0, at + 1), name: path.slice(at + 1) };
123
+ }
124
+ function previewLines(page) {
125
+ return page.lines === 0 ? [] : page.text.split("\n");
126
+ }
127
+ function parseJsonDocument(text) {
128
+ let value;
129
+ try {
130
+ value = JSON.parse(text);
131
+ } catch {
132
+ return void 0;
133
+ }
134
+ return typeof value === "object" && value !== null ? value : void 0;
135
+ }
136
+ function treeFailureLine(t, failure) {
137
+ switch (failure.code) {
138
+ case "workspace-file/not-found":
139
+ return t("tree.error.notFound");
140
+ case "workspace-file/outside-workspace":
141
+ return t("tree.error.outsideWorkspace");
142
+ case "workspace-file/not-directory":
143
+ return t("tree.error.notDirectory");
144
+ // Carrier and unclassified host failures reach the reader as themselves:
145
+ // this tree knows nothing useful to add to a transport-level message.
146
+ default:
147
+ return t("tree.error.unavailable", { message: failure.message });
148
+ }
149
+ }
150
+ function previewFailureLine(t, failure) {
151
+ switch (failure.code) {
152
+ case "workspace-file/not-found":
153
+ return t("preview.error.notFound");
154
+ case "workspace-file/not-text":
155
+ return t("preview.error.notText");
156
+ case "workspace-file/too-large":
157
+ return t("preview.error.tooLarge");
158
+ case "workspace-file/not-regular-file":
159
+ return t("preview.error.notRegularFile");
160
+ default:
161
+ return t("preview.error.unavailable", { message: failure.message });
162
+ }
163
+ }
164
+ function Level({ path, tree }) {
165
+ const { state, t } = tree;
166
+ const level = state.levels[path];
167
+ if (level === void 0 || level.kind === "loading") {
168
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { className: "dsh-fe-note", "data-files-row": "loading", children: t("tree.loading") });
169
+ }
170
+ if (level.kind === "failed") {
171
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
172
+ "li",
173
+ {
174
+ className: "dsh-fe-note dsh-fe-note-error",
175
+ "data-files-row": "failed",
176
+ "data-files-code": level.failure.code,
177
+ children: treeFailureLine(t, level.failure)
178
+ }
179
+ );
180
+ }
181
+ const entries = orderEntries(level.level.entries);
182
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
183
+ entries.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { className: "dsh-fe-note", "data-files-row": "empty", children: t("tree.empty") }),
184
+ entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Entry, { parent: path, entry, tree }, entry.name)),
185
+ level.level.truncated && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { className: "dsh-fe-note", "data-files-row": "truncated", children: t("tree.truncated") })
186
+ ] });
187
+ }
188
+ function Entry({
189
+ parent,
190
+ entry,
191
+ tree
192
+ }) {
193
+ const path = childPath(parent, entry.name);
194
+ if (entry.type === "directory") {
195
+ const expanded = tree.state.expanded.includes(path);
196
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: "dsh-fe-item", "data-files-entry": "directory", "data-files-path": path, children: [
197
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
198
+ "button",
199
+ {
200
+ type: "button",
201
+ className: "dsh-fe-row",
202
+ "aria-expanded": expanded,
203
+ onClick: () => {
204
+ tree.onToggle(path);
205
+ },
206
+ children: [
207
+ expanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconFolderOpen16, { className: "dsh-fe-icon" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconFolderClose16, { className: "dsh-fe-icon" }),
208
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-fe-name", children: entry.name })
209
+ ]
210
+ }
211
+ ),
212
+ expanded && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "dsh-fe-level", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Level, { path, tree }) })
213
+ ] });
214
+ }
215
+ if (entry.type === "file") {
216
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { className: "dsh-fe-item", "data-files-entry": "file", "data-files-path": path, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
217
+ "button",
218
+ {
219
+ type: "button",
220
+ className: "dsh-fe-row",
221
+ "aria-current": tree.state.selected === path,
222
+ onClick: () => {
223
+ tree.onOpen(path);
224
+ },
225
+ children: [
226
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.FileTypeIcon, { kind: (0, import_dsh_client_ui_primitives.classifyFileType)(entry.name), size: 16 }),
227
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-fe-name", children: entry.name })
228
+ ]
229
+ }
230
+ ) });
231
+ }
232
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { className: "dsh-fe-item", "data-files-entry": "other", "data-files-path": path, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-fe-row dsh-fe-row-static", title: tree.t("tree.other"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-fe-name", children: entry.name }) }) });
233
+ }
234
+ function HighlightedSource({
235
+ page,
236
+ lang,
237
+ wrap,
238
+ t
239
+ }) {
240
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-fe-source", "data-wrap": wrap, "data-preview-lang": lang ?? "plain", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
241
+ import_dsh_client_ui_primitives.CodeBlock,
242
+ {
243
+ code: page.text,
244
+ lang,
245
+ lineNumbers: true,
246
+ copyLabel: t("code.copy"),
247
+ copiedLabel: t("code.copied")
248
+ }
249
+ ) });
250
+ }
251
+ function FormattedBody({
252
+ page,
253
+ format,
254
+ jsonDocument,
255
+ t
256
+ }) {
257
+ const copyLabel = t("code.copy");
258
+ const copiedLabel = t("code.copied");
259
+ const footnotes = t("footnotes");
260
+ const markdownLabels = (0, import_react.useMemo)(
261
+ () => ({ code: { copyLabel, copiedLabel }, footnotes }),
262
+ [copyLabel, copiedLabel, footnotes]
263
+ );
264
+ const copyValue = t("json.copyValue");
265
+ const copyJson = t("json.copyJson");
266
+ const copyPath = t("json.copyPath");
267
+ const copyPrettyJson = t("json.copyPrettyJson");
268
+ const copyCompactJson = t("json.copyCompactJson");
269
+ const copied = t("json.copied");
270
+ const copyFailed = t("json.copyFailed");
271
+ const collapseNode = t("json.collapseNode");
272
+ const expandNode = t("json.expandNode");
273
+ const jsonLabels = (0, import_react.useMemo)(() => ({
274
+ copyValue,
275
+ copyJson,
276
+ copyPath,
277
+ copyPrettyJson,
278
+ copyCompactJson,
279
+ copied,
280
+ copyFailed,
281
+ collapseNode,
282
+ expandNode,
283
+ // Reads the live translate at call time, so the tooltip follows a locale
284
+ // change without rebuilding this object; `t` is stable by contract.
285
+ copyButtonTitle: (action) => t("json.copyTitle", { action })
286
+ }), [
287
+ collapseNode,
288
+ copyCompactJson,
289
+ copyFailed,
290
+ copyJson,
291
+ copyPath,
292
+ copyPrettyJson,
293
+ copyValue,
294
+ copied,
295
+ expandNode,
296
+ t
297
+ ]);
298
+ if (format.kind === "markdown") {
299
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-fe-prose", "data-preview-format": "markdown", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.MarkdownText, { text: page.text, labels: markdownLabels }) });
300
+ }
301
+ if (jsonDocument === void 0) return null;
302
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-fe-json", "data-preview-format": "json", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
303
+ import_dsh_client_ui_primitives.JsonTree,
304
+ {
305
+ data: jsonDocument,
306
+ label: t("preview.jsonLabel"),
307
+ labels: jsonLabels,
308
+ expandTopLevel: false
309
+ }
310
+ ) });
311
+ }
312
+ function PreviewBody({
313
+ state,
314
+ content,
315
+ format,
316
+ body,
317
+ jsonDocument,
318
+ jsonFallback,
319
+ t
320
+ }) {
321
+ if (content.kind === "image") {
322
+ const { name: name2 } = pathParts(state.selected ?? "");
323
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-fe-scroll dsh-fe-imagehost", "data-preview-state": "ready", "data-preview-format": "image", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { className: "dsh-fe-image", src: content.image.dataUrl, alt: name2, "data-preview-image": true }) });
324
+ }
325
+ const page = content.page;
326
+ const lines = previewLines(page);
327
+ if (lines.length === 0) {
328
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
329
+ "div",
330
+ {
331
+ className: "dsh-fe-scroll",
332
+ "data-preview-state": "ready",
333
+ "data-preview-format": format.kind,
334
+ "data-preview-lines": "0",
335
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dsh-fe-note", "data-preview-row": "empty", children: t("preview.empty") })
336
+ }
337
+ );
338
+ }
339
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
340
+ "div",
341
+ {
342
+ className: "dsh-fe-scroll",
343
+ "data-preview-state": "ready",
344
+ "data-preview-format": format.kind,
345
+ "data-preview-lines": lines.length,
346
+ "data-preview-body": body,
347
+ children: [
348
+ jsonFallback && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dsh-fe-note dsh-fe-note-error", "data-preview-row": "invalid-json", children: t("preview.jsonInvalid") }),
349
+ body === "rendered" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FormattedBody, { page, format, jsonDocument, t }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HighlightedSource, { page, lang: format.lang, wrap: state.wrap, t }),
350
+ !page.eof && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dsh-fe-note", "data-preview-row": "truncated", children: t("preview.truncated", { lines: page.lines }) })
351
+ ]
352
+ }
353
+ );
354
+ }
355
+ function bodyKindOf(content, format, mode, jsonWalkable) {
356
+ if (content !== null && content.kind === "image") return "image";
357
+ if (!hasSourceToggle(format)) return "source";
358
+ if ((mode ?? "rendered") === "source") return "source";
359
+ if (format.kind === "json" && !jsonWalkable) return "source";
360
+ return "rendered";
361
+ }
362
+ function FilesView({
363
+ sessionId,
364
+ useSessions,
365
+ useStore,
366
+ actions,
367
+ list,
368
+ read,
369
+ t
370
+ }) {
371
+ const cwd = useSessions((sessions) => sessions.byId[sessionId]?.cwd);
372
+ const state = useStore((store) => store);
373
+ const jsonDocument = (0, import_react.useMemo)(() => {
374
+ if (state.selected === null) return void 0;
375
+ if ((state.mode ?? "rendered") === "source") return void 0;
376
+ if (previewFormatFor(state.selected).kind !== "json") return void 0;
377
+ const preview2 = state.preview;
378
+ if (preview2.kind !== "ready" || preview2.content.kind !== "text") return void 0;
379
+ return parseJsonDocument(preview2.content.page.text);
380
+ }, [state.mode, state.preview, state.selected]);
381
+ (0, import_react.useEffect)(() => {
382
+ if (cwd === void 0 || state.root === cwd) return;
383
+ actions.start(cwd);
384
+ list(cwd);
385
+ }, [actions, cwd, list, state.root]);
386
+ if (cwd === void 0) {
387
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-fe-root", "data-files-state": "no-workspace", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-fe-status", children: t("tree.noWorkspace") }) });
388
+ }
389
+ if (state.root === null) return null;
390
+ const tree = {
391
+ state,
392
+ onToggle: (path) => {
393
+ const loaded = state.levels[path] !== void 0;
394
+ actions.toggled(path);
395
+ if (!loaded) list(path);
396
+ },
397
+ onOpen: (path) => {
398
+ read(path);
399
+ },
400
+ t
401
+ };
402
+ const reloadTree = () => {
403
+ actions.reset();
404
+ for (const path of state.expanded) list(path);
405
+ };
406
+ const reloadPreview = () => {
407
+ if (state.selected !== null) read(state.selected);
408
+ };
409
+ const root = pathParts(state.root);
410
+ const selected = state.selected === null ? null : pathParts(state.selected);
411
+ const preview = state.preview;
412
+ const format = state.selected === null ? null : previewFormatFor(state.selected);
413
+ const content = preview.kind === "ready" ? preview.content : null;
414
+ const fallbackFormat = { kind: "text", lang: void 0, mediaType: void 0 };
415
+ const body = bodyKindOf(
416
+ content,
417
+ format ?? fallbackFormat,
418
+ state.mode,
419
+ jsonDocument !== void 0
420
+ );
421
+ const jsonFallback = format?.kind === "json" && (state.mode ?? "rendered") === "rendered" && jsonDocument === void 0 && content !== null && content.kind === "text";
422
+ const meta = preview.kind !== "ready" ? null : preview.content.kind === "text" ? [
423
+ t("preview.lines", { lines: preview.content.page.lines }),
424
+ preview.content.page.bytes === void 0 ? null : (0, import_dsh_client_ui_primitives.fileSizeText)(preview.content.page.bytes)
425
+ ].filter((part) => part !== null).join(" \xB7 ") : preview.content.image.bytes === void 0 ? null : (0, import_dsh_client_ui_primitives.fileSizeText)(preview.content.image.bytes);
426
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
427
+ "div",
428
+ {
429
+ className: "dsh-fe-root",
430
+ "data-files-state": "tree",
431
+ "data-files-root": state.root,
432
+ "data-conversation-composer-overlay": "",
433
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-fe-panes", children: [
434
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-fe-tree", "data-files-pane": "tree", children: [
435
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-fe-head", children: [
436
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-fe-path", title: state.root, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
437
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-fe-path-muted", children: root.directory }),
438
+ root.name
439
+ ] }) }),
440
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
441
+ "button",
442
+ {
443
+ type: "button",
444
+ className: "dsh-fe-tool",
445
+ "aria-label": t("tree.reload"),
446
+ title: t("tree.reload"),
447
+ "data-files-reload": true,
448
+ onClick: reloadTree,
449
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconRefreshOutline16, {})
450
+ }
451
+ )
452
+ ] }),
453
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-fe-scroll", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "dsh-fe-level", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Level, { path: state.root, tree }) }) })
454
+ ] }),
455
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-fe-preview", "data-files-pane": "preview", children: [
456
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-fe-head", children: [
457
+ selected === null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-fe-path dsh-fe-path-muted", children: t("preview.title") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-fe-path", title: state.selected ?? void 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
458
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-fe-path-muted", children: selected.directory }),
459
+ selected.name
460
+ ] }) }),
461
+ meta !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-fe-meta", "data-preview-meta": true, children: meta }),
462
+ format !== null && hasSourceToggle(format) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
463
+ "button",
464
+ {
465
+ type: "button",
466
+ className: "dsh-fe-tool",
467
+ "aria-pressed": body === "source",
468
+ "aria-label": body === "source" ? t("preview.rendered") : t("preview.source"),
469
+ title: body === "source" ? t("preview.rendered") : t("preview.source"),
470
+ "data-preview-mode-toggle": true,
471
+ onClick: () => {
472
+ actions.setMode(body === "source" ? "rendered" : "source");
473
+ },
474
+ children: body === "source" ? t("preview.rendered") : t("preview.source")
475
+ }
476
+ ),
477
+ body === "source" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
478
+ "button",
479
+ {
480
+ type: "button",
481
+ className: "dsh-fe-tool",
482
+ "aria-pressed": state.wrap,
483
+ "aria-label": state.wrap ? t("preview.nowrap") : t("preview.wrap"),
484
+ title: state.wrap ? t("preview.nowrap") : t("preview.wrap"),
485
+ "data-preview-wrap-toggle": true,
486
+ onClick: () => {
487
+ actions.setWrap(!state.wrap);
488
+ },
489
+ children: state.wrap ? "\u21B5" : "\u2192"
490
+ }
491
+ ),
492
+ state.selected !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
493
+ "button",
494
+ {
495
+ type: "button",
496
+ className: "dsh-fe-tool",
497
+ "aria-label": t("preview.reload"),
498
+ title: t("preview.reload"),
499
+ "data-preview-reload": true,
500
+ onClick: reloadPreview,
501
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconRefreshOutline16, {})
502
+ }
503
+ )
504
+ ] }),
505
+ preview.kind === "loading" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-fe-status", children: t("preview.loading") }),
506
+ preview.kind === "failed" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-fe-scroll", "data-preview-state": "failed", children: [
507
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dsh-fe-note dsh-fe-note-error", "data-preview-code": preview.failure.code, children: previewFailureLine(t, preview.failure) }),
508
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "dsh-fe-tool", onClick: reloadPreview, children: t("preview.reload") })
509
+ ] }),
510
+ state.selected === null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-fe-status", children: t("preview.placeholder") }),
511
+ preview.kind === "ready" && content !== null && format !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
512
+ PreviewBody,
513
+ {
514
+ state,
515
+ content,
516
+ format,
517
+ body,
518
+ jsonDocument,
519
+ jsonFallback,
520
+ t
521
+ }
522
+ )
523
+ ] })
524
+ ] })
525
+ }
526
+ );
527
+ }
528
+
529
+ // src/client/face.ts
530
+ var PREVIEW_LINES = 2e3;
531
+ function filesFace(remote, sessionId, signal, actions) {
532
+ const generations = /* @__PURE__ */ new Map();
533
+ let previewGeneration = 0;
534
+ return {
535
+ list(path) {
536
+ if (signal.aborted) return;
537
+ const generation = (generations.get(path) ?? 0) + 1;
538
+ generations.set(path, generation);
539
+ actions.loading(path);
540
+ void remote.workspaceFiles.list(sessionId, path, signal).then((result) => {
541
+ if (signal.aborted || generations.get(path) !== generation) return;
542
+ if (result.ok) {
543
+ actions.loaded(path, {
544
+ entries: result.value.entries,
545
+ truncated: result.value.truncated
546
+ });
547
+ } else {
548
+ actions.failed(path, result.error);
549
+ }
550
+ });
551
+ },
552
+ read(path) {
553
+ if (signal.aborted) return;
554
+ previewGeneration += 1;
555
+ const generation = previewGeneration;
556
+ const format = previewFormatFor(path);
557
+ actions.selecting(path);
558
+ const settle = (write) => {
559
+ if (signal.aborted || previewGeneration !== generation) return;
560
+ write();
561
+ };
562
+ if (format.kind === "image") {
563
+ void remote.workspaceFiles.readAll(sessionId, path, signal).then((result) => {
564
+ settle(() => {
565
+ if (result.ok) {
566
+ actions.previewLoaded(path, {
567
+ kind: "image",
568
+ image: {
569
+ dataUrl: `data:${format.mediaType};base64,${result.value.data}`,
570
+ bytes: result.value.bytes
571
+ }
572
+ });
573
+ } else {
574
+ actions.previewFailed(path, result.error);
575
+ }
576
+ });
577
+ });
578
+ return;
579
+ }
580
+ void remote.workspaceFiles.read(sessionId, path, { offset: 1, limit: PREVIEW_LINES }, signal).then((result) => {
581
+ settle(() => {
582
+ if (result.ok) {
583
+ const page = {
584
+ text: result.value.text,
585
+ lines: result.value.lines,
586
+ eof: result.value.eof,
587
+ bytes: result.value.bytes
588
+ };
589
+ actions.previewLoaded(path, { kind: "text", page });
590
+ } else {
591
+ actions.previewFailed(path, result.error);
592
+ }
593
+ });
594
+ });
595
+ }
596
+ };
597
+ }
598
+
599
+ // src/client/locales.ts
600
+ var NS = "fileExplorer";
601
+ var zh = {
602
+ "view.files": "\u6587\u4EF6",
603
+ "tree.root": "\u5DE5\u4F5C\u533A",
604
+ "tree.reload": "\u91CD\u65B0\u8BFB\u53D6",
605
+ "tree.loading": "\u6B63\u5728\u8BFB\u53D6\u2026",
606
+ "tree.empty": "\u7A7A\u76EE\u5F55",
607
+ "tree.truncated": "\u6761\u76EE\u8FC7\u591A\uFF0C\u53EA\u663E\u793A\u4E86\u4E00\u90E8\u5206\u3002",
608
+ "tree.noWorkspace": "\u8FD9\u4E2A\u4F1A\u8BDD\u6CA1\u6709\u5DE5\u4F5C\u533A\u76EE\u5F55\u3002",
609
+ "tree.other": "\u65E2\u4E0D\u662F\u6587\u4EF6\u4E5F\u4E0D\u662F\u76EE\u5F55\uFF0C\u65E0\u6CD5\u6253\u5F00\u3002",
610
+ "tree.error.notFound": "\u76EE\u5F55\u4E0D\u5B58\u5728\uFF0C\u53EF\u80FD\u5DF2\u88AB\u79FB\u52A8\u6216\u5220\u9664\u3002",
611
+ "tree.error.outsideWorkspace": "\u8BE5\u76EE\u5F55\u5728\u5DE5\u4F5C\u533A\u4E4B\u5916\uFF0C\u65E0\u6CD5\u8BFB\u53D6\u3002",
612
+ "tree.error.notDirectory": "\u8FD9\u4E0D\u662F\u4E00\u4E2A\u76EE\u5F55\u3002",
613
+ "tree.error.unavailable": "\u8BFB\u53D6\u5931\u8D25\uFF1A{message}",
614
+ "preview.placeholder": "\u4ECE\u5DE6\u4FA7\u9009\u62E9\u4E00\u4E2A\u6587\u4EF6\u8FDB\u884C\u9884\u89C8\u3002",
615
+ "preview.empty": "\u7A7A\u6587\u4EF6",
616
+ "preview.rendered": "\u9884\u89C8",
617
+ "preview.source": "\u6E90\u7801",
618
+ "preview.jsonLabel": "JSON \u6587\u6863",
619
+ "preview.jsonInvalid": "\u8FD9\u4E0D\u662F\u53EF\u5C55\u5F00\u7684 JSON\uFF0C\u5DF2\u663E\u793A\u6E90\u7801\u3002",
620
+ "code.copy": "\u590D\u5236",
621
+ "code.copied": "\u5DF2\u590D\u5236",
622
+ "footnotes": "\u811A\u6CE8",
623
+ "json.copyValue": "\u590D\u5236\u503C",
624
+ "json.copyJson": "\u590D\u5236 JSON",
625
+ "json.copyPath": "\u590D\u5236\u8DEF\u5F84",
626
+ "json.copyPrettyJson": "\u590D\u5236\u683C\u5F0F\u5316 JSON",
627
+ "json.copyCompactJson": "\u590D\u5236\u538B\u7F29 JSON",
628
+ "json.copied": "\u5DF2\u590D\u5236",
629
+ "json.copyFailed": "\u590D\u5236\u5931\u8D25",
630
+ "json.collapseNode": "\u6536\u8D77",
631
+ "json.expandNode": "\u5C55\u5F00",
632
+ "json.copyTitle": "{action}",
633
+ "preview.title": "\u9884\u89C8",
634
+ "preview.loading": "\u6B63\u5728\u8BFB\u53D6\u2026",
635
+ "preview.reload": "\u91CD\u65B0\u8BFB\u53D6",
636
+ "preview.truncated": "\u6587\u4EF6\u8F83\u957F\uFF0C\u53EA\u663E\u793A\u524D {lines} \u884C\u3002",
637
+ "preview.wrap": "\u81EA\u52A8\u6362\u884C",
638
+ "preview.nowrap": "\u4E0D\u6362\u884C",
639
+ "preview.lines": "{lines} \u884C",
640
+ "preview.error.notFound": "\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u53EF\u80FD\u5DF2\u88AB\u79FB\u52A8\u6216\u5220\u9664\u3002",
641
+ "preview.error.notText": "\u8FD9\u4E0D\u662F\u53EF\u4EE5\u9884\u89C8\u7684\u6587\u672C\u6587\u4EF6\u3002",
642
+ "preview.error.tooLarge": "\u6587\u4EF6\u592A\u5927\uFF0C\u65E0\u6CD5\u9884\u89C8\u3002",
643
+ "preview.error.notRegularFile": "\u8FD9\u4E0D\u662F\u4E00\u4E2A\u666E\u901A\u6587\u4EF6\u3002",
644
+ "preview.error.unavailable": "\u9884\u89C8\u5931\u8D25\uFF1A{message}"
645
+ };
646
+ var en = {
647
+ "view.files": "Files",
648
+ "tree.root": "Workspace",
649
+ "tree.reload": "Reload",
650
+ "tree.loading": "Reading\u2026",
651
+ "tree.empty": "Empty directory",
652
+ "tree.truncated": "Too many entries, showing only some of them.",
653
+ "tree.noWorkspace": "This session has no workspace directory.",
654
+ "tree.other": "Not a file or a directory, so it cannot be opened.",
655
+ "tree.error.notFound": "That directory is gone. It may have been moved or deleted.",
656
+ "tree.error.outsideWorkspace": "That directory is outside the workspace, so it cannot be read.",
657
+ "tree.error.notDirectory": "That is not a directory.",
658
+ "tree.error.unavailable": "Read failed: {message}",
659
+ "preview.placeholder": "Pick a file on the left to preview it.",
660
+ "preview.empty": "Empty file",
661
+ "preview.rendered": "Rendered",
662
+ "preview.source": "Source",
663
+ "preview.jsonLabel": "JSON document",
664
+ "preview.jsonInvalid": "That is not JSON a tree can walk, so the source is shown.",
665
+ "code.copy": "Copy",
666
+ "code.copied": "Copied",
667
+ "footnotes": "Footnotes",
668
+ "json.copyValue": "Copy value",
669
+ "json.copyJson": "Copy JSON",
670
+ "json.copyPath": "Copy path",
671
+ "json.copyPrettyJson": "Copy pretty JSON",
672
+ "json.copyCompactJson": "Copy compact JSON",
673
+ "json.copied": "Copied",
674
+ "json.copyFailed": "Copy failed",
675
+ "json.collapseNode": "Collapse",
676
+ "json.expandNode": "Expand",
677
+ "json.copyTitle": "{action}",
678
+ "preview.title": "Preview",
679
+ "preview.loading": "Reading\u2026",
680
+ "preview.reload": "Reload",
681
+ "preview.truncated": "This file is long, showing the first {lines} lines.",
682
+ "preview.wrap": "Wrap long lines",
683
+ "preview.nowrap": "Do not wrap long lines",
684
+ "preview.lines": "{lines} lines",
685
+ "preview.error.notFound": "That file is gone. It may have been moved or deleted.",
686
+ "preview.error.notText": "That is not a text file this preview can show.",
687
+ "preview.error.tooLarge": "That file is too large to preview.",
688
+ "preview.error.notRegularFile": "That is not a regular file.",
689
+ "preview.error.unavailable": "Preview failed: {message}"
690
+ };
691
+
692
+ // src/client/store.ts
693
+ var import_dsh_client_store = require("@deepseek-ai/dsh-client-store");
694
+ function emptyState() {
695
+ return {
696
+ root: null,
697
+ levels: {},
698
+ expanded: [],
699
+ selected: null,
700
+ preview: { kind: "idle" },
701
+ wrap: true,
702
+ mode: null
703
+ };
704
+ }
705
+ function createFilesStore() {
706
+ return (0, import_dsh_client_store.defineStore)({
707
+ init: emptyState,
708
+ actions: {
709
+ start: (d, root) => {
710
+ d.root = root;
711
+ d.levels = {};
712
+ d.expanded = [root];
713
+ d.selected = null;
714
+ d.preview = { kind: "idle" };
715
+ },
716
+ loading: (d, path) => {
717
+ d.levels[path] = { kind: "loading" };
718
+ },
719
+ loaded: (d, path, level) => {
720
+ d.levels[path] = { kind: "ready", level };
721
+ },
722
+ failed: (d, path, failure) => {
723
+ d.levels[path] = { kind: "failed", failure };
724
+ },
725
+ toggled: (d, path) => {
726
+ const at = d.expanded.indexOf(path);
727
+ if (at >= 0) d.expanded.splice(at, 1);
728
+ else d.expanded.push(path);
729
+ },
730
+ reset: (d) => {
731
+ d.levels = {};
732
+ },
733
+ selecting: (d, path) => {
734
+ d.selected = path;
735
+ d.preview = { kind: "loading", path };
736
+ d.mode = null;
737
+ },
738
+ previewLoaded: (d, path, content) => {
739
+ if (d.selected !== path) return;
740
+ d.preview = { kind: "ready", path, content };
741
+ },
742
+ previewFailed: (d, path, failure) => {
743
+ if (d.selected !== path) return;
744
+ d.preview = { kind: "failed", path, failure };
745
+ },
746
+ clearPreview: (d) => {
747
+ d.selected = null;
748
+ d.preview = { kind: "idle" };
749
+ },
750
+ setWrap: (d, wrap) => {
751
+ d.wrap = wrap;
752
+ },
753
+ setMode: (d, mode) => {
754
+ d.mode = mode;
755
+ }
756
+ }
757
+ });
758
+ }
759
+
760
+ // src/client/styles.ts
761
+ var STYLE_ATTRIBUTE = "data-dsh-file-explorer";
762
+ var CSS = `
763
+ .dsh-fe-root {
764
+ display: flex;
765
+ flex-direction: column;
766
+ box-sizing: border-box;
767
+ width: 100%;
768
+ height: 100%;
769
+ min-height: 0;
770
+ overflow: hidden;
771
+ color: var(--dsw-alias-label-primary);
772
+ font-size: var(--dsh-content-font-size-secondary, 13px);
773
+ line-height: 1.5;
774
+ }
775
+
776
+ .dsh-fe-panes {
777
+ display: flex;
778
+ flex: 1 1 auto;
779
+ min-height: 0;
780
+ }
781
+
782
+ .dsh-fe-tree,
783
+ .dsh-fe-preview {
784
+ display: flex;
785
+ flex-direction: column;
786
+ min-height: 0;
787
+ }
788
+
789
+ .dsh-fe-tree {
790
+ flex: 0 0 auto;
791
+ width: 280px;
792
+ min-width: 160px;
793
+ max-width: 60%;
794
+ resize: horizontal;
795
+ overflow: hidden;
796
+ border-right: 0.5px solid var(--dsw-alias-border-l3);
797
+ }
798
+
799
+ .dsh-fe-preview {
800
+ flex: 1 1 auto;
801
+ min-width: 0;
802
+ }
803
+
804
+ .dsh-fe-head {
805
+ display: flex;
806
+ flex: 0 0 auto;
807
+ gap: 4px;
808
+ align-items: center;
809
+ box-sizing: border-box;
810
+ height: 38px;
811
+ padding: 0 6px 0 14px;
812
+ border-bottom: 0.5px solid var(--dsw-alias-border-l3);
813
+ }
814
+
815
+ .dsh-fe-path {
816
+ flex: 1 1 auto;
817
+ min-width: 0;
818
+ overflow: hidden;
819
+ font-size: 12px;
820
+ white-space: nowrap;
821
+ text-overflow: ellipsis;
822
+ direction: rtl;
823
+ text-align: left;
824
+ }
825
+
826
+ .dsh-fe-path > span {
827
+ direction: ltr;
828
+ unicode-bidi: embed;
829
+ }
830
+
831
+ .dsh-fe-path-muted {
832
+ color: var(--dsw-alias-label-tertiary);
833
+ }
834
+
835
+ .dsh-fe-meta {
836
+ flex: 0 0 auto;
837
+ color: var(--dsw-alias-label-tertiary);
838
+ font-size: 11px;
839
+ white-space: nowrap;
840
+ }
841
+
842
+ .dsh-fe-tool {
843
+ display: inline-flex;
844
+ flex: none;
845
+ align-items: center;
846
+ justify-content: center;
847
+ min-width: 28px;
848
+ height: 28px;
849
+ padding: 0 6px;
850
+ color: var(--dsw-alias-label-secondary);
851
+ font: inherit;
852
+ font-size: 11px;
853
+ line-height: 1;
854
+ background: transparent;
855
+ border: none;
856
+ border-radius: 14px;
857
+ cursor: pointer;
858
+ }
859
+
860
+ .dsh-fe-tool:hover {
861
+ color: var(--dsw-alias-label-primary);
862
+ background: var(--dsw-alias-interactive-bg-hover);
863
+ }
864
+
865
+ .dsh-fe-tool svg {
866
+ width: 15px;
867
+ height: 15px;
868
+ }
869
+
870
+ .dsh-fe-scroll {
871
+ flex: 1 1 auto;
872
+ min-height: 0;
873
+ padding: 8px 8px calc(var(--dsh-composer-height, 152px) + 24px);
874
+ overflow: auto;
875
+ scrollbar-gutter: stable;
876
+ }
877
+
878
+ .dsh-fe-scroll::-webkit-scrollbar-track {
879
+ margin: 2px;
880
+ }
881
+
882
+ .dsh-fe-level {
883
+ margin: 0;
884
+ padding: 0;
885
+ list-style: none;
886
+ }
887
+
888
+ .dsh-fe-level .dsh-fe-level {
889
+ padding-left: 16px;
890
+ }
891
+
892
+ .dsh-fe-row {
893
+ display: flex;
894
+ gap: 6px;
895
+ align-items: center;
896
+ width: 100%;
897
+ min-width: 0;
898
+ padding: 5px 10px;
899
+ color: inherit;
900
+ font: inherit;
901
+ text-align: left;
902
+ background: transparent;
903
+ border: 0;
904
+ border-radius: 10px;
905
+ cursor: pointer;
906
+ }
907
+
908
+ .dsh-fe-row:hover {
909
+ background: var(--dsw-alias-interactive-bg-hover);
910
+ }
911
+
912
+ .dsh-fe-row[aria-current='true'] {
913
+ background: var(--dsw-alias-interactive-bg-active);
914
+ }
915
+
916
+ .dsh-fe-row-static {
917
+ cursor: default;
918
+ color: var(--dsw-alias-label-tertiary);
919
+ }
920
+
921
+ .dsh-fe-row-static:hover {
922
+ background: transparent;
923
+ }
924
+
925
+ .dsh-fe-icon {
926
+ flex: 0 0 auto;
927
+ color: var(--dsw-alias-label-tertiary);
928
+ }
929
+
930
+ .dsh-fe-name {
931
+ min-width: 0;
932
+ overflow: hidden;
933
+ white-space: nowrap;
934
+ text-overflow: ellipsis;
935
+ }
936
+
937
+ .dsh-fe-note {
938
+ margin: 0;
939
+ padding: 3px 10px;
940
+ color: var(--dsw-alias-label-tertiary);
941
+ font-size: 12px;
942
+ }
943
+
944
+ .dsh-fe-note-error {
945
+ color: var(--dsw-alias-label-error);
946
+ }
947
+
948
+ .dsh-fe-status {
949
+ display: flex;
950
+ flex: 1 1 auto;
951
+ align-items: center;
952
+ justify-content: center;
953
+ padding: 24px;
954
+ color: var(--dsw-alias-label-secondary);
955
+ text-align: center;
956
+ }
957
+
958
+ /* \u2500\u2500 format-aware bodies \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
959
+
960
+ /* Every body the pane can draw comes from the shared primitives, so this sheet
961
+ carries no source-line rail of its own: the code block owns the numbered
962
+ gutter, its counter, and its copy control. */
963
+
964
+ /* The shared CodeBlock draws the highlighted source; this host only swaps the
965
+ chat card's chrome for the pane's: no margin, no radius, no grey fill, and
966
+ the pane's own scroll container. */
967
+ .dsh-fe-source {
968
+ --dsl-code-block-background: transparent;
969
+ --dsl-code-block-border-radius: 0;
970
+ --dsl-code-block-line-white-space: pre;
971
+ }
972
+
973
+ .dsh-fe-source .md-code-block {
974
+ margin: 0;
975
+ }
976
+
977
+ .dsh-fe-source .md-code-block > [data-code-block-banner] > div:first-child:empty {
978
+ display: none;
979
+ }
980
+
981
+ .dsh-fe-source .md-code-block pre {
982
+ box-sizing: border-box;
983
+ min-width: 100%;
984
+ padding: 8px 0;
985
+ overflow: visible;
986
+ white-space: pre;
987
+ word-break: normal;
988
+ overflow-wrap: normal;
989
+ }
990
+
991
+ .dsh-fe-source[data-wrap='true'] {
992
+ --dsl-code-block-line-white-space: pre-wrap;
993
+ }
994
+
995
+ .dsh-fe-source[data-wrap='true'] .md-code-block pre {
996
+ white-space: pre-wrap;
997
+ /* The primitive's default is break-all; keep words whole instead. */
998
+ word-break: normal;
999
+ overflow-wrap: break-word;
1000
+ }
1001
+
1002
+ /* Rendered Markdown: prose lays out in normal white space, with the pane's
1003
+ insets and no monospace inheritance from the source view. */
1004
+ .dsh-fe-prose {
1005
+ min-width: 0;
1006
+ padding: 4px 4px 0;
1007
+ font-family: var(--dsw-font-family);
1008
+ white-space: normal;
1009
+ }
1010
+
1011
+ .dsh-fe-json {
1012
+ min-width: 0;
1013
+ font-family: var(--ds-font-family-code, ui-monospace, SFMono-Regular, Menlo, monospace);
1014
+ font-size: 12px;
1015
+ white-space: normal;
1016
+ }
1017
+
1018
+ /* An image keeps its intrinsic size, centres while it fits, and scales down to
1019
+ the pane rather than overflowing it. */
1020
+ .dsh-fe-imagehost {
1021
+ display: flex;
1022
+ align-items: flex-start;
1023
+ justify-content: center;
1024
+ }
1025
+
1026
+ .dsh-fe-image {
1027
+ display: block;
1028
+ max-width: 100%;
1029
+ height: auto;
1030
+ border-radius: 6px;
1031
+ }
1032
+ `;
1033
+ function installStyles() {
1034
+ if (typeof document === "undefined") return () => {
1035
+ };
1036
+ if (document.querySelector(`style[${STYLE_ATTRIBUTE}]`) !== null) return () => {
1037
+ };
1038
+ const tag = document.createElement("style");
1039
+ tag.setAttribute(STYLE_ATTRIBUTE, "");
1040
+ tag.textContent = CSS;
1041
+ document.head.appendChild(tag);
1042
+ return () => {
1043
+ tag.remove();
1044
+ };
1045
+ }
1046
+
1047
+ // src/client/index.ts
1048
+ var name = "file-explorer";
1049
+ var inject = ["slots", "locale", "remote", "remote.workspaceFiles"];
1050
+ var FILES_VIEW_ID = "files";
1051
+ function apply(ctx) {
1052
+ ctx.effect(installStyles, "@jaxzhou/dsh-file-explorer: stylesheet");
1053
+ ctx.effect(() => ctx.locale.register(NS, { zh, en }), "@jaxzhou/dsh-file-explorer: dictionaries");
1054
+ const t = ctx.locale.bind(NS);
1055
+ const store = createFilesStore();
1056
+ const lifetime = new AbortController();
1057
+ ctx.effect(() => () => {
1058
+ lifetime.abort();
1059
+ }, "@jaxzhou/dsh-file-explorer: request lifetime");
1060
+ ctx.slots.inject("conversation.view", () => ctx.slots.register({
1061
+ name: "conversation.view",
1062
+ id: FILES_VIEW_ID,
1063
+ // After Chat (default) and Trajectory (10), so the strip reads
1064
+ // Chat | Trajectory | Files.
1065
+ order: 20,
1066
+ locale: NS,
1067
+ label: () => t("view.files"),
1068
+ store,
1069
+ inject: (sessionId, actions) => filesFace(ctx.remote, sessionId, lifetime.signal, actions)
1070
+ }, FilesView));
1071
+ }
1072
+ return module.exports; } });
1073
+ //# sourceMappingURL=client.js.map