@dsh-xhl/dsh-file-explorer 0.1.3 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -7
- package/cordis.patch.yml +8 -8
- package/lib/client.js +108 -49
- package/lib/index.js +3 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,29 +4,31 @@
|
|
|
4
4
|
|
|
5
5
|
## 功能
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
- **编辑器**(默认):点击打开全屏文件预览 / 编辑弹窗(Ctrl+P 亦可)
|
|
7
|
+
- **聊天页标题栏图标**(`conversation.session.header.utilities`):一个内置编辑器图标,点击打开文件预览 / 编辑弹窗(聊天页保持与现状一致,无下拉)
|
|
8
|
+
- **Hero / 新建会话页 ButtonGroup**:同一浮层位置由插件定位到会话列右上角(hero 阶段显示,有记录后由标题栏图标接管,无重复);hero 上为**左主按钮 + 右下拉**的组合:
|
|
9
|
+
- **编辑器**(默认):点击打开文件预览 / 编辑弹窗(Ctrl+P 亦可)
|
|
11
10
|
- **文件夹**:点击直接打开会话工作区所在的**系统文件夹**(Windows `explorer` / macOS `open` / Linux `xdg-open`)
|
|
12
|
-
- **VSCode**:点击用 `code` 命令行在 **VS Code** 中打开会话工作区(自动探测安装位置 / PATH
|
|
11
|
+
- **VSCode**:点击用 `code` 命令行在 **VS Code** 中打开会话工作区(自动探测安装位置 / PATH;未安装则该项自动隐藏)
|
|
13
12
|
- 选择记忆在 localStorage,点击后底部提示确认打开的路径;下拉选中某项会先切换默认打开方式,随后立即执行对应的打开动作
|
|
13
|
+
- 纯插件实现,不改动框架代码(详见 `docs/hero-filex-button.md`)
|
|
14
|
+
- **对话内点击文件 → 编辑器预览**:聊天里的文件路径链接(工具行、产物行、正文提及)默认用系统程序打开;插件拦截 `remote.session.openWorkspacePath` 与 `workspaces.openPath` 两条通道,改为在编辑器弹窗中预览(目录或 cwd 外的路径仍落回系统打开)
|
|
14
15
|
- **文件列表**:左侧目录树(跳过 `node_modules`/`.git`/`dist` 等)
|
|
15
16
|
- **按文件名过滤**:输入即过滤
|
|
16
17
|
- **全文搜索**:正则 / 大小写 / 全词匹配、包含/排除过滤,结果按文件分组、命中高亮,点击跳转并高亮匹配
|
|
17
18
|
- **编辑**:CodeMirror 6(20+ 语言语法高亮含 Vue SFC、行号、撤销/重做、Ctrl+S 保存、只读切换、Tab 缩进)
|
|
18
19
|
- **预览**:图片直接显示、PDF 内嵌查看(Markdown / HTML 预览已移除——大文档渲染会卡死界面)
|
|
20
|
+
- **全屏**:弹窗标题栏的全屏按钮,一键把预览 / 编辑弹窗放大到整个窗口(图标转为「退出全屏」,再点一次还原)
|
|
19
21
|
- **界面**:复用 Web 壳设计系统(`@deepseek-ai/dsh-client-ui-primitives`:Button / Menu / Modal / Input / Toast / Tooltip + `--dsw-*` token),随主题明暗自适应
|
|
20
22
|
|
|
21
23
|
## 架构
|
|
22
24
|
|
|
23
25
|
```
|
|
24
26
|
src/
|
|
25
|
-
index.ts Host:/filex/api JSON 路由(session.cwd / fs.list / fs.read / fs.write / fs.search / fs.reveal)
|
|
27
|
+
index.ts Host:/filex/api JSON 路由(session.cwd / fs.list / fs.read / fs.write / fs.search / fs.reveal / fs.vscode / fs.capabilities)
|
|
26
28
|
+ /filex/file 媒体路由(图片/PDF 字节),loopback 信任围栏
|
|
27
29
|
trust-fence.ts Host-header loopback 校验(DNS-rebinding 防护)
|
|
28
30
|
client/
|
|
29
|
-
index.tsx
|
|
31
|
+
index.tsx 入口:聊天页 header 图标(内置编辑器)+ hero 模式 ButtonGroup + overlay 弹窗 + Ctrl+P 快捷键
|
|
30
32
|
Explorer.tsx 弹窗:文件树 / 文件名过滤 / 全文搜索 / 查看器分派(primitives 重排)
|
|
31
33
|
TextEditor.tsx CodeMirror 6 编辑器 + 搜索跳转高亮
|
|
32
34
|
lang.ts 扩展名 → CodeMirror 语言映射
|
package/cordis.patch.yml
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# dsh-file-explorer bundle patch
|
|
2
|
-
#
|
|
3
|
-
# 通过 bundle 通道挂载:
|
|
4
|
-
# dsh plugin --profile <name> add @dsh-xhl/dsh-file-explorer@<version>
|
|
5
|
-
# 或手动把 '@dsh-xhl/dsh-file-explorer' 加进 profile 的 dsh.profile.bundles 并 link 依赖。
|
|
6
|
-
- insert:
|
|
7
|
-
- id: dsh-file-explorer
|
|
8
|
-
name: '@dsh-xhl/dsh-file-explorer'
|
|
1
|
+
# dsh-file-explorer bundle patch
|
|
2
|
+
#
|
|
3
|
+
# 通过 bundle 通道挂载:
|
|
4
|
+
# dsh plugin --profile <name> add @dsh-xhl/dsh-file-explorer@<version>
|
|
5
|
+
# 或手动把 '@dsh-xhl/dsh-file-explorer' 加进 profile 的 dsh.profile.bundles 并 link 依赖。
|
|
6
|
+
- insert:
|
|
7
|
+
- id: dsh-file-explorer
|
|
8
|
+
name: '@dsh-xhl/dsh-file-explorer'
|
package/lib/client.js
CHANGED
|
@@ -37010,16 +37010,28 @@ window.__ModuleLoader__.load({
|
|
|
37010
37010
|
* inputs, modals, toasts, tooltips) is left to them; this sheet only covers
|
|
37011
37011
|
* the explorer's bespoke layout — the split body, tree rows, search rows,
|
|
37012
37012
|
* editor chrome — and the small adjustments that compose primitives into
|
|
37013
|
-
* native-looking pieces (the header
|
|
37013
|
+
* native-looking pieces (the header icon, the modal surface).
|
|
37014
37014
|
*/
|
|
37015
37015
|
const CSS = `
|
|
37016
|
-
/* ── header
|
|
37017
|
-
.
|
|
37018
|
-
|
|
37019
|
-
|
|
37016
|
+
/* ── header icon (utilities slot) ────────────────────────────────────── */
|
|
37017
|
+
/* Same 28×28 round button as dsh-git-gui's header entry (.gg-header-btn):
|
|
37018
|
+
the primitive sm button is already 28px tall with a 16px icon, so only
|
|
37019
|
+
the width / padding / radius need pinning down. */
|
|
37020
|
+
.filex-header-btn{width:28px;height:28px;padding:0;border-radius:14px}
|
|
37021
|
+
|
|
37022
|
+
/* ── hero ButtonGroup (shell.overlay entry) ──────────────────────────── */
|
|
37023
|
+
/* The mode group shown only on the hero / new-session screen: the left
|
|
37024
|
+
button carries the remembered mode's icon, the right chevron the mode
|
|
37025
|
+
dropdown. Outer corners reuse the in-chat header-button radius (14px on
|
|
37026
|
+
a 28px-tall button = a fully round cap), so the group reads as one pill
|
|
37027
|
+
with the same curve as the session header icon. */
|
|
37028
|
+
.filex-group{display:inline-flex;align-items:center;position:relative;height:28px}
|
|
37029
|
+
.filex-group .filex-group-main,.filex-group .filex-group-trigger{height:28px}
|
|
37030
|
+
.filex-group .filex-group-main{border-radius:14px 0 0 14px;padding:0 9px}
|
|
37031
|
+
.filex-group .filex-group-trigger{margin-left:-1px;border-radius:0 14px 14px 0;border-left:0;padding:0 7px}
|
|
37020
37032
|
|
|
37021
37033
|
/* ── hero floating utility (shell.overlay entry) ─────────────────────── */
|
|
37022
|
-
/* The
|
|
37034
|
+
/* The ButtonGroup, pinned by the plugin to the conversation column's
|
|
37023
37035
|
top-right while the column is in its hero phase. The shell.overlay layer
|
|
37024
37036
|
is click-through by design, so the entry opts back into pointer events;
|
|
37025
37037
|
no explicit z-index keeps it below sibling overlay entries (modal,
|
|
@@ -37033,6 +37045,12 @@ window.__ModuleLoader__.load({
|
|
|
37033
37045
|
|
|
37034
37046
|
/* ── modal surface (headless primitives Modal) ───────────────────────── */
|
|
37035
37047
|
.filex-modal{width:min(1200px,92vw);height:min(780px,88vh);gap:0;padding:0;border-radius:16px}
|
|
37048
|
+
/* Full-viewport mode (header toggle). The shell's dialog sits in a fixed
|
|
37049
|
+
root with 24px padding, so a fixed inset:0 card fills the whole window
|
|
37050
|
+
without being inset by that padding. */
|
|
37051
|
+
.filex-modal-full{position:fixed;inset:0;width:auto;height:auto;border-radius:0}
|
|
37052
|
+
/* The expand-corners glyph rotated 180° reads as "exit fullscreen". */
|
|
37053
|
+
.filex-fs-on{transform:rotate(180deg)}
|
|
37036
37054
|
|
|
37037
37055
|
/* ── explorer frame ──────────────────────────────────────────────────── */
|
|
37038
37056
|
.filex-explorer{display:flex;flex-direction:column;height:100%;min-height:0}
|
|
@@ -37357,6 +37375,8 @@ window.__ModuleLoader__.load({
|
|
|
37357
37375
|
const [jumpRanges, setJumpRanges] = (0, react.useState)(void 0);
|
|
37358
37376
|
const [collapsed, setCollapsed] = (0, react.useState)(/* @__PURE__ */ new Set());
|
|
37359
37377
|
const [savedFlash, setSavedFlash] = (0, react.useState)("");
|
|
37378
|
+
/** Full-viewport mode: the modal card fills the whole window (toggle in the header). */
|
|
37379
|
+
const [fullscreen, setFullscreen] = (0, react.useState)(false);
|
|
37360
37380
|
const [sideMenu, setSideMenu] = (0, react.useState)(null);
|
|
37361
37381
|
const [sideToast, setSideToast] = (0, react.useState)("");
|
|
37362
37382
|
const [toastKey, setToastKey] = (0, react.useState)(0);
|
|
@@ -37714,7 +37734,7 @@ window.__ModuleLoader__.load({
|
|
|
37714
37734
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
37715
37735
|
open: true,
|
|
37716
37736
|
headless: true,
|
|
37717
|
-
className: "filex-modal"
|
|
37737
|
+
className: `filex-modal${fullscreen ? " filex-modal-full" : ""}`,
|
|
37718
37738
|
title: openPath ?? "文件预览 / 编辑",
|
|
37719
37739
|
closeLabel: "关闭",
|
|
37720
37740
|
onClose: handleClose,
|
|
@@ -37732,18 +37752,30 @@ window.__ModuleLoader__.load({
|
|
|
37732
37752
|
})
|
|
37733
37753
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
37734
37754
|
className: "filex-header-actions",
|
|
37735
|
-
children: [
|
|
37736
|
-
|
|
37737
|
-
|
|
37738
|
-
|
|
37739
|
-
|
|
37740
|
-
|
|
37741
|
-
|
|
37742
|
-
|
|
37743
|
-
|
|
37744
|
-
|
|
37745
|
-
|
|
37746
|
-
|
|
37755
|
+
children: [
|
|
37756
|
+
savedFlash !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37757
|
+
className: `filex-badge${savedFlash.startsWith("保存失败") ? " filex-badge-warn" : ""}`,
|
|
37758
|
+
children: savedFlash
|
|
37759
|
+
}),
|
|
37760
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
37761
|
+
type: "button",
|
|
37762
|
+
size: "sm",
|
|
37763
|
+
variant: "ghost",
|
|
37764
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFullscreenOutline16, { className: fullscreen ? "filex-fs-on" : void 0 }),
|
|
37765
|
+
title: fullscreen ? "退出全屏" : "全屏",
|
|
37766
|
+
"aria-label": fullscreen ? "退出全屏" : "全屏",
|
|
37767
|
+
onClick: () => setFullscreen((v) => !v)
|
|
37768
|
+
}),
|
|
37769
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
37770
|
+
type: "button",
|
|
37771
|
+
size: "sm",
|
|
37772
|
+
variant: "ghost",
|
|
37773
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, {}),
|
|
37774
|
+
title: "关闭(Esc)",
|
|
37775
|
+
"aria-label": "关闭",
|
|
37776
|
+
onClick: handleClose
|
|
37777
|
+
})
|
|
37778
|
+
]
|
|
37747
37779
|
})]
|
|
37748
37780
|
}),
|
|
37749
37781
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -38023,26 +38055,23 @@ window.__ModuleLoader__.load({
|
|
|
38023
38055
|
//#endregion
|
|
38024
38056
|
//#region src/client/index.tsx
|
|
38025
38057
|
/**
|
|
38026
|
-
* Client half of dsh-file-explorer
|
|
38027
|
-
* the file-explorer modal (editor mode), the session's working folder in the
|
|
38028
|
-
* OS file manager (folder mode), or the workspace in VS Code (vscode mode),
|
|
38029
|
-
* plus the overlay modal, the Ctrl+P shortcut, and transient notices.
|
|
38058
|
+
* Client half of dsh-file-explorer.
|
|
38030
38059
|
*
|
|
38031
|
-
* The
|
|
38032
|
-
*
|
|
38033
|
-
*
|
|
38034
|
-
*
|
|
38035
|
-
*
|
|
38036
|
-
*
|
|
38060
|
+
* The in-chat session header (`conversation.session.header.utilities`) keeps
|
|
38061
|
+
* a single built-in-editor icon: clicking it opens the file-explorer modal
|
|
38062
|
+
* (preview / edit). The hero / new-session floating utility rendered by the
|
|
38063
|
+
* plugin itself through the generic `shell.overlay` layer carries the full
|
|
38064
|
+
* ButtonGroup — the left button performs the remembered open action
|
|
38065
|
+
* (内置编辑器 / 系统文件夹 / VS Code) and the right chevron opens a dropdown
|
|
38066
|
+
* to switch between them. Selecting an entry both persists it as the new
|
|
38067
|
+
* default and immediately runs that action.
|
|
38037
38068
|
*
|
|
38038
|
-
* The
|
|
38039
|
-
*
|
|
38040
|
-
* plugin-owned entry pins it to the conversation column's top-right while
|
|
38041
|
-
* the column is in its hero phase — the no-session hero and the
|
|
38069
|
+
* The floating entry pins itself to the conversation column's top-right
|
|
38070
|
+
* while the column is in its hero phase — the no-session hero and the
|
|
38042
38071
|
* blank-session (new chat) hero, where the session header and its utilities
|
|
38043
|
-
* seat are absent or deliberately hidden.
|
|
38044
|
-
*
|
|
38045
|
-
*
|
|
38072
|
+
* seat are absent or deliberately hidden. It resolves its session itself:
|
|
38073
|
+
* the actions fall back to the live selection (`useSessions` →
|
|
38074
|
+
* `state.current`) and show a notice when none exists.
|
|
38046
38075
|
*
|
|
38047
38076
|
* Session binding: every /filex request is conversation-scoped, so the modal
|
|
38048
38077
|
* must know WHICH session it belongs to — the host resolves the workspace
|
|
@@ -38193,6 +38222,7 @@ window.__ModuleLoader__.load({
|
|
|
38193
38222
|
showNotice(`用 VS Code 打开失败:${error instanceof Error ? error.message : String(error)}`);
|
|
38194
38223
|
}
|
|
38195
38224
|
}
|
|
38225
|
+
/** Close the modal (session binding stays for the next open). */
|
|
38196
38226
|
function closeExplorer() {
|
|
38197
38227
|
store = {
|
|
38198
38228
|
...store,
|
|
@@ -38256,20 +38286,49 @@ window.__ModuleLoader__.load({
|
|
|
38256
38286
|
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(VscodeIcon, {})
|
|
38257
38287
|
}
|
|
38258
38288
|
];
|
|
38259
|
-
/** The header
|
|
38260
|
-
function
|
|
38289
|
+
/** The in-chat header icon: a single built-in-editor entry. */
|
|
38290
|
+
function HeaderIcon(props) {
|
|
38291
|
+
const title = "文件预览 / 编辑(Ctrl+P)";
|
|
38292
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
38293
|
+
label: title,
|
|
38294
|
+
side: "bottom",
|
|
38295
|
+
delayMs: 400,
|
|
38296
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
38297
|
+
type: "button",
|
|
38298
|
+
className: "filex-header-btn",
|
|
38299
|
+
size: "sm",
|
|
38300
|
+
variant: "outline",
|
|
38301
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutline16, {}),
|
|
38302
|
+
title,
|
|
38303
|
+
"aria-label": "文件预览 / 编辑",
|
|
38304
|
+
onClick: (e) => {
|
|
38305
|
+
e.stopPropagation();
|
|
38306
|
+
openExplorer(props.sessionId);
|
|
38307
|
+
}
|
|
38308
|
+
})
|
|
38309
|
+
});
|
|
38310
|
+
}
|
|
38311
|
+
/**
|
|
38312
|
+
* The hero ButtonGroup: the left button carries the remembered mode's icon and
|
|
38313
|
+
* runs its action, the right chevron opens the mode dropdown. Rendered only on
|
|
38314
|
+
* the hero / new-session screen — the in-chat header keeps the single
|
|
38315
|
+
* built-in-editor `HeaderIcon`.
|
|
38316
|
+
*/
|
|
38317
|
+
function HeroGroup(props) {
|
|
38261
38318
|
const state = (0, react.useSyncExternalStore)(subscribe, getSnapshot);
|
|
38262
38319
|
const [menuOpen, setMenuOpen] = (0, react.useState)(false);
|
|
38263
|
-
const
|
|
38320
|
+
const useSessions = props.useSessions ?? (() => void 0);
|
|
38321
|
+
const sessionId = useSessions((s) => s.current);
|
|
38322
|
+
const sessionCwd = useSessions((s) => sessionId !== void 0 ? s.byId?.[sessionId]?.cwd : void 0);
|
|
38264
38323
|
const mode = state.mode;
|
|
38265
38324
|
const items = state.vscode ? MODE_ITEMS : MODE_ITEMS.filter((item) => item.id !== "vscode");
|
|
38266
38325
|
const mainIcon = mode === "folder" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpen16, {}) : mode === "vscode" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(VscodeIcon, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutline16, {});
|
|
38267
38326
|
const mainTitle = mode === "folder" ? "打开系统文件夹" : mode === "vscode" ? "用 VSCode 打开工作区" : "文件预览 / 编辑(Ctrl+P)";
|
|
38268
38327
|
const onMainClick = (e) => {
|
|
38269
38328
|
e.stopPropagation();
|
|
38270
|
-
if (mode === "folder") openSystemFolder(
|
|
38271
|
-
else if (mode === "vscode") openInVscode(
|
|
38272
|
-
else openExplorer(
|
|
38329
|
+
if (mode === "folder") openSystemFolder(sessionId, sessionCwd);
|
|
38330
|
+
else if (mode === "vscode") openInVscode(sessionId, sessionCwd);
|
|
38331
|
+
else openExplorer(sessionId);
|
|
38273
38332
|
};
|
|
38274
38333
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
38275
38334
|
label: mainTitle,
|
|
@@ -38286,9 +38345,9 @@ window.__ModuleLoader__.load({
|
|
|
38286
38345
|
const next = id === "folder" || id === "vscode" ? id : "editor";
|
|
38287
38346
|
setMode(next);
|
|
38288
38347
|
setMenuOpen(false);
|
|
38289
|
-
if (next === "folder") openSystemFolder(
|
|
38290
|
-
else if (next === "vscode") openInVscode(
|
|
38291
|
-
else openExplorer(
|
|
38348
|
+
if (next === "folder") openSystemFolder(sessionId, sessionCwd);
|
|
38349
|
+
else if (next === "vscode") openInVscode(sessionId, sessionCwd);
|
|
38350
|
+
else openExplorer(sessionId);
|
|
38292
38351
|
},
|
|
38293
38352
|
onClose: () => setMenuOpen(false),
|
|
38294
38353
|
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -38320,7 +38379,7 @@ window.__ModuleLoader__.load({
|
|
|
38320
38379
|
});
|
|
38321
38380
|
}
|
|
38322
38381
|
/**
|
|
38323
|
-
* Hero / new-session floating utility: the
|
|
38382
|
+
* Hero / new-session floating utility: the hero ButtonGroup, rendered by the
|
|
38324
38383
|
* plugin itself through the generic `shell.overlay` floating layer (no shell
|
|
38325
38384
|
* change needed) and pinned to the conversation column's top-right corner —
|
|
38326
38385
|
* the spot where the session-header utilities sit once a conversation has
|
|
@@ -38328,7 +38387,7 @@ window.__ModuleLoader__.load({
|
|
|
38328
38387
|
* (no session at all, or a blank session whose header is deliberately
|
|
38329
38388
|
* hidden); the position is measured from the rendered column root
|
|
38330
38389
|
* (`[data-phase]`), so sidebar collapse and details-panel toggles are
|
|
38331
|
-
* tracked automatically. Clicking behaves exactly like the
|
|
38390
|
+
* tracked automatically. Clicking behaves exactly like the in-chat icon: in a
|
|
38332
38391
|
* blank-session hero the actions bind to that session, and with no session
|
|
38333
38392
|
* at all they surface the no-session notice.
|
|
38334
38393
|
*/
|
|
@@ -38368,7 +38427,7 @@ window.__ModuleLoader__.load({
|
|
|
38368
38427
|
top: pos.top,
|
|
38369
38428
|
right: pos.right
|
|
38370
38429
|
},
|
|
38371
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
38430
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HeroGroup, { useSessions: props.useSessions })
|
|
38372
38431
|
});
|
|
38373
38432
|
}
|
|
38374
38433
|
/** The overlay entry: keyboard shortcut + modal + transient notice. */
|
|
@@ -38445,7 +38504,7 @@ window.__ModuleLoader__.load({
|
|
|
38445
38504
|
id: "file-explorer",
|
|
38446
38505
|
order: 10,
|
|
38447
38506
|
label: "文件预览 / 编辑"
|
|
38448
|
-
},
|
|
38507
|
+
}, HeaderIcon));
|
|
38449
38508
|
ctx.slots.inject("shell.overlay", () => {
|
|
38450
38509
|
const overlay = ctx.slots.register({
|
|
38451
38510
|
name: "shell.overlay",
|
package/lib/index.js
CHANGED
|
@@ -43,8 +43,9 @@ function isTrustedApiRequest(request) {
|
|
|
43
43
|
//#region src/index.ts
|
|
44
44
|
/**
|
|
45
45
|
* dsh-file-explorer host half: the /filex JSON API (session cwd, file list,
|
|
46
|
-
* read / write / content search
|
|
47
|
-
* PDFs). Every route passes the same
|
|
46
|
+
* read / write / content search, OS file-manager reveal, VS Code launch) and
|
|
47
|
+
* the /filex/file media route (images / PDFs). Every route passes the same
|
|
48
|
+
* loopback browser-trust fence.
|
|
48
49
|
*
|
|
49
50
|
* All operations are conversation-scoped: requests carry a sessionId and the
|
|
50
51
|
* session's authoritative cwd comes from the session store.
|
package/package.json
CHANGED