@jaxzhou/dsh-file-explorer 0.1.0 → 0.1.2
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 +91 -190
- package/README.zh.md +73 -155
- package/lib/client.js +386 -102
- package/lib/client.js.map +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,14 +5,18 @@
|
|
|
5
5
|
|
|
6
6
|
English | [中文](README.zh.md)
|
|
7
7
|
|
|
8
|
-
> Published on npm as **`@jaxzhou/dsh-file-explorer
|
|
9
|
-
> `dsh-file-explorer
|
|
10
|
-
> authors' plugins, so this one carries its publisher's scope.
|
|
8
|
+
> Published on npm as **`@jaxzhou/dsh-file-explorer`** — the unscoped name
|
|
9
|
+
> `dsh-file-explorer` belongs to a different author's plugin.
|
|
11
10
|
|
|
12
|
-
A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
A **Files** tab for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness),
|
|
12
|
+
beside **Chat** and **Trajectory**: the session workspace as a tree, and a preview
|
|
13
|
+
that adapts to what the file is — rendered Markdown, a JSON tree, highlighted
|
|
14
|
+
source, an image, or plain text. Read-only, no configuration, nothing stored.
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
dsh plugin --profile web add @jaxzhou/dsh-file-explorer
|
|
18
|
+
dsh --profile web
|
|
19
|
+
```
|
|
16
20
|
|
|
17
21
|
## Demo
|
|
18
22
|
|
|
@@ -20,74 +24,49 @@ chosen per file category beside it.
|
|
|
20
24
|
on the right a preview that highlights source, renders Markdown and JSON, and
|
|
21
25
|
offers a Rendered/Source toggle](media/demo.gif)](media/demo.mp4)
|
|
22
26
|
|
|
23
|
-
*30
|
|
24
|
-
NestJS workspace, it previews TypeScript, Swift, Dart, HTML, YAML and JavaScript
|
|
25
|
-
source with syntax highlighting and line numbers, shows a `README.md` rendered
|
|
26
|
-
and then as source through the **Rendered / Source** toggle, and ends on a
|
|
27
|
-
`tsconfig.json` that explains itself before falling back to highlighted source —
|
|
28
|
-
its trailing comma makes it JSONC, not strict JSON, so no tree can walk it.
|
|
29
|
-
|
|
30
|
-
## What it does
|
|
31
|
-
|
|
32
|
-
- **Workspace tree.** The session's working directory, listed one level at a
|
|
33
|
-
time, directories first, then files by natural name order. A level is fetched
|
|
34
|
-
the first time it is expanded and kept while collapsed.
|
|
35
|
-
- **A preview body per file category.**
|
|
36
|
-
|
|
37
|
-
| Category | Suffixes | Body |
|
|
38
|
-
|---|---|---|
|
|
39
|
-
| Markdown | `md` `markdown` `mkd` `mdown` `mdwn` | Rendered GFM document — headings, tables, task lists, quotes, KaTeX math, footnotes, and syntax-highlighted code fences — with a **Source** toggle |
|
|
40
|
-
| JSON | `json` `jsonc` `jsonl` `ndjson` `map` `webmanifest` | Collapsible tree with per-value copy, with a **Source** toggle; a file the tree cannot walk says so above its highlighted source — a syntax error, a truncated page, a bare scalar, or the JSONC that `tsconfig.json` and friends actually contain |
|
|
41
|
-
| Source code | 24 grammars: TypeScript/JavaScript, shell, Python, Ruby, Go, Rust, Java, C, C++, C#, Kotlin, Swift, PHP, YAML, TOML, INI, HTML, CSS, SCSS, Less, SQL, XML, Lua, MDX | Syntax-highlighted, numbered, with a copy control |
|
|
42
|
-
| Images | `png` `apng` `jpg` `jpeg` `jfif` `gif` `webp` `avif` `bmp` `ico` `svg` | Drawn, centred and scaled to the pane. An SVG draws through `<img>`, so its scripts never run |
|
|
43
|
-
| Anything else | every other suffix | Numbered, copyable plain text |
|
|
44
|
-
|
|
45
|
-
An unmapped suffix (`.vue`, `.proto`, `.txt`, …) is deliberately plain text
|
|
46
|
-
rather than a guess: a wrong grammar colours a file misleadingly.
|
|
47
|
-
- **Preview reading.** Text bodies read the file's leading 2 000 lines; an image
|
|
48
|
-
reads its complete bytes. Long lines wrap at their spaces and keep every word
|
|
49
|
-
whole; only a token with no break opportunity inside it — a long URL, one
|
|
50
|
-
minified run — is split, because the alternative is hiding it behind a
|
|
51
|
-
horizontal scrollbar. A wrapped continuation hangs under the text, not under
|
|
52
|
-
the line number. The wrap toggle applies to source bodies, where it means
|
|
53
|
-
something.
|
|
54
|
-
- **State that survives.** Expansion and the selected file live in an exclusive
|
|
55
|
-
per-session store, so switching to Chat and back — which unmounts the view —
|
|
56
|
-
does not lose your place.
|
|
57
|
-
|
|
58
|
-
Everything is read-only. The plugin browses and previews; it never writes,
|
|
59
|
-
renames, or deletes.
|
|
60
|
-
|
|
61
|
-
## Compatibility
|
|
62
|
-
|
|
63
|
-
Built and verified against **DeepSeek Harness `0.1.5-rc.2`** on the **Web**
|
|
64
|
-
surface (`dsh web`, or a profile composed from `@deepseek-ai/dsh-base` +
|
|
65
|
-
`@deepseek-ai/dsh-web-app`). It needs the Composition's
|
|
66
|
-
`@deepseek-ai/dsh-api-workspace-files` row, which the shipped Web bundle
|
|
67
|
-
mounts; a headless or SDK profile has no browser and gets no tab.
|
|
68
|
-
|
|
69
|
-
The plugin itself declares no configuration fields, so nothing in `cordis.yml`
|
|
70
|
-
needs setting.
|
|
27
|
+
*30 seconds — click for the full-quality MP4.*
|
|
71
28
|
|
|
72
|
-
##
|
|
29
|
+
## What you get
|
|
73
30
|
|
|
74
|
-
|
|
31
|
+
The left pane is the session's working directory, listed one level at a time,
|
|
32
|
+
directories first. An expanded level stays expanded while you move between
|
|
33
|
+
preview tabs.
|
|
75
34
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
35
|
+
Clicking a file opens it in a tab, so several files stay open at once — each with
|
|
36
|
+
its own body and its own wrap setting. A file that is already open is focused
|
|
37
|
+
rather than reopened, tabs whose names collide show their directory, and the tab's
|
|
38
|
+
× or a middle click closes one.
|
|
80
39
|
|
|
81
|
-
|
|
82
|
-
|
|
40
|
+
The right pane picks each tab's body from the file:
|
|
41
|
+
|
|
42
|
+
| Category | Preview |
|
|
43
|
+
|---|---|
|
|
44
|
+
| **Markdown** | Rendered GFM — headings, tables, task lists, quotes, math, footnotes, highlighted code fences — with a **Source** toggle |
|
|
45
|
+
| **JSON** | A collapsible tree with per-value copy, and the same toggle |
|
|
46
|
+
| **Source code** | Syntax highlighting, line numbers, and a copy button for 24 grammars: TypeScript/JavaScript, shell, Python, Ruby, Go, Rust, Java, C, C++, C#, Kotlin, Swift, PHP, YAML, TOML, INI, HTML, CSS, SCSS, Less, SQL, XML, Lua, MDX |
|
|
47
|
+
| **Images** | PNG, JPEG, GIF, WebP, AVIF, BMP, ICO and SVG, drawn to the pane. An SVG goes through `<img>`, so its scripts never run |
|
|
48
|
+
| **Anything else** | Numbered plain text — an unmapped suffix (`.vue`, `.proto`, `.txt`) stays plain rather than guessing a wrong grammar |
|
|
49
|
+
|
|
50
|
+
Text previews wrap at their spaces and keep every word whole; an image reads its
|
|
51
|
+
complete bytes. Every text body carries a **Copy** control in the pane's toolbar,
|
|
52
|
+
which copies the file's own text — a rendered Markdown document copies its
|
|
53
|
+
Markdown source.
|
|
54
|
+
|
|
55
|
+
## Requirements
|
|
56
|
+
|
|
57
|
+
DeepSeek Harness **0.1.5-rc.2** on the **Web** surface — `dsh web`, or a profile
|
|
58
|
+
composed from `@deepseek-ai/dsh-base` + `@deepseek-ai/dsh-web-app`. A headless or
|
|
59
|
+
SDK profile has no browser and gets no tab. The plugin declares no configuration,
|
|
60
|
+
so nothing in `cordis.yml` needs setting.
|
|
61
|
+
|
|
62
|
+
## Install
|
|
83
63
|
|
|
84
64
|
```sh
|
|
85
|
-
dsh plugin --profile web add /
|
|
86
|
-
dsh
|
|
65
|
+
dsh plugin --profile web add @jaxzhou/dsh-file-explorer
|
|
66
|
+
dsh --profile web # bundle membership is read at startup
|
|
87
67
|
```
|
|
88
68
|
|
|
89
|
-
|
|
90
|
-
template first so the browser composition exists:
|
|
69
|
+
A custom profile needs the Web composition first:
|
|
91
70
|
|
|
92
71
|
```sh
|
|
93
72
|
dsh --profile myprofile --from-default-profile web
|
|
@@ -95,146 +74,68 @@ dsh plugin --profile myprofile add @jaxzhou/dsh-file-explorer
|
|
|
95
74
|
dsh --profile myprofile
|
|
96
75
|
```
|
|
97
76
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
directory.
|
|
101
|
-
|
|
102
|
-
### Verify the install
|
|
77
|
+
Prefer a checkout or a git ref? Nothing needs building — the runtime artifacts are
|
|
78
|
+
committed:
|
|
103
79
|
|
|
104
80
|
```sh
|
|
105
|
-
dsh --profile web
|
|
81
|
+
dsh plugin --profile web add /path/to/dsh-file-explorer
|
|
82
|
+
dsh plugin --profile web add github:jaxzhou/dsh-file-explorer
|
|
106
83
|
```
|
|
107
84
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
network panel shows the plugin bundle inside one `/plugins/??…` combo response,
|
|
111
|
-
and the page head carries a `<style data-dsh-file-explorer>` tag once the plugin
|
|
112
|
-
materializes.
|
|
113
|
-
|
|
114
|
-
## Disable and uninstall
|
|
115
|
-
|
|
116
|
-
- **Disable without uninstalling** — add a row override to the profile's
|
|
117
|
-
`cordis.patch.yml` (applied after every bundle layer):
|
|
118
|
-
|
|
119
|
-
```yaml
|
|
120
|
-
- id: jaxzhou-file-explorer
|
|
121
|
-
disabled: true
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
Removing that entry and saving brings the tab back: a `patchReload: live`
|
|
125
|
-
profile re-applies the file without a restart.
|
|
126
|
-
|
|
127
|
-
- **Uninstall** — `dsh plugin --profile web remove @jaxzhou/dsh-file-explorer`,
|
|
128
|
-
then restart the profile.
|
|
129
|
-
|
|
130
|
-
## Data path and permissions
|
|
131
|
-
|
|
132
|
-
- **Reads** go through the harness's own `workspaceFiles` Remote namespace:
|
|
133
|
-
`list(sessionId, path)` for one directory level and
|
|
134
|
-
`read(sessionId, path, { offset, limit })` for one text page. The Host's
|
|
135
|
-
composed filesystem decides readability, so the plugin holds no file access,
|
|
136
|
-
no path resolution, and no credentials of its own.
|
|
137
|
-
- **Writes**: none. The Remote namespace exposes no mutation operation.
|
|
138
|
-
- **Storage**: none. The plugin persists nothing — not to disk, not to the
|
|
139
|
-
session log. All state is in-memory view state, discarded with the session
|
|
140
|
-
binding.
|
|
141
|
-
- **Host authority**: the Host half of the package is inert; it registers no
|
|
142
|
-
service, tool, prompt section, or event.
|
|
143
|
-
|
|
144
|
-
## Development
|
|
85
|
+
Then open a session that has a workspace and click **Files**. To confirm the layer
|
|
86
|
+
landed:
|
|
145
87
|
|
|
146
88
|
```sh
|
|
147
|
-
|
|
148
|
-
npm run check # typecheck, build both runtime artifacts, run the tests
|
|
89
|
+
dsh --profile web --dump-config | grep -A 2 jaxzhou-file-explorer
|
|
149
90
|
```
|
|
150
91
|
|
|
151
|
-
|
|
152
|
-
tarball install loads them directly and needs no build step or `allowBuilds`
|
|
153
|
-
permission.
|
|
92
|
+
## Disable or uninstall
|
|
154
93
|
|
|
155
|
-
|
|
156
|
-
|
|
94
|
+
Disable the tab without uninstalling by adding an override to the profile's
|
|
95
|
+
`cordis.patch.yml` — it is applied after every bundle layer, and a
|
|
96
|
+
`patchReload: live` profile picks it up without a restart:
|
|
157
97
|
|
|
158
|
-
```
|
|
159
|
-
|
|
98
|
+
```yaml
|
|
99
|
+
- id: jaxzhou-file-explorer
|
|
100
|
+
disabled: true
|
|
160
101
|
```
|
|
161
102
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
`@deepseek-ai/dsh-client-store`, `@deepseek-ai/dsh-client-ui-primitives`, …);
|
|
165
|
-
every other dsh package is imported type-only and erased, so no `require` in the
|
|
166
|
-
artifact can miss the table.
|
|
103
|
+
Uninstall with `dsh plugin --profile web remove @jaxzhou/dsh-file-explorer`, then
|
|
104
|
+
restart the profile.
|
|
167
105
|
|
|
168
|
-
|
|
169
|
-
numbered gutter, its copy control, and the shiki grammars all come from
|
|
170
|
-
`@deepseek-ai/dsh-client-ui-primitives`, which the shell shares into that table.
|
|
171
|
-
This plugin contributes the format decision and the pane, not a second
|
|
172
|
-
renderer.
|
|
173
|
-
|
|
174
|
-
### Layout
|
|
175
|
-
|
|
176
|
-
| Path | Role |
|
|
177
|
-
|---|---|
|
|
178
|
-
| `src/index.ts` | Host half: an inert Loader module |
|
|
179
|
-
| `src/client/index.ts` | Client plugin: stylesheet, dictionaries, and the `conversation.view` registration |
|
|
180
|
-
| `src/client/FilesView.tsx` | The two-pane page: tree, headers, and the per-format preview bodies |
|
|
181
|
-
| `src/client/format.ts` | Suffix → preview format, and the grammar/media-type tables |
|
|
182
|
-
| `src/client/store.ts` | The exclusive per-session view store |
|
|
183
|
-
| `src/client/face.ts` | The injected face: Remote listing, paged text reads, and complete-byte image reads |
|
|
184
|
-
| `src/client/styles.ts` | The plugin-owned stylesheet |
|
|
185
|
-
| `src/client/locales.ts` | `fileExplorer` dictionaries (zh, en) and the namespace declaration |
|
|
186
|
-
| `cordis.patch.yml` | The bundle layer: one inserted row || `tests/contract.test.mjs` | Contract tests over the built artifacts |
|
|
187
|
-
|
|
188
|
-
Each source focus is a separate module with its own header comment; start there
|
|
189
|
-
for the reasoning behind a choice.
|
|
190
|
-
|
|
191
|
-
### Regenerating the demo
|
|
192
|
-
|
|
193
|
-
The README embeds a GIF and links the MP4 beside it. GitHub renders a committed
|
|
194
|
-
video only on its own file page, so the animation is what plays inline; the
|
|
195
|
-
poster frame and the link are the same recording at full quality.
|
|
196
|
-
|
|
197
|
-
```sh
|
|
198
|
-
SRC="screen recording.mov"
|
|
199
|
-
# Full-quality MP4: half the capture's width, which is a 2x screenshot's worth.
|
|
200
|
-
ffmpeg -i "$SRC" -vf scale=1680:-2:flags=lanczos -r 30 \
|
|
201
|
-
-c:v libx264 -preset slow -crf 24 -pix_fmt yuv420p -movflags +faststart -an media/demo.mp4
|
|
202
|
-
# Inline GIF: fewer frames and a smaller palette, which is where the bytes go.
|
|
203
|
-
ffmpeg -i "$SRC" -vf "fps=12,scale=1200:-2:flags=lanczos,split[a][b];\
|
|
204
|
-
[a]palettegen=max_colors=128:stats_mode=diff[p];\
|
|
205
|
-
[b][p]paletteuse=dither=bayer:bayer_scale=3:diff_mode=rectangle" -loop 0 media/demo.gif
|
|
206
|
-
```
|
|
106
|
+
## Privacy
|
|
207
107
|
|
|
208
|
-
|
|
209
|
-
|
|
108
|
+
- **Read-only.** Reads go through the harness's own `workspaceFiles` Remote
|
|
109
|
+
namespace; the Host's filesystem decides what is readable. The plugin holds no
|
|
110
|
+
file access, no path resolution, and no credentials of its own.
|
|
111
|
+
- **Nothing stored.** No disk writes and nothing added to the session log; view
|
|
112
|
+
state lives in memory and is discarded with the session.
|
|
113
|
+
- **Inert Host half.** The package's Node side registers no service, tool, prompt
|
|
114
|
+
section, or event.
|
|
210
115
|
|
|
211
116
|
## Known limitations
|
|
212
117
|
|
|
213
|
-
- **Preview only
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
- **
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
- **
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
above it are not browsable, and the Host refuses directory listings outside
|
|
235
|
-
the workspace root anyway.
|
|
236
|
-
- **No editing.** Monospaced, numbered source text with a wrapping option;
|
|
237
|
-
and rendered prose for Markdown — no folding, no search, no in-place edit.
|
|
118
|
+
- **Preview only** — no editing, saving, or diffing.
|
|
119
|
+
- **Strict JSON.** Comments or a trailing comma make a file JSONC, which
|
|
120
|
+
`JSON.parse` rejects — `tsconfig.json` is the common case. The pane says so and
|
|
121
|
+
shows the highlighted source instead of guessing at a tree.
|
|
122
|
+
- **Text previews stop at 2 000 lines**, with a truncation note and no "load
|
|
123
|
+
more"; binary files report why they cannot be shown.
|
|
124
|
+
- **Fixed grammar set.** A suffix the shared highlighter does not carry is plain
|
|
125
|
+
text, never an approximation.
|
|
126
|
+
- **Listing only** — no search, rename, context menu, or file watching; a level
|
|
127
|
+
refreshes through **Reload**.
|
|
128
|
+
- **Loaded previews are bounded.** A working set of five tabs keeps its content;
|
|
129
|
+
an older tab stays open and reads again when you return to it.
|
|
130
|
+
- **One root.** The tree is rooted at the session's working directory, and the
|
|
131
|
+
Host refuses directory listings outside the workspace root.
|
|
132
|
+
- **Markdown has no workspace vocabulary.** Relative image paths and file
|
|
133
|
+
mentions stay inert; only absolute `http(s)` images load.
|
|
134
|
+
|
|
135
|
+
## Contributing
|
|
136
|
+
|
|
137
|
+
Build, checks, the artifact model, and how the client bundle reaches the browser:
|
|
138
|
+
[CONTRIBUTING.md](CONTRIBUTING.md).
|
|
238
139
|
|
|
239
140
|
## License
|
|
240
141
|
|
package/README.zh.md
CHANGED
|
@@ -5,77 +5,63 @@
|
|
|
5
5
|
|
|
6
6
|
[English](README.md) | 中文
|
|
7
7
|
|
|
8
|
-
> npm
|
|
9
|
-
>
|
|
10
|
-
> 用,因此本插件带上发布者作用域。
|
|
8
|
+
> npm 包名是 **`@jaxzhou/dsh-file-explorer`** —— 无作用域的 `dsh-file-explorer`
|
|
9
|
+
> 属于另一位作者的插件。
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
为 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 增加一个
|
|
12
|
+
**文件** 标签,与 **对话**、**轨迹** 并列:左侧是会话工作区的目录树,右侧的预览
|
|
13
|
+
会按文件本身决定形态 —— 渲染后的 Markdown、JSON 树、语法高亮源码、图片,或纯
|
|
14
|
+
文本。只读、无需配置、不落任何数据。
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
dsh plugin --profile web add @jaxzhou/dsh-file-explorer
|
|
18
|
+
dsh --profile web
|
|
19
|
+
```
|
|
15
20
|
|
|
16
21
|
## 演示
|
|
17
22
|
|
|
18
23
|
[](media/demo.mp4)
|
|
20
25
|
|
|
21
|
-
*30 秒录屏 —— 点击可打开完整画质的 MP4。*
|
|
22
|
-
区,依次预览 TypeScript、Swift、Dart、HTML、YAML、JavaScript 源码(带语法高亮与
|
|
23
|
-
行号),用 **预览 / 源码** 切换展示同一个 `README.md` 的渲染结果与原文,最后停在
|
|
24
|
-
一个会先自我解释、再回退到高亮源码的 `tsconfig.json` 上——它尾部的逗号让它成为
|
|
25
|
-
JSONC 而非严格 JSON,所以无法展开成树。
|
|
26
|
+
*30 秒录屏 —— 点击可打开完整画质的 MP4。*
|
|
26
27
|
|
|
27
|
-
##
|
|
28
|
+
## 能做什么
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
称排序。某一层在首次展开时读取,折叠后仍保留内容。
|
|
31
|
-
- **按文件类别选择合适的预览体**:
|
|
30
|
+
左栏是会话的工作目录,逐层展开,目录在前;展开过的层级在切换预览标签后仍然保持。
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
| JSON | `json` `jsonc` `jsonl` `ndjson` `map` `webmanifest` | 可折叠树,每个值可单独复制;同样带 **源码** 切换。无法展开的文件会在高亮源码上方说明原因——语法错误、被截断、纯标量,或 `tsconfig.json` 这类文件里实际存在的 JSONC |
|
|
37
|
-
| 源码 | 24 种语法:TypeScript/JavaScript、shell、Python、Ruby、Go、Rust、Java、C、C++、C#、Kotlin、Swift、PHP、YAML、TOML、INI、HTML、CSS、SCSS、Less、SQL、XML、Lua、MDX | 语法高亮 + 行号 + 复制按钮 |
|
|
38
|
-
| 图片 | `png` `apng` `jpg` `jpeg` `jfif` `gif` `webp` `avif` `bmp` `ico` `svg` | 直接绘制,居中并在超出时缩放到窗格宽度。SVG 通过 `<img>` 绘制,其中的脚本不会执行 |
|
|
39
|
-
| 其它 | 其余全部后缀 | 带行号、可复制的纯文本 |
|
|
32
|
+
点击文件会在标签中打开它,因此可以同时打开多个文件——每个标签有自己的预览体、
|
|
33
|
+
自己的换行设置。已打开的文件会被聚焦而不是重复打开;同名的标签会带上所在目录;
|
|
34
|
+
点标签上的 × 或中键点击即可关闭。
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
误的语法着色比不着色更容易误导。
|
|
43
|
-
- **预览读取**:文本类预览只读取前 2 000 行,图片类读取完整字节。超长行在空
|
|
44
|
-
格处折行,每个单词保持完整;只有内部没有任何断点的 token(超长 URL、压缩后的
|
|
45
|
-
一整段代码)才会被拆开,因为否则它只能被藏在横向滚动条之外。折行后的续行悬挂
|
|
46
|
-
在正文下方,而不是行号下方。换行开关只在源码视图出现(那里才有意义)。
|
|
47
|
-
- **状态保留**:展开状态与当前选中文件保存在按会话独占的 store 中,因此切到
|
|
48
|
-
「对话」再切回来(组件会卸载)不会丢失浏览位置。
|
|
36
|
+
右栏按文件类别选择每个标签的预览体:
|
|
49
37
|
|
|
50
|
-
|
|
38
|
+
| 类别 | 预览 |
|
|
39
|
+
|---|---|
|
|
40
|
+
| **Markdown** | 直接渲染为 GFM —— 标题、表格、任务列表、引用、公式、脚注、高亮的代码围栏 —— 并带 **源码** 切换 |
|
|
41
|
+
| **JSON** | 可折叠树,每个值可单独复制,同样带 **源码** 切换 |
|
|
42
|
+
| **源码** | 24 种语法的语法高亮、行号与复制按钮:TypeScript/JavaScript、shell、Python、Ruby、Go、Rust、Java、C、C++、C#、Kotlin、Swift、PHP、YAML、TOML、INI、HTML、CSS、SCSS、Less、SQL、XML、Lua、MDX |
|
|
43
|
+
| **图片** | PNG、JPEG、GIF、WebP、AVIF、BMP、ICO、SVG,自动适配窗格。SVG 经 `<img>` 绘制,其中的脚本不会执行 |
|
|
44
|
+
| **其它** | 带行号的纯文本 —— 未映射的后缀(`.vue`、`.proto`、`.txt`)保持纯文本,而不是猜测一个错误的高亮 |
|
|
51
45
|
|
|
52
|
-
|
|
46
|
+
文本预览在空格处折行、保持单词完整;图片读取完整字节。每一种文本预览在窗格工具栏
|
|
47
|
+
里都有 **复制** 按钮,复制的是文件自身的文本——渲染态的 Markdown 复制的是它的
|
|
48
|
+
Markdown 源码。
|
|
53
49
|
|
|
54
|
-
|
|
55
|
-
`@deepseek-ai/dsh-base` + `@deepseek-ai/dsh-web-app` 组合出的 profile)开发并
|
|
56
|
-
验证。插件依赖组合中的 `@deepseek-ai/dsh-api-workspace-files` 行,官方 Web
|
|
57
|
-
bundle 已挂载;headless / SDK 等无浏览器界面不会出现该标签。
|
|
50
|
+
## 环境要求
|
|
58
51
|
|
|
59
|
-
|
|
52
|
+
DeepSeek Harness **0.1.5-rc.2** 的 **Web** 界面 —— `dsh web`,或由
|
|
53
|
+
`@deepseek-ai/dsh-base` + `@deepseek-ai/dsh-web-app` 组合出的 profile。headless
|
|
54
|
+
或 SDK profile 没有浏览器,不会出现该标签。插件没有配置项,`cordis.yml` 无需
|
|
55
|
+
任何设置。
|
|
60
56
|
|
|
61
57
|
## 安装
|
|
62
58
|
|
|
63
|
-
从 npm 安装:
|
|
64
|
-
|
|
65
59
|
```sh
|
|
66
60
|
dsh plugin --profile web add @jaxzhou/dsh-file-explorer
|
|
67
|
-
dsh --profile web
|
|
61
|
+
dsh --profile web # bundle 成员在启动时读取
|
|
68
62
|
```
|
|
69
63
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
```sh
|
|
73
|
-
dsh plugin --profile web add /path/to/dsh-file-explorer
|
|
74
|
-
dsh plugin --profile web add github:jaxzhou/dsh-file-explorer
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
如果使用自定义 profile(不是官方的 `web`),先基于 Web 模板创建,以保证浏览器
|
|
78
|
-
组合存在:
|
|
64
|
+
自定义 profile 需要先具备 Web 组合:
|
|
79
65
|
|
|
80
66
|
```sh
|
|
81
67
|
dsh --profile myprofile --from-default-profile web
|
|
@@ -83,129 +69,61 @@ dsh plugin --profile myprofile add @jaxzhou/dsh-file-explorer
|
|
|
83
69
|
dsh --profile myprofile
|
|
84
70
|
```
|
|
85
71
|
|
|
86
|
-
|
|
87
|
-
会显示,但页面会提示没有工作区目录。
|
|
88
|
-
|
|
89
|
-
### 验证安装
|
|
72
|
+
偏好本地检出或 git ref?无需构建 —— 运行产物已提交:
|
|
90
73
|
|
|
91
74
|
```sh
|
|
92
|
-
dsh --profile web
|
|
75
|
+
dsh plugin --profile web add /path/to/dsh-file-explorer
|
|
76
|
+
dsh plugin --profile web add github:jaxzhou/dsh-file-explorer
|
|
93
77
|
```
|
|
94
78
|
|
|
95
|
-
|
|
96
|
-
`@jaxzhou/dsh-file-explorer` 的行。随后在运行中的 Web 界面里:开发者工具的网络
|
|
97
|
-
面板中,插件 bundle 位于某个 `/plugins/??…` 合并响应内;插件加载后页面 head 中会
|
|
98
|
-
出现 `<style data-dsh-file-explorer>` 标签。
|
|
99
|
-
|
|
100
|
-
## 停用与卸载
|
|
101
|
-
|
|
102
|
-
- **临时停用**:在 profile 的 `cordis.patch.yml`(在所有 bundle 层之后应用)中
|
|
103
|
-
添加行覆盖:
|
|
104
|
-
|
|
105
|
-
```yaml
|
|
106
|
-
- id: jaxzhou-file-explorer
|
|
107
|
-
disabled: true
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
删掉该条目并保存即可恢复;`patchReload: live` 的 profile 无需重启。
|
|
111
|
-
|
|
112
|
-
- **卸载**:`dsh plugin --profile web remove @jaxzhou/dsh-file-explorer`,然后重启
|
|
113
|
-
profile。
|
|
114
|
-
|
|
115
|
-
## 数据路径与权限
|
|
116
|
-
|
|
117
|
-
- **读取**走 Harness 自带的 `workspaceFiles` Remote 命名空间:
|
|
118
|
-
`list(sessionId, path)` 读取一层目录,`read(sessionId, path, { offset, limit })`
|
|
119
|
-
读取一页文本。是否可读由 Host 组合出的文件系统决定,插件自身不持有文件权限、
|
|
120
|
-
不做路径解析、不接触任何凭据。
|
|
121
|
-
- **写入**:没有。该 Remote 命名空间不提供任何写操作。
|
|
122
|
-
- **存储**:没有。插件不落盘、不写会话日志;所有状态都是内存中的视图状态,
|
|
123
|
-
随会话绑定一起释放。
|
|
124
|
-
- **Host 权限**:包的 Host 半边是空实现,不注册服务、工具、提示词片段或事件。
|
|
125
|
-
|
|
126
|
-
## 开发
|
|
79
|
+
然后打开一个已有工作区的会话,点击 **文件** 标签。确认层已生效:
|
|
127
80
|
|
|
128
81
|
```sh
|
|
129
|
-
|
|
130
|
-
npm run check # 类型检查 + 构建两个运行产物 + 运行测试
|
|
82
|
+
dsh --profile web --dump-config | grep -A 2 jaxzhou-file-explorer
|
|
131
83
|
```
|
|
132
84
|
|
|
133
|
-
|
|
134
|
-
tarball 安装时直接加载,不需要构建步骤,也不需要 `allowBuilds` 授权。
|
|
85
|
+
## 停用与卸载
|
|
135
86
|
|
|
136
|
-
|
|
137
|
-
|
|
87
|
+
不用卸载也能关掉这个标签:在 profile 的 `cordis.patch.yml` 里加一条行覆盖
|
|
88
|
+
(它在所有 bundle 层之后应用;`patchReload: live` 的 profile 无需重启即可生效):
|
|
138
89
|
|
|
139
|
-
```
|
|
140
|
-
|
|
90
|
+
```yaml
|
|
91
|
+
- id: jaxzhou-file-explorer
|
|
92
|
+
disabled: true
|
|
141
93
|
```
|
|
142
94
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
`@deepseek-ai/dsh-client-ui-primitives` 等);其余 dsh 包都是 type-only 导入,
|
|
146
|
-
编译时即被擦除,因此产物中不会出现模块表无法回答的 `require`。
|
|
147
|
-
|
|
148
|
-
Markdown 渲染、JSON 树、语法高亮代码块及其行号与复制控件、以及 shiki 语法本身,
|
|
149
|
-
全部来自 `@deepseek-ai/dsh-client-ui-primitives`——shell 已把它共享进模块表。本插
|
|
150
|
-
件贡献的是格式判定与窗格本身,而不是第二套渲染器。
|
|
95
|
+
卸载:`dsh plugin --profile web remove @jaxzhou/dsh-file-explorer`,然后重启
|
|
96
|
+
profile。
|
|
151
97
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
| 路径 | 作用 |
|
|
155
|
-
|---|---|
|
|
156
|
-
| `src/index.ts` | Host 半边:空的 Loader 模块 |
|
|
157
|
-
| `src/client/index.ts` | 客户端插件:样式表、字典与 `conversation.view` 注册 |
|
|
158
|
-
| `src/client/FilesView.tsx` | 双栏页面:目录树、两处表头,以及按格式分发的预览体 |
|
|
159
|
-
| `src/client/format.ts` | 后缀 → 预览格式,以及语法/媒体类型表 |
|
|
160
|
-
| `src/client/store.ts` | 按会话独占的视图 store |
|
|
161
|
-
| `src/client/face.ts` | 注入面:Remote 列目录、分页读文本、整块读图片字节 |
|
|
162
|
-
| `src/client/styles.ts` | 插件自有样式表 |
|
|
163
|
-
| `src/client/locales.ts` | `fileExplorer` 字典(zh、en)与命名空间声明 |
|
|
164
|
-
| `cordis.patch.yml` | bundle 层:插入一行 |
|
|
165
|
-
| `tests/contract.test.mjs` | 针对构建产物的契约测试 |
|
|
166
|
-
|
|
167
|
-
每个源文件都是一个独立模块,文件头注释说明了其中的取舍。
|
|
168
|
-
|
|
169
|
-
### 重新生成演示
|
|
170
|
-
|
|
171
|
-
README 内嵌一个 GIF、并链接同一段录屏的 MP4。GitHub 只有在视频文件自己的页面上
|
|
172
|
-
才会播放提交进仓库的视频,所以内联动起来的是 GIF;而首帧与链接指向的是同一段
|
|
173
|
-
完整画质的录像。
|
|
174
|
-
|
|
175
|
-
```sh
|
|
176
|
-
SRC="屏幕录制.mov"
|
|
177
|
-
# 完整画质 MP4:取录制宽度的一半,相当于 2x 截图的清晰度。
|
|
178
|
-
ffmpeg -i "$SRC" -vf scale=1680:-2:flags=lanczos -r 30 \
|
|
179
|
-
-c:v libx264 -preset slow -crf 24 -pix_fmt yuv420p -movflags +faststart -an media/demo.mp4
|
|
180
|
-
# 内联 GIF:降帧率、缩调色板,体积主要就省在这里。
|
|
181
|
-
ffmpeg -i "$SRC" -vf "fps=12,scale=1200:-2:flags=lanczos,split[a][b];\
|
|
182
|
-
[a]palettegen=max_colors=128:stats_mode=diff[p];\
|
|
183
|
-
[b][p]paletteuse=dither=bayer:bayer_scale=3:diff_mode=rectangle" -loop 0 media/demo.gif
|
|
184
|
-
```
|
|
98
|
+
## 隐私
|
|
185
99
|
|
|
186
|
-
|
|
100
|
+
- **只读**:读取走 Harness 自带的 `workspaceFiles` Remote 命名空间,可读性由
|
|
101
|
+
Host 的文件系统决定。插件自身不持有文件权限、不做路径解析、不接触凭据。
|
|
102
|
+
- **不落数据**:不写磁盘、不写会话日志;视图状态保存在内存中,随会话一起释放。
|
|
103
|
+
- **Host 半边是空实现**:包的 Node 侧不注册任何服务、工具、提示词片段或事件。
|
|
187
104
|
|
|
188
105
|
## 已知限制
|
|
189
106
|
|
|
190
|
-
-
|
|
191
|
-
- **JSON
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
-
|
|
202
|
-
|
|
203
|
-
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
107
|
+
- **只预览** —— 不编辑、不保存、不做 diff。
|
|
108
|
+
- **JSON 按严格语法解析**:注释或尾逗号会让文件成为 JSONC,`JSON.parse` 会拒绝
|
|
109
|
+
—— `tsconfig.json` 是最常见的情况。此时窗格会说明原因并显示高亮源码,而不是
|
|
110
|
+
勉强猜出一棵树。
|
|
111
|
+
- **文本预览上限 2 000 行**,并提示已截断、没有「加载更多」;二进制文件会说明
|
|
112
|
+
为何无法显示。
|
|
113
|
+
- **固定的语法集**:共享高亮器未包含的后缀按纯文本显示,绝不做近似高亮。
|
|
114
|
+
- **仅目录列表** —— 没有搜索、重命名、右键菜单,也不监听文件变化;某一层通过
|
|
115
|
+
**重新读取** 更新。
|
|
116
|
+
- **已加载的预览有上限**:最近使用的 5 个标签保留内容;更早的标签仍然开着,只是
|
|
117
|
+
回到它时会重新读取。
|
|
118
|
+
- **单一根目录**:目录树以会话工作目录为根,Host 本身也拒绝读取工作区根之外的
|
|
119
|
+
目录列表。
|
|
120
|
+
- **Markdown 不解析工作区词汇**:相对图片路径与文件提及保持原样,只有绝对
|
|
121
|
+
`http(s)` 图片会加载。
|
|
122
|
+
|
|
123
|
+
## 参与开发
|
|
124
|
+
|
|
125
|
+
构建、检查、产物模型,以及客户端 bundle 如何抵达浏览器:
|
|
126
|
+
[CONTRIBUTING.md](CONTRIBUTING.md)。
|
|
209
127
|
|
|
210
128
|
## 许可证
|
|
211
129
|
|