dsh-code-server-app 0.3.20 → 0.3.22
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.en.md +82 -19
- package/README.md +74 -21
- package/assets/extensions/dshcs-editor-bridge/extension.js +120 -64
- package/assets/extensions/dshcs-editor-bridge/lib/ask-panel.js +343 -174
- package/assets/extensions/dshcs-editor-bridge/lib/bridge-client.js +30 -4
- package/assets/extensions/dshcs-editor-bridge/package.json +2 -2
- package/assets/extensions/dshcs-editor-bridge/webview/THIRD-PARTY.md +21 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_AMS-Regular-U6PRYMIZ.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_Caligraphic-Bold-5QL5CMTE.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_Caligraphic-Regular-KX5MEWCF.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_Fraktur-Bold-2QVFK6NQ.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_Fraktur-Regular-2PEIFJSJ.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_Main-Bold-YP5VVQRP.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_Main-BoldItalic-N4V3DX7S.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_Main-Italic-RELBIK7M.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_Main-Regular-ARRPAO67.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_Math-BoldItalic-K4WTGH3J.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_Math-Italic-6KGCHLFN.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_SansSerif-Bold-RRNVJFFW.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_SansSerif-Italic-HMPFTM52.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_SansSerif-Regular-XIQ62X4E.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_Script-Regular-APUWIHLP.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_Size1-Regular-5LRUTBFT.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_Size2-Regular-LELKET5D.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_Size3-Regular-WQRQ47UD.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_Size4-Regular-CDMV7U5C.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/fonts/KaTeX_Typewriter-Regular-VBYJ4NRC.woff2 +0 -0
- package/assets/extensions/dshcs-editor-bridge/webview/src/app.jsx +189 -0
- package/assets/extensions/dshcs-editor-bridge/webview/src/approval.jsx +53 -0
- package/assets/extensions/dshcs-editor-bridge/webview/src/official-tokens.css +8 -0
- package/assets/extensions/dshcs-editor-bridge/webview/src/panel.css +283 -0
- package/assets/extensions/dshcs-editor-bridge/webview/src/thread.jsx +72 -0
- package/assets/extensions/dshcs-editor-bridge/webview/thread.css +1 -0
- package/assets/extensions/dshcs-editor-bridge/webview/thread.js +462 -0
- package/lib/bridge-approval.mjs +189 -0
- package/lib/bridge-session.mjs +3 -1
- package/lib/bridge-thread.mjs +345 -0
- package/lib/bridge.mjs +15 -6
- package/lib/index.js +142 -17
- package/package.json +29 -6
- package/vendor/VENDOR.json +1 -1
- package/lib/bridge-answer.mjs +0 -155
package/README.en.md
CHANGED
|
@@ -12,6 +12,11 @@
|
|
|
12
12
|
|
|
13
13
|
A static profile plugin (npm package with host + client bundle) that ships the **VS Code server tree** from a [code-server](https://github.com/coder/code-server) release as a **platform-independent dependency package** (pack-time artifact `vendor/vscode` → `@jinsiyu/dshcs-vscode-server`, no install scripts, no postinstall). The code-server **Node service layer is replaced by the plugin's own `lib/launcher.mjs`**: it drives `<tree>/lib/vscode/out/server-main.js` (`loadCodeWithNls()` / `createServer()` / `handleRequest()` / `handleUpgrade()`) directly and re-adds the few HTTP endpoints code-server used to provide (`/healthz`, `/manifest.json`, `/_static/*`, `/proxy/:port`). The 16 native modules (node-pty / @vscode/sqlite3 / spdlog / …) come from `@jinsiyu/dshcs-*-win32-<arch>` platform packages selected automatically per architecture by the platform aggregator. VS Code's inner dependencies and the prebuilt native modules are **all installed by the package manager together with the plugin** — no global npm install, no `bin` configuration, no profile config changes, no second install command, **no argon2/C++ toolchain**.
|
|
14
14
|
|
|
15
|
+
> Since 0.3.22 the ask panel renders the session's new content with **DSH's own Markdown renderer** (the same
|
|
16
|
+
> renderer and design tokens as the DSH UI; new content only) and can **answer approval requests in place**
|
|
17
|
+
> (writing outside the workspace / running commands). See "Working with DSH: the editor bridge" and section 21 of
|
|
18
|
+
> `docs/analysis-code-server-as-dsh-plugin.md`.
|
|
19
|
+
|
|
15
20
|
## UI carrier and required DSH version (0.2.3: right-sidebar DSH only)
|
|
16
21
|
|
|
17
22
|
| DSH version | Carrier | Entry points |
|
|
@@ -198,19 +203,35 @@ only the editor knows, and lets editor gestures drive the current session.
|
|
|
198
203
|
| Direction | Capability | Mechanism |
|
|
199
204
|
|---|---|---|
|
|
200
205
|
| editor → agent | **unsaved buffers** (disk ≠ what the user sees), active file and selection, **language-server diagnostics** with `file:line`, source and code | agent tools `editor_context` / `editor_diagnostics`; plus a notice attached before writing a dirty file |
|
|
201
|
-
| editor → DSH | select code → context menu **"DSH: ask about selection"** → an **ask panel** opens (carrying `file:line` and the selection); the question enters the current session as **user input**, and
|
|
206
|
+
| editor → DSH | select code → context menu **"DSH: ask about selection"** → an **ask panel** opens (carrying `file:line` and the selection); the question enters the current session as **user input**, and that session's **new content** is rendered in the panel by DSH's own Markdown renderer | extension command `dsh-code-server.askAboutSelection` (one of the **top two** editor context-menu items) + a webview panel + `POST /ask` + the `thread` field of `/sync` |
|
|
207
|
+
| DSH → editor (approval) | when the agent wants to **write outside the workspace or run a command**, the approval request shows up as a card in the panel (tool, reason, countdown); "allow once" / "reject" takes effect immediately | the `approvals` field of `/sync` + `POST /approve` (the bridge's **only** non-read-only route; constraints under "Security model") |
|
|
202
208
|
| agent → editor | the agent changed a file → a **native diff** opens; if that buffer has unsaved changes you get a warning and **no overwrite** | host watches `tools/result`, the extension polls and opens the diff |
|
|
203
209
|
|
|
204
210
|
- The tools are only registered while the bridge is live (so the model never sees an unusable tool), and the
|
|
205
211
|
system-prompt section renders only then too.
|
|
206
|
-
- **Ask panel** (extension 0.2.0
|
|
207
|
-
|
|
208
|
-
|
|
212
|
+
- **Ask panel** (extension 0.2.0; since 0.2.3 the body goes through the official renderer): the context-menu command
|
|
213
|
+
no longer pops a one-line input box but opens a panel — that session's **new content** on top, input at the bottom.
|
|
214
|
+
The selection is captured **at send time** (so you can change it while the panel stays open).
|
|
215
|
+
The two commands **remember their intent** (0.3.21): "ask about selection" carries a **line range + selection text**
|
|
216
|
+
only when something is actually selected, while "ask about file" **never carries line numbers or a selection** — the
|
|
217
|
+
cursor line is irrelevant to the question and only misleads the agent. With no selection, the selection command also
|
|
218
|
+
degrades to the plain file.
|
|
219
|
+
- **The panel renders exactly what DSH renders** (0.3.22): the panel bundles DSH's official Markdown renderer
|
|
220
|
+
(`MarkdownText` from `@deepseek-ai/dsh-client-ui-primitives`) plus the official design tokens — the same
|
|
221
|
+
micromark/mdast pipeline, the same incremental streaming parser, the same shiki highlighting (boot set:
|
|
222
|
+
typescript / shellscript / json), KaTeX math and the same heading/table typography. Only **new content** is
|
|
223
|
+
rendered (from the moment the panel subscribes); history is **not replayed** and there is no "load earlier".
|
|
224
|
+
- **Approvals are handled right in the panel** (0.3.22): while the panel is open, that session's approval requests
|
|
225
|
+
ask the panel first (8 s by default). Clicking "allow once" / "reject" settles it immediately; if nobody answers,
|
|
226
|
+
the request is handed back **unchanged** to the official path (the DSH UI shows the same card).
|
|
227
|
+
**Nothing is ever auto-approved** — `allowed-once` can only come from a click, and there is no "always allow".
|
|
209
228
|
- The question enters the DSH session as a **plain user message** (`source: { kind: 'user' }`, host 0.3.19): earlier
|
|
210
229
|
versions used `{kind:'plugin'}`, which DSH renders as a *context update* — it did not look like something the user
|
|
211
|
-
said. Provenance stays in the first line of the text: `From the editor: <file
|
|
212
|
-
- **
|
|
213
|
-
|
|
230
|
+
said. Provenance stays in the first line of the text: `From the editor: <file>[:<line>]`.
|
|
231
|
+
- **Read-only with one constrained exception**: the bridge never writes files, applies edits, or runs commands; the
|
|
232
|
+
single non-read-only route is `POST /approve`, which can only **answer an approval request that already exists**
|
|
233
|
+
(see invariant 2 below). The agent's writes still go through its own `fs` tools; the bridge only *knows about* them
|
|
234
|
+
and carries your answer back.
|
|
214
235
|
- Status bar shows `$(plug) DSH` while connected (click it for the log in the "DSH Editor Bridge" output channel).
|
|
215
236
|
- **The extension ships as a built-in** (fixed in 0.3.12): `dshcs-editor-bridge` is installed into
|
|
216
237
|
`<tree>/lib/vscode/extensions/` next to `dshcs-open-file`. 0.3.0–0.3.11 installed it as a *user* extension
|
|
@@ -222,8 +243,9 @@ only the editor knows, and lets editor gestures drive the current session.
|
|
|
222
243
|
### The channels (since 0.3.13 over **local IPC**: a Windows named pipe / unix socket)
|
|
223
244
|
|
|
224
245
|
```
|
|
225
|
-
extension → host POST /code-server-bridge/sync one round trip: push editor state + take
|
|
246
|
+
extension → host POST /code-server-bridge/sync one round trip: push editor state (+ which session the panel watches) + take events and thread deltas
|
|
226
247
|
extension → host POST /code-server-bridge/ask push an editor question into the current session
|
|
248
|
+
extension → host POST /code-server-bridge/approve answer an approval request that **already exists** (the only non-read-only route)
|
|
227
249
|
extension → host GET /code-server-bridge/health unauthenticated liveness probe
|
|
228
250
|
extension → host POST /code-server-bridge/event extension reports open/close etc. (host log tail)
|
|
229
251
|
host → extension <extensionsDir>/.dshcs-bridge/bridge.json endpoint + token, re-read every 5s
|
|
@@ -235,6 +257,14 @@ host → extension <extensionsDir>/.dshcs-bridge/bridge.json endpoint + toke
|
|
|
235
257
|
|
|
236
258
|
Requests use `http.request({ socketPath })` (`fetch` has no socket support) and **no port is ever opened**.
|
|
237
259
|
|
|
260
|
+
The three `/sync` fields the panel actually consumes (0.3.22):
|
|
261
|
+
|
|
262
|
+
| Field | Content | How the panel uses it |
|
|
263
|
+
|---|---|---|
|
|
264
|
+
| `thread` | **new content** entries (user / assistant / tool / approval) of the session the panel watches; bounded: ≤120 entries per session, ≤8000 chars per body, ≤4 watched sessions | assistant bodies go to the official renderer; tools and approvals become compact summary rows |
|
|
265
|
+
| `approvals` | pending approval requests `[{id, toolName, reason, at}]` (≤4) | renders the card with a countdown; a click posts `/approve` |
|
|
266
|
+
| `approvalHoldMs` / `uiVersion` | the approval window (8000 ms by default) / the DSH UI version | countdown basis; a renderer-version mismatch is surfaced in the panel |
|
|
267
|
+
|
|
238
268
|
> **Why not HTTP (settled in 0.3.13, all three measured)**
|
|
239
269
|
> 1. **Desktop has no HTTP surface at all**: the renderer calls `host.fetch()` through Electron IPC
|
|
240
270
|
> (`createSharedFetchHandler('/api')` in `apps/desktop-host/src/index.ts:308`) — an in-process call, unreachable
|
|
@@ -260,20 +290,29 @@ of passing stale data off as fresh).
|
|
|
260
290
|
request/response round trip every 600 ms. Polling also buys two useful properties: it is idempotent (a dropped event
|
|
261
291
|
only costs one notification — the data always lives in the editor) and the cached state is inherently fresh.
|
|
262
292
|
|
|
263
|
-
### Security model (
|
|
293
|
+
### Security model (five invariants; read before touching `lib/bridge.mjs`)
|
|
264
294
|
|
|
265
295
|
The token lives in `<extensionsDir>/.dshcs-bridge/bridge.json`, **readable by any process of the same local
|
|
266
296
|
user**, so:
|
|
267
297
|
|
|
268
|
-
1. **`/code-server-bridge/*` is
|
|
269
|
-
commands. A leaked token is therefore bounded to "sees information
|
|
270
|
-
become arbitrary file writes or command execution. A whitelist
|
|
271
|
-
guards this.
|
|
272
|
-
2. **
|
|
298
|
+
1. **`/code-server-bridge/*` is read-only, with `/approve` as the single exception.** No route writes files,
|
|
299
|
+
edits documents, runs commands, or spawns processes. A leaked token is therefore bounded to "sees information
|
|
300
|
+
that is in the editor" and **can never** become arbitrary file writes or command execution. A whitelist
|
|
301
|
+
assertion in `scripts/test-bridge-routes.mjs` guards this.
|
|
302
|
+
2. **The four constraints on `/approve`** (drop one and it becomes an arbitrary-command-execution back door):
|
|
303
|
+
(a) it can only **answer** an approval request that already exists — the body is exactly `{id, outcome}`, with
|
|
304
|
+
**no free text, paths, or command arguments**, so it can answer questions but never start an action;
|
|
305
|
+
(b) `id` must belong to a request this process created and that is **still pending** (single use);
|
|
306
|
+
(c) `outcome` accepts only `allowed-once` / `rejected` — there is **no "always allow"**;
|
|
307
|
+
(d) when no panel is watching, or the window (8 s by default) expires, the request goes **back to the official
|
|
308
|
+
path** — never auto-approved (DSH's `approval/request` itself fails closed; this bridge can only keep
|
|
309
|
+
"nobody answered" as "nobody answered"). `pnpm test:webview` asserts these four plus the host-side whitelist.
|
|
310
|
+
3. **Any request carrying `Origin` gets 403.** Browsers always send one (including a sandboxed iframe's literal
|
|
273
311
|
`Origin: null`); the Node extension host never does. Origin is checked **before** the token — otherwise the
|
|
274
312
|
bridge would be a "did you guess the token right" oracle for a web page.
|
|
275
|
-
|
|
276
|
-
|
|
313
|
+
4. **Paths are confined to the editor's current workspace folders.**
|
|
314
|
+
5. **Everything is bounded**: 200 diagnostics, 500-char messages, 256 KB request bodies, a 64-entry event ring,
|
|
315
|
+
≤120 thread entries per session (≤8000 chars each, ≤4 watched sessions) and ≤4 pending approvals.
|
|
277
316
|
|
|
278
317
|
This layer stops "another local app or a browser page that got hold of the file". A malicious program running as
|
|
279
318
|
the same user could read your files and the token anyway — that is outside this plugin's threat model, exactly
|
|
@@ -350,13 +389,14 @@ Diagnostics: `GET /api/code-server/status` exposes
|
|
|
350
389
|
|
|
351
390
|
```powershell
|
|
352
391
|
cd C:\Users\User\Desktop\dsh-code-server-app
|
|
353
|
-
pnpm install # dev deps (esbuild +
|
|
392
|
+
pnpm install # dev deps (esbuild + the official-renderer bundling deps); allowBuilds is explicit → no postinstall runs
|
|
354
393
|
pnpm run build:client # src/factory.js → lib/client.js (not committed; must be built first)
|
|
394
|
+
pnpm run build:webview # ask panel: official Markdown renderer + panel shell → webview/thread.{js,css} (not committed; must be built first)
|
|
355
395
|
pnpm run vendor:check # optional: show the bundled tree version vs the latest code-server release
|
|
356
396
|
pnpm run vendor:vscode # ① produce vendor/vscode (the trimmed VS Code tree, ~197MB)
|
|
357
397
|
pnpm run repack:build -- --target win32-arm64,win32-x64 --pack # ② one script builds every sub-package
|
|
358
398
|
pnpm run publish:repacks # ③ publish every @jinsiyu/* sub-package (default dist-tag: next)
|
|
359
|
-
pnpm pack # ④ → dsh-code-server-app-<version>.tgz (~
|
|
399
|
+
pnpm pack # ④ → dsh-code-server-app-<version>.tgz (~750KB, including the panel renderer assets)
|
|
360
400
|
pnpm run publish:plugin # ⑤ publish the plugin itself (default dist-tag: next)
|
|
361
401
|
# once the user has restarted dsh web and confirmed it works, promote latest:
|
|
362
402
|
pnpm run promote -- <version>
|
|
@@ -371,6 +411,14 @@ pnpm run promote -- <version>
|
|
|
371
411
|
> so their dist-tags do not affect resolution, but they default to `next` as well.
|
|
372
412
|
> Inspect the current tags with `npm dist-tag ls dsh-code-server-app`.
|
|
373
413
|
|
|
414
|
+
> `build:webview` bundles DSH's **official** Markdown renderer and design tokens into the panel assets
|
|
415
|
+
> (~1.34MB: 996KB JS + 87KB CSS + 254KB KaTeX fonts), so it needs a local DSH deployment: the script reads the
|
|
416
|
+
> `@deepseek-ai/dsh-web-frontend` version from that deployment and compares it with the renderer version pinned in
|
|
417
|
+
> devDependencies — a mismatch **fails the build** (unless `--allow-version-mismatch`). Same convention as
|
|
418
|
+
> `lib/client.js`: the artifacts are not committed and `prepack` rebuilds them.
|
|
419
|
+
> Rationale (why not an iframe, where the tokens come from, size trade-offs) is section 21 of
|
|
420
|
+
> `docs/analysis-code-server-as-dsh-plugin.md`.
|
|
421
|
+
|
|
374
422
|
`repack:build` (`scripts/vendor-repacks.mjs`) is the **single script that produces every sub-package**:
|
|
375
423
|
|
|
376
424
|
| Sub-package | Content | os/cpu |
|
|
@@ -480,7 +528,9 @@ dsh plugin --profile web add C:\Users\User\Desktop\dsh-code-server-app
|
|
|
480
528
|
>
|
|
481
529
|
> **Changing the client bundle**: edit `src/factory.js` then run `pnpm run build:client`
|
|
482
530
|
> to regenerate `lib/client.js` (that artifact is not tracked; a browser refresh picks it up — no host restart needed).
|
|
483
|
-
>
|
|
531
|
+
> **Changing the ask panel**: edit `assets/extensions/dshcs-editor-bridge/webview/src/*` then run
|
|
532
|
+
> `pnpm run build:webview` (same convention: generated, not tracked; the IDE must be restarted once to pick it up,
|
|
533
|
+
> because the extension host caches the webview resources).
|
|
484
534
|
|
|
485
535
|
### Pack-machine environment (the user machine needs nothing)
|
|
486
536
|
|
|
@@ -700,6 +750,19 @@ What remains on the plugin side:
|
|
|
700
750
|
or by simply calling `editor_context` — 0.3.0–0.3.11 sat in the state "health says bridge:true, extension never
|
|
701
751
|
loaded" (cause above: the user-level install was marked `.obsolete`).
|
|
702
752
|
- **Bridged state can lag by up to 600 ms**, and the tools say "stale" rather than serving data older than 10 s.
|
|
753
|
+
- **The ask panel renders only "new content" (0.3.22)**: the subscription starts when the panel opens, the history
|
|
754
|
+
`records` from `follow`'s opening frame are discarded, and the panel has **no "load earlier"** (the history-paging
|
|
755
|
+
API `sessionController.page()` is deliberately not called in this version). Switch to the DSH UI for older content.
|
|
756
|
+
- **Panel highlighting ships only DSH's boot grammar set** (typescript / shellscript / json): the rest of the
|
|
757
|
+
official grammars load lazily through `import()` (~1.6MB total), and the panel is a single-file IIFE with no
|
|
758
|
+
lazy loading, so those languages render as plain text (exactly like DSH's own first render, no errors).
|
|
759
|
+
For the full set: `node scripts/build-webview.mjs --all-grammars`.
|
|
760
|
+
- **Panel assets are pinned to the DSH version**: the renderer is bundled against the UI version of the deployed
|
|
761
|
+
DSH, so after upgrading DSH you must rebuild the panel (`pnpm run build:webview`; the build fails loudly on a
|
|
762
|
+
version mismatch). The panel also shows a mismatch notice at runtime instead of silently using the wrong renderer.
|
|
763
|
+
- **The approval window in the panel is 8 seconds**: while the panel is open, approvals ask the panel first and are
|
|
764
|
+
handed back to the DSH UI after 8 s — once handed back, that request can **only** be answered in the DSH UI (the
|
|
765
|
+
panel card says "handed to the DSH UI").
|
|
703
766
|
- **Unsaved buffers are reported, not taken over.** The agent still edits via its own `fs` tools, i.e. against
|
|
704
767
|
disk. What the bridge adds is a notice *before* writing a dirty file, a diff *after*, and a warning instead of
|
|
705
768
|
an overwrite. It does not decide whether the user saves — that would mean changing the agent's read path,
|
package/README.md
CHANGED
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
> 0.2.0 起:**argon2 与 code-server 的 136 个运行时依赖(express / proxy-agent / js-yaml / pem / limiter …)
|
|
22
22
|
> 全部不再随包分发**(减少 ~34.5MB + 一条原生构建链);IDE 提供方式见下方「服务方式(serve)」。
|
|
23
23
|
> 依据与实测证据见 `docs/analysis-code-server-as-dsh-plugin.md`(含子路径挂载、WS 路径、命名管道、fence 的逐项验证)。
|
|
24
|
+
>
|
|
25
|
+
> 0.3.22 起:「问 DSH」面板直接渲染 **DSH 官方的 markdown 结果**(与 DSH 界面同一份渲染器 + 同一套设计令牌,
|
|
26
|
+
> 只渲染该会话的新内容),并且**就在面板里处理授权**(工作区外写入 / 执行命令)—— 详见
|
|
27
|
+
> 「与 DSH 的协同:编辑器桥」与 `docs/analysis-code-server-as-dsh-plugin.md` 第 21 节。
|
|
24
28
|
|
|
25
29
|
## UI 载体与 DSH 版本要求(0.2.3 起只支持带右侧栏的 DSH)
|
|
26
30
|
|
|
@@ -194,17 +198,29 @@ DSH 用**资源地址**命名文件,`openFile` 只负责把地址交给右侧栏
|
|
|
194
198
|
| 方向 | 能力 | 落地方式 |
|
|
195
199
|
|---|---|---|
|
|
196
200
|
| 编辑器 → agent | **未保存缓冲区**(磁盘内容 ≠ 用户所见)、活动文件与选区、**语言服务器诊断**(含 file:line、来源、code) | agent 工具 `editor_context` / `editor_diagnostics`;写脏文件前额外附一条提醒 |
|
|
197
|
-
| 编辑器 → DSH | 选中代码 → 右键「DSH: 针对选中内容提问」→ 打开**提问面板**(带 `文件:行` 与选中内容)
|
|
201
|
+
| 编辑器 → DSH | 选中代码 → 右键「DSH: 针对选中内容提问」→ 打开**提问面板**(带 `文件:行` 与选中内容);提问以**用户输入**进当前会话,该会话的**新内容**用 DSH 官方 markdown 渲染器显示在面板里 | 命令 `dsh-code-server.askAboutSelection`(编辑器右键菜单**最上面两条**之一)+ webview 面板 + `POST /ask` + `/sync` 的 `thread` 字段 |
|
|
202
|
+
| DSH → 编辑器(授权) | agent 要**写工作区外的文件 / 执行命令**时的授权请求 → 面板里就地弹卡片(工具名 + 原因 + 倒计时),点「允许一次 / 拒绝」立刻生效 | `/sync` 的 `approvals` 字段 + `POST /approve`(桥里**唯一**的非只读路由,约束见「安全模型」) |
|
|
198
203
|
| agent → 编辑器 | agent 改了哪个文件 → 开**原生 diff** 审阅;缓冲区有未保存改动时**告警而不覆盖** | host 观察 `tools/result`,扩展轮询后开 diff + 非模态告警 |
|
|
199
204
|
|
|
200
205
|
- 工具只在桥就绪时注册(IDE 没起来时模型看不到"有个用不了的工具");提示词段落也只在桥存活时渲染。
|
|
201
|
-
- **提问面板**(扩展 0.2.0
|
|
202
|
-
|
|
206
|
+
- **提问面板**(扩展 0.2.0 起;0.2.3 起正文走官方渲染器):右键命令不再弹一行输入框,而是一个面板 ——
|
|
207
|
+
上面是该会话的**新内容**、下面是输入框;发送时**现取当前选区**(可以在面板开着的同时改选区再问)。
|
|
208
|
+
两个命令的**意图分开记**(0.3.21):「针对选中内容提问」只有真的选了内容才带**行区间 + 选区正文**;
|
|
209
|
+
「针对当前文件提问」**永远不带行号、不带选区** —— 光标停在哪一行跟问题无关,行号只会误导 agent;
|
|
210
|
+
没选区时用选中命令提问也会退化成纯文件。
|
|
211
|
+
- **面板里的正文就是 DSH 的渲染结果**(0.3.22):面板打包了 DSH 官方的 markdown 渲染器
|
|
212
|
+
(`@deepseek-ai/dsh-client-ui-primitives` 的 `MarkdownText`)与官方设计令牌 —— 同一套 micromark/mdast 管线、
|
|
213
|
+
同一个增量流式解析器、同一个 shiki 高亮(启动集 typescript / shellscript / json)、KaTeX 公式、同样的标题与表格排版。
|
|
214
|
+
只渲染**新内容**(从面板订阅那一刻起),**不重放历史**、没有"加载更早"。
|
|
215
|
+
- **授权就在面板里处理**(0.3.22):面板打开着的时候,该会话的授权请求**先问面板**(默认 8 秒),
|
|
216
|
+
点「允许一次」/「拒绝」立刻生效;没人答就把请求**原样交回官方链路**(DSH 界面照旧弹卡)。
|
|
217
|
+
**永不自动放行** —— `allowed-once` 只能来自你的一次点击,面板里没有"以后都允许"这种入口。
|
|
203
218
|
- 提问进 DSH 会话时是**普通用户消息**(`source: { kind: 'user' }`,host 0.3.19 修正):早期版本用
|
|
204
219
|
`{kind:'plugin'}` 会被 DSH 渲染成"上下文更新",看起来不像自己说的话;来源信息靠正文首行
|
|
205
|
-
`From the editor: <file
|
|
206
|
-
-
|
|
207
|
-
|
|
220
|
+
`From the editor: <file>[:<行>]` 保留。
|
|
221
|
+
- **只读 + 一个受限例外**:桥不写文件、不改文档、不执行命令;唯一的非只读路由是 `POST /approve`,
|
|
222
|
+
它只能**回答**已经存在的授权请求(见「安全模型」第 2 条)。agent 的写操作仍然全部走它自己的 `fs` 工具,
|
|
223
|
+
桥只是"知道它写了什么"、并把你对授权的答复带回去。
|
|
208
224
|
- 编辑器侧的入口还有状态栏的 `$(plug) DSH`(连通时显示,点击打开日志),日志在输出面板
|
|
209
225
|
「DSH Editor Bridge」里 —— 出问题时先看它。
|
|
210
226
|
- **扩展装在内置目录**(0.3.12 修正):`dshcs-editor-bridge` 与 `dshcs-open-file` 一样装进
|
|
@@ -216,10 +232,11 @@ DSH 用**资源地址**命名文件,`openFile` 只负责把地址交给右侧栏
|
|
|
216
232
|
### 三条通道(0.3.13 起走**本机 IPC**:Windows 命名管道 / unix socket)
|
|
217
233
|
|
|
218
234
|
```
|
|
219
|
-
扩展 → host POST /code-server-bridge/sync
|
|
220
|
-
扩展 → host POST /code-server-bridge/ask
|
|
221
|
-
扩展 → host
|
|
222
|
-
扩展 → host
|
|
235
|
+
扩展 → host POST /code-server-bridge/sync 一趟来回:上报编辑器状态(+ 面板在看哪个会话)+ 取回待处理事件与对话流
|
|
236
|
+
扩展 → host POST /code-server-bridge/ask 把编辑器里的提问投进当前会话
|
|
237
|
+
扩展 → host POST /code-server-bridge/approve 回答一条**已经存在**的授权请求(唯一的非只读路由)
|
|
238
|
+
扩展 → host GET /code-server-bridge/health 无鉴权探活(便于重启后一眼确认)
|
|
239
|
+
扩展 → host POST /code-server-bridge/event 扩展上报打开/关闭文件等(进 host 日志尾)
|
|
223
240
|
host → 扩展 <extensionsDir>/.dshcs-bridge/bridge.json 端点 + 令牌(扩展每 5s 重读)
|
|
224
241
|
(同一份内容还会写到**内置扩展旁边** `<树>/lib/vscode/extensions/.dshcs-bridge/` ——
|
|
225
242
|
环境变量只在 host spawn IDE 时注入,而被**接管**的 IDE 是上一次启动的进程、拿不到它,
|
|
@@ -228,6 +245,14 @@ host → 扩展 <extensionsDir>/.dshcs-bridge/bridge.json 端点 + 令牌(
|
|
|
228
245
|
|
|
229
246
|
请求走 `http.request({ socketPath })`(`fetch` 不支持 socket),**不开任何端口**。
|
|
230
247
|
|
|
248
|
+
`/sync` 的响应里,面板真正用到的三段(0.3.22):
|
|
249
|
+
|
|
250
|
+
| 字段 | 内容 | 面板怎么用 |
|
|
251
|
+
|---|---|---|
|
|
252
|
+
| `thread` | 被面板 `watch` 的会话的**新内容**条目(user / assistant / tool / approval),有界:每会话 ≤120 条、单条正文 ≤8000 字符、同时 watch ≤4 个会话 | 助手正文交给官方渲染器;工具与授权是紧凑摘要行 |
|
|
253
|
+
| `approvals` | 待决授权请求 `[{id, toolName, reason, at}]`(≤4 条) | 弹卡片 + 倒计时;点按后 `POST /approve` |
|
|
254
|
+
| `approvalHoldMs` / `uiVersion` | 授权窗口长度(默认 8000ms)/ DSH 界面版本 | 倒计时基准;渲染器版本不一致时提示 |
|
|
255
|
+
|
|
231
256
|
> **为什么不是 HTTP(0.3.13 定论,三条都实测过)**
|
|
232
257
|
> 1. **desktop 根本没有 HTTP 面**:渲染进程经 Electron IPC 调 `host.fetch()`
|
|
233
258
|
> (`apps/desktop-host/src/index.ts:308` 的 `createSharedFetchHandler('/api')`)—— 那是进程内函数调用,
|
|
@@ -250,21 +275,29 @@ host 反向请求不到它。所以编辑器状态只能在扩展主动发起的
|
|
|
250
275
|
**为什么不用 SSE/WebSocket**:扩展宿主里没有 HTTP 服务器,而桥的形态是"每 600ms 一趟请求/响应"。
|
|
251
276
|
轮询给了两条好性质:幂等(丢一次事件只是少一次提示,数据本身永远在编辑器里),以及状态天然最新(每趟都刷新)。
|
|
252
277
|
|
|
253
|
-
### 安全模型(
|
|
278
|
+
### 安全模型(五条不变量,改 `lib/bridge.mjs` 之前先读)
|
|
254
279
|
|
|
255
280
|
桥的令牌写在 `<extensionsDir>/.dshcs-bridge/bridge.json`(**对本机同用户进程可读**),所以:
|
|
256
281
|
|
|
257
|
-
1. **`/code-server-bridge/*`
|
|
258
|
-
|
|
282
|
+
1. **`/code-server-bridge/*` 只读,只有 `/approve` 一个例外。** 没有写文件、改文档、执行命令、
|
|
283
|
+
拉起进程的路由。令牌泄露的爆炸半径被封在"看到编辑器里的信息",**不会**变成任意文件写/任意命令执行。
|
|
259
284
|
`scripts/test-bridge-routes.mjs` 里有一条白名单断言盯着这件事(未知后缀一律 404)。
|
|
260
|
-
2.
|
|
285
|
+
2. **`/approve` 的四条约束(缺一条就等于开了任意命令执行的后门,不许放宽)**:
|
|
286
|
+
(a) 只能**回答**已经存在的授权请求,请求体只有 `{id, outcome}`,**不接受任何自由文本 / 路径 / 命令参数**
|
|
287
|
+
—— 它只能"回答问题",不能"发起动作";(b) `id` 必须是本进程自己发起、且**仍未决**的请求(用后即废);
|
|
288
|
+
(c) `outcome` 只接受 `allowed-once` / `rejected`,**没有"永久允许"**;
|
|
289
|
+
(d) 没有面板在看 / 窗口超时(默认 8s)→ **交回官方链路**,绝不自动放行
|
|
290
|
+
(DSH 的 `approval/request` 本身 fail closed,这里只能把"没人答"保持成"没人答")。
|
|
291
|
+
`pnpm test:webview-bundle` 里有针对这四条与宿主侧白名单的断言。
|
|
292
|
+
3. **带 `Origin` 的请求一律 403。** 浏览器发起必带 Origin(含沙箱 iframe 的 `Origin: null`),
|
|
261
293
|
扩展宿主是 Node 进程、不带。判定顺序上 Origin **先于令牌** —— 否则等于给浏览器一个
|
|
262
294
|
"令牌猜对没有"的 oracle。
|
|
263
295
|
实现细节:Node 路由 → Fetch 适配器把**原始 headers** 挂在 request 上(`dshcsRawHeaders`),
|
|
264
296
|
因为 undici 的 `Request` 构造器会把 `origin` 当 forbidden header 归一化掉 —— 读 `request.headers`
|
|
265
297
|
会让这道 403 静默失效(测试里有这条实测记录)。
|
|
266
|
-
|
|
267
|
-
|
|
298
|
+
4. **路径收敛在编辑器当前工作区**(`workspaceFolder` 之外的诊断直接丢弃)。
|
|
299
|
+
5. **有界**:诊断默认 200 条 / 单条截断 500 字符 / 上报体上限 256KB / 事件环形缓冲 64 条 /
|
|
300
|
+
对话流每会话 ≤120 条(单条正文 ≤8000 字符、同时 watch ≤4 个会话)/ 待决授权 ≤4 条。
|
|
268
301
|
|
|
269
302
|
这一层挡的是"本机其它应用或浏览器页面拿到那个文件后乱调桥";**同用户的本地恶意程序**
|
|
270
303
|
本来就能直接读你的文件与令牌文件 —— 那不在本插件的威胁模型内(与「回环端口的安全模型」同一句话)。
|
|
@@ -334,18 +367,25 @@ host 反向请求不到它。所以编辑器状态只能在扩展主动发起的
|
|
|
334
367
|
|
|
335
368
|
```powershell
|
|
336
369
|
cd C:\Users\User\Desktop\dsh-code-server-app
|
|
337
|
-
pnpm install # 开发依赖(esbuild +
|
|
370
|
+
pnpm install # 开发依赖(esbuild + 官方渲染器打包依赖);allowBuilds 已显式声明 → 不执行任何 postinstall
|
|
338
371
|
pnpm run build:client # src/factory.js → lib/client.js(不入库,必须先构建)
|
|
372
|
+
pnpm run build:webview # 「问 DSH」面板:官方 markdown 渲染器 + 面板外壳 → webview/thread.{js,css}(不入库,必须先构建)
|
|
339
373
|
pnpm run vendor:check # 可选:查看内置 VS Code 树版本 vs code-server 最新版
|
|
340
374
|
pnpm run vendor:vscode # ① 生成 vendor/vscode(精简 VS Code 树,≈197MB)
|
|
341
375
|
pnpm run repack:build -- --target win32-arm64,win32-x64 --pack # ② 统一脚本产出全部子包(见下表)
|
|
342
376
|
pnpm run publish:repacks # ③ 发布全部 @jinsiyu/* 子包(默认 dist-tag = next)
|
|
343
|
-
pnpm pack # ④ → dsh-code-server-app-<version>.tgz(约
|
|
377
|
+
pnpm pack # ④ → dsh-code-server-app-<version>.tgz(约 750KB,含面板渲染器产物)
|
|
344
378
|
pnpm run publish:plugin # ⑤ 发布插件本体(默认 dist-tag = next)
|
|
345
379
|
# 用户重启 dsh web 确认无误后,再把 latest 推进到该版本:
|
|
346
380
|
pnpm run promote -- <version>
|
|
347
381
|
```
|
|
348
382
|
|
|
383
|
+
> `build:webview` 会把 DSH **官方**的 markdown 渲染器与设计令牌打进面板产物(≈1.34MB:JS 996KB +
|
|
384
|
+
> CSS 87KB + KaTeX 字体 254KB),所以它要求本机有 DSH 部署:脚本读部署里 `@deepseek-ai/dsh-web-frontend`
|
|
385
|
+
> 的版本,与 devDependency 钉住的渲染器版本比对,**不一致就报错退出**(`--allow-version-mismatch` 才放行)。
|
|
386
|
+
> 它与 `lib/client.js` 同一约定:产物不入 git,`prepack` 里会自动重跑。
|
|
387
|
+
> 细节(为什么不是 iframe、令牌从哪来、体积取舍)见 `docs/analysis-code-server-as-dsh-plugin.md` 第 21 节。
|
|
388
|
+
|
|
349
389
|
> **dist-tag 政策(必须遵守)**:发布一律发到 **`next`**,**不动 `latest`**;
|
|
350
390
|
> `latest` 只保留「最近一个确认无 bug 的版本」,由 `pnpm run promote -- <version>`
|
|
351
391
|
> (= `npm dist-tag add dsh-code-server-app@<version> latest`)在**用户重启 dsh web 确认无误后**才推进。
|
|
@@ -385,8 +425,9 @@ pnpm run promote -- <version>
|
|
|
385
425
|
```powershell
|
|
386
426
|
pnpm test:apply # 桩 ctx 下跑通 apply(回归:apply 期的 ReferenceError)
|
|
387
427
|
pnpm test:claim-types # 认领类型语法与默认值
|
|
388
|
-
pnpm test:bridge-routes #
|
|
389
|
-
pnpm test:bridge-extension # 编辑器桥扩展侧纯逻辑:未保存缓冲区上报、诊断排序截断、diff
|
|
428
|
+
pnpm test:bridge-routes # 编辑器桥:路由表白名单(只读 + /approve)/ Origin 与令牌的判定顺序 / 令牌头三处一致
|
|
429
|
+
pnpm test:bridge-extension # 编辑器桥扩展侧纯逻辑:未保存缓冲区上报、诊断排序截断、diff 判据、投递降级、面板状态机
|
|
430
|
+
pnpm test:webview # 面板 webview 产物:官方渲染器与令牌打包、版本一致、/approve 的四条约束(先跑 build:webview)
|
|
390
431
|
pnpm test:launcher-routes # launcher 的 HTTP 面(起真进程,较慢)
|
|
391
432
|
pnpm test:workspace-switch # 切工作区不重启进程
|
|
392
433
|
pnpm test:fullscreen # 打开标签即全屏
|
|
@@ -487,7 +528,8 @@ dsh plugin --profile web add C:\Users\User\Desktop\dsh-code-server-app
|
|
|
487
528
|
>
|
|
488
529
|
> **改动 client bundle**:编辑 `src/factory.js` 后执行 `pnpm run build:client`
|
|
489
530
|
> 重新生成 `lib/client.js`(仓库不跟踪该产物;浏览器刷新即生效,host 无需重启)。
|
|
490
|
-
>
|
|
531
|
+
> **改动提问面板**:编辑 `assets/extensions/dshcs-editor-bridge/webview/src/*` 后执行
|
|
532
|
+
> `pnpm run build:webview`(同一约定:产物不入库;IDE 需重启一次才会加载新产物,扩展宿主会缓存 webview 资源)。
|
|
491
533
|
|
|
492
534
|
### 打包机环境要求(使用者机器什么都不需要)
|
|
493
535
|
|
|
@@ -681,6 +723,17 @@ desktop profile 由 `apps/desktop-host` 把 `/api/*` 交给同一个 `createShar
|
|
|
681
723
|
- **未保存缓冲区是"上报"而不是"接管"**:agent 仍然通过它自己的 `fs` 工具按磁盘内容编辑。
|
|
682
724
|
桥能做的是**在写之前提醒**、**写之后给 diff**、**冲突时告警而不覆盖** ——
|
|
683
725
|
它不能替用户决定保存与否(那需要改动 agent 的读路径,不在本版本范围内)。
|
|
726
|
+
- **提问面板只渲染"新内容"(0.3.22)**:订阅从面板建立那一刻开始,`follow` 开帧里的历史 `records` 被丢弃,
|
|
727
|
+
面板里**没有"加载更早"**(历史分页 API `sessionController.page()` 在这个版本里刻意不调用)。
|
|
728
|
+
想看更早的内容请回 DSH 界面。
|
|
729
|
+
- **面板的高亮只带 DSH 启动集的三套语法**(typescript / shellscript / json):官方其余语法走**懒加载**
|
|
730
|
+
(按需 `import()`,合计约 1.6MB),面板是单文件 IIFE、没有按需加载,所以那些语言的代码块**纯文本**显示
|
|
731
|
+
(与 DSH 首次渲染时的样子一致,不报错)。要全量:`node scripts/build-webview.mjs --all-grammars`。
|
|
732
|
+
- **面板产物与 DSH 版本绑定**:渲染器按构建时 DSH 部署的界面版本打包,DSH 升级后**要重打面板**
|
|
733
|
+
(`pnpm run build:webview`;构建脚本会在版本不一致时直接报错)。运行期面板顶部也会提示版本不一致,
|
|
734
|
+
不会悄悄用错版本的渲染器。
|
|
735
|
+
- **面板里的授权窗口是 8 秒**:面板打开着的时候授权先问面板,8 秒没人答就交回 DSH 界面
|
|
736
|
+
—— 交回之后这一条**只能**在 DSH 界面里处理(面板上的卡片会显示"已交给 DSH 界面")。
|
|
684
737
|
|
|
685
738
|
- ~~子路径不支持~~ **已不成立(0.2.0 实测更正)**:VS Code 渲染出的 workbench HTML 里
|
|
686
739
|
**资源引用全是相对路径**(实测 9 条引用中绝对路径 0 条,`serverBasePath="."`、`rootEndpoint="."`),
|