dsh-code-server-app 0.3.63 → 0.3.66

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 CHANGED
@@ -21,10 +21,14 @@ A static profile plugin (npm package with host + client bundle) that ships the *
21
21
 
22
22
  ## UI carrier and required DSH version (0.2.3: right-sidebar DSH only)
23
23
 
24
+ Every verdict is a **capability probe**, never a version comparison. The two lines differ in two independent
25
+ places: the **right-sidebar session scope** (`sessionId` standard prop ↔ the snapshot's `current`, see
26
+ "Workspace") and the **settings surface** (seat × data channel, see the "Settings" section):
27
+
24
28
  | DSH version | Carrier | Entry points |
25
29
  |---|---|---|
26
- | **>= 0.1.5-alpha.1** (has `sidebarRight` / `sidebarRightTabs`) | **Right-sidebar tab** (kind `code-server`, chip `Code Server`), which also **claims file addresses** (see below) | ① DSH's own **produced-file chips / presented-file card previews / inline file names in prose** (since 0.2.5, via the official `openFile` → file address → this tab); ② the **Code Server box** on the sidebar's guide ("开始") page; ③ Settings → Plugins → Code Server → **"Open in right sidebar"** |
27
- | older (no sidebar service) | **Unsupported**: nothing but one notice on the settings page | none (Settings → Plugins → Code Server shows an upgrade notice) |
30
+ | **rc line** `0.1.5-rc.x` (latest `0.1.5-rc.3` = npm `latest`/`next`)**and alpha line** `>= 0.1.6-alpha.2` (latest `0.1.7-alpha.1`) — detected by the presence of `sidebarRight` / `sidebarRightTabs`, never by version comparison | **Right-sidebar tab** (kind `code-server`, chip `Code Server`), which also **claims file addresses** (see below) | ① DSH's own **produced-file chips / presented-file card previews / inline file names in prose** (since 0.2.5, via the official `openFile` → file address → this tab); ② the **Code Server box** on the sidebar's guide ("开始") page; ③ the settings block (location per "Settings") → **"Open in right sidebar"** |
31
+ | older (no sidebar service) | **Unsupported**: nothing but one notice in the settings block | none (the settings block shows an upgrade notice) |
28
32
 
29
33
  - Detection: first a synchronous `ctx.get('sidebarRightTabs') / ctx.get('sidebarRight')` probe; because the services may come up after this plugin, `ctx.inject(['sidebarRightTabs','sidebarRight'], …)` is awaited and a **2.5 s timeout marks the DSH as legacy** (no version comparison, and the plugin's own activation is never blocked).
30
34
  Since 0.2.4 that verdict is **reversible** and registration no longer relies on `ctx` property access (which on desktop silently skipped registration — the symptom was "settings card looks normal but the sidebar has no entry"):
@@ -34,9 +38,9 @@ A static profile plugin (npm package with host + client bundle) that ships the *
34
38
  - services arriving late automatically revoke the legacy verdict, register the sidebar, and report `{sidebar:true}` so the host re-enables;
35
39
  - a failed registration is no longer silent: it logs an error and the card's entry row says "right-sidebar services were found but the tab could not be registered".
36
40
  - **0.2.3 dropped legacy-DSH compatibility**: the floating ball and the internal floating window are **deleted**. When the DSH is detected as legacy the plugin
37
- - registers only the settings card (an upgrade notice) — no ball, no floating window, **no file-address claim**, no IDE preload;
41
+ - registers only the settings notice (seat per "Settings") — no ball, no floating window, **no file-address claim**, no IDE preload;
38
42
  - reports `/api/code-server/ui-mode { sidebar:false }` to the host (after the 10 s grace above); the host then **recycles an instance it auto-prestarted** and stops prestarting (a user-started/adopted instance is never touched), and `{sidebar:true}` reverses that if the services show up later;
39
- - upgrading DSH needs **no reinstall** — refresh the page and the card turns back into the full settings card.
43
+ - upgrading DSH needs **no reinstall** — refresh the page and the notice turns back into the full settings form.
40
44
  - The sidebar tab hosts the code-server page (iframe) and follows the current session workspace; the panel can be collapsed/split/floated/fullscreened by DSH's right sidebar.
41
45
  - **Fullscreen on open (0.2.9, on by default)**: opening the Code Server tab (including clicking a produced-file chip / delivered-file preview / inline file name) switches the right sidebar from "side by side with the conversation" to **fullscreen** (fills the window) — an IDE is cramped in a narrow column.
42
46
  It only affects that moment of opening: clicking the sidebar's own "Exit fullscreen" is never fought back; switching away and back, or opening another file tab, goes fullscreen again.
@@ -465,7 +469,7 @@ data call changes; the caller stays as it is).
465
469
  > Since 0.2.3 this plugin no longer supports older DSH versions.
466
470
  > The right-sidebar plugin services `sidebarRightTabs` / `sidebarRight` were not detected, so the plugin exposes no
467
471
  > entry point at all (the old floating ball and floating window have been removed) and will not start the IDE in the
468
- > background. Upgrade DSH to a version with the right sidebar (>= 0.1.5-alpha.1): Code Server then appears as a
472
+ > background. Upgrade DSH to the rc line (0.1.5-rc.x) or the alpha line from 0.1.6-alpha.2 on: Code Server then appears as a
469
473
  > right-sidebar tab, this page shows the full settings again, and no reinstall is needed — a page refresh is enough.
470
474
 
471
475
  - **No other UI**: no `shell.overlay` registration (floating ball), no file-address claim, no resident preload.
@@ -481,8 +485,8 @@ data call changes; the caller stays as it is).
481
485
 
482
486
  - code-server's workspace **follows the active DSH session/workspace**: switching sessions/workspaces while the IDE is open moves code-server to the new directory
483
487
  (resolution order: current session cwd → session's `workspace.path` → workspace of the most recently active session → first workspace.path;
484
- **where "the current session" comes from depends on the DSH version**: ≥ 0.1.6-alpha.2 reads the session-scoped standard prop `sessionId`,
485
- ≤ 0.1.6-alpha.1 falls back to `current` on the session-list snapshot — see the 0.3.48 bullet below; the logic is inlined in `lib/client.js`
488
+ **where "the current session" comes from depends on the DSH version**: the alpha line (≥ 0.1.6-alpha.2) reads the session-scoped standard prop `sessionId`,
489
+ the rc line (≤ 0.1.5-rc.3) falls back to `current` on the session-list snapshot — see the 0.3.48 bullet below; the logic is inlined in `lib/client.js`
486
490
  (the "workspace resolution" section) and the contract for both shapes is pinned by `scripts/test-client-bundle-cwd.mjs` directly against the entry file);
487
491
  the opened directory is shown inside code-server (`?folder=<cwd>`, the page reloads when following a switch);
488
492
  implementation note: the iframe `src` must carry `?folder=<cwd>` — code-server's front-end remembers the "last workspace" and restores it by itself;
@@ -684,7 +688,6 @@ The regression suite (also the single list CI uses) is:
684
688
 
685
689
  ```powershell
686
690
  pnpm test # runs them all: scripts/run-all-tests.mjs
687
- pnpm test:apply # apply() under a stub ctx
688
691
  pnpm test:claim-types # claim-type syntax and defaults
689
692
  pnpm test:bridge-routes # bridge route whitelist (read-only + /approve + /old) / Origin-vs-token order / token header agreement
690
693
  pnpm test:edit-snapshot # pre-write snapshots: value.before from tools/post-execute, session-cwd path resolution, triple-bounded cache, /old's 400-404-200
@@ -692,11 +695,13 @@ pnpm test:bridge-extension # extension-side pure logic (dirty buffers, diagnos
692
695
  pnpm test:ask-dialog # ask-dialog wiring: no artifacts/build chain left, the host's four ask routes, the extension only reporting editor state, the four approval constraints, the bridge's safety invariants
693
696
  pnpm test:launcher-routes # launcher HTTP surface (spawns a real process; slow)
694
697
  pnpm test:workspace-switch # switching workspaces does not restart the process
695
- pnpm test:workspace-cwd # "current workspace directory" resolution (DSH 0.1.6-alpha.2 sessionId vs. the older current)
698
+ pnpm test:workspace-cwd # "current workspace directory" resolution (alpha line: sessionId vs. rc line: the snapshot's current)
696
699
  pnpm test:client-cwd # the same contract, but asserted against the **client entry** lib/client.js
697
700
  pnpm test:client-tabs # "one code-server tab on the DSH side": a new tab closes the old one in the same pane
698
701
  pnpm test:client-entry # client-entry guard: classic script + factory wrapper, require whitelist, src/ gone, parity with lib/claim-types.js
699
- pnpm test:client-seat # which seat the settings card uses: plugins.bundle.config (DSH ≥ 0.1.6-alpha.2) vs settings.plugin.item (≤ alpha.1)
702
+ pnpm test:apply # apply() under a stub ctx (ReferenceError regressions) + both settings data lines: the new one reads volatile leaves and follows settings/document-updated, the legacy one registers a **non-volatile** schema and subscribes scope.watch
703
+ pnpm test:client-seat # settings **seat × data channel**: seat (plugin page plugins.bundle.config ≥ 0.1.6-alpha.2 / settings page settings.plugin.item ≤ 0.1.5-rc.3) × channel (configForms ≥ 0.1.7-alpha.1 / settingsScope earlier)
704
+ # all eight combinations must apply (injection guard) + behaviour for the three real ones: the new line has **mutate** as its only write path, registration is gated by whileServed, the rc line still uses the old seat
700
705
  pnpm test:fullscreen # opening the tab goes fullscreen
701
706
  pnpm test:vendored # repack table ↔ plugin dependency table (no npm: aliases, no aggregator)
702
707
  pnpm test:installed # install smoke: assert on what was **installed into a profile**
@@ -1050,10 +1055,31 @@ Host probe order: `@jinsiyu/dshcs-vscode-server/vscode` (**the real layout since
1050
1055
  `@jinsiyu/dshcs-code-server-<platform>-<arch>/code-server` (the 0.1.37 platform sub-packages) >
1051
1056
  the in-package `vendor/vscode` > the in-package `vendor/code-server` (development). The old install root
1052
1057
  `<profile>\.code-server-app` is only mentioned in a startup log line; nothing writes to it any more.
1053
- ## Settings card (Settings → Plugins → Code Server)
1058
+ ## Settings (since 0.3.50: the plugin page; earlier: Settings → Plugins → Code Server)
1059
+
1060
+ The settings surface is decided by **two independent axes** — the **seat** (where the UI is drawn) and the
1061
+ **data channel** (where values are read from and written to). Their break points are **not the same release**,
1062
+ so three real combinations must all work:
1054
1063
 
1055
- Modeled after dsh-auto-open-web's custom card, registered on the `settings.plugin.item` slot,
1056
- persisted via the official settings domain (`settingsScope`, namespace `code-server`) into the official settings document:
1064
+ | DSH | Seat (declaration-driven: `slots.inject` only fires for a declared slot, so both legs are registered) | Data channel (capability probe) |
1065
+ |---|---|---|
1066
+ | **rc line ≤ 0.1.5-rc.3** (latest rc is still this one) | `settings.plugin.item` (key `code-server`) — the self-drawn collapsible card in Settings → Plugins → Code Server | `ctx.settingsScope` (namespace `code-server`), per-field `set/unset` |
1067
+ | **0.1.6-alpha.2** | `plugins.bundle.config`, **key = package name** `dsh-code-server-app` — plugin page → `dsh-code-server-app` → the settings block sits **between the description and the rows** | same as above (`settingsScope` still exists in this release) |
1068
+ | **alpha line ≥ 0.1.7-alpha.1** (latest 0.1.7-alpha.1) | as above (the page draws title/icon/crumb itself; we only render the form + save control) | `ctx.configForms.get('code-server')` — the configuration **is the plugin entry's own `Config`**, and the only write path is one atomic `mutate(ops, revision)` |
1069
+
1070
+ > Why both legs stay: `settings.plugin.item` retired in ≥ 0.1.6-alpha.2 (the plugin page only renders that
1071
+ > block when `ledger.bundles.has(packageName)` — a wrong key or the old seat makes the settings block
1072
+ > **silently disappear**), while `settingsScope` was **deleted in 0.1.7-alpha.1** (renamed/re-modelled to
1073
+ > `configForms`). Declaring such a service in the client `inject` costs even more: the entry stays **pending
1074
+ > forever**, and the right-sidebar tab, the settings block and the resident preload **all vanish together**,
1075
+ > leaving only `web boot: 1 entry did not activate` / `pending (waiting for service: settingsScope)` in the log.
1076
+ > So the client `inject` keeps only the universally present `['slots']`, and both channels are **probed at
1077
+ > runtime** (`ctx.get`); the host half does the same (`typeof settings.register === 'function'` → legacy path,
1078
+ > otherwise read the volatile leaves). Regressions: `pnpm test:client-seat` (injection guard over the eight
1079
+ > seat × channel combinations plus behaviour for the three real ones) and `pnpm test:apply` (both host lines).
1080
+
1081
+ **Configurable fields** (one shared list for both channels; these fields carry `.volatile()` in the host
1082
+ `Config`, so saving re-resolves that leaf **in place** without remounting the plugin):
1057
1083
 
1058
1084
  | Key | Default | Description |
1059
1085
  |---|---|---|
@@ -1065,13 +1091,19 @@ persisted via the official settings domain (`settingsScope`, namespace `code-ser
1065
1091
  | `fimMultiline` | `true` | **FIM · allow multi-line completions** (0.3.62): off means the host returns the first line only (an empty first line = no completion this time). The model does invent insertions where none are needed, and multi-line amplifies that noise |
1066
1092
  | `fimDisableGlobs` | empty | **FIM · disable by glob** (0.3.62): semicolon/newline separated. `*` does not cross directories, `**` does, a pattern without `/` matches the basename, a pattern with `/` matches any path suffix, and a trailing `/` means `/**`. Examples: `*.md`, `vendor/**`, `**/dist/**`. **Checked on both sides**: the extension first (no request at all), the host again |
1067
1093
 
1094
+ Two more fields are **writable but have no row** (as before, so they can be driven from config/settings
1095
+ documents): `serve` (serving mode, see "Serving mode") and `editorBridge` (editor-bridge switch) — both are
1096
+ editable in the `cordis.patch.yml` `config` and in settings; changes apply immediately (`serve` on next start).
1097
+
1068
1098
  (Since 0.2.9 the card keeps only those settings (0.3.61 added FIM completion, 0.3.62 its three sub-rows); `windowedOpen` and `reserveComposer` are gone — leftover keys in an old
1069
- settings document neither fail nor apply. `serve` remains a key in the settings namespace (usable from a settings document) but
1070
- has **no card row** — see "Serving mode".)
1099
+ settings document neither fail nor apply.)
1071
1100
 
1072
- > Card changes take effect immediately via `scope.watch` (the host status API returns `keepResident`, `claimExtensions` and
1073
- > `fullscreenOnOpen`; the client applies them at once); no dsh restart needed. **After adding new setting keys, restart dsh web before first use**,
1074
- > so the host re-registers the settings namespace (schema includes the new key); otherwise save/validation of the new key won't work.
1101
+ > Changes apply immediately, no dsh restart needed: the legacy channel goes through `scope.watch`, the new one
1102
+ > through the `settings/document-updated` event (both host lines land in the same commit function). The host
1103
+ > status API returns `keepResident`, `claimExtensions` and `fullscreenOnOpen`, and the client applies them at
1104
+ > once. **After adding new setting keys, restart dsh web before first use**: the new line only offers the
1105
+ > **volatile** fields of an active, uniquely locatable entry, and the legacy line must re-register the
1106
+ > settings namespace.
1075
1107
 
1076
1108
  Since 0.2.7 the card has **no** "Entry", "dependency install" or "environment check" rows: the entry lives in the sidebar's
1077
1109
  guide page (and in DSH's own file clicks), and diagnostics stay out of the UI — the `/api/code-server/status` `env` field still
@@ -1259,7 +1291,7 @@ in. Apache-2.0 grants no trademark rights; this project does not use "Continue"
1259
1291
  - **`serve: dsh` shares DSH's origin**, so the iframe is not sandboxed there (same-origin plus `allow-same-origin` is
1260
1292
  escapable by the frame itself); in `loopback` mode the iframe is cross-origin and `sandbox` stays as real protection.
1261
1293
  - **Single instance across sessions**: one shared IDE per host; switching cwd only re-navigates the workbench (since 0.2.12 no process restart, so the old directory's background terminals are not collected).
1262
- - **Older DSH versions are unsupported (since 0.2.3)**: on a DSH without `sidebarRightTabs` / `sidebarRight` the plugin
1294
+ - **Older DSH versions are unsupported (since 0.2.3).** Exactly two lines are supported (converged 2026-09-22): the **rc line** `0.1.5-rc.x` (old seat + `current` on the snapshot) and the **alpha line** `>= 0.1.6-alpha.2` (new seat + the `sessionId` standard prop). Earlier alphas (`0.1.5-alpha.x`, `0.1.6-alpha.1`) are **not separate targets** — they share the rc line's shapes, so the code happens to work, but they are not verified. Detail: on a DSH without `sidebarRightTabs` / `sidebarRight` the plugin
1263
1295
  offers nothing but an upgrade notice on the settings page; older-DSH users should stay on `0.2.2`
1264
1296
  (`dsh plugin --profile web add dsh-code-server-app@0.2.2`).
1265
1297
  - **Sidebar tab switching** (no longer reloads since 0.2.2): DSH's right sidebar renders only the active tab's body, and
package/README.md CHANGED
@@ -27,12 +27,16 @@
27
27
  > 公式都一致,而且**不可能**版本错配),授权也在同一个对话框里就地处理 —— 详见
28
28
  > 「与 DSH 的协同:编辑器桥」。整条链上**没有任何构建步骤**。
29
29
 
30
- ## UI 载体与 DSH 版本要求(0.2.3 起只支持带右侧栏的 DSH)
30
+ ## UI 载体与 DSH 支持范围(0.2.3 起只支持带右侧栏的 DSH;2026-09-22 收敛为下面两条线)
31
+
32
+ 判定一律是**能力是否被声明**,不做版本号比较。两条线上有两处独立的差别:**右侧栏会话作用域**
33
+ (`sessionId` 标准 prop ↔ 列表快照上的 `current`,见「工作区」)与**设置面**
34
+ (座位 × 数据通道,见「设置」一节):
31
35
 
32
36
  | DSH 版本 | 载体 | 入口 |
33
37
  |---|---|---|
34
- | **≥ 0.1.5-alpha.1**(有 `sidebarRight` / `sidebarRightTabs` 服务) | **右侧栏标签**(kind=`code-server`,标签名 `Code Server`),并**认领文件地址**(见下) | ① **DSH 官方的产物 chip / 「交付」卡片预览 / 正文里的文件名**(0.2.5 起,走官方 `openFile` → 文件地址 → 本 tab);② 右侧栏「开始」页的 **Code Server 入口框**;③ 设置 → 插件 → Code Server → **「在右侧栏打开」** |
35
- | 更早(无右侧栏服务) | **不受支持**:除设置页的一条提示外**不提供任何入口** | 无(设置 → 插件 → Code Server 显示升级提示) |
38
+ | **rc 线** `0.1.5-rc.x`(最新 `0.1.5-rc.3` = npm `latest`/`next`)**与 alpha 线** `≥ 0.1.6-alpha.2`(最新 `0.1.7-alpha.1`)—— 判据是**有没有** `sidebarRight` / `sidebarRightTabs` 服务,不按版本号硬判 | **右侧栏标签**(kind=`code-server`,标签名 `Code Server`),并**认领文件地址**(见下) | ① **DSH 官方的产物 chip / 「交付」卡片预览 / 正文里的文件名**(0.2.5 起,走官方 `openFile` → 文件地址 → 本 tab);② 右侧栏「开始」页的 **Code Server 入口框**;③ 设置区(位置见「设置」)→ **「在右侧栏打开」** |
39
+ | 更早(无右侧栏服务) | **不受支持**:除设置区的一条提示外**不提供任何入口** | 无(设置区显示升级提示) |
36
40
 
37
41
  - 检测方式:先 `ctx.get('sidebarRightTabs') / ctx.get('sidebarRight')` 同步探测;
38
42
  服务可能晚于本插件就绪,则 `ctx.inject(['sidebarRightTabs','sidebarRight'], …)` 等待,
@@ -44,10 +48,10 @@
44
48
  - 服务晚到 → 自动撤销旧版判定、补注册侧栏,并上报 `{sidebar:true}` 让 host 恢复;
45
49
  - 注册失败不再静默:控制台报错,设置卡入口行显示"已探测到右侧栏服务,但标签注册失败"。
46
50
  - **0.2.3 起不再兼容旧版 DSH**:悬浮球与内部浮动窗口回退**已删除**。判定为旧版时:
47
- - 只注册设置卡片,内容是一条升级提示(见下),不注册悬浮球/浮窗/**文件地址认领**,也不预热 IDE;
51
+ - 只在设置区留一条升级提示(座位见「设置」),不注册悬浮球/浮窗/**文件地址认领**,也不预热 IDE;
48
52
  - 客户端向 host 上报 `/api/code-server/ui-mode { sidebar:false }`(在上面的 10 s 宽限之后),host 据此**回收自动预启动的实例**
49
53
  并停止预启动(用户手动启动的实例不受影响);服务随后才出现时会再上报 `{sidebar:true}` 撤销;
50
- - 升级 DSH 后**无需重装插件**,刷新页面即可,本页会恢复为完整设置卡片。
54
+ - 升级 DSH 后**无需重装插件**,刷新页面即可,本页会恢复为完整设置表单。
51
55
  - 侧栏标签内即 code-server 页面(iframe),跟随当前会话工作区;面板可折叠/分屏/浮动/全屏(由 DSH 右侧栏提供)。
52
56
  - **打开即全屏(0.2.9 起,默认开)**:打开 Code Server 标签(含点开产物 chip / 交付卡片 / 正文文件名)时,
53
57
  自动把右侧栏从"与对话并排"切到**全屏**(铺满窗口)——IDE 在窄栏里太挤。
@@ -412,12 +416,13 @@ seq,并且 `/sync` 回应里带 `lastSeq`(高水位),扩展据此自查游标是
412
416
 
413
417
  ## 旧版 DSH(0.2.3 起不再支持)
414
418
 
415
- **行为**:探测不到 `sidebarRightTabs` / `sidebarRight` 时,插件只注册一张设置卡片,内容是:
419
+ **行为**:探测不到 `sidebarRightTabs` / `sidebarRight` 时,插件只注册一条升级提示(座位/位置同「设置」一节,
420
+ 两种座位各有一套外壳、同一段文案):
416
421
 
417
422
  > **Code Server** — 当前 DSH 版本不受支持(缺少右侧栏服务)
418
423
  > 本插件自 0.2.3 起不再兼容旧版 DSH。
419
424
  > 未检测到右侧栏插件服务 sidebarRightTabs / sidebarRight,因此插件不提供任何入口(旧版的悬浮球与浮动窗口已移除),
420
- > 也不会后台启动 IDE。升级 DSH 到带右侧栏的版本(≥ 0.1.5-alpha.1)后,Code Server 会出现在右侧栏标签里,
425
+ > 也不会后台启动 IDE。升级 DSH 到 rc 线(0.1.5-rc.x)或 0.1.6-alpha.2 起的 alpha 线后,Code Server 会出现在右侧栏标签里,
421
426
  > 本页同时显示完整设置项;升级后无需重装本插件,刷新页面即可。
422
427
 
423
428
  - **没有任何其他 UI**:不注册 `shell.overlay`(悬浮球)、不认领文件地址、不做常驻预热。
@@ -433,8 +438,8 @@ seq,并且 `/sync` 回应里带 `lastSeq`(高水位),扩展据此自查游标是
433
438
 
434
439
  - code-server 服务目录**跟随活动工作区/会话**:打开期间切换 DSH 会话/工作区,code-server 自动切到新目录
435
440
  (解析优先级:当前会话 cwd → 会话所属 `workspace.path` → 最近活跃会话所属 workspace → 首个 workspace.path;
436
- **"当前会话"的信源随 DSH 版本而变**:≥ 0.1.6-alpha.2 读会话作用域标准 prop `sessionId`,
437
- ≤ 0.1.6-alpha.1 退回会话列表快照上的 `current` —— 详见下面 0.3.48 那条;纯逻辑内联在 `lib/client.js`
441
+ **"当前会话"的信源随支持线而变**:alpha 线(≥ 0.1.6-alpha.2)读会话作用域标准 prop `sessionId`,
442
+ rc 线(≤ 0.1.5-rc.3)退回会话列表快照上的 `current` —— 详见下面 0.3.48 那条;纯逻辑内联在 `lib/client.js`
438
443
  的"工作区解析"段,两版形状的契约由 `scripts/test-client-bundle-cwd.mjs` 直接对**入口**钉住);
439
444
  打开目录显示在 code-server 页面内(`?folder=<cwd>`,跟随切换时页面自动重新加载);
440
445
  实现要点:iframe src 必须带 `?folder=<cwd>`——code-server 前端会记住“最近工作区”并自行恢复,
@@ -542,7 +547,7 @@ pnpm run promote -- <version>
542
547
  ```powershell
543
548
  pnpm test # 一次跑完下面全部(scripts/run-all-tests.mjs;CI 与发布前用的也是它)
544
549
  # ↑ 是唯一清单:新增回归脚本只改 scripts/run-all-tests.mjs,CI/README 都跟着它走
545
- pnpm test:apply # 桩 ctx 下跑通 apply(回归:apply 期的 ReferenceError)
550
+ pnpm test:apply # 桩 ctx 下跑通 apply(回归:apply 期的 ReferenceError)+ 设置数据面两条线:新线按 volatile 活叶子读值并随 settings/document-updated、旧线注册**不带 volatile** 的 schema 并订阅 scope.watch
546
551
  pnpm test:claim-types # 认领类型语法与默认值
547
552
  pnpm test:bridge-routes # 编辑器桥:路由表白名单(只读 + /approve + /old)/ Origin 与令牌的判定顺序 / 令牌头三处一致
548
553
  pnpm test:edit-snapshot # 写前原文快照:从 tools/post-execute 的 value 取完整 before / 路径按会话 cwd 绝对化 / 缓存三重有界 / /old 的 400-404-200
@@ -550,12 +555,13 @@ pnpm test:bridge-extension # 编辑器桥扩展侧纯逻辑:未保存缓冲区
550
555
  pnpm test:ask-dialog # 「问 DSH」对话框的接线:没有产物/构建链了、宿主 4 条 ask 路由、扩展只上报编辑器状态、授权四条、桥的安全不变式
551
556
  pnpm test:launcher-routes # launcher 的 HTTP 面(起真进程,较慢)
552
557
  pnpm test:workspace-switch # 切工作区不重启进程
553
- pnpm test:workspace-cwd # "当前工作区目录"解析:DSH 0.1.6-alpha.2(sessionId)与旧版(current)两套形状
558
+ pnpm test:workspace-cwd # "当前工作区目录"解析:alpha 线(≥0.1.6-alpha.2,sessionId)与 rc 线(≤0.1.5-rc.3,current)两套形状
554
559
  pnpm test:client-cwd # 同一件事但直接对**客户端入口** lib/client.js 验(注册出来的 body 真发不发 cwd、URL 带不带 folder)
555
560
  pnpm test:client-tabs # "DSH 侧只留一个 code-server 标签页":新标签挂载时收掉同窗格旧标签(跨窗格/不可见时不动)
556
561
  pnpm test:client-entry # 客户端入口守卫:经典脚本+工厂包装、require 白名单(= DSH 模块表种子词)、src/ 已消失、与 lib/claim-types.js 逐字一致
557
562
  pnpm test:ask-panel # 「问 DSH」对话框面板(0.3.59 起手写):注入机制已下线、视图白名单、注入 CSS 的选择器/var() 安全、六种条目与授权卡片、三条消息落点、拿不到官方部件时的降级
558
- pnpm test:client-seat # 设置卡住哪个座位:插件页 plugins.bundle.config(DSH ≥ 0.1.6-alpha.2)vs settings.plugin.item(≤ alpha.1;新版已退役)
563
+ pnpm test:client-seat # 设置**座位 × 数据通道**:座位(插件页 plugins.bundle.config ≥ 0.1.6-alpha.2 / 设置页 settings.plugin.item ≤ 0.1.5-rc.3)× 通道(configForms ≥ 0.1.7-alpha.1 / settingsScope 更早)
564
+ # 八种组合都要能 apply(注入守卫)+ 三种真实组合各自钉行为:新线**只有** mutate 一条写路径、注册受 whileServed 门禁、rc 线仍走旧座位
559
565
  pnpm test:fullscreen # 打开标签即全屏
560
566
  pnpm test:vendored # 重打包表 ↔ 插件依赖表一致(无 npm: 别名 / 无聚合包 / vendored.json 进了 files)
561
567
  pnpm test:dsh-resolve # 部署位置表:各平台全局装布局(npm --prefix / nvm / pnpm global / %APPDATA%)都能找到 DSH 部署
@@ -1013,20 +1019,29 @@ host 探测顺序:`@jinsiyu/dshcs-vscode-server/vscode`(**0.2.0+ 正式布局**)
1013
1019
  插件包内 `vendor/vscode` > 插件包内 `vendor/code-server`(开发期)。旧安装根
1014
1020
  `<profile>\.code-server-app` 只在启动日志里提示可删除,不再被使用。
1015
1021
 
1016
- ## 设置卡片(0.3.50 起:插件页;更早:设置 → 插件 → Code Server)
1022
+ ## 设置(0.3.50 起:插件页;更早:设置 → 插件 → Code Server)
1017
1023
 
1018
- **位置随 DSH 版本而变**(两条腿都注册,谁被声明谁生效,不会出现两份):
1024
+ 设置面由**两条独立的轴**决定 —— **座位**(UI 画在哪)和**数据通道**(值从哪读写)。两者的分界点
1025
+ **不在同一版**,所以三种真实组合都要成立:
1019
1026
 
1020
- | DSH | 座位 | 长什么样 |
1027
+ | DSH | 座位(声明驱动:`slots.inject` 只在插槽被声明时才回调 ⇒ 两条腿都注册) | 数据通道(能力探测) |
1021
1028
  |---|---|---|
1022
- | **≥ 0.1.6-alpha.2** | `plugins.bundle.config`,**键 = 包名** `dsh-code-server-app` | 插件页 → 找到 `dsh-code-server-app` → 打开该插件页面,设置区在**描述与各行之间**(页面自己画标题/图标/面包屑,我们只出表单 + 保存控件) |
1023
- | ≤ 0.1.6-alpha.1 | `settings.plugin.item`(key `code-server`) | 设置 → 插件 → Code Server 的自绘可折叠卡片(该插槽在新版**已退役**) |
1024
-
1025
- > 为什么必须跟着搬:上游 agent note《插件页上的插件配置》把配置从设置页搬到插件页,并**删掉了
1026
- > `settings.plugin.item`**;插件页只在 `ledger.bundles.has(包名)` 时才渲染那块区域 —— 键写错或还用旧座位,
1027
- > 表现是**设置卡静默消失**(无报错、无日志)。回归:`pnpm test:client-seat`(对构建产物验两个座位与两种视图)。
1028
-
1029
- 数据经官方 settings 域(`settingsScope`,命名空间 `code-server`)持久化到官方 settings 文档:
1029
+ | **rc 线 ≤ 0.1.5-rc.3**(最新 rc 仍是这一支) | `settings.plugin.item`(key `code-server`)—— 设置 → 插件 → Code Server 的自绘可折叠卡片 | `ctx.settingsScope`(命名空间 `code-server`),逐字段 `set/unset` |
1030
+ | **0.1.6-alpha.2** | `plugins.bundle.config`,**键 = 包名** `dsh-code-server-app` —— 插件页 → `dsh-code-server-app` → 设置区在**描述与各行之间** | 同上(`settingsScope` 这一版还在) |
1031
+ | **alpha 线 ≥ 0.1.7-alpha.1**(最新 0.1.7-alpha.1) | 同上一行(页面自己画标题/图标/面包屑,我们只出表单 + 保存控件) | `ctx.configForms.get('code-server')` —— 配置就是**插件条目自己的 `Config`**,写路径**只有** `mutate(ops, revision)` 一次原子提交 |
1032
+
1033
+ > 为什么必须两条腿都留:`settings.plugin.item` 在 ≥ 0.1.6-alpha.2 已退役(插件页只在
1034
+ > `ledger.bundles.has(包名)` 时才渲染那块区域 —— 键写错或还用旧座位,表现是**设置卡静默消失**);
1035
+ > 而 `settingsScope` 在 **0.1.7-alpha.1 被删除**(改名/改模型为 `configForms`)。把服务写进客户端
1036
+ > `inject` 的代价更大:条目会**永远 pending**,右侧栏标签、设置卡、常驻预热**一起消失**,启动日志只有
1037
+ > `web boot: 1 entry did not activate` / `pending (waiting for service: settingsScope)`。
1038
+ > 所以客户端 `inject` 只留普遍存在的 `['slots']`,两个通道都**运行时探测**(`ctx.get`),
1039
+ > 宿主半同理:`typeof settings.register === 'function'` 走旧路,否则读 volatile 叶子。
1040
+ > 回归:`pnpm test:client-seat`(座位 × 通道八种组合的注入守卫 + 三种真实组合的行为)与
1041
+ > `pnpm test:apply`(宿主两条线)。
1042
+
1043
+ **可配置字段**(两条通道共用同一份清单;宿主 `Config` 里这些字段带 `.volatile()`,
1044
+ 所以保存只**就地重解析**该字段、不重挂插件):
1030
1045
 
1031
1046
  | 键 | 默认 | 说明 |
1032
1047
  |---|---|---|
@@ -1038,16 +1053,20 @@ host 探测顺序:`@jinsiyu/dshcs-vscode-server/vscode`(**0.2.0+ 正式布局**)
1038
1053
  | `fimMultiline` | `true` | **FIM · 允许多行补全**(0.3.62):关掉后宿主只回第一行(首行为空 = 这次不补)。实测模型在不该补的位置会硬凑,多行会放大这种噪声 |
1039
1054
  | `fimDisableGlobs` | 空 | **FIM · 按 glob 禁用**(0.3.62):分号/换行分隔。`*` 不跨目录、`**` 跨目录、不含 `/` 的模式只匹配文件名、含 `/` 的模式按路径尾段匹配、`/` 结尾视作 `/**`。例:`*.md`、`vendor/**`、`**/dist/**`。**两边都判**:扩展侧先判(根本不发请求),宿主侧再判一遍 |
1040
1055
 
1041
- (0.2.9 起卡片只留上面这些设置(0.3.61 加 FIM 补全,0.3.62 加它的三个子项);`windowedOpen` 与 `reserveComposer` 已移除 —— 旧设置文档里残留的键既不报错也不生效。
1042
- `serve` 仍是设置命名空间里的键(便于用设置文档切换),但**没有卡片行**,见「服务方式」。)
1056
+ 另有两个字段**也在可写清单里、但没有卡片行**(一直如此,便于用配置/设置文档切换):
1057
+ `serve`(服务方式,见「服务方式」)与 `editorBridge`(编辑器桥开关)——它们在
1058
+ `cordis.patch.yml` 的 `config` 与设置里都可改,改完即时生效(serve 下次启动生效)。
1059
+
1060
+ (0.2.9 起卡片只留上面这些设置(0.3.61 加 FIM 补全,0.3.62 加它的三个子项);`windowedOpen` 与 `reserveComposer` 已移除 —— 旧设置文档里残留的键既不报错也不生效。)
1043
1061
 
1044
1062
  0.2.7 起卡片**没有**「入口」「依赖安装」「环境检测」三行:入口在右侧栏「开始」页的 Code Server 入口框(或官方的文件点击),
1045
1063
  诊断信息不再进 UI —— `/api/code-server/status` 的 `env` 字段仍返回
1046
1064
  树版本 / `productPath` / server 入口、VS Code 内部依赖、**预编译原生包**(重打包子包名 + 已解析模块数),需要时用脚本查或看 host 日志。
1047
1065
 
1048
- > 卡片改动经 `scope.watch` 实时生效(host 端 status API 同步返回 `keepResident`、`claimExtensions` 与
1049
- > `fullscreenOnOpen`,客户端立即生效);无需重启 dsh。**新增设置键后首次使用前需重启 dsh web**,
1050
- > 让 host 重新注册设置命名空间(schema 含新键),否则新键的保存与校验不生效。
1066
+ > 改动实时生效,无需重启 dsh:旧通道经 `scope.watch`,新通道经 `settings/document-updated` 事件
1067
+ > (宿主两条线都落到同一个 commit 函数);host 端 status API 同步返回 `keepResident`、`claimExtensions`
1068
+ > 与 `fullscreenOnOpen`,客户端立即生效。**新增设置键后首次使用前需重启 dsh web**:
1069
+ > 新线的表单只展示**活动且可唯一定位**的条目里的 **volatile** 字段,旧线要重新注册设置命名空间。
1051
1070
 
1052
1071
  ## 配置(cordis.patch.yml 的 `config`,均有默认值)
1053
1072
 
@@ -1214,7 +1233,8 @@ FIM(Beta)端点,提示词形态由其官方文档与本机实测确定)。标准
1214
1233
  - **`serve: dsh` 的 iframe 与 DSH 同源** → 该模式不挂 `sandbox`(同源 + `allow-same-origin` 可被 frame 自行摘除);
1215
1234
  `loopback` 模式跨源,`sandbox` 作为真防护保留。
1216
1235
  - **跨会话单实例**:host 级共享一份 IDE;切换 cwd 只换 workbench 目录(0.2.12 起不重启进程,旧目录的后台终端不会被收走)。
1217
- - **旧版 DSH 不受支持(0.2.3 起)**:没有 `sidebarRightTabs`/`sidebarRight` 的 DSH 上,除设置页一条升级提示外无任何入口;
1236
+ - **旧版 DSH 不受支持(0.2.3 起)**:没有 `sidebarRightTabs`/`sidebarRight` 的 DSH 上,除设置区一条升级提示外无任何入口;
1237
+ 支持范围**只有两条线**(2026-09-22 收敛):rc 线 `0.1.5-rc.x`(旧座位 + 旧通道 + 快照上的 `current`)与 alpha 线 `≥ 0.1.6-alpha.2`(新座位 + `sessionId` 标准 prop;数据通道在 0.1.7-alpha.1 换成 `configForms`);更早的 alpha(`0.1.5-alpha.x`、`0.1.6-alpha.1`)**不单独支持** —— 形状与 rc 线相同,所以代码走得通,但不作为验证目标。
1218
1238
  旧版用户请留在 `0.2.2`(`dsh plugin --profile web add dsh-code-server-app@0.2.2`)。
1219
1239
  - **侧栏标签切换**(0.2.2 起不再重载):DSH 右侧栏只渲染当前激活标签的 body,React 卸载会移走 iframe;
1220
1240
  插件把 iframe 收成单例常驻面,用 `Element.moveBefore()`(状态保持型原子移动)在停靠位与文档级停放区之间搬,
package/cordis.patch.yml CHANGED
@@ -38,13 +38,14 @@
38
38
  # 诊断、活动选区 —— 这些只有编辑器知道;
39
39
  # 编辑器侧:「问 DSH」右键命令把选区投进当前会话;agent 改文件后开原生 diff 审阅,
40
40
  # 缓冲区有未保存改动时只告警、绝不覆盖。
41
- # 关掉它 = 不写 bridge.json、不注册工具、扩展休眠。也可在设置文档里改实时的
41
+ # 关掉它 = 不写 bridge.json、不注册工具、扩展休眠。也可在设置里改实时的
42
42
  # `code-server.editorBridge`(改完即时生效,无需重启)。
43
43
  # 已知范围:`serve: dsh`(管道模式,无独立端口)下不支持桥 → 自动禁用,不影响其它功能。
44
44
  editorBridge: true
45
45
  # 注:「认领类型」(claimExtensions,默认把 markdown/html/图片/PDF 留给 DSH 自带预览)与
46
- # 「打开即全屏」(fullscreenOnOpen)、「后台常驻」(keepResident)由
47
- # "设置 → 插件 → Code Server"卡片控制,持久化于官方 settings 域(命名空间 code-server),
48
- # 卡片修改即时生效。服务方式(serve)与编辑器桥(editorBridge)没有卡片行:
49
- # 改这里或设置文档(code-server.serve / code-server.editorBridge)。
50
- # 另:不再兼容旧版 DSH(无 sidebarRightTabs/sidebarRight 服务),旧版上仅给设置页提示。
46
+ # 「打开即全屏」(fullscreenOnOpen)、「后台常驻」(keepResident)、「FIM 补全」(fim,实验性)
47
+ # 由设置区控制(座位随 DSH 版本:插件页 ≥0.1.6-alpha.2 / 设置页 ≤0.1.5-rc.3;
48
+ # 数据通道:configForms ≥0.1.7-alpha.1,更早是 settingsScope,命名空间 = 本行 id `code-server`),
49
+ # 改动即时生效。服务方式(serve)与编辑器桥(editorBridge)**也在可写字段里,但没有卡片行**:
50
+ # 改这里或设置里的 code-server.serve / code-server.editorBridge。
51
+ # 另:不再兼容旧版 DSH(无 sidebarRightTabs/sidebarRight 服务),旧版上仅给一条升级提示。
@@ -151,24 +151,44 @@ export function pickAgent(ctx) {
151
151
  * - `'queue'` ⇒ `agent.followup(msg)`(契约:"becomes the sole ordinary message of **its own turn**")
152
152
  * —— 排到下一轮,不打扰当前轮。
153
153
  *
154
- * 读法走官方 API `ctx.settings.get(ns)`(宿主侧 `@deepseek-ai/dsh-settings` 的契约:
155
- * "Read one registered namespace's resolved value")。读不到(命名空间没注册 / 极简组合 / 老版本 DSH)
156
- * 一律回默认 `'queue'`,并且**逐项特性探测** `agent.steer` 是否存在 —— 探测失败绝不抛。
154
+ * **设置数据面的两条线**(与 lib/index.js 的自有配置同一套分界,判据一律是能力):
155
+ * - 旧线(rc 0.1.5-rc.x、0.1.6-alpha.2):`ctx.settings.get(ns)` —— "Read one registered
156
+ * namespace's resolved value";
157
+ * - 新线(alpha ≥ 0.1.7-alpha.1):`SettingsForms` **没有 `get`**(命名空间模型换成"条目自己的
158
+ * Config"),只有 `describe()` —— 返回每个条目 `{ns, value, …}`,`ns` 就是条目 id
159
+ * (`dsh-client-ui-conversation` 客户端自己也是 `ctx.configForms.get('ui-conversation')`)。
160
+ * 读不到(命名空间没注册 / 极简组合 / 老版本 DSH / 探测失败)一律回默认 `'queue'`,绝不抛;
161
+ * `agent.steer` 是否可用另外逐项探测。
157
162
  *
158
163
  * @param {object} ctx cordis 上下文
159
164
  * @returns {'queue'|'steer'}
160
165
  */
161
166
  export function pickBusyEnter(ctx) {
162
167
  const settings = getService(ctx, 'settings');
163
- if (settings === undefined || settings === null || typeof settings.get !== 'function') return 'queue';
164
- try {
165
- const section = settings.get('ui-conversation');
168
+ if (settings === undefined || settings === null) return 'queue';
169
+ const behaviorOf = (section) => {
166
170
  const value = section !== null && typeof section === 'object' ? section.busyEnter : undefined;
167
171
  return value === 'steer' ? 'steer' : 'queue';
168
- } catch {
169
- // 未注册的命名空间在多数实现里是 undefined,但契约允许实现抛 —— 一律当默认值
170
- return 'queue';
172
+ };
173
+ if (typeof settings.get === 'function') {
174
+ try {
175
+ return behaviorOf(settings.get('ui-conversation'));
176
+ } catch {
177
+ // 未注册的命名空间在多数实现里是 undefined,但契约允许实现抛 —— 一律当默认值
178
+ return 'queue';
179
+ }
180
+ }
181
+ if (typeof settings.describe === 'function') {
182
+ try {
183
+ const forms = settings.describe();
184
+ if (!Array.isArray(forms)) return 'queue';
185
+ const entry = forms.find((form) => form !== null && typeof form === 'object' && form.ns === 'ui-conversation');
186
+ return entry === undefined ? 'queue' : behaviorOf(entry.value);
187
+ } catch {
188
+ return 'queue';
189
+ }
171
190
  }
191
+ return 'queue';
172
192
  }
173
193
 
174
194
  /**