@dsh-electron/dsh-plugin-multi-root-workspace 0.1.6 → 0.1.7
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/CHANGELOG.en.md +44 -1
- package/CHANGELOG.md +44 -1
- package/README.en.md +155 -92
- package/README.md +156 -91
- package/cordis.patch.yml +57 -0
- package/lib/client.js +2678 -276
- package/lib/client.js.map +1 -1
- package/lib/command-CESuwlVt.js +1306 -0
- package/lib/command.js +2 -2
- package/lib/{compat-B6ZqbQBy.js → compat-DF_yL1bB.js} +160 -2
- package/lib/compat.js +1 -1
- package/lib/contract-DZ4zczDT.js +238 -0
- package/lib/{fs-D_Sw3o5z.js → fs-9JIzGaf3.js} +55 -19
- package/lib/fs.js +2 -1
- package/lib/index.js +10 -8
- package/lib/{instructions-DfzN-wVf.js → instructions-D19jRxN0.js} +3 -2
- package/lib/instructions.js +1 -1
- package/lib/lsp.js +7 -2
- package/lib/method-wrapper-CFY3p3j2.js +26 -0
- package/lib/process-fence.js +280 -0
- package/lib/providers.js +87 -0
- package/lib/{registry-DySMbjgW.js → registry-DCxC5Lay.js} +256 -35
- package/lib/registry.js +2 -2
- package/lib/{roots-DasWEBJk.js → roots-B-0l8mNG.js} +117 -20
- package/lib/sandbox-Kup4_ZIb.js +747 -0
- package/lib/sandbox.js +2 -1
- package/lib/scope.js +229 -20
- package/lib/types/client/RootSwitcher.d.ts +63 -0
- package/lib/types/client/WorkspaceFoldersAction.d.ts +39 -1
- package/lib/types/client/files-tree/FilesBody.module.css.d.ts +24 -0
- package/lib/types/client/files-tree/FilesTree.d.ts +47 -0
- package/lib/types/client/files-tree/adapter.d.ts +94 -0
- package/lib/types/client/files-tree/directory-node.d.ts +62 -0
- package/lib/types/client/files-tree/face.d.ts +107 -0
- package/lib/types/client/files-tree/locales.d.ts +10 -0
- package/lib/types/client/files-tree/primitives.d.ts +33 -0
- package/lib/types/client/files-tree/store.d.ts +81 -0
- package/lib/types/client/locales.d.ts +56 -10
- package/lib/types/client/open-in-app/OpenInAppAction.d.ts +27 -0
- package/lib/types/client/open-in-app/OpenTargetButton.d.ts +52 -0
- package/lib/types/client/open-in-app/OpenTargetButton.module.css.d.ts +29 -0
- package/lib/types/client/open-in-app/adapter.d.ts +46 -0
- package/lib/types/client/open-in-app/applications.d.ts +4 -0
- package/lib/types/client/open-in-app/controller.d.ts +53 -0
- package/lib/types/client/open-in-app/locales.d.ts +10 -0
- package/lib/types/client/open-in-app/open-failure-toast.d.ts +11 -0
- package/lib/types/client/open-in-app/open-path.d.ts +13 -0
- package/lib/types/client/panel-client.d.ts +2 -1
- package/lib/types/client/styles.d.ts +1 -1
- package/lib/types/command.d.ts +16 -3
- package/lib/types/compat/client-icons.d.ts +18 -0
- package/lib/types/compat/dsh-version.d.ts +1 -1
- package/lib/types/compat/open-in-app-routes.d.ts +38 -0
- package/lib/types/compat/process-entrypoints.d.ts +31 -0
- package/lib/types/compat/process-result.d.ts +14 -0
- package/lib/types/compat/pty-marker.d.ts +83 -0
- package/lib/types/compat/sandbox-confine.d.ts +2 -0
- package/lib/types/compat/storage-zod.d.ts +65 -0
- package/lib/types/compat/windows-deny-preflight.d.ts +21 -0
- package/lib/types/compat/windows-native.d.ts +68 -0
- package/lib/types/compat/windows-path-guard.d.ts +56 -0
- package/lib/types/compat/workspace-files.d.ts +2 -0
- package/lib/types/contract.d.ts +31 -19
- package/lib/types/dialects.d.ts +99 -3
- package/lib/types/fs.d.ts +32 -10
- package/lib/types/index.d.ts +7 -2
- package/lib/types/process-fence.d.ts +54 -0
- package/lib/types/profile-isolation.d.ts +178 -0
- package/lib/types/providers.d.ts +70 -0
- package/lib/types/registry.d.ts +132 -31
- package/lib/types/roots.d.ts +100 -13
- package/lib/types/sandbox.d.ts +59 -3
- package/lib/types/scope.d.ts +200 -14
- package/lib/types/windows-broker.d.ts +17 -0
- package/lib/types/windows-deny.d.ts +1 -0
- package/lib/types/windows-profile.d.ts +10 -13
- package/lib/types/windows-runner-contract.d.ts +97 -0
- package/lib/windows-runner-contract-CEfmZzu0.js +141 -0
- package/lib/windows-runner.js +1256 -13
- package/lib/workspace-files.js +138 -3
- package/lib/workspace-routing-YPxaQ4V3.js +26 -0
- package/package.json +84 -62
- package/scripts/windows-broker/install.ps1 +89 -0
- package/scripts/windows-broker/rights.cs +58 -0
- package/scripts/windows-broker/service.cs +323 -0
- package/scripts/windows-broker/verify-install.ps1 +80 -0
- package/lib/command-CTdNvwt1.js +0 -791
- package/lib/method-wrapper-Zc-JlDP3.js +0 -51
- package/lib/sandbox-BRXl_FpF.js +0 -132
- package/lib/types/client/RootFileTree.d.ts +0 -12
- package/lib/types/panel-files.d.ts +0 -3
- package/lib/windows-profile-CiFsFYIV.js +0 -216
- package/lib/{registry-lease-win32-dy8TQMD9.js → registry-lease-win32-DTO6QpT9.js} +2 -2
package/README.md
CHANGED
|
@@ -1,61 +1,60 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
1
3
|
# dsh-plugin-multi-root-workspace
|
|
2
4
|
|
|
3
5
|
中文 | [English](./README.en.md)
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
DSH(DeepSeek Harness)的外部插件 bundle:把 Workspace 的可写范围从"一个 canonical 目录"扩展为"**一个主根 + N 个附加根**",且**不修改上游仓库任何包**。
|
|
8
|
-
|
|
9
|
-
它解决的问题是:一个开发项目往往由多个独立 Git Repository 组成,而 DSH 原生只把会话原始项目当作唯一的可写根,Agent 跨仓库干活就得反复换会话。
|
|
10
|
-
|
|
11
|
-
这个插件的三个核心价值:
|
|
12
|
-
|
|
13
|
-
- **Agent 零学习成本**:继续使用原生 `read` / `write` / `edit` / `bash` 工具,插件不新增任何 `workspace_*` 工具,只是把"哪些目录属于当前 Workspace"这一个问题的答案变多了。
|
|
14
|
-
- **安全不降级**:多根授权走上游同款机制——进程内 fs fence + 内核级 runner(macOS Seatbelt / Linux bwrap / Landlock),fs 与 bash/PTY 共享同一条 scope;绝不退化为 danger-full-access 或提示词约束。
|
|
15
|
-
- **不装就当不存在**:以 bundle patch 替换上游 `fs-sandbox` 与 `sandbox` 两行 provider;未配置附加根时行为与未装插件逐项一致,misconfiguration 一律响亮报错,从不静默降级。
|
|
7
|
+
</div>
|
|
16
8
|
|
|
17
|
-
|
|
9
|
+
## 项目简介
|
|
18
10
|
|
|
19
|
-
|
|
11
|
+
DSH(DeepSeek Harness)原生只把会话启动的目录当作 Agent 唯一的可写根;本插件是一个不修改上游任何代码的外部扩展,把可写范围扩为"**一个主目录 + 多个附加目录**"。
|
|
20
12
|
|
|
21
|
-
|
|
13
|
+
一个开发项目往往由多个独立 Git 仓库组成,跨仓库干活原本得反复换会话。Codex、Cursor 等同类工具早已支持在一个工作区添加多个文件夹;本插件把同样的能力带给 DSH:把其他仓库登记为附加根,Agent 即可直接读写。
|
|
22
14
|
|
|
23
|
-
|
|
15
|
+
- **Agent 零学习成本**:继续使用原生 `read` / `write` / `edit` / `bash`,插件不新增任何工具,只是授权的目录变多了。
|
|
16
|
+
- **安全不降级**:附加根走上游同款授权机制——进程内文件围栏 + 内核级沙箱(macOS Seatbelt / Linux bwrap / Landlock / Windows ACL),文件与 bash 共享同一份授权范围,绝不退化成全开放或只靠提示词约束。
|
|
17
|
+
- **不配等于没装**:未登记附加根时行为与未装插件逐项一致;配置错误一律明确报错,从不静默降级。
|
|
24
18
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
**v0.1.5 已发布**。当前开发分支包含尚未发布的 DSH `0.2.1-alpha.1` / `0.2.1-alpha.2` 支持、动态 cwd / Session origin 分离,以及 LSP、Windows ACL、附加根文件浏览与 Worktree 能力;这些变更拟纳入 `v0.1.6`,发布状态见[路线账本](./docs/plans/active/2026-09-12-multi-root-workspace.md)。
|
|
28
|
-
|
|
29
|
-
进度、编号与发布状态的唯一真源是[路线图 §进度总账](./docs/plans/active/2026-09-12-multi-root-workspace.md#进度总账)(M1–M4 是 MVP 里程碑编号,H1–H4 是 `v0.1.1` 批次编号,其中 H1 即 M4);逐项证据见各[已完成计划](./docs/plans/README.md),每个版本的用户可见变更见 [CHANGELOG](./CHANGELOG.md)。
|
|
19
|
+
当前发布版本 `v0.1.7`。各版本的用户可见变更见 [CHANGELOG](./CHANGELOG.md);进度与发布状态见[路线图 §进度总账](./docs/plans/active/2026-09-12-multi-root-workspace.md#进度总账)。
|
|
30
20
|
|
|
31
21
|
## 快速开始
|
|
32
22
|
|
|
33
|
-
|
|
23
|
+
插件已发布到 [npm](https://www.npmjs.com/package/@dsh-electron/dsh-plugin-multi-root-workspace)。可以在 DSH 的插件安装页面填入包名 `@dsh-electron/dsh-plugin-multi-root-workspace`,也可以用命令行两步装完:
|
|
34
24
|
|
|
35
25
|
```sh
|
|
36
26
|
dsh plugin --profile web add @dsh-electron/dsh-plugin-multi-root-workspace
|
|
37
27
|
dsh --profile web
|
|
28
|
+
# --profile 按你的启动方式选择,可选值见 DSH 文档
|
|
38
29
|
```
|
|
39
30
|
|
|
40
|
-
|
|
31
|
+
tarball、GitHub、本地源码等其他安装方式见[安装](#安装)。
|
|
41
32
|
|
|
42
33
|
启动后侧栏底部出现 **Folders**(`🗂`)动作,或直接在会话里:
|
|
43
34
|
|
|
44
35
|
```text
|
|
45
|
-
/workspace-folders add ~/code/another-repo
|
|
36
|
+
/workspace-folders add ~/code/another-repo [--inherit|--read-only|--read-write]
|
|
46
37
|
```
|
|
47
38
|
|
|
48
|
-
之后 Agent 即可在该目录读写、跑 bash
|
|
39
|
+
之后 Agent 即可在该目录读写、跑 bash——默认 `inherit`,访问级别跟随会话模式。DSH 的动态 working directory 只影响新操作的相对路径和执行目录,切换 cwd 不会新增授权,也不会改变注册表归属。
|
|
49
40
|
|
|
50
41
|
## 环境要求
|
|
51
42
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
-
|
|
43
|
+
**使用本插件**:一个下表中的 DSH 版本(精确匹配,不是范围)。`dsh plugin` 负责安装,无需本地 Node 工具链。
|
|
44
|
+
|
|
45
|
+
| DSH 系列 | 受支持的版本 |
|
|
46
|
+
| --- | --- |
|
|
47
|
+
| `0.1.5` | `0.1.5-rc.2` |
|
|
48
|
+
| `0.1.6` | `0.1.6-alpha.1`、`0.1.6-alpha.2` |
|
|
49
|
+
| `0.1.7` | `0.1.7-alpha.1`、`0.1.7-alpha.2`、`0.1.7-rc.1`、`0.1.7-rc.2` |
|
|
50
|
+
| `0.2.0` | `0.2.0-rc.1`、`0.2.0-rc.2` |
|
|
51
|
+
| `0.2.1` | `0.2.1-alpha.1`、`0.2.1-alpha.2`、`0.2.1-alpha.3`、`0.2.1-alpha.4`、`0.2.1-alpha.5`、`0.2.1-rc.1`、`0.2.1-rc.2` |
|
|
52
|
+
|
|
53
|
+
DSH 版本不在表内、或 `@deepseek-ai/dsh-*` 各包版本不一致时,插件不会启动,行为等同没装。
|
|
54
|
+
|
|
55
|
+
**从源码构建 / 贡献**:Node.js `^22.19.0 || >=24`,pnpm `11.25.0`(建议经 corepack 启用);开发 pin 的 DSH 为 `0.2.1-rc.2`。
|
|
57
56
|
|
|
58
|
-
|
|
57
|
+
**运行平台**:macOS(Seatbelt)、Linux(bwrap / Landlock)、Windows(root-set ACL runner)。
|
|
59
58
|
|
|
60
59
|
## 安装
|
|
61
60
|
|
|
@@ -63,19 +62,19 @@ dsh --profile web
|
|
|
63
62
|
|
|
64
63
|
| 来源 | 命令 | 说明 |
|
|
65
64
|
| --- | --- | --- |
|
|
66
|
-
| npm 注册表(推荐) | `dsh plugin --profile web add @dsh-electron/dsh-plugin-multi-root-workspace` |
|
|
67
|
-
|
|
|
68
|
-
|
|
|
69
|
-
|
|
|
65
|
+
| npm 注册表(推荐) | `dsh plugin --profile web add @dsh-electron/dsh-plugin-multi-root-workspace` | 预构建产物,即装即用 |
|
|
66
|
+
| GitHub | `dsh plugin --profile web add github:cherrchen/dsh-plugin-multi-root-workspace` | 安装时自动从源码构建;`allowBuilds` 需含本包,建议锁定版本 |
|
|
67
|
+
| tarball | `dsh plugin --profile web add ./dsh-electron-dsh-plugin-multi-root-workspace-<version>.tgz` | 预构建离线包,适合内网/离线 |
|
|
68
|
+
| 从源码安装 | `dsh plugin --profile web add /path/to/package/dsh-plugin-multi-root-workspace` | pnpm `link:` 链接本地 checkout,适合开发调试;无需 `allowBuilds` |
|
|
70
69
|
|
|
71
|
-
|
|
70
|
+
**首次安装时 `dsh plugin add` 会以 `[ERR_PNPM_IGNORED_BUILDS]` 失败**:在该 profile 的 `pnpm-workspace.yaml` 里补上下面这行,再执行一次 `add` 即可:
|
|
72
71
|
|
|
73
72
|
```yaml
|
|
74
73
|
allowBuilds:
|
|
75
|
-
koffi: true
|
|
74
|
+
koffi: true
|
|
76
75
|
```
|
|
77
76
|
|
|
78
|
-
|
|
77
|
+
如果重跑退出 0 但插件没有进入 `dsh.profile.bundles`,做一次 `remove` + `add`。更多排查见[故障排查](./docs/troubleshooting/install-stops-at-build-approval.md)。
|
|
79
78
|
|
|
80
79
|
### 从 npm 安装(推荐)
|
|
81
80
|
|
|
@@ -83,18 +82,18 @@ allowBuilds:
|
|
|
83
82
|
dsh plugin --profile web add @dsh-electron/dsh-plugin-multi-root-workspace
|
|
84
83
|
```
|
|
85
84
|
|
|
86
|
-
|
|
85
|
+
安装的是预构建产物,首次安装需要添加 `allowBuilds`。
|
|
87
86
|
|
|
88
87
|
### 从 tarball 安装
|
|
89
88
|
|
|
90
89
|
```sh
|
|
91
90
|
pnpm pack @dsh-electron/dsh-plugin-multi-root-workspace
|
|
92
91
|
# 或从 GitHub Release 资产下载,例如:
|
|
93
|
-
# https://github.com/cherrchen/dsh-plugin-multi-root-workspace/releases/download/v0.1.
|
|
94
|
-
dsh plugin --profile web add ./dsh-electron-dsh-plugin-multi-root-workspace-0.1.
|
|
92
|
+
# https://github.com/cherrchen/dsh-plugin-multi-root-workspace/releases/download/v0.1.7/dsh-electron-dsh-plugin-multi-root-workspace-0.1.7.tgz
|
|
93
|
+
dsh plugin --profile web add ./dsh-electron-dsh-plugin-multi-root-workspace-0.1.7.tgz
|
|
95
94
|
```
|
|
96
95
|
|
|
97
|
-
|
|
96
|
+
同样是预构建产物,适合内网或离线环境交付;首次安装同样需要添加 `allowBuilds`。
|
|
98
97
|
|
|
99
98
|
### 从 GitHub 安装
|
|
100
99
|
|
|
@@ -102,7 +101,7 @@ dsh plugin --profile web add ./dsh-electron-dsh-plugin-multi-root-workspace-0.1.
|
|
|
102
101
|
dsh plugin --profile web add github:cherrchen/dsh-plugin-multi-root-workspace
|
|
103
102
|
```
|
|
104
103
|
|
|
105
|
-
|
|
104
|
+
GitHub 来源装的是源码,`add` 时会自动构建,不需要手动编译;但 `allowBuilds` 要写两行——本包自身和 `koffi`:
|
|
106
105
|
|
|
107
106
|
```yaml
|
|
108
107
|
allowBuilds:
|
|
@@ -110,93 +109,155 @@ allowBuilds:
|
|
|
110
109
|
koffi: true
|
|
111
110
|
```
|
|
112
111
|
|
|
113
|
-
|
|
112
|
+
建议锁定版本(如 `#v0.1.7`),让后续推送无法悄悄改变实际运行的内容:
|
|
114
113
|
|
|
115
114
|
```sh
|
|
116
|
-
dsh plugin --profile web add github:cherrchen/dsh-plugin-multi-root-workspace#v0.1.
|
|
115
|
+
dsh plugin --profile web add github:cherrchen/dsh-plugin-multi-root-workspace#v0.1.7
|
|
117
116
|
```
|
|
118
117
|
|
|
119
|
-
###
|
|
118
|
+
### 从本地源码安装
|
|
120
119
|
|
|
121
120
|
```sh
|
|
122
121
|
git clone https://github.com/cherrchen/dsh-plugin-multi-root-workspace.git
|
|
123
122
|
cd dsh-plugin-multi-root-workspace
|
|
124
|
-
export CI=true
|
|
123
|
+
export CI=true
|
|
125
124
|
pnpm install
|
|
126
|
-
pnpm build
|
|
127
|
-
dsh plugin --profile web add
|
|
125
|
+
pnpm build
|
|
126
|
+
dsh plugin --profile web add /path/to/repo
|
|
128
127
|
```
|
|
129
128
|
|
|
130
|
-
>
|
|
129
|
+
> [!TIP]
|
|
130
|
+
> `dsh` 不在 PATH 里时(例如用源码仓库跑 DSH),把命令里的 `dsh` 换成 `pnpm dsh`。
|
|
131
131
|
|
|
132
132
|
## 运行方法
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
开发自检:
|
|
135
135
|
|
|
136
136
|
```sh
|
|
137
|
-
pnpm lint && pnpm typecheck
|
|
138
|
-
pnpm test
|
|
139
|
-
pnpm kernel:probe
|
|
140
|
-
pnpm smoke
|
|
141
|
-
pnpm docs:check
|
|
137
|
+
pnpm lint && pnpm typecheck
|
|
138
|
+
pnpm test
|
|
139
|
+
pnpm kernel:probe
|
|
140
|
+
pnpm smoke
|
|
141
|
+
pnpm docs:check
|
|
142
142
|
```
|
|
143
143
|
|
|
144
144
|
安装进 DSH 运行时并验证组合:
|
|
145
145
|
|
|
146
146
|
```sh
|
|
147
|
-
dsh plugin --profile web add
|
|
148
|
-
dsh --profile web --dump-config
|
|
147
|
+
dsh plugin --profile web add /path/to/repo
|
|
148
|
+
dsh --profile web --dump-config | grep -A3 'multi-root'
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
预期输出:
|
|
152
|
+
|
|
153
|
+
```text
|
|
154
|
+
# == @deepseek-ai/dsh-base, patched by @dsh-electron/dsh-plugin-multi-root-workspace
|
|
155
|
+
- id: sandbox
|
|
156
|
+
name: '@deepseek-ai/dsh-sandbox-local'
|
|
157
|
+
disabled: true
|
|
158
|
+
--
|
|
159
|
+
# == @deepseek-ai/dsh-base, patched by @dsh-electron/dsh-plugin-multi-root-workspace
|
|
160
|
+
- id: fs-sandbox
|
|
161
|
+
name: '@deepseek-ai/dsh-fs-sandbox'
|
|
162
|
+
disabled: true
|
|
163
|
+
--
|
|
164
|
+
# == @dsh-electron/dsh-plugin-multi-root-workspace
|
|
165
|
+
- id: multi-root-compat
|
|
166
|
+
name: '@dsh-electron/dsh-plugin-multi-root-workspace/compat'
|
|
167
|
+
- id: multi-root-fs
|
|
168
|
+
name: '@dsh-electron/dsh-plugin-multi-root-workspace/fs'
|
|
169
|
+
- id: multi-root-sandbox
|
|
170
|
+
name: '@dsh-electron/dsh-plugin-multi-root-workspace/sandbox'
|
|
171
|
+
- id: multi-root-providers
|
|
172
|
+
name: '@dsh-electron/dsh-plugin-multi-root-workspace/providers'
|
|
173
|
+
- id: multi-root-scope
|
|
174
|
+
name: '@dsh-electron/dsh-plugin-multi-root-workspace/scope'
|
|
175
|
+
config:
|
|
176
|
+
toolAccess: {}
|
|
177
|
+
- id: multi-root-registry
|
|
178
|
+
name: '@dsh-electron/dsh-plugin-multi-root-workspace/registry'
|
|
179
|
+
config:
|
|
180
|
+
leasePath: !!js dshHomePath('storages/multi_root_workspace.lock')
|
|
181
|
+
maxAdditionalRoots: 16
|
|
182
|
+
- id: multi-root-instructions
|
|
183
|
+
name: '@dsh-electron/dsh-plugin-multi-root-workspace/instructions'
|
|
184
|
+
config:
|
|
185
|
+
maxBytes: 65536
|
|
186
|
+
- id: multi-root-lsp
|
|
187
|
+
name: '@dsh-electron/dsh-plugin-multi-root-workspace/lsp'
|
|
188
|
+
- id: multi-root-workspace-files
|
|
189
|
+
name: '@dsh-electron/dsh-plugin-multi-root-workspace/workspace-files'
|
|
190
|
+
- id: multi-root-command
|
|
191
|
+
name: '@dsh-electron/dsh-plugin-multi-root-workspace/command'
|
|
192
|
+
- id: multi-root-client
|
|
193
|
+
name: '@dsh-electron/dsh-plugin-multi-root-workspace'
|
|
149
194
|
```
|
|
150
195
|
|
|
151
|
-
|
|
196
|
+
即上游 `fs-sandbox` 与 `sandbox` 两行被禁用、由插件同名服务接管,插件自身的 `multi-root-*` 行全部挂载。启动后侧栏底部会出现 **Folders** 动作。
|
|
152
197
|
|
|
153
198
|
## 使用方法
|
|
154
199
|
|
|
155
|
-
|
|
200
|
+
### 命令
|
|
156
201
|
|
|
157
202
|
```text
|
|
158
|
-
/workspace-folders
|
|
159
|
-
/workspace-folders add <绝对路径>
|
|
160
|
-
/workspace-folders
|
|
161
|
-
/workspace-folders
|
|
162
|
-
/workspace-folders
|
|
203
|
+
/workspace-folders [list] # 列出主根与附加根(含每根访问级别与状态)
|
|
204
|
+
/workspace-folders add <绝对路径> [--inherit|--read-only|--read-write] # 不带路径时打开系统目录选择器;新登记默认 inherit
|
|
205
|
+
/workspace-folders access <序号|路径> inherit|read-only|read-write # 切换访问级别(扩权要求该根此刻可用)
|
|
206
|
+
/workspace-folders alias <序号|路径> [别名] # 不带别名则清除已有别名
|
|
207
|
+
/workspace-folders remove <序号|路径> # 序号即 list 输出的编号
|
|
208
|
+
/workspace-folders reveal <序号|路径> # 在文件管理器中显示
|
|
209
|
+
/workspace-folders isolate-profiles [--apply] # 检查 $DSH_HOME profile 依赖导入方式与多链接文件;--apply 写入 copy 配置
|
|
210
|
+
/workspace-folders help # 查看命令帮助
|
|
163
211
|
```
|
|
164
212
|
|
|
165
|
-
|
|
213
|
+
路径可带引号;与已有根重复、嵌套在已有根内部、或就是主根本身的路径会被拒绝。
|
|
214
|
+
|
|
215
|
+
访问级别是三态的([ADR-0017](./docs/decisions/ADR-0017-three-state-root-access-and-sandbox-modes.md),语义细节见[使用指南](./docs/guide/README.md#访问级别数量上限与-per-tool-封顶)):`inherit` 跟随会话模式——`workspace-write` 可写、`read-only` 拒写、`danger-full-access` 不受限;`read-only` 在任何模式下都拒写(包括 Full-access);`read-write` 固定在只读会话里仍可写。旧版插件登记的可写记录升级后按 `inherit` 读。每个主根最多登记 16 个附加根(`maxAdditionalRoots` 配置可调至 64)。宿主还可以在 `multi-root-scope` 行配置 `toolAccess`,例如 `{ bash: 'read-only' }` 让 bash 永远不能写任何附加根(仍可写主根)。
|
|
216
|
+
|
|
217
|
+
`add` 后执行 `list` 的预期输出(`workspace-write` 会话,website 登记为只读):
|
|
166
218
|
|
|
167
219
|
```text
|
|
168
220
|
Workspace root (primary; access follows the current sandbox mode): /home/me/monorepo
|
|
169
|
-
1 /home/me/payments-service [支付]
|
|
170
|
-
2 /home/me/website
|
|
171
|
-
|
|
221
|
+
1 /home/me/payments-service [支付] (inherit)
|
|
222
|
+
2 /home/me/website (read-only)
|
|
223
|
+
2 of 16 additional roots.
|
|
224
|
+
Writable additional roots under the current mode: 1 of 2.
|
|
172
225
|
```
|
|
173
226
|
|
|
174
|
-
|
|
227
|
+
### 面板
|
|
228
|
+
|
|
229
|
+
侧栏底部的 **Folders** 对话框列出主根与附加根,支持添加、移除、别名、切换只读/可写、复制路径、在文件管理器中显示与上下移排序。
|
|
230
|
+
|
|
231
|
+
### 模型侧
|
|
175
232
|
|
|
176
|
-
|
|
233
|
+
附加根的拓扑信息会注入系统提示词,让模型知道当前有哪些目录可用,授权变化时信息随之更新,不需要向模型提供新的工具。
|
|
177
234
|
|
|
178
235
|
## 项目结构
|
|
179
236
|
|
|
180
237
|
```text
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
238
|
+
.
|
|
239
|
+
├── src/
|
|
240
|
+
│ ├── roots.ts 纯规则层:canonical 化、冲突校验、登记状态分类(available/missing/redirected/invalid)
|
|
241
|
+
│ ├── registry.ts 根注册表:dsh-storage-domain 持久化,同一主根的变更在一条队列里串行
|
|
242
|
+
│ ├── registry-lease.ts 跨进程 Registry Authority:POSIX flock(进程死亡由内核释放)
|
|
243
|
+
│ ├── registry-lease-win32.ts 同上,Windows named semaphore 实现
|
|
244
|
+
│ ├── scope.ts ctx.multiRootScope:唯一的授权源,兼发模型可见的拓扑快照
|
|
245
|
+
│ ├── fs.ts 多根文件系统 provider(进程内 fence,子类自上游 LocalFileSystem)
|
|
246
|
+
│ ├── sandbox.ts 多根内核沙箱 provider(子类自上游 LocalSandboxProvider)
|
|
247
|
+
│ ├── dialects.ts Seatbelt / bwrap / Landlock profile 的识别与附加 grant 拼装(不认识即响亮报错)
|
|
248
|
+
│ ├── windows-*.ts Windows root-set ACL runner 与 restricted-token 执行
|
|
249
|
+
│ ├── containment.ts 路径包含判定(词法快速路径 + dev/ino 别名回退)
|
|
250
|
+
│ ├── instructions.ts 附加根 AGENTS.md / CLAUDE.md 的发现、增量投递、预算与撤回(顶层 + 本会话触碰过的子目录,经 agent/pre-step 注入)
|
|
251
|
+
│ ├── lsp.ts 附加根按所在根初始化独立 LSP workspace
|
|
252
|
+
│ ├── workspace-files.ts Files 页签附加根文件浏览的 host 路由与 confinement
|
|
253
|
+
│ ├── compat.ts multi-root-compat 启动门禁(版本 allowlist 与混装判定)
|
|
254
|
+
│ ├── compat/ 版本差异适配层:dsh-version / sandbox-confine / agent-instructions / llm-message 等(可选 peer 按需加载)
|
|
255
|
+
│ ├── command.ts /workspace-folders 命令与面板 RPC 的 host 半部
|
|
256
|
+
│ ├── contract.ts 面板线协议(zod 双端校验,可内联进浏览器 bundle)
|
|
257
|
+
│ └── client/ 浏览器半部:侧栏动作、Folders 对话框、Files 页签根切换器、双语词典
|
|
258
|
+
├── tests/ 差分 parity、方言真实执行矩阵、契约往返、组件与 locale 门禁、跨进程 lease e2e、指令注入
|
|
259
|
+
├── scripts/ 冒烟(compose / behavior / journey)、文档与内核 runner 检查、兼容性契约检查、升级流程
|
|
260
|
+
└── docs/ 需求、架构、决策记录(ADR)、计划、开发工作流
|
|
200
261
|
```
|
|
201
262
|
|
|
202
263
|
## 贡献指南
|
|
@@ -215,8 +276,11 @@ docs/ 需求、架构、决策记录(ADR)、计划、开发工
|
|
|
215
276
|
- 跨进程单写者:同一 `$DSH_HOME` 上同时只允许一个 DSH 进程持有根登记表;另一个进程显示登记表不可用(`registry-contended`),持锁者退出或崩溃后刷新即接管——这是刻意的 fail-closed,不是待修的竞态([ADR-0007](./docs/decisions/ADR-0007-registry-authority-lease.md))。
|
|
216
277
|
- 支持矩阵是精确版本 allowlist:宿主版本不在清单上、或核心包混装了不同版本时,`fs` / `sandbox` / `registry` / `instructions` / `lsp` / `workspace-files` 六行**不启动**,组合退化为"没装这个插件"([ADR-0009](./docs/decisions/ADR-0009-dsh-compat-contract.md))。
|
|
217
278
|
- Windows 多根 runner 继承上游 partial enforcement、caller-owned 目录及 private temp 分离条件;已启动进程保留启动时根集合,后续进程使用更新后的集合([ADR-0011](./docs/decisions/ADR-0011-multi-root-workspace-consumers.md))。
|
|
218
|
-
-
|
|
219
|
-
-
|
|
279
|
+
- **Windows 上的网络与设备路径不能成为附加根**:UNC(`\\server\share`)、`\\?\`、`\\.\` 与映射网络盘在登记时即以 `unsupported-path` 拒绝——restricted token 的 capability SID 无法绑定 SMB 访问([ADR-0011 修订](./docs/decisions/ADR-0011-multi-root-workspace-consumers.md))。
|
|
280
|
+
- **Windows 受限 shell 是 pwsh,不含 Git Bash**:MSYS 在 restricted Low-integrity token 下无法启动(上游 runner 与插件 runner 表现一致,属上游限制);上游 runner 的 confined 子进程因继承 ignore-Ctrl+C 标志而收不到 Ctrl+C,插件 runner 下子进程能收到并由 runner 镜像其退出码。
|
|
281
|
+
- 附加根访问级别是三态的:新登记默认 `inherit`(跟随会话模式),`--read-only` 在任何模式下都拒写(包括 Full-access),`--read-write` 固定在只读会话里仍可写(写授权问题,不是读 confinement;[ADR-0017](./docs/decisions/ADR-0017-three-state-root-access-and-sandbox-modes.md))。已启动的进程与持久终端保留启动时的 deny 集——一个在某根变为只读之前就启动的终端保持不受限,直到重启;cap/access 变化只约束之后的调用与新进程([ADR-0013](./docs/decisions/ADR-0013-per-root-and-per-tool-access.md));提供 workingDirectory 的宿主可以把附加根作为后续工具的执行目录,Session 原始项目与登记身份不变([ADR-0012](./docs/decisions/ADR-0012-session-origin-and-effective-cwd.md))。
|
|
282
|
+
- **上游选择 Landlock 的 Linux 主机上,受限 Full-access 需要 bwrap**:Landlock 的 allowlist 表达不了「全部可写、除这些根」,该组合改选 bubblewrap 拼出拒写边界;主机没有可用的 bwrap(未安装或禁用非特权 userns)时,存在任何拒写边界(只读根或受保护的 `$DSH_HOME`)的 Full-access 命令在启动前失败关闭。启用 bwrap,或在该主机上避免在 Full-access 下使用显式只读根([ADR-0017](./docs/decisions/ADR-0017-three-state-root-access-and-sandbox-modes.md))。
|
|
283
|
+
- 附加根文件树由 **Files 页签的根选择器**承载:头部入口列出主根与全部附加根,旁边仍显示选中根的完整路径;选中附加根时逐字节复刻的上游 Files 树体接管树区(懒加载目录、原生行式与图标、watch 自动刷新、文件点击进宿主 viewer、header 原位提供手动刷新),header 右侧「在应用中打开」按钮同时由逐字节复刻的上游控件顶替、对选中根而非主根发起打开;切回主根即恢复原生视图;对话框回归纯管理。该接管依赖上游 `data-*` DOM 钩子,钩子失效时静默退化为原生观感([ADR-0015](./docs/decisions/ADR-0015-files-tab-plugin-owned-browsing.md)、[ADR-0016](./docs/decisions/ADR-0016-files-tab-native-tree-fork.md))。LSP 按附加文件所在根初始化独立 workspace;需要宿主配置对应语言服务器([ADR-0011](./docs/decisions/ADR-0011-multi-root-workspace-consumers.md))。
|
|
220
284
|
- 命令的输出文案为英文(host 侧没有活动语言信息),面板文案中英双语跟随界面语言。
|
|
221
285
|
- Workspace Folders 面板是「侧栏底部动作 + 对话框」,不是独立全屏面板:`sidebar.footer.action` 是所有受支持版本都提供的插槽,而 `sidebar.panellist`/`main` 不是。
|
|
222
286
|
|
|
@@ -225,6 +289,7 @@ docs/ 需求、架构、决策记录(ADR)、计划、开发工
|
|
|
225
289
|
项目长期文档位于 [`docs/`](./docs/README.md):
|
|
226
290
|
|
|
227
291
|
- [版本变更记录(CHANGELOG)](./CHANGELOG.md)
|
|
292
|
+
- [用户指南](./docs/guide/README.md)
|
|
228
293
|
- [需求](./docs/requirements/multi-root-workspace.md)
|
|
229
294
|
- [目标架构](./docs/architecture/multi-root-workspace.md)
|
|
230
295
|
- [上游调研](./docs/reference/multi-root-workspace-research.md)
|
package/cordis.patch.yml
CHANGED
|
@@ -42,14 +42,43 @@
|
|
|
42
42
|
name: '@dsh-electron/dsh-plugin-multi-root-workspace/fs'
|
|
43
43
|
- id: multi-root-sandbox
|
|
44
44
|
name: '@dsh-electron/dsh-plugin-multi-root-workspace/sandbox'
|
|
45
|
+
# The provider-conflict gate: `ctx.fs` and `ctx.sandbox` must be THIS
|
|
46
|
+
# bundle's branded providers — verified by a well-known symbol, not
|
|
47
|
+
# instanceof, so duplicated installs still count. If another plugin's
|
|
48
|
+
# provider took either key (or took it over later — cordis restarts an
|
|
49
|
+
# injecting fiber when an injected service changes, so this row re-checks),
|
|
50
|
+
# the row logs which service is foreign and throws. Every widened-authority
|
|
51
|
+
# row below injects `multiRootProviders`, so a conflicted composition keeps
|
|
52
|
+
# the registry unmounted, the scope empty, and nothing granted, regardless
|
|
53
|
+
# of patch order — fail loud, never a widened grant on an unverified
|
|
54
|
+
# provider.
|
|
55
|
+
- id: multi-root-providers
|
|
56
|
+
name: '@dsh-electron/dsh-plugin-multi-root-workspace/providers'
|
|
45
57
|
- id: multi-root-scope
|
|
46
58
|
name: '@dsh-electron/dsh-plugin-multi-root-workspace/scope'
|
|
59
|
+
config:
|
|
60
|
+
# Per-tool write caps: a tool listed here may never write ANY
|
|
61
|
+
# additional root (the primary root is unaffected). `read-only` is the
|
|
62
|
+
# only legal value; anything else fails closed — every additional-root
|
|
63
|
+
# write is refused for the session. Empty map: no cap at all.
|
|
64
|
+
toolAccess: {}
|
|
65
|
+
# The harness home holds the store, the lease file, and the user's
|
|
66
|
+
# profiles — nothing an ambient Full-access process may touch. While
|
|
67
|
+
# ANY deny boundary exists under danger-full-access (a restricted root
|
|
68
|
+
# or an unavailable registry authority), the scope appends this path
|
|
69
|
+
# to the deny set, so fs writes and spawned processes refuse it.
|
|
70
|
+
dshHome: !!js dshHomePath()
|
|
47
71
|
- id: multi-root-registry
|
|
48
72
|
name: '@dsh-electron/dsh-plugin-multi-root-workspace/registry'
|
|
49
73
|
config:
|
|
50
74
|
# Store-wide kernel lease beside the JSON domain document. A custom
|
|
51
75
|
# storage-json.root must override this path in lockstep (ADR-0007).
|
|
52
76
|
leasePath: !!js dshHomePath('storages/multi_root_workspace.lock')
|
|
77
|
+
# Cap on stored additional-root records per primary root (integer,
|
|
78
|
+
# 1..64; the count covers every state, so it is stable). A store that
|
|
79
|
+
# already exceeds it keeps granting — only new adds are refused. Bench
|
|
80
|
+
# evidence for the default: docs/reference/bench-root-scale-*.json.
|
|
81
|
+
maxAdditionalRoots: 16
|
|
53
82
|
# Upstream `agent-instructions` only discovers instruction files from the
|
|
54
83
|
# session cwd upward, so an additional root's own AGENTS.md is invisible to
|
|
55
84
|
# the model. This row closes that gap for the additional roots only; the
|
|
@@ -63,7 +92,35 @@
|
|
|
63
92
|
name: '@dsh-electron/dsh-plugin-multi-root-workspace/lsp'
|
|
64
93
|
- id: multi-root-workspace-files
|
|
65
94
|
name: '@dsh-electron/dsh-plugin-multi-root-workspace/workspace-files'
|
|
95
|
+
# The B9 consumer seam for `danger-full-access`: the shell executor, the
|
|
96
|
+
# PTC runtime, and the PTY backend all skip `ctx.sandbox.confine` in that
|
|
97
|
+
# mode, so an explicit `read-only` additional root would silently stay
|
|
98
|
+
# writable. This row wraps `ctx.subprocess.spawn` / `spawnTerminal`,
|
|
99
|
+
# `ctx.shell.execute` (and `run` / `start` where a release still exposes
|
|
100
|
+
# them), and `ctx.ptcRuntime.run` at their public methods — under
|
|
101
|
+
# Full-access with restricted roots it asks `ctx.sandbox` for a restricted
|
|
102
|
+
# profile prefix and runs the call inside it, and while the registry
|
|
103
|
+
# authority is unavailable (contended, storage-failed, config-invalid) it
|
|
104
|
+
# limits the same calls to primary-root-only writes (no shared temp) instead of
|
|
105
|
+
# trusting the empty deny set. `spawnTerminal` only confines agent PTYs:
|
|
106
|
+
# every supported `dsh-terminal-bash` backend stamps `DSH_PTY_SESSION_ID`
|
|
107
|
+
# into the spawn env; a spec without it — the panel's terminal controller
|
|
108
|
+
# calls `spawnTerminal` directly — is a USER terminal and passes through
|
|
109
|
+
# in every mode (`ctx.terminals` is `isolate`d on the web profile, so the
|
|
110
|
+
# registry entry itself is not a reachable seam). The marker is a load
|
|
111
|
+
# contract, not an assumption: `multi-root-compat` probes the installed
|
|
112
|
+
# `dsh-terminal-bash` build for `DSH_PTY_SESSION_ID` at startup and refuses
|
|
113
|
+
# to load when an installed backend no longer stamps it. A dialect that
|
|
114
|
+
# cannot express "ambient minus subtree" (Landlock, Windows ACL) fails
|
|
115
|
+
# closed before the process starts.
|
|
116
|
+
- id: multi-root-process-fence
|
|
117
|
+
name: '@dsh-electron/dsh-plugin-multi-root-workspace/process-fence'
|
|
66
118
|
- id: multi-root-command
|
|
67
119
|
name: '@dsh-electron/dsh-plugin-multi-root-workspace/command'
|
|
120
|
+
config:
|
|
121
|
+
# `/workspace-folders isolate-profiles` inspects the same canonical
|
|
122
|
+
# home the scope protects; spelled exactly like the scope row so the
|
|
123
|
+
# two can never disagree about which home was checked.
|
|
124
|
+
dshHome: !!js dshHomePath()
|
|
68
125
|
- id: multi-root-client
|
|
69
126
|
name: '@dsh-electron/dsh-plugin-multi-root-workspace'
|