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

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 CHANGED
@@ -8,6 +8,17 @@ 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.11] - 2026-10-29
12
+
13
+ ### Added
14
+
15
+ - **Exact support for DSH `0.2.1-rc.4` and `0.2.2-alpha.2`**: the `rc.4` probe was fully green with no adapter changes; `0.2.2-alpha.2` splits tool execution out of `dsh-tools` into executors and gives `AgentRegistry` a new `sessionProjections` injection — neither touches plugin source. Upstream's new `SandboxExecutionPolicy.additionalWritableRoots` (a native third writable-root path unrelated to this fork) composes correctly with the widened provider, pinned by a new regression spec asserting both grants take effect. The dev pin moves to `0.2.2-alpha.2` (cordis `4.0.6-alpha.1`, Node ≥24.9). The client forks (files-tree, open-in-app) are re-synced to the `0.2.2-alpha.2` baseline — hover rules moved under `@media (hover: hover)` and open-in-app failure feedback became an app-wide `shell.overlay` outcome toast.
16
+ - **Upgrade lane and CI**: the CI verify matrix now routes by a known list — `0.1.*` / `0.2.0` / `0.2.1` run on Node `22.19.0`, everything else (including 0.2.2 and later) on `24.9.0`; the upgrade script additionally pins the target release's own cordis ecosystem (plugin-loader/group/include, schemastery, cosmokit) when repointing, so an older tree cannot mix with the alpha-line packages the committed lockfile prefers.
17
+
18
+ ### Fixed
19
+
20
+ - **Skills refresh feedback loop caused by repeated Registry-authority notifications ([Issue #24](https://github.com/cherrchen/dsh-plugin-multi-root-workspace/issues/24))**: while a second DSH process contends for the registry lease (or the store fails to open), every additional-root Skills query retried the lease through `refresh()`; on failure `setRegistryAuthority(false)` notified listeners even though the state had not changed, invalidating the Skills cache and broadcasting `skills/change` — clients re-query on every event, closing an unbounded feedback loop: the contending Host burned about one CPU core while idle, grew memory, and eventually died of V8 OOM, and zero additional roots did not prevent it. Listeners are now notified only on a real `available`/`unavailable` transition; the lease retry, takeover after the holder exits, and the fail-closed "primary root only while authority is unavailable" semantics are unchanged ([troubleshooting](./docs/troubleshooting/registry-owned-by-another-process.md#skills-查询导致持续刷新issue-24), [ADR-0023 revision](./docs/decisions/ADR-0023-multi-root-skill-discovery-and-invocation.md#4-生命周期缓存与撤销)).
21
+
11
22
  ## [0.1.10] - 2026-10-25
12
23
 
13
24
  ### Added
@@ -181,7 +192,8 @@ The first release: the three MVP milestones (M1–M3).
181
192
 
182
193
  - 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.
183
194
 
184
- [Unreleased]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.10...HEAD
195
+ [Unreleased]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.11...HEAD
196
+ [0.1.11]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.10...v0.1.11
185
197
  [0.1.10]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.9...v0.1.10
186
198
  [0.1.9]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.8...v0.1.9
187
199
  [0.1.8]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.7...v0.1.8
package/CHANGELOG.md CHANGED
@@ -8,6 +8,17 @@ 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.11] - 2026-10-29
12
+
13
+ ### Added
14
+
15
+ - **精确支持 DSH `0.2.1-rc.4` 与 `0.2.2-alpha.2`**:`rc.4` 探针全绿、无需任何适配改动;`0.2.2-alpha.2` 把工具执行从 `dsh-tools` 拆出为独立执行器,`AgentRegistry` 新增注入 `sessionProjections`,本插件源码均不受影响。上游新增 `SandboxExecutionPolicy.additionalWritableRoots`(原生与 fork 无关的第三路可写根),宽授权 provider 与其正确复合——新回归用例钉住双方 grant 同时生效。开发 pin 提升到 `0.2.2-alpha.2`(cordis `4.0.6-alpha.1`,Node ≥24.9)。客户端 fork(files-tree、open-in-app)已对齐 `0.2.2-alpha.2` 基线——hover 规则移入 `@media (hover: hover)`,open-in-app 失败反馈改为应用级 `shell.overlay` outcome toast。
16
+ - **升级通道与 CI**:CI verify 矩阵改为按已知名单分流——`0.1.*` / `0.2.0` / `0.2.1` 走 Node `22.19.0`,其余(含 0.2.2 及以后)走 Node `24.9.0`;升级脚本在重指旧版本时会顺带钉住该版本自带的 cordis 生态(plugin-loader/group/include、schemastery、cosmokit),避免与提交锁文件的 alpha 行混树。
17
+
18
+ ### Fixed
19
+
20
+ - **Registry Authority 重复通知引发的 Skills 刷新反馈循环([Issue #24](https://github.com/cherrchen/dsh-plugin-multi-root-workspace/issues/24))**:第二个 DSH 进程争用登记表 lease(或存储打开失败)时,附加根 Skills 的每次查询都经 `refresh()` 重试 lease;失败后 `setRegistryAuthority(false)` 即使状态没有变化也通知监听者,使 Skills 缓存失效并广播 `skills/change`,收到事件的客户端立即重查,形成无界反馈循环——等待方 Host 空闲时持续占用约一个 CPU 核心、内存增长直至 V8 OOM,零附加根同样可触发。现在仅在实际状态变化时通知;lease 重试、持锁方退出后的接管、以及「权限不可用时仅主根可写」的 fail-closed 语义不变([故障排查](./docs/troubleshooting/registry-owned-by-another-process.md#skills-查询导致持续刷新issue-24)、[ADR-0023 修订](./docs/decisions/ADR-0023-multi-root-skill-discovery-and-invocation.md#4-生命周期缓存与撤销))。
21
+
11
22
  ## [0.1.10] - 2026-10-25
12
23
 
13
24
  ### Added
@@ -181,7 +192,8 @@ English: [CHANGELOG.en.md](./CHANGELOG.en.md)
181
192
 
182
193
  - 发布前外部评审提出的 8 项发现(其中 3 项发布阻断)全部修复,每项各带一个回归测试:登记目录被替换为符号链接后授权转移(引入 `recordedPath`,**重新解析路径不等于重新授权**)、并发修改注册表丢写或复活已撤销的授权(每个主根的变更串行)、刷新不重新检查目录、手输路径被目录选择器覆盖、`reveal` 的应答契约与失败码、重复 id 未校验、主根未纳入嵌套校验、CI 先测后构建。
183
194
 
184
- [Unreleased]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.10...HEAD
195
+ [Unreleased]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.11...HEAD
196
+ [0.1.11]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.10...v0.1.11
185
197
  [0.1.10]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.9...v0.1.10
186
198
  [0.1.9]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.8...v0.1.9
187
199
  [0.1.8]: https://github.com/cherrchen/dsh-plugin-multi-root-workspace/compare/v0.1.7...v0.1.8
package/README.en.md CHANGED
@@ -20,7 +20,7 @@ Not every project is a monorepo. A real development project is usually several i
20
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.
21
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.
22
22
 
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#进度总账).
23
+ Current released version: `v0.1.11`. 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#进度总账).
24
24
 
25
25
  ## Quick Start
26
26
 
@@ -49,11 +49,12 @@ The agent can now read, write, and run bash in that directory — the default is
49
49
  | `0.1.6` | `0.1.6-alpha.1`, `0.1.6-alpha.2` |
50
50
  | `0.1.7` | `0.1.7-alpha.1`, `0.1.7-alpha.2`, `0.1.7-rc.1`, `0.1.7-rc.2` |
51
51
  | `0.2.0` | `0.2.0-rc.1`, `0.2.0-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` |
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`, `0.2.1-rc.4` |
53
+ | `0.2.2` | `0.2.2-alpha.2` |
53
54
 
54
55
  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.
55
56
 
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`.
57
+ **Building from source / contributing**: Node.js `^22.19.0 || >=24`, pnpm `11.25.0` (enable via corepack); the dev-pinned DSH is `0.2.2-alpha.2` (Node ≥24.9).
57
58
 
58
59
  **Platforms**: macOS (Seatbelt), Linux (bwrap / Landlock), Windows (root-set ACL runner).
59
60
 
@@ -92,8 +93,8 @@ This installs pre-built artifacts; the first install needs the `allowBuilds` add
92
93
  ```sh
93
94
  pnpm pack @dsh-electron/dsh-plugin-multi-root-workspace
94
95
  # or download the tgz from the GitHub Release assets, e.g.:
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
96
+ # https://github.com/cherrchen/dsh-plugin-multi-root-workspace/releases/download/v0.1.11/dsh-electron-dsh-plugin-multi-root-workspace-0.1.11.tgz
97
+ dsh plugin --profile web add ./dsh-electron-dsh-plugin-multi-root-workspace-0.1.11.tgz
97
98
  ```
98
99
 
99
100
  Also pre-built, handy for air-gapped or offline delivery; the first install needs the same `allowBuilds` addition.
@@ -112,10 +113,10 @@ allowBuilds:
112
113
  koffi: true
113
114
  ```
114
115
 
115
- Pinning a version (e.g. `#v0.1.10`) is recommended so a later push cannot silently change what actually runs:
116
+ Pinning a version (e.g. `#v0.1.11`) is recommended so a later push cannot silently change what actually runs:
116
117
 
117
118
  ```sh
118
- dsh plugin --profile web add github:cherrchen/dsh-plugin-multi-root-workspace#v0.1.10
119
+ dsh plugin --profile web add github:cherrchen/dsh-plugin-multi-root-workspace#v0.1.11
119
120
  ```
120
121
 
121
122
  ### Install from a local clone
package/README.md CHANGED
@@ -20,7 +20,7 @@
20
20
  - **附属根 Skills**:发现附属目录的 `.dsh/skills` 与 `.agents/skills`,附属根经 `/alias-id:skill-name` 命名空间调用原生 `skill` 工具;每根独立开关、可编辑 `aliasId`,全局设置默认开启。
21
21
  - **不配等于没装**:未登记附加根时行为与未装插件逐项一致;配置错误一律明确报错,从不静默降级。
22
22
 
23
- 当前发布版本 `v0.1.10`。各版本的用户可见变更见 [CHANGELOG](./CHANGELOG.md);进度与发布状态见[路线图 §进度总账](./docs/plans/active/2026-09-12-multi-root-workspace.md#进度总账)。
23
+ 当前发布版本 `v0.1.11`。各版本的用户可见变更见 [CHANGELOG](./CHANGELOG.md);进度与发布状态见[路线图 §进度总账](./docs/plans/active/2026-09-12-multi-root-workspace.md#进度总账)。
24
24
 
25
25
  ## 快速开始
26
26
 
@@ -51,11 +51,12 @@ tarball、GitHub、本地源码等其他安装方式见[安装](#安装)。
51
51
  | `0.1.6` | `0.1.6-alpha.1`、`0.1.6-alpha.2` |
52
52
  | `0.1.7` | `0.1.7-alpha.1`、`0.1.7-alpha.2`、`0.1.7-rc.1`、`0.1.7-rc.2` |
53
53
  | `0.2.0` | `0.2.0-rc.1`、`0.2.0-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` |
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`、`0.2.1-rc.4` |
55
+ | `0.2.2` | `0.2.2-alpha.2` |
55
56
 
56
57
  DSH 版本不在表内、或 `@deepseek-ai/dsh-*` 各包版本不一致时,插件不会启动,行为等同没装。
57
58
 
58
- **从源码构建 / 贡献**:Node.js `^22.19.0 || >=24`,pnpm `11.25.0`(建议经 corepack 启用);开发 pin 的 DSH 为 `0.2.1-rc.3`。
59
+ **从源码构建 / 贡献**:Node.js `^22.19.0 || >=24`,pnpm `11.25.0`(建议经 corepack 启用);开发 pin 的 DSH 为 `0.2.2-alpha.2`(Node ≥24.9)。
59
60
 
60
61
  **运行平台**:macOS(Seatbelt)、Linux(bwrap / Landlock)、Windows(root-set ACL runner)。
61
62
 
@@ -94,8 +95,8 @@ dsh plugin --profile web add @dsh-electron/dsh-plugin-multi-root-workspace
94
95
  ```sh
95
96
  pnpm pack @dsh-electron/dsh-plugin-multi-root-workspace
96
97
  # 或从 GitHub Release 资产下载,例如:
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
98
+ # https://github.com/cherrchen/dsh-plugin-multi-root-workspace/releases/download/v0.1.11/dsh-electron-dsh-plugin-multi-root-workspace-0.1.11.tgz
99
+ dsh plugin --profile web add ./dsh-electron-dsh-plugin-multi-root-workspace-0.1.11.tgz
99
100
  ```
100
101
 
101
102
  同样是预构建产物,适合内网或离线环境交付;首次安装同样需要添加 `allowBuilds`。
@@ -114,10 +115,10 @@ allowBuilds:
114
115
  koffi: true
115
116
  ```
116
117
 
117
- 建议锁定版本(如 `#v0.1.10`),让后续推送无法悄悄改变实际运行的内容:
118
+ 建议锁定版本(如 `#v0.1.11`),让后续推送无法悄悄改变实际运行的内容:
118
119
 
119
120
  ```sh
120
- dsh plugin --profile web add github:cherrchen/dsh-plugin-multi-root-workspace#v0.1.10
121
+ dsh plugin --profile web add github:cherrchen/dsh-plugin-multi-root-workspace#v0.1.11
121
122
  ```
122
123
 
123
124
  ### 从本地源码安装
package/lib/client.js CHANGED
@@ -5986,7 +5986,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5986
5986
 
5987
5987
  /* ── files-tree fork (verbatim rules, renamed classes) ─────────────────────
5988
5988
  Copied from upstream's FilesBody.module.css (ui-sidebar-files @
5989
- 0.2.1-alpha.2) with local names mapped to mrfw-ft* so the rules cannot
5989
+ 0.2.2-alpha.2) with local names mapped to mrfw-ft* so the rules cannot
5990
5990
  collide with host DOM — and so the fork's own body (which must NOT carry
5991
5991
  data-files-body) stays visible while the rules above hide the native one.
5992
5992
  The header-only rules (root/header/path/tool/status/statusLine/titleIcon)
@@ -6043,8 +6043,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6043
6043
  cursor: pointer;
6044
6044
  }
6045
6045
 
6046
- .mrfw-ftRow:hover {
6047
- background: var(--dsw-alias-interactive-bg-hover);
6046
+ @media (hover: hover) {
6047
+ .mrfw-ftRow:hover {
6048
+ background: var(--dsw-alias-interactive-bg-hover);
6049
+ }
6048
6050
  }
6049
6051
 
6050
6052
  /* The folder glyph rides the tertiary ink, as the workspace tree's does. */
@@ -6072,8 +6074,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6072
6074
  cursor: default;
6073
6075
  }
6074
6076
 
6075
- .mrfw-ftOther:hover {
6076
- background: transparent;
6077
+ @media (hover: hover) {
6078
+ .mrfw-ftOther:hover {
6079
+ background: transparent;
6080
+ }
6077
6081
  }
6078
6082
 
6079
6083
  .mrfw-ftNote {
@@ -6898,7 +6902,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6898
6902
  * Named imports cannot spell both releases: each name is absent from the
6899
6903
  * other release's declaration, so the compiler is told once, here.
6900
6904
  */
6901
- const installed$1 = _deepseek_ai_dsh_client_ui_primitives;
6905
+ const installed$2 = _deepseek_ai_dsh_client_ui_primitives;
6902
6906
  /**
6903
6907
  * Pick the first export name this release actually provides.
6904
6908
  * @param module - the icon module to read.
@@ -6921,7 +6925,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6921
6925
  */
6922
6926
  function maybeIcon(names) {
6923
6927
  for (const name of names) {
6924
- const found = installed$1[name];
6928
+ const found = installed$2[name];
6925
6929
  if (found !== void 0) return found;
6926
6930
  }
6927
6931
  }
@@ -6936,7 +6940,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6936
6940
  }
6937
6941
  /** Resolved once, against the installed module. */
6938
6942
  function icon(pixelName, regularName) {
6939
- return selectIcon(installed$1, [pixelName, regularName]);
6943
+ return selectIcon(installed$2, [pixelName, regularName]);
6940
6944
  }
6941
6945
  const IconChevronDown = icon("IconChevronDownOutline14", "IconChevronDownOutlineRegular");
6942
6946
  const IconChevronUp = icon("IconChevronUpOutline14", "IconChevronUpOutlineRegular");
@@ -6953,7 +6957,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6953
6957
  const IconAccessReadOnly = maybeIcon(["PermissionIconReadOnlyRegular", "IconReadOnlyRegular"]);
6954
6958
  const IconAccessInherit = maybeIcon(["IconWorkspaceTreeOutline16", "IconWorkspaceTreeOutlineRegular"]);
6955
6959
  //#endregion
6956
- //#region node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.2.1-rc.3_@deepseek-ai+cordis@4.0.5/node_modules/@deepseek-ai/dsh-typert-protocol/lib/index.js
6960
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.2.2-alpha.2_@deepseek-ai+cordis@4.0.6-alpha.1/node_modules/@deepseek-ai/dsh-typert-protocol/lib/index.js
6957
6961
  /** The one Remote failure class shared by owners, the Gateway, and consumers. */
6958
6962
  /**
6959
6963
  * One Remote call failure: a real Error carrying its stable code and typed
@@ -7463,7 +7467,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7463
7467
  return n;
7464
7468
  }
7465
7469
  //#endregion
7466
- //#region node_modules/.pnpm/@deepseek-ai+dsh-util-workspace-path@0.2.1-rc.3_@deepseek-ai+cordis@4.0.5/node_modules/@deepseek-ai/dsh-util-workspace-path/lib/index.js
7470
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-util-workspace-path@0.2.2-alpha.2_@deepseek-ai+cordis@4.0.6-alpha.1/node_modules/@deepseek-ai/dsh-util-workspace-path/lib/index.js
7467
7471
  /**
7468
7472
  * The `dsh-resource://file/…` address grammar: how a file is named across the
7469
7473
  * Sidebar and the resource model, built and parsed without touching a
@@ -7885,7 +7889,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7885
7889
  };
7886
7890
  }
7887
7891
  //#endregion
7888
- //#region node_modules/.pnpm/@deepseek-ai+dsh-host-open-in-app@0.2.1-rc.3_@deepseek-ai+cordis@4.0.5_@deepseek-ai+dsh_5b371ee77d0b761177ea40ae8a5dc767/node_modules/@deepseek-ai/dsh-host-open-in-app/lib/types/shared.js
7892
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-host-open-in-app@0.2.2-alpha.2_@deepseek-ai+cordis@4.0.6-alpha.1_@deep_d76f08f4e35ff3a756a48d7d013379f6/node_modules/@deepseek-ai/dsh-host-open-in-app/lib/types/shared.js
7889
7893
  var shared_exports = /* @__PURE__ */ __exportAll({
7890
7894
  OPEN_IN_APP_APPS_PATH: () => OPEN_IN_APP_APPS_PATH,
7891
7895
  OPEN_IN_APP_APPS_ROUTE: () => OPEN_IN_APP_APPS_ROUTE,
@@ -7941,7 +7945,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7941
7945
  * Named imports cannot spell both eras: each name is absent from the other
7942
7946
  * era's declaration, so the compiler is told once, here.
7943
7947
  */
7944
- const installed = shared_exports;
7948
+ const installed$1 = shared_exports;
7945
7949
  /**
7946
7950
  * Pick the first export name this release actually provides.
7947
7951
  * @param module - the shared module to read.
@@ -7963,7 +7967,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7963
7967
  * `iconUrl` on runtimes whose glyph gate already passed, and on the pixel era
7964
7968
  * the absolute form is exactly what upstream's own client fetched.
7965
7969
  */
7966
- const OPEN_IN_APP_ICON_URL_PREFIX = selectSharedRoute(installed, ["OPEN_IN_APP_ICON_PREFIX_ROUTE", "OPEN_IN_APP_ICON_PREFIX"]);
7970
+ const OPEN_IN_APP_ICON_URL_PREFIX = selectSharedRoute(installed$1, ["OPEN_IN_APP_ICON_PREFIX_ROUTE", "OPEN_IN_APP_ICON_PREFIX"]);
7967
7971
  //#endregion
7968
7972
  //#region src/client/open-in-app/applications.ts
7969
7973
  /** Label keys for applications supported by this client. */
@@ -8059,10 +8063,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8059
8063
  * @param appId - catalog id from the availability list.
8060
8064
  * @param path - the session's absolute workspace directory.
8061
8065
  * Concurrent gestures are ignored until the current Host request settles.
8062
- * @returns after the host acknowledged the launch; rejects on any failure.
8066
+ * @returns the acknowledged handoff, or `{ kind: 'skipped' }` while another
8067
+ * launch holds the operation, or a named failure when the Host refuses or
8068
+ * cannot be reached. Host and transport failures resolve without rejecting.
8063
8069
  */
8064
8070
  async launch(appId, path) {
8065
- if (this.operation.getSnapshot().phase === "busy") return;
8071
+ if (this.operation.getSnapshot().phase === "busy") return { kind: "skipped" };
8066
8072
  this.operation.set({
8067
8073
  phase: "busy",
8068
8074
  path
@@ -8082,12 +8088,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8082
8088
  phase: "idle",
8083
8089
  path
8084
8090
  });
8085
- } catch (error) {
8091
+ return { kind: "opened" };
8092
+ } catch (_error) {
8086
8093
  this.operation.set({
8087
8094
  phase: "error",
8088
8095
  path
8089
8096
  });
8090
- throw error;
8097
+ return {
8098
+ kind: "failed",
8099
+ failure: "openError"
8100
+ };
8091
8101
  }
8092
8102
  }
8093
8103
  async run() {
@@ -8107,36 +8117,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8107
8117
  /** Dictionary namespace owned by upstream's plugin (verbatim). */
8108
8118
  const NS = "open-in-app";
8109
8119
  //#endregion
8110
- //#region src/client/open-in-app/open-failure-toast.tsx
8111
- /** Per-control failure banner for path gestures. */
8112
- /**
8113
- * Transient failure banner owned by the control that initiated the gesture,
8114
- * so one failed request announces once, from the control the user pressed.
8115
- * @returns `toast` owned by the control and `show` to announce one
8116
- * failure with resolved copy; announcing again replays the banner.
8117
- */
8118
- function useOpenFailureToast() {
8119
- const seq = (0, react.useRef)(0);
8120
- const [banner, setBanner] = (0, react.useState)(null);
8121
- const dismiss = (0, react.useCallback)(() => {
8122
- setBanner(null);
8123
- }, []);
8124
- return {
8125
- toast: banner === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
8126
- text: banner.text,
8127
- icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutlineRegular, {}),
8128
- onDone: dismiss
8129
- }, banner.seq),
8130
- show: (text) => {
8131
- seq.current += 1;
8132
- setBanner({
8133
- seq: seq.current,
8134
- text
8135
- });
8136
- }
8137
- };
8138
- }
8139
- //#endregion
8140
8120
  //#region src/client/open-in-app/OpenTargetButton.module.css.ts
8141
8121
  /**
8142
8122
  * Fork-facing shim for upstream `OpenTargetButton.module.css`.
@@ -8168,27 +8148,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8168
8148
  };
8169
8149
  //#endregion
8170
8150
  //#region src/client/open-in-app/OpenTargetButton.tsx
8171
- /** Shared file and directory opener: one default action, application menu, and per-gesture feedback. */
8151
+ /** Shared file and directory opener: one default action, application menu, and one reported outcome per gesture. */
8172
8152
  /**
8173
- * Serialize gestures and announce their failures through the initiating control's toast.
8174
- * @param execute - target adapter that returns the failure to announce, or null.
8175
- * @param t - localized control copy.
8176
- * @returns the pending state, feedback, and guarded action callback.
8153
+ * Serialize gestures and report the outcome each one settles on to the app-wide
8154
+ * announcer, which outlives this control and the panel holding it.
8155
+ * @param execute - target adapter that settles on the gesture's outcome.
8156
+ * @param report - announcement seat the settled outcome is sent to.
8157
+ * @returns the pending state and the guarded action callback.
8177
8158
  */
8178
- function useOpenTargetGesture(execute, t) {
8159
+ function useOpenTargetGesture(execute, report) {
8179
8160
  const [pending, setPending] = (0, react.useState)(false);
8180
8161
  const inFlight = (0, react.useRef)(false);
8181
- const { toast, show } = useOpenFailureToast();
8182
8162
  return {
8183
8163
  pending,
8184
- toast,
8185
8164
  act: (operation) => {
8186
8165
  if (inFlight.current) return;
8187
8166
  inFlight.current = true;
8188
8167
  setPending(true);
8189
- execute(operation).then((failure) => {
8190
- if (failure !== null) show(t(`path.${failure}`));
8191
- }).finally(() => {
8168
+ execute(operation).then(report).finally(() => {
8192
8169
  inFlight.current = false;
8193
8170
  setPending(false);
8194
8171
  });
@@ -8214,12 +8191,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8214
8191
  * Render identical split buttons for files and directories. File reveal always
8215
8192
  * stays last; it is the default only when no application is registered.
8216
8193
  * @param props - target applications, default selection, and operations.
8217
- * @returns the control and its transient failure feedback.
8194
+ * @returns the control alone: its settled outcomes are announced by the seat it reports to.
8218
8195
  */
8219
8196
  function OpenTargetButton(props) {
8220
8197
  const { applications, defaultId, kind, t } = props;
8221
8198
  const [menuOpen, setMenuOpen] = (0, react.useState)(false);
8222
- const { pending, toast, act } = useOpenTargetGesture(props.execute, t);
8199
+ const { pending, act } = useOpenTargetGesture(props.execute, props.report);
8223
8200
  const preferred = kind === "file" ? applications.find((app) => app.id === defaultId) ?? applications[0] : applications.find((app) => app.id === defaultId);
8224
8201
  const disabled = pending || props.busy === true || props.loading === true;
8225
8202
  const hasMenu = props.loading === true || props.failed || applications.length + (kind === "file" ? 1 : 0) > 1;
@@ -8255,7 +8232,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8255
8232
  source: preferred?.icon ?? null,
8256
8233
  size: props.prominent ? 18 : 13
8257
8234
  }, preferred?.icon);
8258
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
8235
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
8259
8236
  className: css.menuAnchor,
8260
8237
  open: menuOpen && !disabled && hasMenu,
8261
8238
  autoFocus: true,
@@ -8323,13 +8300,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8323
8300
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { size: props.prominent ? 14 : 10 })
8324
8301
  })]
8325
8302
  })
8326
- }), toast] });
8303
+ });
8327
8304
  }
8328
8305
  //#endregion
8329
8306
  //#region src/client/open-in-app/OpenInAppAction.tsx
8330
8307
  /**
8331
8308
  * Adapt the installed directory catalog to the shared opening control.
8332
- * @param props - displayed directory, installed catalog, and launch operations.
8309
+ * @param props - displayed directory, installed catalog, launch operations, and the announcement seat.
8333
8310
  * @returns the shared control, or null without an eligible application.
8334
8311
  */
8335
8312
  function OpenInAppAction(props) {
@@ -8356,19 +8333,101 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8356
8333
  t,
8357
8334
  busy: operation.phase === "busy",
8358
8335
  shortcut,
8336
+ report: props.report,
8359
8337
  execute: async (operation) => {
8360
8338
  const id = operation.kind === "application" ? operation.id : preferred.id;
8361
- try {
8362
- await props.launch(id, absolutePath);
8363
- } catch (_error) {
8364
- return "openError";
8365
- }
8366
- if (operation.kind === "application") props.choose(id);
8367
- return null;
8339
+ const outcome = await props.launch(id, absolutePath);
8340
+ if (outcome.kind === "opened" && operation.kind === "application") props.choose(id);
8341
+ return outcome;
8368
8342
  }
8369
8343
  }, absolutePath);
8370
8344
  }
8371
8345
  //#endregion
8346
+ //#region src/compat/open-in-app-device.ts
8347
+ /**
8348
+ * Compatibility adapter for `isMobileDevice` from
8349
+ * `@deepseek-ai/dsh-client-ui-primitives`.
8350
+ *
8351
+ * ```text
8352
+ * 0.1.5-rc.2 through 0.2.1-rc.4 no `isMobileDevice` export
8353
+ * 0.2.2-alpha.2 + `isMobileDevice` exported
8354
+ * ```
8355
+ *
8356
+ * The open-in-app fork's verbatim `open-toast.tsx` spells the detector as a
8357
+ * primitives import — a name absent before `0.2.2-alpha.2` — so the lookup
8358
+ * is by export name, not by release string (the `client-icons.ts` pattern).
8359
+ * An older runtime falls back to upstream's identical detection: mobile
8360
+ * userAgent, or a touch-capable MacIntel platform, memoized like upstream's.
8361
+ *
8362
+ * @module @dsh-electron/dsh-plugin-multi-root-workspace/compat/open-in-app-device
8363
+ */
8364
+ /** The primitives module, addressed by export name. */
8365
+ const installed = _deepseek_ai_dsh_client_ui_primitives;
8366
+ /** Upstream's own detector when the installed release carries it (verbatim logic below otherwise). */
8367
+ const upstream = typeof installed.isMobileDevice === "function" ? installed.isMobileDevice : void 0;
8368
+ let fallbackResult;
8369
+ /**
8370
+ * Whether this browser is a mobile device — upstream's detection verbatim.
8371
+ * @returns true for a mobile userAgent or a touch-capable macOS surface.
8372
+ */
8373
+ function isMobileDeviceFallback() {
8374
+ fallbackResult ??= /Android|iPhone|iPad|iPod/i.test(navigator.userAgent) || navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1;
8375
+ return fallbackResult;
8376
+ }
8377
+ /**
8378
+ * Resolve the installed release's `isMobileDevice`, or the identical local
8379
+ * fallback on releases that predate the export.
8380
+ * @returns the mobile-device verdict.
8381
+ */
8382
+ function isMobileDevice() {
8383
+ return upstream === void 0 ? isMobileDeviceFallback() : upstream();
8384
+ }
8385
+ //#endregion
8386
+ //#region src/client/open-in-app/open-toast.tsx
8387
+ /**
8388
+ * Create the one outcome store the overlay entry shows.
8389
+ * @returns the observable notice with its report and dismiss actions.
8390
+ */
8391
+ function createOpenInAppToastSource() {
8392
+ const store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(null);
8393
+ let seq = 0;
8394
+ return {
8395
+ hooks: { toast: store },
8396
+ report: (outcome) => {
8397
+ if (outcome.kind === "skipped") return;
8398
+ if (outcome.kind !== "failed" && !isMobileDevice()) return;
8399
+ seq += 1;
8400
+ store.set({
8401
+ ...outcome,
8402
+ seq
8403
+ });
8404
+ },
8405
+ dismiss: () => {
8406
+ store.set(null);
8407
+ }
8408
+ };
8409
+ }
8410
+ /**
8411
+ * Render a mobile handoff confirmation or a native-open failure.
8412
+ * @param props - the notice hook, its dismissal, and the locale seat.
8413
+ * @returns the banner on display, or null.
8414
+ */
8415
+ function OpenInAppToast({ useToast, dismiss, t }) {
8416
+ const toast = useToast((current) => current);
8417
+ if (toast === null) return null;
8418
+ const key = `open-in-app-${String(toast.seq)}`;
8419
+ if (toast.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
8420
+ text: t(toast.failure === "revealError" ? "path.revealError" : "path.openError"),
8421
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutlineRegular, {}),
8422
+ onDone: dismiss
8423
+ }, key);
8424
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
8425
+ text: t(toast.kind === "opened" ? "path.opened" : "path.revealed"),
8426
+ tone: "success",
8427
+ onDone: dismiss
8428
+ }, key);
8429
+ }
8430
+ //#endregion
8372
8431
  //#region src/client/open-in-app/adapter.tsx
8373
8432
  /**
8374
8433
  * The plugin-owned wiring around the verbatim open-in-app fork.
@@ -8433,17 +8492,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8433
8492
  if (!REQUIRED_GLYPHS.every((name) => maybeIcon([name]) !== void 0)) return void 0;
8434
8493
  const controller = new OpenInAppController();
8435
8494
  controller.load();
8495
+ const toast = createOpenInAppToastSource();
8436
8496
  return {
8437
- useOpenInAppApps: bindSnapshot(controller.apps),
8438
- useOpenInAppChoice: bindSnapshot(controller.choice),
8439
- useOpenInAppLaunch: bindSnapshot(controller.operation),
8440
- useShortcuts: bindSnapshot(deps.shortcuts ?? NO_SHORTCUTS),
8441
- launch: (appId, path) => controller.launch(appId, path),
8442
- choose: (appId) => {
8443
- controller.choose(appId);
8444
- },
8445
- iconUrl: (appId) => `${OPEN_IN_APP_ICON_URL_PREFIX}/${appId}`,
8446
- t: deps.t
8497
+ toast,
8498
+ adapter: {
8499
+ useOpenInAppApps: bindSnapshot(controller.apps),
8500
+ useOpenInAppChoice: bindSnapshot(controller.choice),
8501
+ useOpenInAppLaunch: bindSnapshot(controller.operation),
8502
+ useShortcuts: bindSnapshot(deps.shortcuts ?? NO_SHORTCUTS),
8503
+ launch: (appId, path) => controller.launch(appId, path),
8504
+ report: toast.report,
8505
+ choose: (appId) => {
8506
+ controller.choose(appId);
8507
+ },
8508
+ iconUrl: (appId) => `${OPEN_IN_APP_ICON_URL_PREFIX}/${appId}`,
8509
+ t: deps.t
8510
+ }
8447
8511
  };
8448
8512
  }
8449
8513
  //#endregion
@@ -9747,6 +9811,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9747
9811
  t: ctx.locale.bind(NS),
9748
9812
  shortcuts: readService(ctx, "shortcuts")?.catalog
9749
9813
  });
9814
+ if (openInApp !== void 0) {
9815
+ const { toast } = openInApp;
9816
+ ctx.slots.inject("shell.overlay", () => ctx.slots.register({
9817
+ name: "shell.overlay",
9818
+ id: "multi-root-open-in-app.toast",
9819
+ locale: NS,
9820
+ inject: () => ({
9821
+ hooks: toast.hooks,
9822
+ dismiss: toast.dismiss
9823
+ })
9824
+ }, OpenInAppToast));
9825
+ }
9750
9826
  const filesTreeSeats = createFilesTreeSeats(ctx);
9751
9827
  const filesTreeT = ctx.locale.bind(NS$1);
9752
9828
  ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
@@ -9790,7 +9866,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9790
9866
  sessionId: paneSessionId,
9791
9867
  subscribeSession,
9792
9868
  t,
9793
- openInApp,
9869
+ openInApp: openInApp?.adapter,
9794
9870
  filesTree
9795
9871
  });
9796
9872
  }));