@dsh-electron/dsh-plugin-multi-root-workspace 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.
Files changed (43) hide show
  1. package/CHANGELOG.en.md +89 -0
  2. package/CHANGELOG.md +89 -0
  3. package/README.en.md +96 -20
  4. package/README.md +97 -19
  5. package/cordis.patch.yml +22 -1
  6. package/lib/client.js +234 -71
  7. package/lib/client.js.map +1 -1
  8. package/lib/{command-BSkrYOAf.js → command-DyOWujPo.js} +24 -61
  9. package/lib/command.js +2 -2
  10. package/lib/compat-CRdv0vPw.js +272 -0
  11. package/lib/compat.js +2 -0
  12. package/lib/{fs-D7UoCb7T.js → fs-D_Sw3o5z.js} +7 -3
  13. package/lib/fs.js +1 -1
  14. package/lib/index.js +8 -6
  15. package/lib/instructions-Cn1Jj5Xi.js +703 -0
  16. package/lib/instructions.js +2 -0
  17. package/lib/registry-DySMbjgW.js +793 -0
  18. package/lib/registry-lease-win32-dy8TQMD9.js +93 -0
  19. package/lib/registry.js +2 -466
  20. package/lib/{sandbox-BhuMTDgH.js → sandbox-D8Fw95FM.js} +51 -4
  21. package/lib/sandbox.js +1 -1
  22. package/lib/scope.js +1 -1
  23. package/lib/types/client/locales.d.ts +6 -0
  24. package/lib/types/client/panel-client.d.ts +0 -2
  25. package/lib/types/command.d.ts +17 -0
  26. package/lib/types/compat/agent-instructions.d.ts +138 -0
  27. package/lib/types/compat/client-icons.d.ts +40 -0
  28. package/lib/types/compat/client-session.d.ts +32 -0
  29. package/lib/types/compat/dsh-version.d.ts +119 -0
  30. package/lib/types/compat/llm-message.d.ts +72 -0
  31. package/lib/types/compat/sandbox-confine.d.ts +58 -0
  32. package/lib/types/compat/tool-result.d.ts +29 -0
  33. package/lib/types/compat.d.ts +85 -0
  34. package/lib/types/contract.d.ts +6 -8
  35. package/lib/types/index.d.ts +19 -5
  36. package/lib/types/instructions.d.ts +125 -0
  37. package/lib/types/registry-lease-win32.d.ts +29 -0
  38. package/lib/types/registry-lease.d.ts +62 -0
  39. package/lib/types/registry.d.ts +130 -19
  40. package/lib/types/roots.d.ts +1 -1
  41. package/lib/types/sandbox.d.ts +22 -2
  42. package/package.json +60 -13
  43. package/lib/{roots-DyT2jgEP.js → roots-DasWEBJk.js} +1 -1
@@ -0,0 +1,89 @@
1
+ # Changelog
2
+
3
+ This file records the user-visible changes of every **released** version.
4
+
5
+ 中文:[CHANGELOG.md](./CHANGELOG.md)
6
+
7
+ - The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow [Semantic Versioning](https://semver.org/).
8
+ - For installation sources, the supported upstream runtimes, and known limitations, see the [README](./README.en.md).
9
+ - The evidence, numbering, and release state of each version live in the [roadmap progress ledger](./docs/plans/active/2026-09-12-multi-root-workspace.md#进度总账). The body of each GitHub Release is generated from the commit history by `scripts/release-notes.mjs` and is the complete raw list behind this file.
10
+
11
+ ## [Unreleased]
12
+
13
+ ## [0.1.2] - 2026-09-22
14
+
15
+ With the exact allowlist contract from `v0.1.1` unchanged, the supported upstream runtimes grow to `0.1.6-alpha.2` and `0.1.7-alpha.1`; the reasoning is still [ADR-0009](./docs/decisions/ADR-0009-dsh-compat-contract.md).
16
+
17
+ ### Added
18
+
19
+ - **Support for the upstream runtime `0.1.6-alpha.2`**, alongside `0.1.5-rc.2` and `0.1.6-alpha.1`. `confine` stays asynchronous and the instruction renderer keeps the `0.1.6-alpha.1` name; the client current-session id now comes from the catalog row's `retainedBy.mainView` (see Fixed). The development pin remains `0.1.5-rc.2`.
20
+ - **Support for the upstream runtime `0.1.7-alpha.1`**. `confine` and the instruction renderer keep their previous shapes, but this release needs adapters: session format 4 rejects `kind: 'plugin'`, so additional-root instructions use this plugin's own source kind `multi-root-workspace` (format 3 and earlier still use `plugin`); the tool-failure bit moved from the content block onto the message; panel icons moved from pixel names to the Regular weight; in-process boot uses `createRuntimeResolution` plus `PluginPackages`; bash execution moved from `shell.run` to `shell.execute().result()`. This release's `dsh` depends on cordis `^4.0.3`, and a probe must pin cordis to that version — two copies of `@deepseek-ai/dsh-tools` make the tool scheduler's Symbol miss, and tool calls die on the first step. The development pin remains `0.1.5-rc.2`.
21
+
22
+ ### Fixed
23
+
24
+ - **An open session on `0.1.6-alpha.2` was shown as "No active session"** in the Workspace Folders panel. That release dropped `current` from the Session list snapshot; the session on screen is the catalog row whose `retainedBy.mainView` is positive, because the main view retains it with source `mainView`. `src/compat/client-session.ts` probes both shapes structurally. A populated catalog with nobody retained still shows the empty state and never falls back to `ids[0]`.
25
+
26
+ ## [0.1.1] - 2026-09-16
27
+
28
+ The **hardening batch (H1–H4)** after `v0.1.0`: no new user-facing features, but four boundary gaps closed — cross-process authority, panel authority, upstream compatibility, and additional-root instructions. The reasoning lives in [ADR-0007](./docs/decisions/ADR-0007-registry-authority-lease.md), [ADR-0008](./docs/decisions/ADR-0008-panel-session-derived-authority.md), [ADR-0009](./docs/decisions/ADR-0009-dsh-compat-contract.md), and [ADR-0010](./docs/decisions/ADR-0010-additional-root-instruction-scope.md).
29
+
30
+ ### Upgrade Notes (Breaking Changes)
31
+
32
+ - **The first `dsh plugin add` fails once, from every install source**: this release introduces the native dependency `koffi` (the FFI wrapper behind Registry Authority on Windows), and pnpm ≥10 runs no dependency build script by default, so the first `add` exits with `[ERR_PNPM_IGNORED_BUILDS]` and the plugin never reaches `dsh.profile.bundles`. `dsh` leaves the pending decision in that profile's `pnpm-workspace.yaml` (`koffi: set this to true or false`); set it to `true` and run `add` again. The npm and tarball sources had no such step in `v0.1.0`. See [Troubleshooting: the install stops at build approval](./docs/troubleshooting/install-stops-at-build-approval.md).
33
+ - **The supported upstream runtimes narrow to the exact list `0.1.5-rc.2`, `0.1.6-alpha.1`** (they used to be the range `>=0.1.2-alpha.4 <0.2.0`). When the host release is neither of those, or several `@deepseek-ai/dsh-*` packages are mixed across versions, the `fs` / `sandbox` / `registry` / `instructions` rows **do not start**: the composition degrades to "this plugin is not installed" and prints an explanation at startup. The reason is that this plugin replaces the fence itself and works by recognizing argv shapes measured on specific upstream releases, so a semver range is a promise about versions nobody verified ([ADR-0009](./docs/decisions/ADR-0009-dsh-compat-contract.md)). The diagnosis steps are in [Troubleshooting: a DSH release outside the support matrix](./docs/troubleshooting/unsupported-dsh-release.md). **If you are still on the `0.1.2-rc.1` runtime that `v0.1.0` was measured against (for example a runtime bundled with an installed desktop app), upgrade that runtime first — otherwise this release has no effect.**
34
+ - **The panel no longer accepts a client-named root**: every panel endpoint requires `sessionId`, and the primary root comes only from the host-side `session.header.cwd`. The client `primaryRoot` field and the `sandboxPolicy` fallback are gone. When the browser has no active session, the panel shows "No active session" and does not call the host at all ([ADR-0008](./docs/decisions/ADR-0008-panel-session-derived-authority.md)).
35
+
36
+ ### Added
37
+
38
+ - **Cross-process Registry Authority (H1)**: at most one DSH process may hold the root registry per `$DSH_HOME` (POSIX `flock` / Windows named semaphore, released by the kernel when the process exits or crashes). A contending process fails closed — it publishes an empty scope and registry mutations report `registry-contended`; once the holder exits, `/workspace-folders list` or a panel refresh takes over through `refresh()` ([ADR-0007](./docs/decisions/ADR-0007-registry-authority-lease.md)).
39
+ - **An additional root's own instruction files now reach the model (H4)**: the root's **top-level** `AGENTS.md` / `CLAUDE.md` are injected before the first step of a session; instruction files in the subdirectories the session has **successfully** touched with `read` / `write` / `edit` (including every ancestor directory of a touched file, up to the additional root) are injected incrementally as those directories come up for examination; a changed file is re-sent on its own, and a file or root that disappears is **explicitly withdrawn**. All additional roots share a 64 KiB budget, and delivery is a `user`-role `{ kind: 'plugin', form: 'instructions' }` message (never `systemPrompt`). Upstream discovery walks upward from the session cwd and can never reach an additional root — that is why this exists ([ADR-0010](./docs/decisions/ADR-0010-additional-root-instruction-scope.md)).
40
+ - **Support for a second upstream runtime, `0.1.6-alpha.1`**, alongside the `0.1.5-rc.2` baseline; both have run the full matrix (the sync/async shape of `confine`, the renamed instruction renderer, and the two LLM wire protocols are absorbed by the adapter layer and the smoke scripts).
41
+ - **`pnpm compat:check`**: a consistency gate over the allowlist / `peerDependencies` / development pin / installed tree, run as the first CI step.
42
+ - **The `multi-root-compat` startup gate row**: the version verdict became a precondition for the other security-relevant rows instead of a log line.
43
+ - **A weekly upgrade lane** (`upgrade.yml`): it re-points the pin at the newest upstream pre-release and runs the full matrix, with read-only permissions, no commits, and no automatic widening of the allowlist.
44
+ - Two troubleshooting entries: [a DSH release outside the support matrix](./docs/troubleshooting/unsupported-dsh-release.md) and [the registry owned by another process](./docs/troubleshooting/registry-owned-by-another-process.md).
45
+
46
+ ### Changed
47
+
48
+ - Version differences are concentrated in the `src/compat/` adapter layer and decided by **structural probes** (is the return value thenable? which export name exists?) rather than by comparing version strings; business code contains no version checks at all.
49
+ - The two optional peers (`@deepseek-ai/dsh-llm`, `@deepseek-ai/dsh-agent-instructions`) are now **loaded on demand**: the barrel's load-time dependency set equals the required-package set, so a minimal composition that never builds a message cannot fail while loading.
50
+ - `pnpm verify:all` deliberately **excludes** `compat:check` (the upgrade lane must run the full matrix on a candidate that is not on the allowlist yet); the main CI lane runs it separately, first.
51
+ - New `./compat` and `./instructions` subpath exports.
52
+ - Installation and release: the `prepare` script is now self-contained (git installs build on the spot through pnpm, after the user authorizes `allowBuilds`); the README documents all four installation sources (npm / tarball / local path / GitHub); npm publishing moved to **trusted publishing (OIDC)**, so the repository stores no npm credential at all.
53
+
54
+ ### Fixed
55
+
56
+ - **Authority teardown order**: the old code released the kernel lease *before* closing the domain, so a successor process could acquire the lease and open a snapshot missing this process's last write. The whole teardown now runs inside the store-wide authority transition queue as "drain in-flight mutations → close the domain → release the lease", and sets `disposed` to refuse later acquisitions (`tests/registry-lease.spec.ts`).
57
+ - **Instruction delivery state is committed from the actual artifact**: a renderer that omits or truncates a file no longer records a full digest; a message that fails to build or is cancelled is no longer treated as delivered; a spent budget still runs withdrawals, so cross-root withdrawals and deferred touches are no longer skipped.
58
+ - **Instruction files in intermediate directories** of an additional root could never reach the model (only the touched file's parent directory was examined); every ancestor directory is now examined.
59
+ - **`DSH_MULTI_ROOT_COMPAT=warn` tightened**: it relaxes `unsupported` only (a consistent tree the allowlist does not name yet — exactly what the upgrade lane probes). `mixed` / `incomplete` are rejected in both modes.
60
+ - **"Package absent" is separated from "installed but failed to evaluate"**: the latter is no longer cached as an absence, so the process cannot silently stop delivering additional-root instructions.
61
+ - **Windows lock naming is normalized by physical path**: two processes reaching one store through a path alias (junction / symlink) used to hash different names and could both become the authority.
62
+ - **Session event pairing is scoped per session**: the same `tool/call` id in two sessions no longer overwrites the other session's pending call.
63
+ - **Shell input handling in the upgrade workflow**: the manual version and the candidate version travel through step `env` and are validated as a single line instead of being interpolated into `run`.
64
+ - **A local pack no longer carries earlier builds**: `lib/` is stripped of the previous build's JavaScript before `bundle` runs (tsdown's shared chunks are content-hashed, so an old name never disappears on its own). The tarball `pnpm pack` produces now contains exactly one build's artifacts instead of shipping historical chunks as dead code (`files` publishes every `lib/*.js`).
65
+
66
+ ## [0.1.0] - 2026-09-13
67
+
68
+ The first release: the three MVP milestones (M1–M3).
69
+
70
+ ### Added
71
+
72
+ - **Plugin skeleton and composition (M1)**: a bundle patch replaces the upstream `fs-sandbox` and `sandbox` provider rows and inserts the plugin's rows (`bash-sandbox` stays upstream — all bash and PTY confinement goes through `ctx.sandbox`). With no additional root configured, behavior is item-for-item identical to an uninstalled harness; the three structural risks (composition, disable/insert ordering, duplicate provides) are pinned by differential tests.
73
+ - **Multi-root capability (M2)**: `ctx.multiRootScope` (the single grant source), `MultiRootFileSystem` (the in-process containment fence, subclassing upstream's `LocalFileSystem`, which has no fence of its own), and `MultiRootSandboxProvider` (cloning the upstream grant spelling onto Seatbelt / bwrap / Landlock profiles for the additional roots). The fs side and bash/PTY share one scope; security does not degrade.
74
+ - **A model-visible topology snapshot**: emitted through `systemPrompt.context` only under `workspace-write` with a non-empty root set (same workspace, cwd unchanged); empty-root and read-only output stays byte-identical.
75
+ - **The root registry (M3)**: persisted in the `multi_root_workspace` storage domain keyed by the canonical primary root, validated on every write and every read; each record carries a `recordedPath`, and **re-resolving a path is not re-authorizing it** — a directory replaced by a symlink pointing elsewhere is marked `redirected` and stops being granted.
76
+ - **The `/workspace-folders` command**: `list` / `add <path>` (with no argument it opens the system directory picker) / `alias` / `remove` / `reveal`, all usable in headless compositions too.
77
+ - **The Workspace Folders browser panel**: a sidebar-foot action plus a self-drawn dialog talking to the host over the plugin's own Connection RPC channel; bilingual copy following the UI language, with every color taken from the host's `var(--dsw-*)` design tokens.
78
+ - **A cross-repository journey e2e** (`pnpm smoke:journey`): it drives a real agent turn in both the `web` and `headless` compositions across two Git repositories (primary root `repo-a`, additional root `repo-b`) and asserts that writes outside the roots are refused. No model credentials are needed (the model endpoint is scripted).
79
+ - **Installation sources**: npm registry / tarball / local path / GitHub; a tag-triggered `release.yml` runs verify → npm publish (with provenance) → GitHub Release.
80
+ - **Platform scope**: full kernel-level multi-root on macOS (Seatbelt) and Linux (bwrap / Landlock); Windows covers the `fs` write path, while multi-root for confined bash/PTY is out of scope for this phase (a one-time explicit warning is printed when the scope is non-empty).
81
+
82
+ ### Fixed
83
+
84
+ - All eight findings of the pre-release external review (three of them release-blocking) are fixed, each with a regression test: a registered directory replaced by a symlink transplanting its authority (which introduced `recordedPath` — **re-resolving a path is not re-authorizing it**), concurrent registry mutations losing a write or reviving a revoked grant (per-primary-root mutations are serialized), a refresh not re-checking directories, a typed path being overwritten by the directory picker, the `reveal` response contract and failure code, duplicate ids not validated, the primary root missing from nesting validation, and CI testing before building.
85
+
86
+ [Unreleased]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.2...HEAD
87
+ [0.1.2]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.1...v0.1.2
88
+ [0.1.1]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.0...v0.1.1
89
+ [0.1.0]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/releases/tag/v0.1.0
package/CHANGELOG.md ADDED
@@ -0,0 +1,89 @@
1
+ # Changelog
2
+
3
+ 本文件记录每个**已发布**版本对使用者可见的变更。
4
+
5
+ English: [CHANGELOG.en.md](./CHANGELOG.en.md)
6
+
7
+ - 格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循 [Semantic Versioning](https://semver.org/lang/zh-CN/)。
8
+ - 安装方式、受支持的上游运行时与已知限制见 [README](./README.md)。
9
+ - 每个版本的实施证据、编号口径与发布状态见[路线图 §进度总账](./docs/plans/active/2026-09-12-multi-root-workspace.md#进度总账);GitHub Release 的正文由 `scripts/release-notes.mjs` 从 commit 历史生成,是本文件之外的完整原始清单。
10
+
11
+ ## [Unreleased]
12
+
13
+ ## [0.1.2] - 2026-09-22
14
+
15
+ 在 `v0.1.1` 的精确 allowlist 契约不变的前提下,把受支持的上游运行时扩展到 `0.1.6-alpha.2` 与 `0.1.7-alpha.1`;设计取舍仍见 [ADR-0009](./docs/decisions/ADR-0009-dsh-compat-contract.md)。
16
+
17
+ ### Added
18
+
19
+ - **支持上游运行时 `0.1.6-alpha.2`**,与 `0.1.5-rc.2`、`0.1.6-alpha.1` 一起进 allowlist。该版本的 `confine` 异步形状与 instruction renderer 名字与 `0.1.6-alpha.1` 相同;客户端当前会话改从目录行的 `retainedBy.mainView` 读取(见 Fixed)。开发 pin 仍是 `0.1.5-rc.2`。
20
+ - **支持上游运行时 `0.1.7-alpha.1`**。`confine` 与 instruction renderer 的形状没变,但这一版有几处必须适配:session format 4 不再接受 `kind: 'plugin'`,附加根指令改用本插件自己的 source kind `multi-root-workspace`(format 3 及更早仍是 `plugin`);工具失败位从 content block 移到消息本身;面板图标从像素命名改为 Regular 线宽;进程内启动改为 `createRuntimeResolution` + `PluginPackages`;bash 执行从 `shell.run` 改为 `shell.execute().result()`。该版本的 `dsh` 依赖 cordis `^4.0.3`,探测时必须把 cordis 钉到这个版本,否则两份 `@deepseek-ai/dsh-tools` 会让工具调度用的 Symbol 对不上、工具调用在第一步失败。开发 pin 仍是 `0.1.5-rc.2`。
21
+
22
+ ### Fixed
23
+
24
+ - **`0.1.6-alpha.2` 上已打开的会话被面板显示成「当前没有活动会话」**:该版本从 Session 目录快照删除了 `current`,当前会话改由主视图 `retain(..., { source: 'mainView' })` 持有,投影在目录行的 `retainedBy.mainView`。`src/compat/client-session.ts` 用结构探测同时认两种形状;目录有行但没有主视图时仍显示空态,不会把 `ids[0]` 当成当前会话。
25
+
26
+ ## [0.1.1] - 2026-09-16
27
+
28
+ `v0.1.0` 之后的**硬化批次(H1–H4)**:不新增面向使用者的"功能",而是补齐跨进程、面板权威、上游兼容性与附加根指令四类边界。设计取舍见 [ADR-0007](./docs/decisions/ADR-0007-registry-authority-lease.md)、[ADR-0008](./docs/decisions/ADR-0008-panel-session-derived-authority.md)、[ADR-0009](./docs/decisions/ADR-0009-dsh-compat-contract.md)、[ADR-0010](./docs/decisions/ADR-0010-additional-root-instruction-scope.md)。
29
+
30
+ ### 升级注意(不兼容变更)
31
+
32
+ - **首次 `dsh plugin add` 会失败一次,四种安装来源皆然**:本版本新引入原生依赖 `koffi`(Windows 上 Registry Authority 的 FFI 封装),而 pnpm ≥10 默认不运行依赖的构建脚本,因此第一次 `add` 会以 `[ERR_PNPM_IGNORED_BUILDS]` 退出、插件不会进 `dsh.profile.bundles`。`dsh` 会把待决项留在该 profile 的 `pnpm-workspace.yaml` 里(`koffi: set this to true or false`),改成 `true` 再执行一次 `add` 即完成。`v0.1.0` 的 npm / tarball 来源没有这一步。详见[故障排查:安装停在构建授权](./docs/troubleshooting/install-stops-at-build-approval.md)。
33
+ - **支持的上游运行时收窄为精确清单 `0.1.5-rc.2`、`0.1.6-alpha.1`**(原先是 `>=0.1.2-alpha.4 <0.2.0` 范围)。宿主版本不在这两个之一,或若干 `@deepseek-ai/dsh-*` 包混装了不同版本时,`fs` / `sandbox` / `registry` / `instructions` 四行**不启动**,组合退化为"未装这个插件"并在启动时打印说明。理由是这个插件替换的是围栏本身、靠识别上游实测出的方言 argv 形状工作,而 npm 语义化范围等于对未验证版本做承诺([ADR-0009](./docs/decisions/ADR-0009-dsh-compat-contract.md))。诊断步骤见[故障排查:DSH 版本不在支持矩阵上](./docs/troubleshooting/unsupported-dsh-release.md)。**若你仍在 `v0.1.0` 时代实测可用的 `0.1.2-rc.1` 运行时上(例如某些已安装的桌面端自带运行时),请先升级该运行时,否则本版本不会生效。**
34
+ - **面板不再接受客户端指名的根**:所有面板端点必填 `sessionId`,主根只来自 host 侧的 `session.header.cwd`;客户端 `primaryRoot` 字段与 `sandboxPolicy` 回退已删除。浏览器当前没有活动会话时,面板显示"当前没有活动会话"并且不向 host 发请求([ADR-0008](./docs/decisions/ADR-0008-panel-session-derived-authority.md))。
35
+
36
+ ### Added
37
+
38
+ - **跨进程 Registry Authority(H1)**:同一 `$DSH_HOME` 上同时只允许一个 DSH 进程持有根登记表(POSIX `flock` / Windows named semaphore,进程退出或崩溃由内核释放锁)。争用方 fail-closed——发布空 scope、注册表写操作报 `registry-contended`;持锁者退出后,`/workspace-folders list` 或面板刷新即经 `refresh()` 接管([ADR-0007](./docs/decisions/ADR-0007-registry-authority-lease.md))。
39
+ - **附加根自身的指令文件进入模型上下文(H4)**:附加根**顶层**的 `AGENTS.md` / `CLAUDE.md` 在会话第一步之前注入;本会话**成功** `read` / `write` / `edit` 触碰过的子目录(含被触碰文件的每个祖先目录,直到该附加根)在其目录被考察到时增量补投;文件内容变化只重发该文件,文件或根消失时**显式撤回**。全部附加根共享 64 KiB 预算,以 `user` role 的 `{ kind: 'plugin', form: 'instructions' }` 消息投递(不是 `systemPrompt`)。上游的指令发现从会话 cwd 向上走,永远到不了附加根,这是本项存在的原因([ADR-0010](./docs/decisions/ADR-0010-additional-root-instruction-scope.md))。
40
+ - **支持第二个上游运行时 `0.1.6-alpha.1`**,与基线 `0.1.5-rc.2` 一起进 allowlist;两者都跑过完整矩阵(`confine` 的同步/异步形状差异、instruction renderer 改名、两种 LLM wire 协议均由适配层与 smoke 吸收)。
41
+ - **`pnpm compat:check`**:allowlist / `peerDependencies` / 开发 pin / 已安装树四者一致性门禁,是 CI 的第一步。
42
+ - **`multi-root-compat` 启动门禁行**:版本判定变成其余安全相关行的前置条件,而不是一条日志。
43
+ - **按周升级车道**(`upgrade.yml`):自动重指最新上游 pre-release 并跑完整矩阵,只读权限、不提交、不自动扩大 allowlist。
44
+ - 两个故障排查条目:[DSH 版本不在支持矩阵上](./docs/troubleshooting/unsupported-dsh-release.md)、[根登记表被另一个进程持有](./docs/troubleshooting/registry-owned-by-another-process.md)。
45
+
46
+ ### Changed
47
+
48
+ - 上游版本差异集中在 `src/compat/` 适配层,一律按**结构探测**(返回值是否 thenable、导出的是哪个名字)判断,不比较版本字符串;业务代码不再出现任何版本判断。
49
+ - 两个可选 peer(`@deepseek-ai/dsh-llm`、`@deepseek-ai/dsh-agent-instructions`)改为**按需加载**:barrel 的加载期依赖集合等于必需包集合,一个从不需要构造消息的最小组合不会在加载时失败。
50
+ - `pnpm verify:all` 有意**不含** `compat:check`(升级车道要在一个还不在 allowlist 上的候选版本上跑完整矩阵);CI 主车道单独把它排在最前。
51
+ - 新增 `./compat` 与 `./instructions` 子路径导出。
52
+ - 安装与发版:`prepare` 脚本改为自包含(git 安装由 pnpm 现场构建,用户需先授权 `allowBuilds`);README 补齐 npm / tarball / 本地路径 / GitHub 四种安装来源;npm 发布改用 **trusted publishing(OIDC)**,仓库不再保存任何 npm 凭证。
53
+
54
+ ### Fixed
55
+
56
+ - **注册表拆除顺序**:原先"先释放内核 lease 再关闭 domain",继任进程可能拿到 lease 后打开一份缺了本进程最后一次写入的快照;现在整个拆除在 store-wide authority 转场队列内按"排空在飞 mutation → 关闭 domain → 释放 lease"执行,并置 `disposed` 拒绝后续 acquisition(`tests/registry-lease.spec.ts`)。
57
+ - **指令投递状态按实际产物提交**:renderer 省略或截断文件时不再记录完整 digest;消息构造失败或被取消不再把指令当成已送达;预算耗尽后仍检查撤回,跨根撤回与延迟触碰不再被跳过。
58
+ - **附加根中间目录的指令文件**此前永远到不了模型(只考察被触碰文件的父目录),现在其每个祖先目录都会被考察。
59
+ - **`DSH_MULTI_ROOT_COMPAT=warn` 收紧**:只放宽 `unsupported`(版本一致、allowlist 未列名——升级车道要探测的正是这一种),`mixed` / `incomplete` 在两种模式下都拒绝。
60
+ - **"包不存在"与"已安装但求值失败"分离**:后者不再被当成缺失缓存,进程不会静默停止投递附加根指令。
61
+ - **Windows 锁命名按物理路径归一化**:经路径别名(junction / 符号链接)访问同一 store 的两个进程此前会各持一把锁,可同时成为 authority。
62
+ - **会话事件配对按会话分隔**:不同会话使用相同 `tool/call` id 时不再互相覆盖、把目录记到另一个会话。
63
+ - **升级工作流的 shell 输入处理**:手动版本与候选版本经 step `env` 传值并校验为单行,不再拼进 `run` 源码。
64
+ - **本地打包不再夹带历史构建产物**:`lib/` 在 `bundle` 之前先清掉上一轮的 JS 面(tsdown 的共享 chunk 按内容哈希命名,旧名字不会自己消失)。`pnpm pack` 出的 tarball 现在只含一轮构建的制品,不再把历史 chunk 当死代码发出去(`files` 里的 `lib/*.js` 会全部进包)。
65
+
66
+ ## [0.1.0] - 2026-09-13
67
+
68
+ 首个发布版本:MVP 的三个里程碑(M1–M3)。
69
+
70
+ ### Added
71
+
72
+ - **插件骨架与组合方式(M1)**:以 bundle patch 替换上游 `fs-sandbox` 与 `sandbox` 两行 provider 并插入本插件的行(`bash-sandbox` 保持上游——bash 与 PTY 的 confinement 全部经 `ctx.sandbox`)。未配置附加根时行为与未装插件逐项一致;组合、disable/insert 时序与 provide 冲突三类结构性风险由差分测试钉住。
73
+ - **多根能力(M2)**:`ctx.multiRootScope`(唯一授权源)、`MultiRootFileSystem`(进程内 containment fence,子类自上游 `LocalFileSystem`,`LocalFileSystem` 自身没有 fence)、`MultiRootSandboxProvider`(在 Seatbelt / bwrap / Landlock 三种方言的 profile 上克隆上游 grant 拼法追加附加根);fs 与 bash/PTY 共享同一条 scope,安全不降级。
74
+ - **模型可见的拓扑快照**:仅 `workspace-write` + 非空附加根时经 `systemPrompt.context` 输出(同 workspace、cwd 不变);空根与只读模式逐字节不变。
75
+ - **根注册表(M3)**:以 canonical 主根为键持久化在 `multi_root_workspace` storage domain,写入与读取都做校验;每条记录带 `recordedPath`,**重新解析路径不等于重新授权**——目录被替换成指向别处的符号链接时该根标为 `redirected` 并暂不授予。
76
+ - **`/workspace-folders` 命令**:`list` / `add <路径>`(无参数时打开系统目录选择器)/ `alias` / `remove` / `reveal`,headless 下同样可用。
77
+ - **Workspace Folders 浏览器面板**:侧栏底部动作 + 自绘对话框,经插件自己的 Connection RPC 通道与 host 通信;文案中英双语跟随界面语言,配色全部使用 host 的 `var(--dsw-*)` 设计 token。
78
+ - **跨仓库旅程 e2e**(`pnpm smoke:journey`):在 `web` 与 `headless` 两种组合下各驱动一轮真实 agent 回合,跨两个 Git 仓库(主根 `repo-a`、附加根 `repo-b`)并断言根外写入被拒。无需模型凭据(脚本化模型端点)。
79
+ - **安装形态**:npm 注册表 / tarball / 本地路径 / GitHub;tag 触发的 `release.yml` 完成 verify → npm publish(provenance)→ GitHub Release。
80
+ - **平台范围**:macOS(Seatbelt)与 Linux(bwrap / Landlock)的内核级多根全量;Windows 覆盖 `fs` 写路径,受限 bash/PTY 的多根不在本期(非空 scope 时输出一次显式告警)。
81
+
82
+ ### Fixed
83
+
84
+ - 发布前外部评审提出的 8 项发现(其中 3 项发布阻断)全部修复,每项各带一个回归测试:登记目录被替换为符号链接后授权转移(引入 `recordedPath`,**重新解析路径不等于重新授权**)、并发修改注册表丢写或复活已撤销的授权(每个主根的变更串行)、刷新不重新检查目录、手输路径被目录选择器覆盖、`reveal` 的应答契约与失败码、重复 id 未校验、主根未纳入嵌套校验、CI 先测后构建。
85
+
86
+ [Unreleased]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.2...HEAD
87
+ [0.1.2]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.1...v0.1.2
88
+ [0.1.1]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.0...v0.1.1
89
+ [0.1.0]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/releases/tag/v0.1.0
package/README.en.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # dsh-plugin-multi-root-workspace
2
2
 
3
+ [中文](./README.md) | English
4
+
3
5
  ## What & Why
4
6
 
5
7
  An out-of-tree plugin bundle for DSH (DeepSeek Harness) that widens the Workspace write scope from a single canonical directory to "**one primary root + N additional roots**" — **without modifying any package in the upstream repository**.
@@ -12,15 +14,20 @@ Three things make this plugin worth looking at:
12
14
  - **Security does not degrade**: the additional roots are granted through the same mechanisms the harness already uses — the in-process fs fence plus kernel-level runners (Seatbelt on macOS, bwrap / Landlock on Linux) — with the fs side and bash/PTY sharing one and the same scope. It never degenerates into danger-full-access or prompt-level constraints.
13
15
  - **Absent when absent**: it replaces the upstream `fs-sandbox` and `sandbox` provider rows through a bundle patch; with no additional root configured its behavior is item-for-item identical to an uninstalled harness, and every misconfiguration fails loudly instead of silently degrading.
14
16
 
15
- The first release (MVP) is complete and accepted: M1 composition and empty-root pass-through, M2 multi-root capability and dialect grants, M3 root registry / the `/workspace-folders` command / the Workspace Folders panel / a cross-repository journey e2e. Evidence lives in the [completed plans](./docs/plans/README.md).
17
+ **Done and released: the MVP `v0.1.0` (milestones M1–M3)** — composition and empty-root pass-through, multi-root capability and dialect grants, the root registry / the `/workspace-folders` command / the Workspace Folders panel / a cross-repository journey e2e.
18
+
19
+ **Done and released: the `v0.1.1` hardening batch (H1–H4)** — a cross-process Registry Authority Lease (when two DSH processes share one `$DSH_HOME`, only the lease holder grants additional roots; the other fails closed and takes over once the holder exits), panel primary-root authority derived from the host session (a client-named root is no longer accepted), DSH compatibility turned from a documented agreement into a **code contract enforced at startup** (an exact allowlist, mixed-install detection, a `src/compat/` adapter layer — see the "Upgrade Notes" in the [CHANGELOG](./CHANGELOG.en.md)), and **an additional root's own `AGENTS.md` / `CLAUDE.md` reaching the model** — native instruction discovery walks upward from the session cwd, so it can never reach an additional root.
20
+
21
+ **Done and released: `v0.1.2`** — with the `v0.1.1` contract unchanged, the supported upstream runtimes grow to `0.1.6-alpha.2` and `0.1.7-alpha.1` (the latter needs adapters for session format 4, in-process `PluginPackages`, bash `execute().result()`, and more); it also fixes the Workspace Folders panel on `0.1.6-alpha.2`, where dropping `current` from the Session catalog wrongly showed "No active session". See the [CHANGELOG](./CHANGELOG.en.md).
22
+
23
+ The single source of truth for progress, numbering, and release state is the [roadmap progress ledger](./docs/plans/active/2026-09-12-multi-root-workspace.md#进度总账) (M1–M4 are the MVP milestone numbers, H1–H4 are the `v0.1.1` batch numbers, and H1 is M4); per-item evidence lives in the [completed plans](./docs/plans/README.md), and the user-visible changes of each version are in the [CHANGELOG](./CHANGELOG.en.md).
16
24
 
17
25
  ## Quick Start
18
26
 
19
- With a DSH runtime at hand (web / Electron desktop / headless all work), the shortest path is three commands:
27
+ With a DSH runtime at hand (web / Electron desktop / headless all work), the shortest path is two commands — the plugin is published on [npm](https://www.npmjs.com/package/@dsh-electron/dsh-plugin-multi-root-workspace):
20
28
 
21
29
  ```sh
22
- git clone https://github.com/cherrchen/dsh-plugin-multi-root-workspace.git
23
- dsh plugin --profile web add ./dsh-plugin-multi-root-workspace
30
+ dsh plugin --profile web add @dsh-electron/dsh-plugin-multi-root-workspace
24
31
  dsh --profile web
25
32
  ```
26
33
 
@@ -30,19 +37,78 @@ Once it is up, the **Folders** action (`🗂`) appears at the sidebar foot — o
30
37
  /workspace-folders add ~/code/another-repo
31
38
  ```
32
39
 
33
- The agent can now read, write, and run bash in that directory, with the same rights as this session's workspace.
40
+ The agent can now read, write, and run bash in that directory, with the same rights as this session's workspace. Other install sources (the GitHub repository / a local clone) and the command differences of running DSH from a source checkout are covered under [Installation](#installation).
34
41
 
35
42
  ## Requirements
36
43
 
37
- - **Node.js** `^22.19.0 || >=24` (pinned by the repository's `engines`) and **Git**
38
- - **pnpm 11** (`packageManager` pins `pnpm@11.25.0`; corepack recommended)
39
- - **DSH runtime `0.1.5-rc.2`** (exact dev pin; the upgrade procedure lives in the [development workflow](./docs/development/plugin-development-workflow.md))
40
- - **Platforms**: kernel-level multi-root is complete on macOS (Seatbelt) and Linux (bwrap or Landlock); on Windows only the `fs` write path covers additional roots (confined bash/PTY does not — see [known limitations](#known-limitations-first-release))
41
- - Running the smoke tests needs **no model credentials**: the e2e model turns are served by an inline scripted OpenAI-compatible endpoint
44
+ - **Using the published plugin**: you need a *supported* DSH runtime — currently **`0.1.5-rc.2`, `0.1.6-alpha.1`, `0.1.6-alpha.2`, and `0.1.7-alpha.1`**, and nothing else will install or run (see below). `dsh plugin` installs the package into the matching profile, and no local Node toolchain is required
45
+ - **Building from source / contributing**: **Node.js** `^22.19.0 || >=24` (pinned by the repository's `engines`), **Git**, and **pnpm 11** (`packageManager` pins `pnpm@11.25.0`; corepack recommended)
46
+ - **DSH runtime**: the dev pin is exactly `0.1.5-rc.2`, the baseline among the supported releases; the upgrade procedure lives in the [development workflow](./docs/development/plugin-development-workflow.md)
47
+ - **Platforms**: kernel-level multi-root is complete on macOS (Seatbelt) and Linux (bwrap or Landlock); on Windows only the `fs` write path covers additional roots (confined bash/PTY does not — see [known limitations](#known-limitations))
48
+ - Running the smoke tests needs **no model credentials**: the e2e model turns are served by an inline scripted model endpoint
49
+
50
+ **The supported DSH versions are an exact list, not a range.** This plugin replaces `ctx.fs` and `ctx.sandbox` — the security boundary itself — and it recognizes kernel sandbox dialects from argv shapes measured against specific upstream releases. So `peerDependencies` names only the releases that have actually been through the full verification, and startup checks again: if the host's release is not on the list, or several `@deepseek-ai/dsh-*` packages disagree about which release they are, the fs / sandbox / registry / instructions rows **do not start**, the composition degrades to "this plugin is not installed", and one explanatory line is logged. To diagnose, see [troubleshooting: unsupported DSH release](./docs/troubleshooting/unsupported-dsh-release.md); for the reasoning, [ADR-0009](./docs/decisions/ADR-0009-dsh-compat-contract.md).
42
51
 
43
52
  ## Installation
44
53
 
45
- Prepare a development environment from source:
54
+ `dsh plugin` supports four install sources. All commands below use the web profile as the example; for the Electron desktop swap `--profile web` for `--profile desktop` — the install method is the same.
55
+
56
+ | Source | Command | Notes |
57
+ | --- | --- | --- |
58
+ | npm registry (recommended) | `dsh plugin --profile web add @dsh-electron/dsh-plugin-multi-root-workspace` | Pre-built artifacts, ready to use; the first `add` needs one `allowBuilds` answer (below) |
59
+ | tarball | `dsh plugin --profile web add ./dsh-electron-dsh-plugin-multi-root-workspace-<version>.tgz` | Pre-built offline package, handy for air-gapped or offline delivery — with the same one-time `allowBuilds` answer |
60
+ | local path | `dsh plugin --profile web add /path/to/package/dsh-plugin-multi-root-workspace` | pnpm `link:` to a local checkout; its dependencies are already installed in this repository — best for development |
61
+ | GitHub / git | `dsh plugin --profile web add github:cherrchen/dsh-plugin-multi-root-workspace` | Pulls source and builds it on the spot through `prepare`; needs **two** `allowBuilds` answers (this package plus `koffi`); pin a tag |
62
+
63
+ **Every install source needs one `allowBuilds` answer the first time.** The plugin carries a native dependency that must be built, `koffi` (the FFI wrapper behind Registry Authority on Windows; installed but unused elsewhere), and pnpm ≥10 runs no dependency lifecycle script by default. So the first `dsh plugin add` fails with `[ERR_PNPM_IGNORED_BUILDS]` and leaves the pending decision in that profile's `pnpm-workspace.yaml`:
64
+
65
+ ```yaml
66
+ allowBuilds:
67
+ koffi: true # the placeholder dsh leaves is "set this to true or false"
68
+ ```
69
+
70
+ Set it to `true` and run `add` again. Read that line as **letting the dependency's install script run on your machine** (outside any sandbox the agent runs in) — `koffi`'s script only precompiles locally. Diagnosis steps: [Troubleshooting: the install stops at build approval](./docs/troubleshooting/install-stops-at-build-approval.md).
71
+
72
+ ### Install from npm (recommended)
73
+
74
+ ```sh
75
+ dsh plugin --profile web add @dsh-electron/dsh-plugin-multi-root-workspace
76
+ ```
77
+
78
+ This installs pre-built artifacts (the plugin itself is never compiled), but the first install still needs the `allowBuilds` answer above.
79
+
80
+ ### Install from a tarball
81
+
82
+ ```sh
83
+ pnpm pack @dsh-electron/dsh-plugin-multi-root-workspace
84
+ # or download the tgz from the GitHub Release assets, e.g.:
85
+ # https://github.com/cherrchen/dsh-plugin-multi-root-workspace/releases/download/v0.1.2/dsh-electron-dsh-plugin-multi-root-workspace-0.1.2.tgz
86
+ dsh plugin --profile web add ./dsh-electron-dsh-plugin-multi-root-workspace-0.1.2.tgz
87
+ ```
88
+
89
+ Also pre-built (the plugin itself is never compiled here), handy for air-gapped or offline delivery — and the first `add` needs the same `allowBuilds` answer.
90
+
91
+ ### Install from GitHub
92
+
93
+ ```sh
94
+ dsh plugin --profile web add github:cherrchen/dsh-plugin-multi-root-workspace
95
+ ```
96
+
97
+ With pnpm ≥10 the first `add` fails: a git install pulls **source code rather than build artifacts**, so the package's self-contained `prepare` script must build it on the spot (a direct transpile of `src/`, no type-checking). Follow `dsh`'s guidance and copy the exact package keys pnpm prints into the profile's `pnpm-workspace.yaml` — this source has **two** pending decisions:
98
+
99
+ ```yaml
100
+ allowBuilds:
101
+ '@dsh-electron/dsh-plugin-multi-root-workspace': true
102
+ koffi: true
103
+ ```
104
+
105
+ Then run `add` again. Pinning a tag (e.g. `#v0.1.2`) is recommended so a later push cannot silently change what actually runs:
106
+
107
+ ```sh
108
+ dsh plugin --profile web add github:cherrchen/dsh-plugin-multi-root-workspace#v0.1.2
109
+ ```
110
+
111
+ ### Install from a local clone (development & debugging)
46
112
 
47
113
  ```sh
48
114
  git clone https://github.com/cherrchen/dsh-plugin-multi-root-workspace.git
@@ -50,8 +116,11 @@ cd dsh-plugin-multi-root-workspace
50
116
  export CI=true # without a TTY, pnpm's dependency self-check aborts; see the development workflow §8
51
117
  pnpm install
52
118
  pnpm build # produces lib/ (not tracked by Git); the artifact test and installation both need it
119
+ dsh plugin --profile web add "$PWD"
53
120
  ```
54
121
 
122
+ > **Tip**: if your DSH comes from a source checkout (rather than `npm install -g @deepseek-ai/deepseek-harness`), the `dsh` binary is not on the global PATH — replace `dsh` with `pnpm dsh` in the commands above, e.g. `pnpm dsh plugin --profile web add ...` and `pnpm dsh --profile web`.
123
+
55
124
  ## Running
56
125
 
57
126
  Development gates, with the result each step should produce:
@@ -60,7 +129,7 @@ Development gates, with the result each step should produce:
60
129
  pnpm lint && pnpm typecheck # expect: 0 warnings, 0 errors; both tsconfigs pass
61
130
  pnpm test # expect: all pass; dialect cases without a local kernel runner skip explicitly, with a reason
62
131
  pnpm kernel:probe # expect: reports the kernel runners this host has (seatbelt / bwrap / landlock)
63
- pnpm smoke # expect: compose 34/34, behavior 99/99, journey 28/28
132
+ pnpm smoke # expect: compose 40/40, behavior 99/99, journey 55/55
64
133
  pnpm docs:check # expect: 0 errors, 0 warnings
65
134
  ```
66
135
 
@@ -71,7 +140,7 @@ dsh plugin --profile web add "$PWD"
71
140
  dsh --profile web --dump-config
72
141
  ```
73
142
 
74
- Expected: **only** the `fs-sandbox` and `sandbox` rows are replaced by the plugin's `multi-root-fs` / `multi-root-sandbox`, with three rows inserted (scope / registry / command); `bash-sandbox` stays upstream (bash and the PTY backend take their roots from `ctx.sandbox`). After starting `dsh --profile web`, the Folders action appears at the sidebar foot.
143
+ Expected: **only** the `fs-sandbox` and `sandbox` rows are replaced by the plugin's `multi-root-fs` / `multi-root-sandbox`, with eight rows inserted (`multi-root-compat` / `fs` / `sandbox` / `scope` / `registry` / `instructions` / `command`, plus the client carrier row `multi-root-client`); `bash-sandbox` stays upstream (bash and the PTY backend take their roots from `ctx.sandbox`). After starting `dsh --profile web`, the Folders action appears at the sidebar foot.
75
144
 
76
145
  ## Usage
77
146
 
@@ -104,16 +173,21 @@ Writable additional roots: 2 of 2.
104
173
  src/
105
174
  roots.ts pure rules: canonicalization, conflict validation, record classification (available/missing/redirected/invalid)
106
175
  registry.ts the root registry: dsh-storage-domain persistence, mutations of one primary root serialized in one queue
176
+ registry-lease.ts / registry-lease-win32.ts
177
+ cross-process Registry Authority: POSIX flock and a Windows named semaphore (the kernel releases it on process death)
107
178
  scope.ts ctx.multiRootScope: the single authorization source, plus the model-visible topology snapshot
108
179
  fs.ts the multi-root filesystem provider (in-process fence, extends the upstream LocalFileSystem)
109
180
  sandbox.ts the multi-root kernel-sandbox provider (extends the upstream LocalSandboxProvider)
110
181
  dialects.ts Seatbelt / bwrap / Landlock profile recognition and additional-grant assembly (unrecognized shapes fail loudly)
111
182
  containment.ts path containment (lexical fast path plus a dev/ino alias fallback)
183
+ instructions.ts discovery, incremental delivery, budget and revocation for an additional root's AGENTS.md / CLAUDE.md (top level plus the subdirectories this session touched, injected from agent/pre-step)
184
+ compat.ts the multi-root-compat startup gate (version allowlist and mixed-install detection)
185
+ compat/ the version-difference adapters: dsh-version / sandbox-confine / agent-instructions / llm-message (optional peers loaded on demand)
112
186
  command.ts the /workspace-folders command and the host half of the panel RPC
113
187
  contract.ts the panel wire protocol (zod-validated on both ends, inlinable into the browser bundle)
114
188
  client/ the browser half: sidebar action, dialog, bilingual dictionaries
115
- tests/ differential parity, real-execution dialect matrix, contract round-trips, component and locale gates
116
- scripts/ smoke batteries (compose / behavior / journey) plus the docs and kernel-runner checks
189
+ tests/ differential parity, real-execution dialect matrix, contract round-trips, component and locale gates, cross-process lease e2e, instruction injection
190
+ scripts/ smoke batteries (compose / behavior / journey) plus the docs, kernel-runner, compatibility-contract and upgrade checks
117
191
  docs/ requirements, architecture, decision records (ADRs), plans, development workflow
118
192
  ```
119
193
 
@@ -121,24 +195,28 @@ docs/ requirements, architecture, decision records (ADRs), plans, de
121
195
 
122
196
  Issues and PRs are welcome:
123
197
 
124
- 1. Read [`AGENTS.md`](./AGENTS.md) (repository-wide rules) and the [development workflow](./docs/development/plugin-development-workflow.md) (environment, commands, the two-runtime matrix, the upgrade procedure) first.
198
+ 1. Read [`AGENTS.md`](./AGENTS.md) (repository-wide rules) and the [development workflow](./docs/development/plugin-development-workflow.md) (environment, commands, the runtime support matrix, the upgrade procedure) first.
125
199
  2. Branch from `main`; follow conventional commits (`feat` / `fix` / `perf` / `refactor` + scope) — see the existing history.
126
200
  3. All of these must pass locally before a PR: `pnpm lint`, `pnpm typecheck`, `pnpm build`, `pnpm test`, `pnpm docs:check`, `pnpm smoke` (CI runs the same order, build before test).
127
201
  4. Behavior changes update the matching document under `docs/` in the same change; keep the README bilingual pair in sync; record engineering decisions that involve trade-offs as ADRs.
128
202
  5. Hard constraint: **never modify any package of the upstream repository (deepseek-harness)**; the plugin stays an out-of-tree extension.
129
203
 
130
- ## Known Limitations (first release)
204
+ ## Known Limitations
131
205
 
206
+ - An additional root's instruction files arrive as they become relevant: the one at the root's top level is injected before the session's first step, and a subdirectory's is injected once the session has **successfully** worked in that directory. A nested file is re-examined only when its directory is examined (the root's own every step; a subdirectory's because it was delivered from, or because of a fresh touch), delivery state is in-process (so a resumed session may be told again), and only the `read` / `write` / `edit` tool names count. The primary root's chain and the user-global file remain upstream's job, and this plugin does not inject them a second time ([ADR-0010](./docs/decisions/ADR-0010-additional-root-instruction-scope.md)).
207
+ - Single writer per store: only one DSH process at a time may hold the root registry for a given `$DSH_HOME`; another process reports the registry as unavailable (`registry-contended`) and takes over on refresh once the holder exits or crashes. That is deliberate fail-closed behavior, not a race waiting to be fixed ([ADR-0007](./docs/decisions/ADR-0007-registry-authority-lease.md)).
208
+ - The supported matrix is an exact-version allowlist: on a host whose release is not on the list, or whose core packages disagree about the release, the `fs` / `sandbox` / `registry` / `instructions` rows **do not start** and the composition degrades to "the plugin is not installed" ([ADR-0009](./docs/decisions/ADR-0009-dsh-compat-contract.md)).
132
209
  - Kernel-level multi-root does not exist on Windows: the `fs` write path covers additional roots, but confined bash/PTY cannot write them (the plugin emits one explicit warning for a populated scope); see the first-release scope in the [requirements document](./docs/requirements/multi-root-workspace.md).
133
210
  - An additional root has the same rights as the primary root (no per-root read-only), and cannot become the default working directory of bash/PTY (session cwd semantics are unchanged).
134
211
  - The `workspace-files` client file tree still sees the primary root only.
135
212
  - The command's own output text is English (a host-side handler has no active locale to consult); the panel is bilingual.
136
- - The Workspace Folders panel is a sidebar footer action plus a dialog rather than a full panel: the `sidebar.panellist` / `main` slots exist only in 0.1.5, while the installed 0.1.2 desktop runtime has neither, and one implementation keeps both runtimes supported.
213
+ - The Workspace Folders panel is a sidebar footer action plus a dialog rather than a full panel: `sidebar.footer.action` is offered by every supported release, whereas `sidebar.panellist` / `main` are not.
137
214
 
138
215
  ## Documentation
139
216
 
140
217
  Long-term project documentation lives in [`docs/`](./docs/README.md):
141
218
 
219
+ - [Changelog](./CHANGELOG.en.md)
142
220
  - [Requirements](./docs/requirements/multi-root-workspace.md)
143
221
  - [Target architecture](./docs/architecture/multi-root-workspace.md)
144
222
  - [Upstream research](./docs/reference/multi-root-workspace-research.md)
@@ -149,8 +227,6 @@ Long-term project documentation lives in [`docs/`](./docs/README.md):
149
227
 
150
228
  Repository-wide rules for Coding Agents are defined in [`AGENTS.md`](./AGENTS.md).
151
229
 
152
- Chinese documentation: [`README.md`](./README.md)
153
-
154
230
  ## License
155
231
 
156
232
  [MIT](./LICENSE)