@dsh-electron/dsh-plugin-multi-root-workspace 0.1.8 → 0.1.10

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 (75) hide show
  1. package/CHANGELOG.en.md +22 -1
  2. package/CHANGELOG.md +22 -1
  3. package/README.en.md +39 -16
  4. package/README.md +47 -24
  5. package/cordis.patch.yml +10 -0
  6. package/lib/auto-review-packages-nRjnb4pU.js +15 -0
  7. package/lib/auto-review.js +166 -0
  8. package/lib/client.js +573 -131
  9. package/lib/client.js.map +1 -1
  10. package/lib/{command-CESuwlVt.js → command-BGdz7VBH.js} +68 -8
  11. package/lib/command.js +1 -1
  12. package/lib/{compat-DR2LvmYZ.js → compat-D-MljsPV.js} +13 -2
  13. package/lib/compat.js +1 -1
  14. package/lib/{contract-DZ4zczDT.js → contract-CStSEOcK.js} +44 -1
  15. package/lib/fork-CzbeWxHp.js +670 -0
  16. package/lib/fs.js +1 -1
  17. package/lib/index.js +9 -8
  18. package/lib/{instructions-D19jRxN0.js → instructions-MePoRigy.js} +213 -263
  19. package/lib/instructions.js +1 -1
  20. package/lib/llm-message-fYORacvh.js +206 -0
  21. package/lib/lsp.js +1 -1
  22. package/lib/metadata-DgqSdVX_.js +35 -0
  23. package/lib/{registry-DCxC5Lay.js → registry-KSsmU393.js} +66 -13
  24. package/lib/registry.js +1 -1
  25. package/lib/review-context-AH-SXHmj.js +98 -0
  26. package/lib/review-context.js +2 -0
  27. package/lib/{roots-B-0l8mNG.js → roots-Ca_W1S9n.js} +1 -1
  28. package/lib/{sandbox-CVAcT_gy.js → sandbox-CXk5h-ct.js} +3 -3
  29. package/lib/sandbox.js +1 -1
  30. package/lib/scope.js +15 -6
  31. package/lib/skills.js +790 -0
  32. package/lib/types/auto-review/entry.d.ts +5 -0
  33. package/lib/types/client/WorkspaceFoldersAction.d.ts +1 -1
  34. package/lib/types/client/locales.d.ts +26 -16
  35. package/lib/types/client/skills-client.d.ts +23 -0
  36. package/lib/types/client/skills-settings.d.ts +10 -0
  37. package/lib/types/client/skills.d.ts +36 -0
  38. package/lib/types/client/styles.d.ts +1 -1
  39. package/lib/types/command.d.ts +1 -1
  40. package/lib/types/compat/auto-review-contract.d.ts +3 -0
  41. package/lib/types/compat/auto-review-loader.d.ts +33 -0
  42. package/lib/types/compat/auto-review-packages.d.ts +1 -0
  43. package/lib/types/compat/client-session.d.ts +2 -0
  44. package/lib/types/compat/dsh-version.d.ts +5 -5
  45. package/lib/types/compat/instruction-activity.d.ts +17 -0
  46. package/lib/types/compat/review-session.d.ts +2 -0
  47. package/lib/types/compat/skill-content.d.ts +3 -0
  48. package/lib/types/compat/skills-client.d.ts +33 -0
  49. package/lib/types/compat/skills-settings.d.ts +8 -0
  50. package/lib/types/compat/skills.d.ts +13 -0
  51. package/lib/types/compat/storage-zod.d.ts +1 -0
  52. package/lib/types/contract.d.ts +12 -1
  53. package/lib/types/instructions.d.ts +18 -1
  54. package/lib/types/registry.d.ts +7 -0
  55. package/lib/types/review-context.d.ts +49 -0
  56. package/lib/types/roots.d.ts +4 -1
  57. package/lib/types/scope.d.ts +5 -0
  58. package/lib/types/skills/catalog.d.ts +34 -0
  59. package/lib/types/skills/invocation.d.ts +7 -0
  60. package/lib/types/skills/metadata.d.ts +13 -0
  61. package/lib/types/skills/pool.d.ts +19 -0
  62. package/lib/types/skills/reader.d.ts +3 -0
  63. package/lib/types/skills/routing.d.ts +2 -0
  64. package/lib/types/skills-contract.d.ts +39 -0
  65. package/lib/types/skills.d.ts +43 -0
  66. package/lib/windows-runner.js +2 -2
  67. package/lib/workspace-files.js +2 -2
  68. package/package.json +121 -68
  69. package/src/auto-review/FORK.md +26 -0
  70. package/src/auto-review/LICENSE +21 -0
  71. package/src/auto-review/README.en.md +22 -0
  72. package/src/auto-review/README.md +22 -0
  73. package/lib/{fs-Nlp2AiRX.js → fs-BTXySwSG.js} +1 -1
  74. package/lib/{registry-lease-win32-DTO6QpT9.js → registry-lease-win32-DVTq9d4D.js} +1 -1
  75. package/lib/{windows-runner-contract-CEfmZzu0.js → windows-runner-contract-B5R2K3mM.js} +1 -1
package/CHANGELOG.en.md CHANGED
@@ -8,6 +8,25 @@ This file records the user-visible changes of every **released** version.
8
8
  - For installation sources, the supported upstream runtimes, and known limitations, see the [README](./README.en.md).
9
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
10
 
11
+ ## [0.1.10] - 2026-10-25
12
+
13
+ ### Added
14
+
15
+ - **Additional-root Skills**: skills are discovered in each additional folder's `.dsh/skills` and `.agents/skills`; names and descriptions are visible before the first model step and bodies load on invocation. The primary root uses `/skill-name`; additional roots always use the namespaced `/alias-id:skill-name` reference (completable from the Slash menu, invoked by the model through the native `skill` tool under an internal name). New `inherit` / `read-write` registrations enable Skills by default, `read-only` ones disable them; the Workspace Folders dialog provides an independent Skills toggle and `aliasId` editing, and the global **Enable additional-root Skills** switch under Settings → Plugins → Multi-root Workspace defaults to on — disabling it only stops new discovery and invocation while preserving each root's choice. On upgrade, legacy `inherit` / `read-write` registrations start with Skills enabled; migration preserves existing grants, but an older plugin writing the registry may strip `aliasId` and manual toggles — **lossless downgrade of Skills preferences is not guaranteed** (back up `$DSH_HOME/storages/multi_root_workspace.json` before downgrading). Enabling Skills on a read-only root grants no write access; disabling does not reclaim delivered bodies or stop started processes ([ADR-0023](./docs/decisions/ADR-0023-multi-root-skill-discovery-and-invocation.md)).
16
+ - **Exact support for DSH `0.2.1-rc.3`**. The upstream `rc.2`→`rc.3` delta is purely additive (new sidebar slots, navigation pins, and a DeepSeek `/models` listing), so no new adapter branch is needed; the dev pin moves to `0.2.1-rc.3` (cordis `4.0.5` unchanged).
17
+
18
+ ### Fixed
19
+
20
+ - **Workspace Folders panel aligned with upstream UI**: the settings switch row layout, the Skills toggle folded into the icon actions, button backgrounds confined to hover, action appearance preserved during saves, and the folder policy and effective access combined into one label; the move up/down reorder buttons (the ordering interface is retained for a future drag interaction) and the permission introduction text at the top of the dialog are removed.
21
+ - **Namespaced skill reference rendering**: a sent `/alias-id:skill-name` reference renders as ordinary user text, without a dedicated button style, highlighting, or click-to-preview (same-day ADR-0023 revision); ordinary session activity/title updates no longer close an open skill body preview.
22
+
23
+ ## [0.1.9] - 2026-10-20
24
+
25
+ ### Added
26
+
27
+ - **Optional Auto Review (off by default)**: the main package gains an `./auto-review` subpath export and a `multi-root-auto-review` patch row — a fork of upstream's experimental "auto review" that feeds the reviewer the additional roots' context: the current workspace topology, each root's effective access level, and live instruction files. The row ships `disabled: true`; while off it mounts neither the reviewer nor the review context and does not register the Auto preset. The ordinary support matrix is unchanged — only DSH `0.2.1-rc.2` can enable it, and enabling it on any other release fails loudly rather than silently degrading. To turn it on, open the `@dsh-electron/dsh-plugin-multi-root-workspace/auto-review` row in the Plugin Manager row list (profiles without hot reload ask for a restart), or set `disabled: false` in the profile's `cordis.patch.yml`; the context and the reviewer share this single switch.
28
+ - **Takes over the official reviewer while on**: the same switch mounts the multi-root review context and the fork reviewer, and stops the official `@deepseek-ai/dsh-experimental-auto-review` row in the same group at run time — the official bundle may sit before or after this package, the takeover only touches runtime state and never writes back the official row's persisted configuration; when the official bundle was never selected, the row runs standalone (it registers its own Auto preset). Disabling restores the official row per its original configuration on the next reload/restart and never re-selects Auto on its own; unloading any live Auto owner keeps the official Auto → Full access semantics. A profile that ever installed the old standalone companion package from a local tarball/link must remove its bundle selection and dependency before enabling this row (a leftover companion alongside the built-in entry is refused explicitly). Usage notes live in [src/auto-review/README.en.md](./src/auto-review/README.en.md) ([ADR-0021](./docs/decisions/ADR-0021-auto-review-context-companion.md), [ADR-0022](./docs/decisions/ADR-0022-auto-review-loader-entry.md)).
29
+
11
30
  ## [0.1.8] - 2026-10-18
12
31
 
13
32
  ### Fixed
@@ -162,7 +181,9 @@ The first release: the three MVP milestones (M1–M3).
162
181
 
163
182
  - 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.
164
183
 
165
- [Unreleased]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.8...HEAD
184
+ [Unreleased]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.10...HEAD
185
+ [0.1.10]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.9...v0.1.10
186
+ [0.1.9]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.8...v0.1.9
166
187
  [0.1.8]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.7...v0.1.8
167
188
  [0.1.7]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.6...v0.1.7
168
189
  [0.1.6]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.5...v0.1.6
package/CHANGELOG.md CHANGED
@@ -8,6 +8,25 @@ English: [CHANGELOG.en.md](./CHANGELOG.en.md)
8
8
  - 安装方式、受支持的上游运行时与已知限制见 [README](./README.md)。
9
9
  - 每个版本的实施证据、编号口径与发布状态见[路线图 §进度总账](./docs/plans/active/2026-09-12-multi-root-workspace.md#进度总账);GitHub Release 的正文由 `scripts/release-notes.mjs` 从 commit 历史生成,是本文件之外的完整原始清单。
10
10
 
11
+ ## [0.1.10] - 2026-10-25
12
+
13
+ ### Added
14
+
15
+ - **附属根 Skills**:发现附属目录的 `.dsh/skills` 和 `.agents/skills`,首个模型步骤可见名称与描述,正文按需加载。主根使用 `/skill-name`;附属根始终使用 `/alias-id:skill-name` 命名空间引用(Slash 菜单可补全,模型经原生 `skill` 工具用内部名称调用)。新登记的 `inherit` / `read-write` 根默认开启,`read-only` 根默认关闭;Workspace Folders 对话框提供独立的 Skills 开关与 `aliasId` 编辑,Settings → Plugins → Multi-root Workspace 的「启用附属根 Skills」全局开关默认开启,关闭只阻止新发现与调用、保留每根选择。升级时旧 `inherit` / `read-write` 登记默认开启 Skills;持久化迁移保留原有 grant,但旧版写回可能剥离 `aliasId` 与手动开关,**不保证 Skills 配置无损降级**(降级前可备份 `$DSH_HOME/storages/multi_root_workspace.json`)。只读根开启 Skills 不授予写权限;禁用不回收已投递正文或已启动进程([ADR-0023](./docs/decisions/ADR-0023-multi-root-skill-discovery-and-invocation.md))。
16
+ - **精确支持 DSH `0.2.1-rc.3`**。上游 `rc.2`→`rc.3` 的差异全部为新增(新 sidebar 槽位、导航 pins、DeepSeek `/models` 列表),不需要新增适配分支;开发 pin 提升到 `0.2.1-rc.3`(cordis `4.0.5` 不变)。
17
+
18
+ ### Fixed
19
+
20
+ - **Workspace Folders 面板与上游 UI 对齐**:设置开关行布局、Skills 开关收入图标动作区、按钮背景只出现在 hover、保存期间动作外观保持、根策略与生效访问合并为一个标签;移除上移/下移排序按钮(排序接口保留,供后续拖动排序)与对话框顶部的权限说明文字。
21
+ - **命名空间 Skill 引用的展示**:已发送的 `/alias-id:skill-name` 引用按普通用户文字渲染,不再携带独立按钮样式、高亮或点击预览(ADR-0023 同日修订);普通会话的 activity/title 更新不再误关闭已打开的 Skill 正文预览。
22
+
23
+ ## [0.1.9] - 2026-10-20
24
+
25
+ ### Added
26
+
27
+ - **可选 Auto Review(默认关闭)**:主包新增 `./auto-review` 子路径导出与 `multi-root-auto-review` patch 行——fork 上游实验性「自动授权审查」,向 Reviewer 补充附加根的审查上下文:当前工作区拓扑、各根有效访问级别与实时指令文件。该行出厂 `disabled: true`,关闭时不挂载 reviewer 或 review context、不注册 Auto preset;普通支持矩阵不变,仅 DSH `0.2.1-rc.2` 可启用——在任何其他版本上打开会响亮失败,不会静默降级。启用方式:在插件管理器的行列表中打开 `@dsh-electron/dsh-plugin-multi-root-workspace/auto-review` 行(无热重载的 profile 按提示重启),或在 profile 的 `cordis.patch.yml` 中置 `disabled: false`;context 与 reviewer 共用这一个开关。
28
+ - **启用后接管官方 reviewer**:同一个开关挂载多根 review context 与 fork reviewer,并在运行时停止同组官方 `@deepseek-ai/dsh-experimental-auto-review` 行——官方 bundle 位于主包前后均可,接管只改运行时状态、不写回官方的持久配置;官方 bundle 未被选择时该行独立运行(自带注册 Auto preset)。关闭后官方按原配置随 reload/restart 恢复,不自动重选 Auto;任何存活 Auto owner 的卸载沿用官方 Auto → Full access 语义。曾以本地 tarball/link 安装过旧独立 companion 包的 profile,须先移除其 bundle 与依赖再启用本行(残留 companion 与内置入口共存会被明确拒绝)。使用说明见 [src/auto-review/README.md](./src/auto-review/README.md)([ADR-0021](./docs/decisions/ADR-0021-auto-review-context-companion.md)、[ADR-0022](./docs/decisions/ADR-0022-auto-review-loader-entry.md))。
29
+
11
30
  ## [0.1.8] - 2026-10-18
12
31
 
13
32
  ### Fixed
@@ -162,7 +181,9 @@ English: [CHANGELOG.en.md](./CHANGELOG.en.md)
162
181
 
163
182
  - 发布前外部评审提出的 8 项发现(其中 3 项发布阻断)全部修复,每项各带一个回归测试:登记目录被替换为符号链接后授权转移(引入 `recordedPath`,**重新解析路径不等于重新授权**)、并发修改注册表丢写或复活已撤销的授权(每个主根的变更串行)、刷新不重新检查目录、手输路径被目录选择器覆盖、`reveal` 的应答契约与失败码、重复 id 未校验、主根未纳入嵌套校验、CI 先测后构建。
164
183
 
165
- [Unreleased]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.8...HEAD
184
+ [Unreleased]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.10...HEAD
185
+ [0.1.10]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.9...v0.1.10
186
+ [0.1.9]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.8...v0.1.9
166
187
  [0.1.8]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.7...v0.1.8
167
188
  [0.1.7]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.6...v0.1.7
168
189
  [0.1.6]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.5...v0.1.6
package/README.en.md CHANGED
@@ -1,5 +1,7 @@
1
1
  <div align="center">
2
2
 
3
+ <img src="public/multi-root-mark.svg" width="120" />
4
+
3
5
  # dsh-plugin-multi-root-workspace
4
6
 
5
7
  [中文](./README.md) | English
@@ -8,24 +10,25 @@
8
10
 
9
11
  ## What & Why
10
12
 
11
- DSH (DeepSeek Harness) natively treats only the directory a session starts in as the agent's sole writable root; this plugin is an out-of-tree extension that modifies no upstream code and widens that scope to "**one primary root + N additional roots**".
13
+ By default, [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) treats the directory a new workspace is created in as the agent's primary directory; under the default workspace read-write mode (`workspace-write`), the sandbox's read-write scope covers that directory alone. This plugin extends DSH's workspace scope to "one primary root + N additional roots".
12
14
 
13
- A real development project is usually several independent Git repositories, and working across them meant juggling sessions. Peer harnesses already treat this as standard: Codex offers `--add-dir`, and Cursor lets you add folders to a workspace. This plugin brings the same capability to DSH — register the other repositories as additional roots, and the agent can read and write them directly.
15
+ Not every project is a monorepo. A real development project is usually several independent Git repositories, and working across them meant juggling sessions. Peer harnesses already support adding multiple folders to a single workspace. This plugin brings the same capability to DSH — register the other repositories as additional roots, grant each read-only, read-write, or unrestricted access, and the agent can work in them within that grant.
14
16
 
15
- - **Zero learning cost for the agent**: it keeps using the native `read` / `write` / `edit` / `bash` tools — the plugin adds no new tools at all, it only grants more directories.
16
- - **Security does not degrade**: additional roots are authorized through the same mechanism the harness already uses — an in-process filesystem fence plus kernel-level sandboxes (macOS Seatbelt / Linux bwrap / Landlock / Windows ACL), with files and bash sharing one and the same scope. It never degenerates into full access or prompt-level constraints.
17
+ - **No new tools**: the agent keeps using the native `read` / `write` / `edit` / `bash`; only the granted directories grow.
18
+ - **Sandbox confinement**: an additional root may inherit the session's (primary root's) permission setting, or be pinned to read-only or read-write; under read-only and read-write, confinement does not rest on system prompts — it is enforced by an in-process filesystem fence plus kernel-level sandboxes (macOS Seatbelt / Linux bwrap / Landlock / Windows ACL), with files and bash sharing one and the same scope.
19
+ - **Optional Auto review (off by default)**: a fork of upstream's experimental auto-review that gives the reviewer the additional directories' context — the current workspace topology, each root's access level, and live instruction files; it ships disabled and only takes effect once the `@dsh-electron/dsh-plugin-multi-root-workspace/auto-review` row is explicitly enabled in the Plugin Manager row list, taking over the official bundle while on.
20
+ - **Additional-root Skills**: discovers `.dsh/skills` and `.agents/skills` inside additional folders, invoked through the namespaced `/alias-id:skill-name` reference and the native `skill` tool; each root has an independent toggle and editable `aliasId`, with a global setting that defaults to on.
17
21
  - **Absent when absent**: with no additional root configured, its behavior is item-for-item identical to an uninstalled harness; every misconfiguration fails loudly instead of silently degrading.
18
22
 
19
- Current released version: `v0.1.8`. The user-visible changes of each version live in the [CHANGELOG](./CHANGELOG.en.md); progress and release state live in the [roadmap progress ledger](./docs/plans/active/2026-09-12-multi-root-workspace.md#进度总账).
23
+ Current released version: `v0.1.10`. The user-visible changes of each version live in the [CHANGELOG](./CHANGELOG.en.md); progress and release state live in the [roadmap progress ledger](./docs/plans/active/2026-09-12-multi-root-workspace.md#进度总账).
20
24
 
21
25
  ## Quick Start
22
26
 
23
- The plugin is published on [npm](https://www.npmjs.com/package/@dsh-electron/dsh-plugin-multi-root-workspace). You can paste the package name `@dsh-electron/dsh-plugin-multi-root-workspace` into DSH's plugin install page, or install it in two commands:
27
+ The plugin is published on [npm](https://www.npmjs.com/package/@dsh-electron/dsh-plugin-multi-root-workspace). Open the **Plugins** page in the sidebar, choose **Add plugin**, and paste the package name `@dsh-electron/dsh-plugin-multi-root-workspace` — or install it in two commands:
24
28
 
25
29
  ```sh
26
30
  dsh plugin --profile web add @dsh-electron/dsh-plugin-multi-root-workspace
27
- dsh --profile web
28
- # pick the --profile for how you launch DSH; see its docs for the values
31
+ dsh --profile web # pick the --profile for how you launch DSH; see its docs for the values
29
32
  ```
30
33
 
31
34
  Once it is up, the **Folders** action (`🗂`) appears at the sidebar foot — or, straight in a session:
@@ -46,16 +49,18 @@ The agent can now read, write, and run bash in that directory — the default is
46
49
  | `0.1.6` | `0.1.6-alpha.1`, `0.1.6-alpha.2` |
47
50
  | `0.1.7` | `0.1.7-alpha.1`, `0.1.7-alpha.2`, `0.1.7-rc.1`, `0.1.7-rc.2` |
48
51
  | `0.2.0` | `0.2.0-rc.1`, `0.2.0-rc.2` |
49
- | `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
+ | `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`, `0.2.1-rc.3` |
50
53
 
51
54
  The plugin does not start — as if it were not installed — when the DSH release is not in the table or the `@deepseek-ai/dsh-*` packages disagree on a version.
52
55
 
53
- **Building from source / contributing**: Node.js `^22.19.0 || >=24`, pnpm `11.25.0` (enable via corepack); the dev-pinned DSH is `0.2.1-rc.2`.
56
+ **Building from source / contributing**: Node.js `^22.19.0 || >=24`, pnpm `11.25.0` (enable via corepack); the dev-pinned DSH is `0.2.1-rc.3`.
54
57
 
55
58
  **Platforms**: macOS (Seatbelt), Linux (bwrap / Landlock), Windows (root-set ACL runner).
56
59
 
57
60
  ## Installation
58
61
 
62
+ The same install is available without the CLI: open **Plugins** in the sidebar, choose **Add plugin**, and enter the npm package name (or a Git address, tarball, or absolute local path).
63
+
59
64
  `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.
60
65
 
61
66
  | Source | Command | Notes |
@@ -72,7 +77,7 @@ allowBuilds:
72
77
  koffi: true
73
78
  ```
74
79
 
75
- If the retry exits 0 but the plugin never lands in `dsh.profile.bundles`, do a `remove` + `add`. Further diagnosis: [troubleshooting](./docs/troubleshooting/install-stops-at-build-approval.md).
80
+ If the retry `exits 0` but the plugin never lands in `dsh.profile.bundles`, do a `remove` + `add`. Further diagnosis: [troubleshooting](./docs/troubleshooting/install-stops-at-build-approval.md).
76
81
 
77
82
  ### Install from npm (recommended)
78
83
 
@@ -87,8 +92,8 @@ This installs pre-built artifacts; the first install needs the `allowBuilds` add
87
92
  ```sh
88
93
  pnpm pack @dsh-electron/dsh-plugin-multi-root-workspace
89
94
  # or download the tgz from the GitHub Release assets, e.g.:
90
- # https://github.com/cherrchen/dsh-plugin-multi-root-workspace/releases/download/v0.1.8/dsh-electron-dsh-plugin-multi-root-workspace-0.1.8.tgz
91
- dsh plugin --profile web add ./dsh-electron-dsh-plugin-multi-root-workspace-0.1.8.tgz
95
+ # https://github.com/cherrchen/dsh-plugin-multi-root-workspace/releases/download/v0.1.10/dsh-electron-dsh-plugin-multi-root-workspace-0.1.10.tgz
96
+ dsh plugin --profile web add ./dsh-electron-dsh-plugin-multi-root-workspace-0.1.10.tgz
92
97
  ```
93
98
 
94
99
  Also pre-built, handy for air-gapped or offline delivery; the first install needs the same `allowBuilds` addition.
@@ -107,10 +112,10 @@ allowBuilds:
107
112
  koffi: true
108
113
  ```
109
114
 
110
- Pinning a version (e.g. `#v0.1.8`) is recommended so a later push cannot silently change what actually runs:
115
+ Pinning a version (e.g. `#v0.1.10`) is recommended so a later push cannot silently change what actually runs:
111
116
 
112
117
  ```sh
113
- dsh plugin --profile web add github:cherrchen/dsh-plugin-multi-root-workspace#v0.1.8
118
+ dsh plugin --profile web add github:cherrchen/dsh-plugin-multi-root-workspace#v0.1.10
114
119
  ```
115
120
 
116
121
  ### Install from a local clone
@@ -201,6 +206,8 @@ The upstream `fs-sandbox` and `sandbox` rows are disabled and taken over by the
201
206
  /workspace-folders [list] # list the primary root and the additional roots (access and state included)
202
207
  /workspace-folders add <absolute path> [--inherit|--read-only|--read-write] # no path opens the OS directory picker; new registrations default to inherit
203
208
  /workspace-folders access <n|path> inherit|read-only|read-write # switch access (widening requires the root to be available right now)
209
+ /workspace-folders skills <n|path> on|off # toggle additional-root Skills independently of write access
210
+ /workspace-folders alias-id <n|path> <kebab-case> # edit the stable Skill namespace
204
211
  /workspace-folders alias <n|path> [name] # omitting the name clears the alias
205
212
  /workspace-folders remove <n|path> # n is the number list prints
206
213
  /workspace-folders reveal <n|path> # show it in the file manager
@@ -222,14 +229,30 @@ Workspace root (primary; access follows the current sandbox mode): /home/me/mono
222
229
  Writable additional roots under the current mode: 1 of 2.
223
230
  ```
224
231
 
232
+ ### Additional-root Skills
233
+
234
+ Skills are discovered in each additional folder’s `.dsh/skills` and `.agents/skills`. Names and descriptions are available before the first model step; bodies are loaded on invocation. The primary root uses `/skill-name`; additional roots always use `/alias-id:skill-name`, with Slash completion and manual entry. The model uses the native `skill` tool with an internal name. Internal IDs can appear in tool logs; human menus list namespaced references.
235
+
236
+ New `inherit` and `read-write` registrations enable Skills by default; `read-only` registrations disable them. The Workspace Folders dialog provides an independent Skills toggle and editable `aliasId`. Renaming the display Alias keeps `aliasId` stable. An actual change to registered access resets the toggle; session sandbox mode changes, same-value access updates, and re-registration without an access change preserve the manual choice. Enabling Skills on a read-only root grants no write access.
237
+
238
+ **Enable additional-root Skills** under Settings → Plugins → Multi-root Workspace controls all additional roots and defaults to on. Disabling it stops new discovery and invocation while preserving each root’s choice. Re-enabling restores discovery according to those choices. Primary-root Skills, instructions, LSP, browsing, and sandbox permissions retain their behavior. Older hosts use the compatible plugin settings page. Namespaced references appear as ordinary user text, without a separate background, highlighting, or click-to-preview action. Native draft highlighting does not yet support colon references.
239
+
240
+ On upgrade, legacy `inherit` and `read-write` registrations start with Skills enabled. Migration preserves existing grants. An older plugin can strip `aliasId` and manual toggles when it writes the registry; upgrading again applies the defaults. **Lossless downgrade of Skills preferences is not guaranteed.** Back up `$DSH_HOME/storages/multi_root_workspace.json` before downgrading if preferences must survive. Disabling Skills does not remove previously delivered bodies from history or stop processes already started.
241
+
242
+ See [ADR-0023](./docs/decisions/ADR-0023-multi-root-skill-discovery-and-invocation.md) for the architecture and acceptance boundaries, and the [progress ledger](./docs/plans/active/2026-09-12-multi-root-workspace.md#multi-root-skills-架构验证2026-10-23) for implementation and platform evidence.
243
+
225
244
  ### Panel
226
245
 
227
- The **Folders** dialog at the sidebar foot lists the primary root and the additional roots, and offers add, remove, alias, read-only/read-write switching, copy path, reveal in the file manager, and move up/down.
246
+ The **Folders** dialog at the sidebar foot lists the primary root and the additional roots, and offers add, remove, alias, read-only/read-write switching, copy path, and reveal in the file manager.
228
247
 
229
248
  ### Model side
230
249
 
231
250
  The additional-root topology is injected into the system prompt so the model knows which directories are available, and the information updates when grants change. No new tool needs to be exposed to the model.
232
251
 
252
+ ## Optional Auto Review integration
253
+
254
+ For multi-root reviewer context, enable the default-disabled [Auto Review row](./src/auto-review/README.en.md) in the main package’s Plugin Manager row list. The joint integration targets only DSH `0.2.1-rc.2`; ordinary installation keeps the existing support matrix and does not enable or select Auto.
255
+
233
256
  ## Project Structure
234
257
 
235
258
  ```text
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  <div align="center">
2
2
 
3
+ <img src="public/multi-root-mark.svg" width="120" />
4
+
3
5
  # dsh-plugin-multi-root-workspace
4
6
 
5
7
  中文 | [English](./README.en.md)
@@ -8,24 +10,25 @@
8
10
 
9
11
  ## 项目简介
10
12
 
11
- DSH(DeepSeek Harness)原生只把会话启动的目录当作 Agent 唯一的可写根;本插件是一个不修改上游任何代码的外部扩展,把可写范围扩为"**一个主目录 + 多个附加目录**"。
13
+ [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 默认把新建工作区所在的目录作为 Agent 的主目录,在默认的工作区读写模式(`workspace-write`)下,沙箱的读写范围也仅覆盖这一个目录。本插件将 DSH 的工作区范围拓展到“一个主目录 + 多个附加目录”。
12
14
 
13
- 一个开发项目往往由多个独立 Git 仓库组成,跨仓库干活原本得反复换会话。Codex、Cursor 等同类工具早已支持在一个工作区添加多个文件夹;本插件把同样的能力带给 DSH:把其他仓库登记为附加根,Agent 即可直接读写。
15
+ 并非所有项目都是 monorepo。一个开发项目往往由多个独立 Git 仓库组成,跨仓库干活原本得反复换会话。同类工具早已支持在一个工作区添加多个文件夹,本插件把同样的能力带给 DSH:把其他仓库登记为附加根,并按需授予只读、读写或不受限的访问级别,Agent 即可在授权范围内读写。
14
16
 
15
- - **Agent 零学习成本**:继续使用原生 `read` / `write` / `edit` / `bash`,插件不新增任何工具,只是授权的目录变多了。
16
- - **安全不降级**:附加根走上游同款授权机制——进程内文件围栏 + 内核级沙箱(macOS Seatbelt / Linux bwrap / Landlock / Windows ACL),文件与 bash 共享同一份授权范围,绝不退化成全开放或只靠提示词约束。
17
+ - **不新增工具**:Agent 照旧使用原生 `read` / `write` / `edit` / `bash`,只是授权的目录变多了。
18
+ - **沙箱约束**:附加根可继承会话(主目录)的权限设置,也可单独固定为只读或读写;在只读与读写下,约束不靠系统提示词,而由进程内文件围栏 + 内核级沙箱(macOS Seatbelt / Linux bwrap / Landlock / Windows ACL)执行,文件与 bash 共享同一份授权范围。
19
+ - **可选 Auto review(默认关闭)**:fork 上游实验性「自动授权审查」,向 Reviewer 补充附加目录的审查上下文——当前工作区拓扑、各根访问级别与实时指令文件;出厂关闭,需在插件管理器的行列表中显式打开 `@dsh-electron/dsh-plugin-multi-root-workspace/auto-review` 行后生效,启用时接管官方同名 bundle。
20
+ - **附属根 Skills**:发现附属目录的 `.dsh/skills` 与 `.agents/skills`,附属根经 `/alias-id:skill-name` 命名空间调用原生 `skill` 工具;每根独立开关、可编辑 `aliasId`,全局设置默认开启。
17
21
  - **不配等于没装**:未登记附加根时行为与未装插件逐项一致;配置错误一律明确报错,从不静默降级。
18
22
 
19
- 当前发布版本 `v0.1.8`。各版本的用户可见变更见 [CHANGELOG](./CHANGELOG.md);进度与发布状态见[路线图 §进度总账](./docs/plans/active/2026-09-12-multi-root-workspace.md#进度总账)。
23
+ 当前发布版本 `v0.1.10`。各版本的用户可见变更见 [CHANGELOG](./CHANGELOG.md);进度与发布状态见[路线图 §进度总账](./docs/plans/active/2026-09-12-multi-root-workspace.md#进度总账)。
20
24
 
21
25
  ## 快速开始
22
26
 
23
- 插件已发布到 [npm](https://www.npmjs.com/package/@dsh-electron/dsh-plugin-multi-root-workspace)。可以在 DSH 的插件安装页面填入包名 `@dsh-electron/dsh-plugin-multi-root-workspace`,也可以用命令行两步装完:
27
+ 插件已发布到 [npm](https://www.npmjs.com/package/@dsh-electron/dsh-plugin-multi-root-workspace)。在 DSH 侧栏的**插件**页点**添加插件**、填入包名 `@dsh-electron/dsh-plugin-multi-root-workspace` 即可安装;也可以用命令行两步装完:
24
28
 
25
29
  ```sh
26
30
  dsh plugin --profile web add @dsh-electron/dsh-plugin-multi-root-workspace
27
- dsh --profile web
28
- # --profile 按你的启动方式选择,可选值见 DSH 文档
31
+ dsh --profile web # --profile 按你的启动方式选择,可选值见 DSH 文档
29
32
  ```
30
33
 
31
34
  tarball、GitHub、本地源码等其他安装方式见[安装](#安装)。
@@ -48,16 +51,18 @@ tarball、GitHub、本地源码等其他安装方式见[安装](#安装)。
48
51
  | `0.1.6` | `0.1.6-alpha.1`、`0.1.6-alpha.2` |
49
52
  | `0.1.7` | `0.1.7-alpha.1`、`0.1.7-alpha.2`、`0.1.7-rc.1`、`0.1.7-rc.2` |
50
53
  | `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` |
54
+ | `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`、`0.2.1-rc.3` |
52
55
 
53
56
  DSH 版本不在表内、或 `@deepseek-ai/dsh-*` 各包版本不一致时,插件不会启动,行为等同没装。
54
57
 
55
- **从源码构建 / 贡献**:Node.js `^22.19.0 || >=24`,pnpm `11.25.0`(建议经 corepack 启用);开发 pin 的 DSH 为 `0.2.1-rc.2`。
58
+ **从源码构建 / 贡献**:Node.js `^22.19.0 || >=24`,pnpm `11.25.0`(建议经 corepack 启用);开发 pin 的 DSH 为 `0.2.1-rc.3`。
56
59
 
57
60
  **运行平台**:macOS(Seatbelt)、Linux(bwrap / Landlock)、Windows(root-set ACL runner)。
58
61
 
59
62
  ## 安装
60
63
 
64
+ 不使用命令行时,DSH 侧栏的**插件**页提供同一安装入口:点**添加插件**,填入 npm 包名(或 Git 地址、tarball、本地绝对路径)。
65
+
61
66
  `dsh plugin` 支持四种安装来源。以下均以 web profile 为例;桌面端(Electron)把 `--profile web` 换成 `--profile desktop`,安装方式同源。
62
67
 
63
68
  | 来源 | 命令 | 说明 |
@@ -74,7 +79,7 @@ allowBuilds:
74
79
  koffi: true
75
80
  ```
76
81
 
77
- 如果重跑退出 0 但插件没有进入 `dsh.profile.bundles`,做一次 `remove` + `add`。更多排查见[故障排查](./docs/troubleshooting/install-stops-at-build-approval.md)。
82
+ 如果重跑 `退出 0` 但插件没有进入 `dsh.profile.bundles`,做一次 `remove` + `add`。更多排查见[故障排查](./docs/troubleshooting/install-stops-at-build-approval.md)。
78
83
 
79
84
  ### 从 npm 安装(推荐)
80
85
 
@@ -89,8 +94,8 @@ dsh plugin --profile web add @dsh-electron/dsh-plugin-multi-root-workspace
89
94
  ```sh
90
95
  pnpm pack @dsh-electron/dsh-plugin-multi-root-workspace
91
96
  # 或从 GitHub Release 资产下载,例如:
92
- # https://github.com/cherrchen/dsh-plugin-multi-root-workspace/releases/download/v0.1.8/dsh-electron-dsh-plugin-multi-root-workspace-0.1.8.tgz
93
- dsh plugin --profile web add ./dsh-electron-dsh-plugin-multi-root-workspace-0.1.8.tgz
97
+ # https://github.com/cherrchen/dsh-plugin-multi-root-workspace/releases/download/v0.1.10/dsh-electron-dsh-plugin-multi-root-workspace-0.1.10.tgz
98
+ dsh plugin --profile web add ./dsh-electron-dsh-plugin-multi-root-workspace-0.1.10.tgz
94
99
  ```
95
100
 
96
101
  同样是预构建产物,适合内网或离线环境交付;首次安装同样需要添加 `allowBuilds`。
@@ -109,10 +114,10 @@ allowBuilds:
109
114
  koffi: true
110
115
  ```
111
116
 
112
- 建议锁定版本(如 `#v0.1.8`),让后续推送无法悄悄改变实际运行的内容:
117
+ 建议锁定版本(如 `#v0.1.10`),让后续推送无法悄悄改变实际运行的内容:
113
118
 
114
119
  ```sh
115
- dsh plugin --profile web add github:cherrchen/dsh-plugin-multi-root-workspace#v0.1.8
120
+ dsh plugin --profile web add github:cherrchen/dsh-plugin-multi-root-workspace#v0.1.10
116
121
  ```
117
122
 
118
123
  ### 从本地源码安装
@@ -200,14 +205,16 @@ dsh --profile web --dump-config | grep -A3 'multi-root'
200
205
  ### 命令
201
206
 
202
207
  ```text
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 # 查看命令帮助
208
+ /workspace-folders [list] # 列出主根与附加根(含每根访问级别与状态)
209
+ /workspace-folders add <absolute path> [--inherit|--read-only|--read-write] # 不带路径时打开系统目录选择器;新登记默认 inherit
210
+ /workspace-folders access <order|path> inherit|read-only|read-write # 切换访问级别(扩权要求该根此刻可用)
211
+ /workspace-folders skills <order|path> on|off # 独立切换附属根 Skills,不改变写权限
212
+ /workspace-folders alias-id <order|path> <kebab-case> # 编辑稳定 Skill 命名空间
213
+ /workspace-folders alias <order|path> [alias] # 不带别名则清除已有别名
214
+ /workspace-folders remove <order|path> # 序号即 list 输出的编号
215
+ /workspace-folders reveal <order|path> # 在文件管理器中显示
216
+ /workspace-folders isolate-profiles [--apply] # 检查 $DSH_HOME profile 依赖导入方式与多链接文件;--apply 写入 copy 配置
217
+ /workspace-folders help # 查看命令帮助
211
218
  ```
212
219
 
213
220
  路径可带引号;与已有根重复、嵌套在已有根内部、或就是主根本身的路径会被拒绝。
@@ -224,14 +231,30 @@ Workspace root (primary; access follows the current sandbox mode): /home/me/mono
224
231
  Writable additional roots under the current mode: 1 of 2.
225
232
  ```
226
233
 
234
+ ### 附属根 Skills
235
+
236
+ 发现附属目录的 `.dsh/skills` 和 `.agents/skills`,首个模型步骤可见名称与描述,正文按需加载。主根使用 `/skill-name`;附属根始终使用 `/alias-id:skill-name`,可在 Slash 菜单补全或手动输入。模型通过原生 `skill` 工具调用内部名称;工具日志中可能显示内部 ID,人类菜单只列命名空间引用。
237
+
238
+ 新登记的 `inherit` / `read-write` 根默认开启,`read-only` 根默认关闭;Workspace Folders Dialog 可独立切换 Skills 并编辑 `aliasId`。显示 Alias 的修改不改变 `aliasId`。只有登记权限的实际变化才重置开关;切换会话沙箱模式、同值权限设置和未改变权限的重新登记都保留手动选择。只读根开启 Skills 后仍没有写权限。
239
+
240
+ Settings → Plugins → Multi-root Workspace 中的 **启用附属根 Skills** 控制全部附属根,默认开启。关闭后阻止新的发现与调用,保留每根选择;恢复后按原值发现。主根 Skills、指令、LSP、文件浏览及沙箱权限不受此开关影响。旧版宿主使用兼容的插件设置页。命名空间引用按普通用户输入显示,不添加背景、高亮或点击预览;草稿内的原生 Skill 高亮暂不支持冒号引用。
241
+
242
+ 升级时旧 `inherit` / `read-write` 登记会默认开启 Skills。持久化迁移保留原有 grant;旧版写回可能剥离 `aliasId` 和手动开关,再升级时重新按默认值迁移,**不保证 Skills 配置无损降级**。如需保留选择,降级前备份 `$DSH_HOME/storages/multi_root_workspace.json`。已投递正文仍留在历史中,禁用不会结束已经启动的进程。
243
+
244
+ 架构与验收边界见 [ADR-0023](./docs/decisions/ADR-0023-multi-root-skill-discovery-and-invocation.md),实施和平台状态见[路线账本](./docs/plans/active/2026-09-12-multi-root-workspace.md#multi-root-skills-架构验证2026-10-23)。
245
+
227
246
  ### 面板
228
247
 
229
- 侧栏底部的 **Folders** 对话框列出主根与附加根,支持添加、移除、别名、切换只读/可写、复制路径、在文件管理器中显示与上下移排序。
248
+ 侧栏底部的 **Folders** 对话框列出主根与附加根,支持添加、移除、别名、切换只读/可写、复制路径与在文件管理器中显示。
230
249
 
231
250
  ### 模型侧
232
251
 
233
252
  附加根的拓扑信息会注入系统提示词,让模型知道当前有哪些目录可用,授权变化时信息随之更新,不需要向模型提供新的工具。
234
253
 
254
+ ## 可选 Auto Review 适配
255
+
256
+ 需要 Auto Review 多根上下文时,在插件管理器的主包行列表中启用默认关闭的 [Auto Review 入口](./src/auto-review/README.md)。该集成仅面向 DSH `0.2.1-rc.2`;普通安装保持原支持范围且不会启用或选择 Auto。
257
+
235
258
  ## 项目结构
236
259
 
237
260
  ```text
package/cordis.patch.yml CHANGED
@@ -92,6 +92,10 @@
92
92
  # the model. This row closes that gap for the additional roots only; the
93
93
  # primary root and the user-global file stay upstream's. The budget is the
94
94
  # total for ALL additional roots, not per root.
95
+ - id: multi-root-skills
96
+ name: '@dsh-electron/dsh-plugin-multi-root-workspace/skills'
97
+ config:
98
+ enabled: true
95
99
  - id: multi-root-instructions
96
100
  name: '@dsh-electron/dsh-plugin-multi-root-workspace/instructions'
97
101
  config:
@@ -132,3 +136,9 @@
132
136
  dshHome: !!js dshHomePath()
133
137
  - id: multi-root-client
134
138
  name: '@dsh-electron/dsh-plugin-multi-root-workspace'
139
+ # One optional row owns its context service and review owner. It remains
140
+ # inert until explicitly enabled in the Plugin Manager row list.
141
+ - id: multi-root-auto-review
142
+ name: '@dsh-electron/dsh-plugin-multi-root-workspace/auto-review'
143
+ disabled: true
144
+ required: true
@@ -0,0 +1,15 @@
1
+ import { createRequire } from "node:module";
2
+ import { readFileSync } from "node:fs";
3
+ //#region src/compat/auto-review-packages.ts
4
+ /** Exact fork execution copies; ordinary Multi-root keeps its broader contract. */
5
+ function assertForkPackages() {
6
+ const require = createRequire(import.meta.url);
7
+ for (const name of [
8
+ "@deepseek-ai/dsh-llm",
9
+ "@deepseek-ai/dsh-tools",
10
+ "@deepseek-ai/dsh-permission-presets",
11
+ "@deepseek-ai/dsh-util-values"
12
+ ]) if (JSON.parse(readFileSync(require.resolve(`${name}/package.json`), "utf8")).version !== "0.2.1-rc.2") throw new Error(`multi-root Auto Review: incompatible execution copy of ${name}`);
13
+ }
14
+ //#endregion
15
+ export { assertForkPackages as t };
@@ -0,0 +1,166 @@
1
+ import { n as assertAutoReviewRelease, t as MultiRootReviewContext } from "./review-context-AH-SXHmj.js";
2
+ import { t as assertForkPackages } from "./auto-review-packages-nRjnb4pU.js";
3
+ import { t as wrapMethod } from "./method-wrapper-CFY3p3j2.js";
4
+ //#region src/compat/auto-review-loader.ts
5
+ const OFFICIAL_AUTO_REVIEW = "@deepseek-ai/dsh-experimental-auto-review";
6
+ const takeovers = /* @__PURE__ */ new WeakMap();
7
+ function cloneRows(value) {
8
+ try {
9
+ return structuredClone(value);
10
+ } catch {
11
+ return Array.isArray(value) ? value.map((row) => ({ ...row })) : { ...value };
12
+ }
13
+ }
14
+ /**
15
+ * internal/plugin is emitted before Fiber checks dependencies or runs apply.
16
+ * Disposing there also stops an import already in flight when takeover began.
17
+ * The group update wrapper preserves desired configuration and drains our
18
+ * owner BEFORE the update that lets the official owner run again.
19
+ */
20
+ var AutoReviewTakeover = class {
21
+ ctx;
22
+ entry;
23
+ group;
24
+ restoreUpdate;
25
+ predecessor;
26
+ closed;
27
+ releaseClosed;
28
+ stopHook;
29
+ desired;
30
+ stopOwner = async () => {};
31
+ exiting = false;
32
+ closing;
33
+ draining = /* @__PURE__ */ new Set();
34
+ constructor(ctx) {
35
+ this.ctx = ctx;
36
+ const entry = ctx.fiber.entry;
37
+ if (entry === void 0) throw new Error("multi-root Auto Review must be mounted as a Loader entry");
38
+ if (entry.disabled) throw new Error("multi-root Auto Review mounted on a disabled Loader entry");
39
+ this.entry = entry;
40
+ this.group = entry.parent;
41
+ const previous = takeovers.get(this.group);
42
+ if (previous !== void 0 && previous.entry !== entry && previous.closing === void 0) throw new Error("Only one multi-root Auto Review Loader entry may own a group");
43
+ this.desired = cloneRows(previous?.desired ?? this.group.data);
44
+ if (this.desired.some((row) => row.name === "@dsh-electron/dsh-plugin-multi-root-auto-review")) throw new Error("Remove the legacy @dsh-electron/dsh-plugin-multi-root-auto-review package/bundle before enabling the built-in Auto Review entry");
45
+ this.predecessor = previous?.closed ?? Promise.resolve();
46
+ this.closed = new Promise((resolve) => {
47
+ this.releaseClosed = resolve;
48
+ });
49
+ previous?.restoreUpdate();
50
+ takeovers.set(this.group, this);
51
+ const self = this;
52
+ this.restoreUpdate = wrapMethod(this.group, "update", (original) => function(config) {
53
+ self.desired = cloneRows(config);
54
+ if (config.some((row) => row.name === "@dsh-electron/dsh-plugin-multi-root-auto-review")) return Promise.reject(/* @__PURE__ */ new Error("Remove the legacy multi-root Auto Review companion before reloading this profile"));
55
+ const own = config.find((row) => row.id === self.entry.options.id);
56
+ if (own === void 0 || own.name !== self.entry.options.name || self.isDisabled(own)) {
57
+ self.exiting = true;
58
+ self.entry.options.disabled = true;
59
+ self.entry.fiber?.dispose();
60
+ }
61
+ return Reflect.apply(original, this, [config.filter((row) => row.name !== OFFICIAL_AUTO_REVIEW)]);
62
+ });
63
+ this.stopHook = ctx.on("internal/plugin", (fiber) => {
64
+ const candidate = fiber.entry;
65
+ if (fiber.uid === null || candidate?.parent !== this.group || candidate.options.name !== "@deepseek-ai/dsh-experimental-auto-review") return;
66
+ this.suppress(candidate, fiber);
67
+ }, { global: true });
68
+ }
69
+ isDisabled(options) {
70
+ const value = options.disabled;
71
+ return typeof value === "object" && value !== null && "__jsExpr" in value ? Boolean(this.entry.evaluate(String(value.__jsExpr))) : Boolean(value);
72
+ }
73
+ suppress(entry, fiber = entry.fiber) {
74
+ entry.options.disabled = true;
75
+ if (this.group.tree.store[entry.options.id] === entry) this.group.remove(entry.options.id);
76
+ if (fiber === void 0) return;
77
+ const task = Promise.resolve(fiber.dispose()).then(async () => {
78
+ await fiber.await();
79
+ });
80
+ this.draining.add(task);
81
+ task.finally(() => this.draining.delete(task)).catch((error) => this.ctx.logger.error(error));
82
+ }
83
+ async suspendOfficial() {
84
+ await this.predecessor;
85
+ for (const entry of Object.values(this.group.tree.store)) if (entry.parent === this.group && entry.options.name === "@deepseek-ai/dsh-experimental-auto-review") this.suppress(entry);
86
+ await Promise.allSettled([...this.draining]);
87
+ }
88
+ /** Called before any asynchronous startup, so early unload also drains it. */
89
+ setOwnerDisposer(stop) {
90
+ this.stopOwner = stop;
91
+ }
92
+ close(restore = true) {
93
+ return this.closing ??= this.finish(restore).finally(() => this.releaseClosed());
94
+ }
95
+ async finish(restore) {
96
+ await this.stopOwner();
97
+ await Promise.allSettled([...this.draining]);
98
+ this.stopHook();
99
+ this.restoreUpdate();
100
+ if (!restore || takeovers.get(this.group) !== this || !(this.exiting || this.entry.disabled) || this.group.ctx.fiber.state === 5 || this.group.ctx.fiber.uid === null) return;
101
+ for (const [index, options] of this.desired.entries()) {
102
+ if (options.name !== "@deepseek-ai/dsh-experimental-auto-review" || this.group.tree.store[options.id] !== void 0) continue;
103
+ const copy = cloneRows(options);
104
+ this.group.data.splice(Math.min(index, this.group.data.length), 0, copy);
105
+ const id = await this.group.create(copy);
106
+ await this.group.tree.store[id]?.fiber?.await();
107
+ }
108
+ takeovers.delete(this.group);
109
+ }
110
+ };
111
+ //#endregion
112
+ //#region src/auto-review/entry.ts
113
+ const name = "multi-root-auto-review";
114
+ const inject = [
115
+ "loader",
116
+ "multiRootCompat",
117
+ "multiRootProviders",
118
+ "multiRootScope",
119
+ "multiRootRegistry",
120
+ "multiRootInstructions",
121
+ "sandboxPolicy",
122
+ "workingDirectory",
123
+ "fs",
124
+ "approval",
125
+ "llm",
126
+ "permissionPresets",
127
+ "sessions",
128
+ "tools"
129
+ ];
130
+ async function apply(ctx) {
131
+ assertAutoReviewRelease(ctx.multiRootCompat.release);
132
+ assertForkPackages();
133
+ await ctx.effect(async function* () {
134
+ const takeover = new AutoReviewTakeover(ctx);
135
+ yield takeover.stopHook;
136
+ yield () => takeover.close();
137
+ let context;
138
+ let reviewer;
139
+ const setup = (async () => {
140
+ await takeover.suspendOfficial();
141
+ ctx.fiber.assertActive();
142
+ const mountedContext = ctx.plugin(MultiRootReviewContext);
143
+ context = mountedContext.ctx.fiber;
144
+ await mountedContext;
145
+ if (context.state !== 2) throw new Error("multi-root Auto Review context did not activate");
146
+ const fork = await import("./fork-CzbeWxHp.js");
147
+ ctx.fiber.assertActive();
148
+ const mountedReviewer = ctx.plugin(fork);
149
+ reviewer = mountedReviewer.ctx.fiber;
150
+ await mountedReviewer;
151
+ if (reviewer.state !== 2) throw new Error("multi-root Auto Review owner did not activate");
152
+ })();
153
+ takeover.setOwnerDisposer(async () => {
154
+ await setup.catch(() => {});
155
+ await reviewer?.dispose();
156
+ await reviewer?.await();
157
+ await context?.dispose();
158
+ await context?.await();
159
+ });
160
+ await setup;
161
+ if (context !== void 0) yield context.dispose;
162
+ if (reviewer !== void 0) yield reviewer.dispose;
163
+ }, "optional Auto Review integration");
164
+ }
165
+ //#endregion
166
+ export { apply, inject, name };