@jingyi0605/codingns4dsh 0.2.1-beta.2 → 0.2.1-beta.3

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 (156) hide show
  1. package/README.en.md +8 -8
  2. package/README.md +11 -9
  3. package/data/build/dist/client/bundle.js +169 -35
  4. package/data/build/dist/client/bundle.js.map +1 -1
  5. package/data/build/dist/client/locales/peerHostWorkspace.d.ts.map +1 -1
  6. package/data/build/dist/client/locales/peerHostWorkspace.js +16 -2
  7. package/data/build/dist/client/locales/peerHostWorkspace.js.map +1 -1
  8. package/data/build/dist/client/peer-host-native-projection.d.ts +4 -3
  9. package/data/build/dist/client/peer-host-native-projection.d.ts.map +1 -1
  10. package/data/build/dist/client/peer-host-native-projection.js +7 -6
  11. package/data/build/dist/client/peer-host-native-projection.js.map +1 -1
  12. package/data/build/dist/client/peer-host-native-store-projection.js +9 -21
  13. package/data/build/dist/client/peer-host-native-store-projection.js.map +1 -1
  14. package/data/build/dist/client/peer-host-workspace-tab.d.ts.map +1 -1
  15. package/data/build/dist/client/peer-host-workspace-tab.js +139 -10
  16. package/data/build/dist/client/peer-host-workspace-tab.js.map +1 -1
  17. package/data/build/dist/client/skill-command.d.ts +1 -1
  18. package/data/build/dist/client/skill-command.d.ts.map +1 -1
  19. package/data/build/dist/client/skill-command.js +25 -2
  20. package/data/build/dist/client/skill-command.js.map +1 -1
  21. package/data/build/dist/client/skill-reference-dom.js +1 -1
  22. package/data/build/dist/client/skill-reference-dom.js.map +1 -1
  23. package/data/build/dist/client/terminal/styles.js +2 -2
  24. package/data/build/dist/dsh-capabilities/host/sidebar-session-compat.d.ts +28 -0
  25. package/data/build/dist/dsh-capabilities/host/sidebar-session-compat.d.ts.map +1 -0
  26. package/data/build/dist/dsh-capabilities/host/sidebar-session-compat.js +109 -0
  27. package/data/build/dist/dsh-capabilities/host/sidebar-session-compat.js.map +1 -0
  28. package/data/build/dist/host/cli-adapters/acp-cli-driver.d.ts +18 -1
  29. package/data/build/dist/host/cli-adapters/acp-cli-driver.d.ts.map +1 -1
  30. package/data/build/dist/host/cli-adapters/acp-cli-driver.js +26 -8
  31. package/data/build/dist/host/cli-adapters/acp-cli-driver.js.map +1 -1
  32. package/data/build/dist/host/cli-adapters/attachment-utils.d.ts +16 -5
  33. package/data/build/dist/host/cli-adapters/attachment-utils.d.ts.map +1 -1
  34. package/data/build/dist/host/cli-adapters/attachment-utils.js +152 -42
  35. package/data/build/dist/host/cli-adapters/attachment-utils.js.map +1 -1
  36. package/data/build/dist/host/cli-adapters/claude-driver.d.ts +14 -8
  37. package/data/build/dist/host/cli-adapters/claude-driver.d.ts.map +1 -1
  38. package/data/build/dist/host/cli-adapters/claude-driver.js +101 -76
  39. package/data/build/dist/host/cli-adapters/claude-driver.js.map +1 -1
  40. package/data/build/dist/host/cli-adapters/codex-driver.d.ts.map +1 -1
  41. package/data/build/dist/host/cli-adapters/codex-driver.js +74 -6
  42. package/data/build/dist/host/cli-adapters/codex-driver.js.map +1 -1
  43. package/data/build/dist/host/cli-adapters/command-code-acp-loader.d.ts +23 -0
  44. package/data/build/dist/host/cli-adapters/command-code-acp-loader.d.ts.map +1 -0
  45. package/data/build/dist/host/cli-adapters/command-code-acp-loader.js +39 -0
  46. package/data/build/dist/host/cli-adapters/command-code-acp-loader.js.map +1 -0
  47. package/data/build/dist/host/cli-adapters/command-code-driver.d.ts +17 -6
  48. package/data/build/dist/host/cli-adapters/command-code-driver.d.ts.map +1 -1
  49. package/data/build/dist/host/cli-adapters/command-code-driver.js +430 -20
  50. package/data/build/dist/host/cli-adapters/command-code-driver.js.map +1 -1
  51. package/data/build/dist/host/cli-adapters/command-code-subscription.d.ts +1 -1
  52. package/data/build/dist/host/cli-adapters/command-code-subscription.d.ts.map +1 -1
  53. package/data/build/dist/host/cli-adapters/command-code-subscription.js +7 -4
  54. package/data/build/dist/host/cli-adapters/command-code-subscription.js.map +1 -1
  55. package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts.map +1 -1
  56. package/data/build/dist/host/cli-adapters/dsh-message-projector.js +28 -0
  57. package/data/build/dist/host/cli-adapters/dsh-message-projector.js.map +1 -1
  58. package/data/build/dist/host/cli-adapters/dsh-tool-history.d.ts.map +1 -1
  59. package/data/build/dist/host/cli-adapters/dsh-tool-history.js +23 -1
  60. package/data/build/dist/host/cli-adapters/dsh-tool-history.js.map +1 -1
  61. package/data/build/dist/host/cli-adapters/feature.js +1 -1
  62. package/data/build/dist/host/cli-adapters/feature.js.map +1 -1
  63. package/data/build/dist/host/cli-adapters/grok-driver.d.ts +4 -2
  64. package/data/build/dist/host/cli-adapters/grok-driver.d.ts.map +1 -1
  65. package/data/build/dist/host/cli-adapters/grok-driver.js +208 -9
  66. package/data/build/dist/host/cli-adapters/grok-driver.js.map +1 -1
  67. package/data/build/dist/host/cli-adapters/json-rpc-process.d.ts +2 -0
  68. package/data/build/dist/host/cli-adapters/json-rpc-process.d.ts.map +1 -1
  69. package/data/build/dist/host/cli-adapters/json-rpc-process.js +8 -3
  70. package/data/build/dist/host/cli-adapters/json-rpc-process.js.map +1 -1
  71. package/data/build/dist/host/cli-adapters/kimi-driver.d.ts +4 -0
  72. package/data/build/dist/host/cli-adapters/kimi-driver.d.ts.map +1 -1
  73. package/data/build/dist/host/cli-adapters/kimi-driver.js +11 -4
  74. package/data/build/dist/host/cli-adapters/kimi-driver.js.map +1 -1
  75. package/data/build/dist/host/cli-adapters/mcode-driver.js +2 -2
  76. package/data/build/dist/host/cli-adapters/mcode-driver.js.map +1 -1
  77. package/data/build/dist/host/cli-adapters/new-api-subscription.d.ts.map +1 -1
  78. package/data/build/dist/host/cli-adapters/new-api-subscription.js +11 -58
  79. package/data/build/dist/host/cli-adapters/new-api-subscription.js.map +1 -1
  80. package/data/build/dist/host/cli-adapters/opencode-driver.d.ts +5 -2
  81. package/data/build/dist/host/cli-adapters/opencode-driver.d.ts.map +1 -1
  82. package/data/build/dist/host/cli-adapters/opencode-driver.js +136 -18
  83. package/data/build/dist/host/cli-adapters/opencode-driver.js.map +1 -1
  84. package/data/build/dist/host/cli-adapters/pi-driver.d.ts.map +1 -1
  85. package/data/build/dist/host/cli-adapters/pi-driver.js +2 -1
  86. package/data/build/dist/host/cli-adapters/pi-driver.js.map +1 -1
  87. package/data/build/dist/host/cli-adapters/process-utils.d.ts +10 -0
  88. package/data/build/dist/host/cli-adapters/process-utils.d.ts.map +1 -1
  89. package/data/build/dist/host/cli-adapters/process-utils.js +20 -0
  90. package/data/build/dist/host/cli-adapters/process-utils.js.map +1 -1
  91. package/data/build/dist/host/cli-adapters/provider-subscription.d.ts +3 -0
  92. package/data/build/dist/host/cli-adapters/provider-subscription.d.ts.map +1 -1
  93. package/data/build/dist/host/cli-adapters/provider-subscription.js +42 -8
  94. package/data/build/dist/host/cli-adapters/provider-subscription.js.map +1 -1
  95. package/data/build/dist/host/cli-adapters/registry.d.ts.map +1 -1
  96. package/data/build/dist/host/cli-adapters/registry.js +5 -3
  97. package/data/build/dist/host/cli-adapters/registry.js.map +1 -1
  98. package/data/build/dist/host/cli-adapters/rpc-driver-utils.d.ts.map +1 -1
  99. package/data/build/dist/host/cli-adapters/rpc-driver-utils.js +2 -9
  100. package/data/build/dist/host/cli-adapters/rpc-driver-utils.js.map +1 -1
  101. package/data/build/dist/host/cli-adapters/skill-filesystem.d.ts +25 -0
  102. package/data/build/dist/host/cli-adapters/skill-filesystem.d.ts.map +1 -0
  103. package/data/build/dist/host/cli-adapters/skill-filesystem.js +161 -0
  104. package/data/build/dist/host/cli-adapters/skill-filesystem.js.map +1 -0
  105. package/data/build/dist/host/cli-adapters/standard-stream-driver.d.ts +1 -0
  106. package/data/build/dist/host/cli-adapters/standard-stream-driver.d.ts.map +1 -1
  107. package/data/build/dist/host/cli-adapters/standard-stream-driver.js +4 -0
  108. package/data/build/dist/host/cli-adapters/standard-stream-driver.js.map +1 -1
  109. package/data/build/dist/host/cli-adapters/zcode-driver.d.ts +8 -2
  110. package/data/build/dist/host/cli-adapters/zcode-driver.d.ts.map +1 -1
  111. package/data/build/dist/host/cli-adapters/zcode-driver.js +166 -55
  112. package/data/build/dist/host/cli-adapters/zcode-driver.js.map +1 -1
  113. package/data/build/dist/host/cli-adapters/zcode-interactions.d.ts +18 -0
  114. package/data/build/dist/host/cli-adapters/zcode-interactions.d.ts.map +1 -0
  115. package/data/build/dist/host/cli-adapters/zcode-interactions.js +90 -0
  116. package/data/build/dist/host/cli-adapters/zcode-interactions.js.map +1 -0
  117. package/data/build/dist/host/cli-adapters/zcode-provider-config.d.ts +26 -0
  118. package/data/build/dist/host/cli-adapters/zcode-provider-config.d.ts.map +1 -0
  119. package/data/build/dist/host/cli-adapters/zcode-provider-config.js +102 -0
  120. package/data/build/dist/host/cli-adapters/zcode-provider-config.js.map +1 -0
  121. package/data/build/dist/host/cli-adapters/zcode-subscription.d.ts +2 -7
  122. package/data/build/dist/host/cli-adapters/zcode-subscription.d.ts.map +1 -1
  123. package/data/build/dist/host/cli-adapters/zcode-subscription.js.map +1 -1
  124. package/data/build/dist/host/cli-adapters/zcode-telemetry.d.ts +17 -0
  125. package/data/build/dist/host/cli-adapters/zcode-telemetry.d.ts.map +1 -0
  126. package/data/build/dist/host/cli-adapters/zcode-telemetry.js +124 -0
  127. package/data/build/dist/host/cli-adapters/zcode-telemetry.js.map +1 -0
  128. package/data/build/dist/host/cli-bridge/injections.d.ts +2 -9
  129. package/data/build/dist/host/cli-bridge/injections.d.ts.map +1 -1
  130. package/data/build/dist/host/cli-bridge/injections.js +7 -17
  131. package/data/build/dist/host/cli-bridge/injections.js.map +1 -1
  132. package/data/build/dist/host/features/peer-host.d.ts.map +1 -1
  133. package/data/build/dist/host/features/peer-host.js +23 -0
  134. package/data/build/dist/host/features/peer-host.js.map +1 -1
  135. package/data/build/dist/host/index.d.ts.map +1 -1
  136. package/data/build/dist/host/index.js +3 -0
  137. package/data/build/dist/host/index.js.map +1 -1
  138. package/data/build/dist/host/modules/peer-host/peer-host-native-protocol.d.ts +2 -0
  139. package/data/build/dist/host/modules/peer-host/peer-host-native-protocol.d.ts.map +1 -1
  140. package/data/build/dist/host/modules/peer-host/peer-host-native-protocol.js +5 -0
  141. package/data/build/dist/host/modules/peer-host/peer-host-native-protocol.js.map +1 -1
  142. package/data/build/dist/host/modules/peer-host/peer-host-remote-summary-source.d.ts.map +1 -1
  143. package/data/build/dist/host/modules/peer-host/peer-host-remote-summary-source.js +3 -1
  144. package/data/build/dist/host/modules/peer-host/peer-host-remote-summary-source.js.map +1 -1
  145. package/data/build/dist/host/rpc.d.ts.map +1 -1
  146. package/data/build/dist/host/rpc.js +5 -0
  147. package/data/build/dist/host/rpc.js.map +1 -1
  148. package/data/build/dist/shared/contracts/cli-adapter.d.ts +4 -0
  149. package/data/build/dist/shared/contracts/cli-adapter.d.ts.map +1 -1
  150. package/data/build/dist/shared/contracts/version.d.ts +1 -1
  151. package/data/build/dist/shared/contracts/version.js +1 -1
  152. package/package.json +3 -1
  153. package/profile/README.md +2 -2
  154. package/profile/package.json +2 -2
  155. package/profile/version.json +1 -1
  156. package/version.json +1 -1
package/README.en.md CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  [简体中文](README.md) · **English**
13
13
 
14
- **Current release `@jingyi0605/codingns4dsh@0.2.1-beta.2`** · DSH **`>=0.2.0-rc.2 <=0.2.1-alpha.1`** (tested with `0.2.1-alpha.1`) · Node **`>= 22.19`** · macOS / Linux / Windows
14
+ **Current release `@jingyi0605/codingns4dsh@0.2.1-beta.3`** · DSH **`>=0.2.0-rc.2 <=0.2.1-alpha.1`** (tested with `0.2.1-alpha.1`) · Node **`>= 22.19`** · macOS / Linux / Windows
15
15
 
16
16
  **[GitHub](https://github.com/jingyi0605/Codingns4DSH)** · **[npm](https://www.npmjs.com/package/@jingyi0605/codingns4dsh)** · **QQ group 1092985965**
17
17
 
@@ -76,14 +76,14 @@ Detected on the Host by command name; version and models come from the CLI itsel
76
76
 
77
77
  | Agent | id | Command | Protocol | Capabilities | Notes |
78
78
  | --- | --- | --- | --- | --- | --- |
79
- | Command Code | `command-code` | `command-code`, `commandcode`, `cmdc` | single-shot CLI | models, streaming, resume, interrupt, tools, thinking, usage | DSH permission state maps to CLI safety modes; no verifiable interactive approval/question wire |
79
+ | Command Code | `command-code` | `command-code`, `commandcode`, `cmdc` | CLI + ACP | models, streaming, resume, interrupt, tools, thinking, usage, approvals, questions | The formal Host runtime uses `cmd acp`; DSH permissions map to `--plan`, `--permission-mode accept-edits`, or `--yolo`, and questions return through Command Code's `session/request_permission` extension |
80
80
  | Claude Code | `claude-code` | `claude` | stream-json | models, streaming, resume, interrupt, tools, thinking, usage, approvals, questions | `can_use_tool` approvals and `AskUserQuestion` |
81
81
  | Kimi CLI | `kimi` | `kimi`, `kimi-cli` | stream-json | all of the above + approvals, questions, steering | — |
82
82
  | Gemini CLI | `gemini` | `gemini` | ACP | models, streaming, resume, interrupt, tools, thinking, usage, approvals, questions | ACP permissions and form elicitation |
83
83
  | Pi Agent | `pi` | `pi`, `pi-agent` | JSON-RPC | models, streaming, resume, interrupt, tools, thinking, usage, steering | No verifiable DSH approval/question response wire in the current protocol |
84
- | Codex | `codex` | `codex` | JSON-RPC (app-server) | all + approvals, questions, steering | — |
84
+ | Codex | `codex` | `codex` | JSON-RPC (app-server) | all + approvals, questions, steering | app-server enables `request_user_input`; DSH renders the native question panel |
85
85
  | OpenCode | `opencode` | `opencode`, or `OPENCODE_SERVER_URL` (default `http://127.0.0.1:4096`) | HTTP + SSE | all + approvals, questions | — |
86
- | Grok Build | `grok` | `grok`, `grok-build` | ACP | models, streaming, tools, thinking, usage, approvals, questions | ACP permissions and form elicitation |
86
+ | Grok Build | `grok` | `grok`, `grok-build` | ACP | models, streaming, tools, thinking, usage, approvals, questions | ACP permissions plus Grok's private `x.ai/ask_user_question` structured question method |
87
87
  | MiniMax Code | `mcode` | `mcode` | ACP / stream-json | models, streaming, resume, interrupt, tools, thinking, usage, approvals, questions | Interactive requests use ACP; the explicit-effort `exec` path has no interactive response wire |
88
88
  | ZCode | `zcode` | `zcode`, bundled desktop runtime | JSON-RPC bare envelope | models, streaming, resume, interrupt, usage | No verifiable DSH approval/question response wire |
89
89
  | CodeBuddy (auto-detects CN/international) | `codebuddy` | `codebuddy`, `codebuddy-code`, `cbc`, and Windows `.cmd` entry points; region selected from environment and auth domain | ACP (`--acp`) | models, streaming, resume, interrupt, tools, thinking, usage, approvals, questions | Supports stdio ACP and HTTP sidecar ACP |
@@ -98,7 +98,7 @@ Detected on the Host by command name; version and models come from the CLI itsel
98
98
 
99
99
  Unlisted capabilities are unsupported by that CLI or version. Install and log in to each Agent outside DSH; Codingns4DSH never stores Agent credentials.
100
100
 
101
- Approvals and questions are rendered by DSH's native components. Adapters with an interactive response wire normalize Provider requests into `permission-request` or `question-request` events, pass them to the native approval/question components, then send the typed answer back with the Provider's original request ID. ACP adapters use the standard `session/request_permission` and `elicitation/create` form requests; URL elicitation requires a browser security-consent flow and is not advertised. Agents without a verifiable response wire keep those capabilities undeclared; Command Code and Antigravity only map DSH permission state to CLI safety modes.
101
+ Approvals and questions are rendered by DSH's native components. The Web Client Bundle must inject `@deepseek-ai/dsh-client-ui-user-questions`; otherwise the Host may receive a question event without having a question panel to mount. Adapters with an interactive response wire normalize Provider requests into `permission-request` or `question-request` events, pass them to the native approval/question components, then send the typed answer back with the Provider's original request ID. ACP adapters use the standard `session/request_permission` and `elicitation/create` form requests; Grok Build's `grok_build/ask_user_question` tool call returns through the private `x.ai/ask_user_question` method with an `outcome`; Command Code's `ask_user_question` also uses `session/request_permission`, distinguished by `toolCall.kind=other` and `toolCall.rawInput.question/options`. Fixed choices are returned using the original `optionId`; free text is carried in ACP `_meta["codingns/questionAnswer"]` and returned to the Command Code tool through a Node loader that only affects the child process memory and does not modify the user's installed package. The Codex app-server explicitly enables `default_mode_request_user_input` so it emits `item/tool/requestUserInput` requests. URL elicitation requires a browser security-consent flow and is not advertised. Antigravity only maps DSH permission state to CLI safety modes.
102
102
 
103
103
  ---
104
104
 
@@ -234,7 +234,7 @@ The “access” line tells you whether you entered DSH Web locally, over the LA
234
234
  DSH automatically initializes the `web` profile on first use. You do not need to create a config file or run `--dump-config`:
235
235
 
236
236
  ```bash
237
- dsh plugin --profile web add @jingyi0605/codingns4dsh@0.2.1-beta.2
237
+ dsh plugin --profile web add @jingyi0605/codingns4dsh@0.2.1-beta.3
238
238
  dsh web
239
239
  ```
240
240
 
@@ -244,7 +244,7 @@ If you do not want to modify the built-in `web` profile, create a separate profi
244
244
 
245
245
  ```bash
246
246
  dsh codingns --from-default-profile web --dump-config
247
- dsh plugin --profile codingns add @jingyi0605/codingns4dsh@0.2.1-beta.2
247
+ dsh plugin --profile codingns add @jingyi0605/codingns4dsh@0.2.1-beta.3
248
248
  dsh codingns
249
249
  ```
250
250
 
@@ -265,7 +265,7 @@ dsh plugin --profile web remove @jingyi0605/codingns4dsh
265
265
  ```bash
266
266
  git clone https://github.com/jingyi0605/Codingns4DSH.git && cd Codingns4DSH
267
267
  pnpm install && pnpm build
268
- dsh plugin --profile web add "$PWD" # or: npm pack, then add ./jingyi0605-codingns4dsh-0.2.1-beta.2.tgz
268
+ dsh plugin --profile web add "$PWD" # or: npm pack, then add ./jingyi0605-codingns4dsh-0.2.1-beta.3.tgz
269
269
  dsh web
270
270
  ```
271
271
 
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  **简体中文** · [English](README.en.md)
13
13
 
14
- **当前版本 `@jingyi0605/codingns4dsh@0.2.1-beta.2`** · DSH **`>=0.2.0-rc.2 <=0.2.1-alpha.1`**(已验证 `0.2.1-alpha.1`)· Node **`>= 22.19`** · macOS / Linux / Windows
14
+ **当前版本 `@jingyi0605/codingns4dsh@0.2.1-beta.3`** · DSH **`>=0.2.0-rc.2 <=0.2.1-alpha.1`**(已验证 `0.2.1-alpha.1`)· Node **`>= 22.19`** · macOS / Linux / Windows
15
15
 
16
16
  **[GitHub](https://github.com/jingyi0605/Codingns4DSH)** · **[npm](https://www.npmjs.com/package/@jingyi0605/codingns4dsh)** · **QQ 群 1092985965**
17
17
 
@@ -76,14 +76,14 @@ DSH 原生部分不会被替换:对话、会话列表、侧栏、设置、权
76
76
 
77
77
  | Agent | id | 命令 | 协议 | 能力 | 备注 |
78
78
  | --- | --- | --- | --- | --- | --- |
79
- | Command Code | `command-code` | `command-code`、`commandcode`、`cmdc` | 单轮 CLI | 模型、流式、恢复、打断、工具、思考、用量 | 权限按 DSH 状态映射为 CLI 安全模式;没有可回传的交互式权限/提问协议 |
80
- | Claude Code | `claude-code` | `claude` | stream-json | 模型、流式、恢复、打断、工具、思考、用量、权限确认、提问 | `can_use_tool` 权限确认与 `AskUserQuestion` 提问 |
79
+ | Command Code | `command-code` | `command-code`、`commandcode`、`cmdc` | CLI + ACP | 模型、Skill、流式、恢复、打断、工具、思考、用量、权限、提问 | 正式 Host 运行时使用 `cmd acp`;DSH 权限映射为 `--plan`、`--permission-mode accept-edits` 或 `--yolo`,问题通过 Command Code 的 `session/request_permission` 扩展回传 |
80
+ | Claude Code | `claude-code` | `claude` | stream-json | 模型、Skill、流式、恢复、打断、工具、思考、用量、权限确认、提问 | 原生 `.claude/skills` 目录与 `/name` 调用,`can_use_tool` 权限确认与 `AskUserQuestion` 提问 |
81
81
  | Kimi CLI | `kimi` | `kimi`、`kimi-cli` | stream-json | 上述全部 + 权限确认、提问、插话 | — |
82
82
  | Gemini CLI | `gemini` | `gemini` | ACP | 模型、流式、恢复、打断、工具、思考、用量、权限确认、提问 | ACP 权限与 form elicitation(表单式询问) |
83
83
  | Pi Agent | `pi` | `pi`、`pi-agent` | JSON-RPC | 模型、流式、恢复、打断、工具、思考、用量、插话 | 当前协议没有可验证的 DSH 权限/提问回传 |
84
- | Codex | `codex` | `codex` | JSON-RPC(app-server) | 全部 + 权限确认、提问、插话 | — |
85
- | OpenCode | `opencode` | `opencode`,或 `OPENCODE_SERVER_URL`(默认 `http://127.0.0.1:4096`) | HTTP + SSE | 全部 + 权限确认、提问 | — |
86
- | Grok Build | `grok` | `grok`、`grok-build` | ACP | 模型、流式、工具、思考、用量、权限确认、提问 | ACP 权限与 form elicitation(表单式询问) |
84
+ | Codex | `codex` | `codex` | JSON-RPC(app-server) | 全部 + 权限确认、提问、插话 | app-server 显式开启 `request_user_input`,由 DSH 原生问题面板承载 |
85
+ | OpenCode | `opencode` | `opencode`,或 `OPENCODE_SERVER_URL`(默认 `http://127.0.0.1:4096`) | HTTP + SSE | 全部 + Skill、权限确认、提问 | 原生 `/skill` 或 `debug skill` 目录,`session/.../command` 展开显式 Skill |
86
+ | Grok Build | `grok` | `grok`、`grok-build` | ACP | 模型、Skill、流式、工具、思考、用量、权限确认、提问 | 原生 `grok inspect --json` Skill 目录、ACP 权限与 Grok 私有 `_x.ai/ask_user_question` 结构化提问 |
87
87
  | MiniMax Code | `mcode` | `mcode` | ACP / stream-json | 模型、流式、恢复、打断、工具、思考、用量、权限确认、提问 | 默认 ACP 路径支持交互;显式思考档位的 `exec` 路径没有交互式回传;上游贡献者:[chenjunyi000](https://github.com/chenjunyi000);提交 PR [#6](https://github.com/jingyi0605/Codingns4DSH/pull/6)、[#7](https://github.com/jingyi0605/Codingns4DSH/pull/7) |
88
88
  | ZCode | `zcode` | `zcode`、桌面端内置运行时 | JSON-RPC 裸信封 | 模型、流式、恢复、打断、用量 | 上游贡献者:[chenjunyi000](https://github.com/chenjunyi000);提交 PR [#6](https://github.com/jingyi0605/Codingns4DSH/pull/6)、[#7](https://github.com/jingyi0605/Codingns4DSH/pull/7) |
89
89
  | CodeBuddy(自动识别 CN/国际版) | `codebuddy` | `codebuddy`、`codebuddy-code`、`cbc` 及 Windows `.cmd` 入口;按环境变量与认证域名自动选择区域 | ACP(`--acp`) | 模型、流式、恢复、打断、工具、思考、用量、权限确认、提问 | 支持 stdio ACP 与 HTTP sidecar(旁路服务) ACP;CodexHost 上游贡献者:[mouzhi](https://github.com/mouzhi);首次适配 [f30b000](https://github.com/BytePioneer-AI/codex-host/commit/f30b000f88950c40844b071eec2f6f385c6bcb49) |
@@ -98,7 +98,9 @@ DSH 原生部分不会被替换:对话、会话列表、侧栏、设置、权
98
98
 
99
99
  未列出的能力表示该 CLI 或其版本不支持;Agent 的安装与登录都在 DSH 之外完成,Codingns4DSH 不保存 Agent 凭据。
100
100
 
101
- 权限确认和提问都由 DSH 原生组件承载。支持交互式回传的适配器会把 Provider 请求转换为公共的 `permission-request` 或 `question-request` 事件,交给 DSH 原生审批/问题组件,再按 Provider 协议和原始请求 ID 回传。ACP 适配器接入标准 `session/request_permission` 与 `elicitation/create` form(表单式询问);URL elicitation(URL 询问)需要浏览器安全确认流程,当前不宣告该能力。没有可验证回传协议的 Agent 保持能力未声明;Command Code 和 Antigravity 只根据 DSH 权限状态下发 CLI 安全模式。
101
+ 权限确认和提问都由 DSH 原生组件承载。Web Client Bundle 必须注入 `@deepseek-ai/dsh-client-ui-user-questions`,否则即使 Host 收到问题事件也没有问题面板。支持交互式回传的适配器会把 Provider 请求转换为公共的 `permission-request` 或 `question-request` 事件,交给 DSH 原生审批/问题组件,再按 Provider 协议和原始请求 ID 回传。ACP 适配器接入标准 `session/request_permission` 与 `elicitation/create` form(表单式询问);Grok Build 的 `grok_build/ask_user_question` tool_call 由 `_x.ai/ask_user_question` 私有 ext_method 回传 `outcome`;Codex app-server 启动时显式开启 `default_mode_request_user_input`,才会产生 `item/tool/requestUserInput` 请求。Command Code 的 `ask_user_question` 在 ACP 中也使用 `session/request_permission`,通过 `toolCall.kind=other` 和 `toolCall.rawInput.question/options` 区分问题。固定选项按原始 `optionId` 回传;自由文本通过 ACP 回包 `_meta["codingns/questionAnswer"]` 携带,并由只作用于子进程内存的 Node loader 接回 Command Code 工具结果,不修改用户安装包。URL elicitation(URL 询问)需要浏览器安全确认流程,当前不宣告该能力。Antigravity 仍只根据 DSH 权限状态下发 CLI 安全模式。
102
+
103
+ Command Code ACP 的模型、权限和思考强度通过 `session/set_model`、`session/set_mode` 和 `session/set_config_option` 在发送提问前设置;恢复会话同样重新应用当前选择。普通 CLI 启动参数不能代替 ACP 会话配置,设置失败时立即中止。订阅查询遵循 CLI 的凭据优先级:`COMMAND_CODE_API_KEY` 环境变量优先,其次是 `~/.commandcode/auth.json`,避免订阅卡片与实际请求使用不同账户。
102
104
 
103
105
  ---
104
106
 
@@ -240,7 +242,7 @@ DSH 设置按钮旁的账户入口会显示登录状态、访问路径与延迟
240
242
  DSH 的 `web` Profile 会在首次使用时自动初始化,不需要手动创建配置文件,也不需要执行 `--dump-config`:
241
243
 
242
244
  ```bash
243
- dsh plugin --profile web add @jingyi0605/codingns4dsh@0.2.1-beta.2
245
+ dsh plugin --profile web add @jingyi0605/codingns4dsh@0.2.1-beta.3
244
246
  dsh web
245
247
  ```
246
248
 
@@ -250,7 +252,7 @@ dsh web
250
252
 
251
253
  ```bash
252
254
  dsh codingns --from-default-profile web --dump-config
253
- dsh plugin --profile codingns add @jingyi0605/codingns4dsh@0.2.1-beta.2
255
+ dsh plugin --profile codingns add @jingyi0605/codingns4dsh@0.2.1-beta.3
254
256
  dsh codingns
255
257
  ```
256
258
 
@@ -814,11 +814,18 @@ window.__ModuleLoader__.load({
814
814
  "peerHostWorkspace.tabRemote": "Remote HOST",
815
815
  "peerHostWorkspace.sourceLabel": "Workspace source",
816
816
  "peerHostWorkspace.heading": "Remote HOST workspaces",
817
- "peerHostWorkspace.hint": "Choose a Host, then one of its registered workspaces; added workspaces appear only in the local sidebar.",
817
+ "peerHostWorkspace.hint": "Choose a Host to view its added workspaces; use the candidates below to add another one.",
818
818
  "peerHostWorkspace.loadingHosts": "Reading registered Hosts…",
819
819
  "peerHostWorkspace.noHosts": "No other Host is registered yet. Add one under “Manage other DSH Hosts” first.",
820
820
  "peerHostWorkspace.loadingWorkspaces": "Reading the workspaces registered on this Host…",
821
821
  "peerHostWorkspace.noWorkspaces": "This Host has no registered workspaces.",
822
+ "peerHostWorkspace.addedHeading": "Added workspaces",
823
+ "peerHostWorkspace.availableHeading": "Add a workspace",
824
+ "peerHostWorkspace.noAddedWorkspaces": "No remote workspace has been added to this Host yet.",
825
+ "peerHostWorkspace.columnWorkspace": "Workspace",
826
+ "peerHostWorkspace.columnSessions": "Sessions",
827
+ "peerHostWorkspace.columnHost": "Remote HOST",
828
+ "peerHostWorkspace.columnPath": "Path",
822
829
  "peerHostWorkspace.noSessions": "No sessions",
823
830
  "peerHostWorkspace.sessionCount": "{count} sessions",
824
831
  "peerHostWorkspace.added": "Added; the workspace appears in the sidebar after you close this dialog.",
@@ -845,11 +852,18 @@ window.__ModuleLoader__.load({
845
852
  "peerHostWorkspace.tabRemote": "远程 HOST",
846
853
  "peerHostWorkspace.sourceLabel": "工作区来源",
847
854
  "peerHostWorkspace.heading": "远程 HOST 工作区",
848
- "peerHostWorkspace.hint": "选择一台 Host,再选择它上面已登记的工作区;添加后只在本机侧栏显示这些工作区。",
855
+ "peerHostWorkspace.hint": "选择一台 Host 查看已添加的工作区;可在下方候选列表继续添加工作区。",
849
856
  "peerHostWorkspace.loadingHosts": "正在读取已登记的 Host…",
850
857
  "peerHostWorkspace.noHosts": "尚未登记其他 Host。请先在“管理其他 DSH Host”中添加。",
851
858
  "peerHostWorkspace.loadingWorkspaces": "正在读取该 Host 已登记的工作区…",
852
859
  "peerHostWorkspace.noWorkspaces": "该 Host 上没有已登记的工作区。",
860
+ "peerHostWorkspace.addedHeading": "已添加的远程工作区",
861
+ "peerHostWorkspace.availableHeading": "添加远程工作区",
862
+ "peerHostWorkspace.noAddedWorkspaces": "该 Host 尚未添加远程工作区。",
863
+ "peerHostWorkspace.columnWorkspace": "工作区名称",
864
+ "peerHostWorkspace.columnSessions": "会话数",
865
+ "peerHostWorkspace.columnHost": "所属远程 HOST",
866
+ "peerHostWorkspace.columnPath": "路径",
853
867
  "peerHostWorkspace.noSessions": "无会话",
854
868
  "peerHostWorkspace.sessionCount": "{count} 个会话",
855
869
  "peerHostWorkspace.added": "已添加;关闭对话框后该工作区会出现在侧栏。",
@@ -2792,7 +2806,7 @@ window.__ModuleLoader__.load({
2792
2806
  return /^0\.1\.5(?:-|$)/u.test(version);
2793
2807
  }
2794
2808
  /** Codingns4DSH 插件自身的 npm 版本。 */
2795
- const CODINGNS_VERSION = "0.2.1-beta.2";
2809
+ const CODINGNS_VERSION = "0.2.1-beta.3";
2796
2810
  /** 判断宿主版本是否落在当前插件声明的 DSH 兼容范围内;范围省略上界时不校验上限。 */
2797
2811
  function isDshVersionCompatible(version) {
2798
2812
  const match = /^>=([^ ]+)(?: <=([^ ]+))?$/u.exec(DSH_COMPATIBILITY);
@@ -17114,7 +17128,7 @@ window.__ModuleLoader__.load({
17114
17128
  function findSkillReferenceMentions(value, names) {
17115
17129
  const byLowerName = new Map([...names].map((name) => [name.toLocaleLowerCase(), name]));
17116
17130
  const matches = [];
17117
- for (const match of value.matchAll(/\/[A-Za-z0-9][A-Za-z0-9._-]*(?=\s|$)/gu)) {
17131
+ for (const match of value.matchAll(/\/[A-Za-z0-9][A-Za-z0-9._:/-]*(?=\s|$)/gu)) {
17118
17132
  const token = match[0] ?? "";
17119
17133
  const start = match.index ?? -1;
17120
17134
  const before = start > 0 ? value[start - 1] : void 0;
@@ -17255,7 +17269,8 @@ window.__ModuleLoader__.load({
17255
17269
  const SKILL_INPUT_SOURCE = "codingns-skills";
17256
17270
  const SKILL_CATALOG_CACHE_TTL_MS = 3e4;
17257
17271
  const skillCatalogCache = /* @__PURE__ */ new Map();
17258
- /** 把 Codex 原生 Skill 目录接入 DSH `/` 菜单。 */
17272
+ const skillCapabilityCache = /* @__PURE__ */ new Map();
17273
+ /** 把声明了 Skill 能力的外部 Agent 目录接入 DSH `/` 菜单。 */
17259
17274
  function registerSkillCommand(ctx, options) {
17260
17275
  const state = {
17261
17276
  catalogReady: false,
@@ -17423,11 +17438,20 @@ window.__ModuleLoader__.load({
17423
17438
  return false;
17424
17439
  }
17425
17440
  }
17426
- /** 按会话与 Agent 选择版本缓存目录,避免输入每个字符都请求 Codex。 */
17441
+ /** 按会话与 Agent 选择版本缓存目录,避免输入每个字符都请求外部 CLI。 */
17427
17442
  async function loadSkillCatalog(rpc, sessionId, signal, forceReload) {
17428
17443
  const selectionRevision = cliSessionSelectionRevision(sessionId);
17429
17444
  const cached = skillCatalogCache.get(sessionId);
17430
17445
  if (!forceReload && cached !== void 0 && cached.selectionRevision === selectionRevision && Date.now() - cached.loadedAt < SKILL_CATALOG_CACHE_TTL_MS) return cached.catalog;
17446
+ if (!await supportsSelectedAgentSkills(rpc, sessionId, selectionRevision)) {
17447
+ skillCatalogCache.set(sessionId, {
17448
+ selectionRevision,
17449
+ loadedAt: Date.now(),
17450
+ catalog: []
17451
+ });
17452
+ publishSkillCatalog(sessionId, []);
17453
+ return [];
17454
+ }
17431
17455
  const catalog = await callCliRpc(rpc, "skills", {
17432
17456
  sessionId,
17433
17457
  forceReload: true
@@ -17440,6 +17464,25 @@ window.__ModuleLoader__.load({
17440
17464
  publishSkillCatalog(sessionId, catalog);
17441
17465
  return catalog;
17442
17466
  }
17467
+ /** 让原生 DSH Skill UI 处理 dsh 会话,插件只为声明了 skills 的外部适配器请求目录。 */
17468
+ async function supportsSelectedAgentSkills(rpc, sessionId, selectionRevision) {
17469
+ const cached = skillCapabilityCache.get(sessionId);
17470
+ if (cached?.selectionRevision === selectionRevision) return cached.supported;
17471
+ const session = await callCliRpc(rpc, "session/get", { sessionId });
17472
+ if (session.adapterId === "dsh") {
17473
+ skillCapabilityCache.set(sessionId, {
17474
+ selectionRevision,
17475
+ supported: false
17476
+ });
17477
+ return false;
17478
+ }
17479
+ const supported = (await callCliRpc(rpc, "catalog", {})).find((item) => item.id === session.adapterId)?.capabilities?.includes("skills") === true;
17480
+ skillCapabilityCache.set(sessionId, {
17481
+ selectionRevision,
17482
+ supported
17483
+ });
17484
+ return supported;
17485
+ }
17443
17486
  function skillCommandSpan(draft, draftRev, selection) {
17444
17487
  const caret = selection?.end ?? draft.length;
17445
17488
  const token = /\/(?:skills|技能)(?=\s|$)/gu;
@@ -58662,12 +58705,13 @@ window.__ModuleLoader__.load({
58662
58705
  //#region src/client/peer-host-native-projection.ts
58663
58706
  init_session_adapter_cache();
58664
58707
  /**
58665
- * 为混合工作区生成只用于原生侧栏树归属的稳定路径。
58708
+ * 为需要稳定显示标识的调用方生成虚拟 URI。
58666
58709
  *
58667
58710
  * DSH 会把 `workspace.path` 的目录前缀关系解释成父子工作区。不同 Host 的真实
58668
58711
  * 路径以及本地工作区之间都可能发生前缀重叠,因此列表层不能继续暴露真实目录。
58669
- * 这里使用不对应本机文件系统的 URI,并把完整虚拟 ID 编码成单一段,保证所有
58670
- * 工作区都是同一层的兄弟节点。文件和会话请求仍使用所属 Host 的真实路径。
58712
+ * 这里使用不对应本机文件系统的 URI,并把完整虚拟 ID 编码成单一段。Workspace
58713
+ * Store 使用这个值保证不同 Host 的同路径工作区仍是并列条目;真正的文件请求会在
58714
+ * Host 转发边界按虚拟 Workspace ID还原为目标 Host 的真实路径。
58671
58715
  */
58672
58716
  function createPeerHostWorkspaceDisplayPath(virtualWorkspaceId) {
58673
58717
  return `codingns-peer-host://${encodeURIComponent(virtualWorkspaceId)}`;
@@ -58741,8 +58785,8 @@ window.__ModuleLoader__.load({
58741
58785
  }
58742
58786
  function projectWorkspace(virtualHostId, workspace) {
58743
58787
  const virtualWorkspaceId = createVirtualWorkspaceId(virtualHostId, workspace.workspaceId);
58744
- const displayPath = createPeerHostWorkspaceDisplayPath(virtualWorkspaceId);
58745
58788
  const realPath = workspace.path;
58789
+ const displayPath = createPeerHostWorkspaceDisplayPath(virtualWorkspaceId);
58746
58790
  const sessionIds = [];
58747
58791
  const archivedSessionIds = [];
58748
58792
  const sessions = [];
@@ -58898,7 +58942,7 @@ window.__ModuleLoader__.load({
58898
58942
  }));
58899
58943
  const injected = virtual.filter((workspace) => !known.has(workspace.workspaceId));
58900
58944
  const archivedSessionIds = mergeArchivedSessionIds(record.archivedSessionIds, virtual);
58901
- const mergedItems = normalizeWorkspaceDisplayPaths(orderWorkspaceItems([...items, ...injected], orderedWorkspaceIds, localHostId), localHostId);
58945
+ const mergedItems = normalizeRemoteWorkspaceDisplayPaths(orderWorkspaceItems([...items, ...injected], orderedWorkspaceIds, localHostId));
58902
58946
  if (!(mergedItems.length !== items.length || mergedItems.some((item, index) => item !== items[index])) && archivedSessionIds === void 0) return snapshot;
58903
58947
  return {
58904
58948
  ...record,
@@ -58906,20 +58950,14 @@ window.__ModuleLoader__.load({
58906
58950
  ...archivedSessionIds === void 0 ? {} : { archivedSessionIds }
58907
58951
  };
58908
58952
  }
58909
- /**
58910
- * 原生 Remote 返回的远端工作区可能已经存在于底层 Store,此时不会走 injected
58911
- * 分支;本地条目也可能因真实目录前缀形成树层级。按虚拟 ID统一规范化 path,
58912
- * 保证所有工作区在 DSH 列表中都是同层兄弟节点。
58913
- */
58914
- function normalizeWorkspaceDisplayPaths(items, localHostId) {
58953
+ /** 原生 Remote 可能先把远端条目写入底层 Store,仍需强制保持扁平虚拟显示路径。 */
58954
+ function normalizeRemoteWorkspaceDisplayPaths(items) {
58915
58955
  let changed = false;
58916
58956
  const normalized = items.map((item) => {
58917
58957
  const record = asRecord$1(item);
58918
58958
  const workspaceId = record?.workspaceId;
58919
- if (record === null || typeof workspaceId !== "string") return item;
58920
- const virtualWorkspaceId = parseVirtualWorkspaceId(workspaceId) !== null ? workspaceId : localHostId === void 0 ? void 0 : createVirtualWorkspaceId(localHostId, workspaceId);
58921
- if (virtualWorkspaceId === void 0) return item;
58922
- const displayPath = createPeerHostWorkspaceDisplayPath(virtualWorkspaceId);
58959
+ if (record === null || typeof workspaceId !== "string" || parseVirtualWorkspaceId(workspaceId) === null) return item;
58960
+ const displayPath = createPeerHostWorkspaceDisplayPath(workspaceId);
58923
58961
  if (record.path === displayPath) return item;
58924
58962
  changed = true;
58925
58963
  return {
@@ -58930,9 +58968,8 @@ window.__ModuleLoader__.load({
58930
58968
  return changed ? normalized : items;
58931
58969
  }
58932
58970
  /**
58933
- * 原生会话列表只把空白会话的 cwd 用于判断是否能复用。工作区树扁平化后,
58934
- * 让空白行看到同一个显示路径即可保留该判断;正式会话继续保留真实 cwd,
58935
- * 避免 Git、文件面板或远端工具拿到虚拟 URI。
58971
+ * 原生会话列表只把空白会话的 cwd 用于判断是否能复用;同步工作区真实路径即可
58972
+ * 保留该判断,正式会话也继续保留真实 cwd,避免 Git、文件面板或远端工具拿到虚拟 URI。
58936
58973
  */
58937
58974
  function installSessionDisplayPathProjection(workspaceStore, sessionStore) {
58938
58975
  if (sessionStore === void 0) return () => void 0;
@@ -59388,6 +59425,18 @@ window.__ModuleLoader__.load({
59388
59425
  .${TAB_CLASS}-rowName{overflow:hidden;font-size:13px;font-weight:500;line-height:20px;text-overflow:ellipsis;white-space:nowrap}
59389
59426
  .${TAB_CLASS}-rowMeta{overflow:hidden;font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap}
59390
59427
  .${TAB_CLASS}-rowCount{flex:none;font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums}
59428
+ .${TAB_CLASS}-sectionTitle{margin:4px 0 0;font-size:13px;font-weight:510;line-height:20px;color:var(--dsw-alias-label-primary)}
59429
+ .${TAB_CLASS}-tableWrap{flex:none;overflow-x:auto;margin:0 -8px;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-sm)}
59430
+ .${TAB_CLASS}-table{width:100%;min-width:520px;border-collapse:collapse;table-layout:fixed;font-size:12px;line-height:18px}
59431
+ .${TAB_CLASS}-table th{padding:8px;text-align:left;font-size:11px;font-weight:500;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-interactive-bg-hover);white-space:nowrap}
59432
+ .${TAB_CLASS}-table td{padding:9px 8px;border-top:.5px solid var(--dsw-alias-border-l4);color:var(--dsw-alias-label-primary);vertical-align:top}
59433
+ .${TAB_CLASS}-table th:nth-child(1),.${TAB_CLASS}-table td:nth-child(1){width:25%}
59434
+ .${TAB_CLASS}-table th:nth-child(2),.${TAB_CLASS}-table td:nth-child(2){width:13%;white-space:nowrap}
59435
+ .${TAB_CLASS}-table th:nth-child(3),.${TAB_CLASS}-table td:nth-child(3){width:20%;white-space:nowrap}
59436
+ .${TAB_CLASS}-table th:nth-child(4),.${TAB_CLASS}-table td:nth-child(4){width:42%}
59437
+ .${TAB_CLASS}-tableName{display:block;overflow:hidden;font-weight:500;text-overflow:ellipsis;white-space:nowrap}
59438
+ .${TAB_CLASS}-tablePath{display:block;overflow:hidden;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap}
59439
+ .${TAB_CLASS}-tableEmpty{padding:10px 0;margin:0;font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary)}
59391
59440
  [${PEER_HOST_WORKSPACE_TAB_STATE_ATTRIBUTE}='remote'] ${CRUMB_BAR_SELECTOR},
59392
59441
  [${PEER_HOST_WORKSPACE_TAB_STATE_ATTRIBUTE}='remote'] ${CONTENT_SELECTOR},
59393
59442
  [${PEER_HOST_WORKSPACE_TAB_STATE_ATTRIBUTE}='remote'] ${FOOTER_BAR_SELECTOR}{display:none !important}
@@ -59455,12 +59504,12 @@ window.__ModuleLoader__.load({
59455
59504
  }
59456
59505
  /** 注入样式表;用插件自有标记,停用时按标记精确移除。 */
59457
59506
  function installStyle(dom) {
59458
- if (dom.querySelector(`style[data-plugin-css="${TAB_STYLE_ID}"]`) !== null) return;
59459
- const style = dom.createElement("style");
59507
+ const existing = dom.querySelector(`style[data-plugin-css="${TAB_STYLE_ID}"]`);
59508
+ const style = existing ?? dom.createElement("style");
59460
59509
  style.dataset.plugin = "codingns4dsh";
59461
59510
  style.dataset.pluginCss = TAB_STYLE_ID;
59462
59511
  style.textContent = TAB_STYLE_TEXT;
59463
- dom.head?.appendChild(style);
59512
+ if (existing === null) dom.head?.appendChild(style);
59464
59513
  }
59465
59514
  /** 在原生对话框里建立标签栏与远端面板。 */
59466
59515
  function inject$1(dialog, editorScope, options, previous = null) {
@@ -59496,6 +59545,7 @@ window.__ModuleLoader__.load({
59496
59545
  records: previous?.records ?? null,
59497
59546
  selectedHostId: previous?.selectedHostId ?? null,
59498
59547
  candidates: previous?.candidates ?? null,
59548
+ addedWorkspaces: previous?.addedWorkspaces ?? null,
59499
59549
  loading: false,
59500
59550
  message: previous?.message ?? null,
59501
59551
  messageKind: previous?.messageKind ?? "info",
@@ -59571,6 +59621,7 @@ window.__ModuleLoader__.load({
59571
59621
  if (options === null || state.selectedHostId === record.id) return;
59572
59622
  state.selectedHostId = record.id;
59573
59623
  state.candidates = null;
59624
+ state.addedWorkspaces = null;
59574
59625
  state.message = null;
59575
59626
  render(state, options);
59576
59627
  if (record.status === "ready") loadCandidates(state, options);
@@ -59588,15 +59639,35 @@ window.__ModuleLoader__.load({
59588
59639
  state.panel.append(note(dom, t("peerHostWorkspace.loadingWorkspaces"), "info"));
59589
59640
  return;
59590
59641
  }
59591
- if (state.candidates.length === 0) {
59642
+ if (state.candidates.length === 0 && (state.addedWorkspaces === null || state.addedWorkspaces.length === 0)) {
59592
59643
  if (state.message !== null) state.panel.append(note(dom, state.message, state.messageKind));
59593
59644
  else state.panel.append(note(dom, t("peerHostWorkspace.noWorkspaces"), "info"));
59594
59645
  return;
59595
59646
  }
59647
+ const addedIds = new Set(selected?.visibleWorkspaceIds ?? []);
59648
+ const addedCandidates = state.addedWorkspaces === null ? state.candidates.filter((candidate) => addedIds.has(candidate.workspaceId)) : state.addedWorkspaces;
59649
+ const addedWorkspaceIds = new Set(addedCandidates.map((candidate) => candidate.workspaceId));
59650
+ const availableCandidates = state.candidates.filter((candidate) => !addedWorkspaceIds.has(candidate.workspaceId) && !addedIds.has(candidate.workspaceId));
59651
+ const addedHeading = dom.createElement("strong");
59652
+ addedHeading.className = `${TAB_CLASS}-sectionTitle`;
59653
+ addedHeading.textContent = t("peerHostWorkspace.addedHeading");
59654
+ state.panel.append(addedHeading);
59655
+ if (addedCandidates.length === 0) {
59656
+ const empty = dom.createElement("p");
59657
+ empty.className = `${TAB_CLASS}-tableEmpty`;
59658
+ empty.textContent = t("peerHostWorkspace.noAddedWorkspaces");
59659
+ state.panel.append(empty);
59660
+ } else state.panel.append(createWorkspaceTable(dom, t, selected?.displayName ?? "", addedCandidates));
59661
+ if (availableCandidates.length > 0) {
59662
+ const availableHeading = dom.createElement("strong");
59663
+ availableHeading.className = `${TAB_CLASS}-sectionTitle`;
59664
+ availableHeading.textContent = t("peerHostWorkspace.availableHeading");
59665
+ state.panel.append(availableHeading);
59666
+ }
59596
59667
  const list = dom.createElement("div");
59597
59668
  list.className = `${TAB_CLASS}-list`;
59598
59669
  list.setAttribute("role", "list");
59599
- for (const candidate of state.candidates) {
59670
+ for (const candidate of availableCandidates) {
59600
59671
  const row = dom.createElement("button");
59601
59672
  row.type = "button";
59602
59673
  row.className = `${TAB_CLASS}-row`;
@@ -59624,9 +59695,56 @@ window.__ModuleLoader__.load({
59624
59695
  });
59625
59696
  list.append(row);
59626
59697
  }
59627
- state.panel.append(list);
59698
+ if (availableCandidates.length > 0) state.panel.append(list);
59628
59699
  if (state.message !== null) state.panel.append(note(dom, state.message, state.messageKind));
59629
59700
  }
59701
+ /** 渲染已添加工作区的只读信息表;添加动作仍由下方候选列表负责。 */
59702
+ function createWorkspaceTable(dom, t, hostName, candidates) {
59703
+ const wrapper = dom.createElement("div");
59704
+ wrapper.className = `${TAB_CLASS}-tableWrap`;
59705
+ const table = dom.createElement("table");
59706
+ table.className = `${TAB_CLASS}-table`;
59707
+ table.setAttribute("aria-label", t("peerHostWorkspace.addedHeading"));
59708
+ const head = dom.createElement("thead");
59709
+ const headerRow = dom.createElement("tr");
59710
+ for (const label of [
59711
+ t("peerHostWorkspace.columnWorkspace"),
59712
+ t("peerHostWorkspace.columnSessions"),
59713
+ t("peerHostWorkspace.columnHost"),
59714
+ t("peerHostWorkspace.columnPath")
59715
+ ]) {
59716
+ const cell = dom.createElement("th");
59717
+ cell.setAttribute("scope", "col");
59718
+ cell.textContent = label;
59719
+ headerRow.append(cell);
59720
+ }
59721
+ head.append(headerRow);
59722
+ const body = dom.createElement("tbody");
59723
+ for (const candidate of candidates) {
59724
+ const row = dom.createElement("tr");
59725
+ row.setAttribute("data-codingns-peer-host-tab-added-workspace", candidate.workspaceId);
59726
+ const name = dom.createElement("td");
59727
+ const nameText = dom.createElement("span");
59728
+ nameText.className = `${TAB_CLASS}-tableName`;
59729
+ nameText.textContent = candidate.displayName;
59730
+ name.append(nameText);
59731
+ const sessions = dom.createElement("td");
59732
+ sessions.textContent = candidate.sessionCount === 0 ? t("peerHostWorkspace.noSessions") : t("peerHostWorkspace.sessionCount", { count: candidate.sessionCount });
59733
+ const host = dom.createElement("td");
59734
+ host.textContent = hostName;
59735
+ const path = dom.createElement("td");
59736
+ path.title = candidate.path;
59737
+ const pathText = dom.createElement("span");
59738
+ pathText.className = `${TAB_CLASS}-tablePath`;
59739
+ pathText.textContent = candidate.path;
59740
+ path.append(pathText);
59741
+ row.append(name, sessions, host, path);
59742
+ body.append(row);
59743
+ }
59744
+ table.append(head, body);
59745
+ wrapper.append(table);
59746
+ return wrapper;
59747
+ }
59630
59748
  async function loadRecords(state, options) {
59631
59749
  const generation = ++state.generation;
59632
59750
  try {
@@ -59646,12 +59764,21 @@ window.__ModuleLoader__.load({
59646
59764
  if (hostId === null) return;
59647
59765
  const generation = ++state.generation;
59648
59766
  try {
59649
- const candidates = await options.api.workspaceCandidates(hostId);
59767
+ const [candidateResult, aggregateResult] = await Promise.allSettled([options.api.workspaceCandidates(hostId), options.api.aggregate()]);
59650
59768
  if (state.generation !== generation || state.selectedHostId !== hostId) return;
59651
- state.candidates = candidates;
59769
+ if (candidateResult.status === "rejected") throw candidateResult.reason;
59770
+ state.candidates = candidateResult.value;
59771
+ const aggregateHost = aggregateResult.status === "fulfilled" ? aggregateResult.value.find((result) => result.targetHostId === hostId) : void 0;
59772
+ state.addedWorkspaces = aggregateHost?.availability === "ready" ? aggregateHost.workspaces.map((workspace) => ({
59773
+ workspaceId: workspace.workspaceId,
59774
+ displayName: workspace.displayName,
59775
+ path: workspace.path,
59776
+ sessionCount: workspace.sessions.length + (workspace.archivedSessions?.length ?? 0)
59777
+ })) : null;
59652
59778
  } catch (error) {
59653
59779
  if (state.generation !== generation || state.selectedHostId !== hostId) return;
59654
59780
  state.candidates = [];
59781
+ state.addedWorkspaces = [];
59655
59782
  state.message = message(error);
59656
59783
  state.messageKind = "error";
59657
59784
  }
@@ -59664,7 +59791,14 @@ window.__ModuleLoader__.load({
59664
59791
  state.message = null;
59665
59792
  render(state, options);
59666
59793
  try {
59667
- await options.api.setWorkspaceVisibility(hostId, workspaceId, true);
59794
+ const updated = await options.api.setWorkspaceVisibility(hostId, workspaceId, true);
59795
+ if (updated !== void 0) state.records = state.records?.map((record) => record.id === hostId ? updated : record) ?? state.records;
59796
+ const added = state.candidates?.find((candidate) => candidate.workspaceId === workspaceId);
59797
+ if (added !== void 0) {
59798
+ const visibleIds = new Set(state.records?.find((record) => record.id === hostId)?.visibleWorkspaceIds ?? []);
59799
+ const current = state.addedWorkspaces ?? state.candidates?.filter((candidate) => visibleIds.has(candidate.workspaceId)) ?? [];
59800
+ if (!current.some((workspace) => workspace.workspaceId === added.workspaceId)) state.addedWorkspaces = [...current, added];
59801
+ }
59668
59802
  state.message = state.t("peerHostWorkspace.added");
59669
59803
  state.messageKind = "success";
59670
59804
  await options.onWorkspaceAdded?.(hostId, workspaceId);
@@ -66575,10 +66709,10 @@ window.__ModuleLoader__.load({
66575
66709
  .${terminalClass.toolAction}[aria-pressed="true"],.${terminalClass.toolModifierActive}{background:var(--dsw-alias-button-ghost-active-fill,var(--dsw-alias-interactive-bg-active));box-shadow:inset 0 0 0 .5px var(--dsw-alias-button-ghost-active-border,var(--dsw-alias-border-l3))}
66576
66710
  .${terminalClass.listRow}{box-sizing:border-box;display:flex;align-items:center;height:28px;min-width:110px;max-width:220px;border-radius:var(--dsw-radius-sm,6px);background:transparent;flex:none}
66577
66711
  .${terminalClass.listRowSelected}{background:var(--dsw-alias-interactive-bg-hover);box-shadow:var(--dsw-elevation-soft,0 1px 2px rgba(0,0,0,.08))}
66578
- .${terminalClass.listSelect}{box-sizing:border-box;min-width:0;height:28px;min-height:28px;flex:1;text-align:left;color:inherit;border:0;background:transparent;cursor:pointer;padding:0 8px;display:flex;align-items:center;gap:5px;font:inherit;line-height:20px}
66712
+ .${terminalClass.listSelect}{box-sizing:border-box;min-width:0;height:28px;min-height:28px;flex:1;text-align:left;color:inherit;border:0;background:transparent;cursor:pointer;padding:0 8px;display:flex;align-items:center;gap:5px;font:inherit;font-size:12px;line-height:20px}
66579
66713
  .${terminalClass.listSelect} span{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
66580
66714
  .${terminalClass.listSelect} small{color:var(--dsw-alias-label-caption);font-size:11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
66581
- .${terminalClass.listInput}{box-sizing:border-box;min-width:0;height:24px;min-height:24px;flex:1;margin:0 4px;color:inherit;background:var(--dsw-alias-bg-base);border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-sm,6px);padding:0 6px;font:inherit;line-height:20px}
66715
+ .${terminalClass.listInput}{box-sizing:border-box;min-width:0;height:24px;min-height:24px;flex:1;margin:0 4px;color:inherit;background:var(--dsw-alias-bg-base);border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-sm,6px);padding:0 6px;font:inherit;font-size:12px;line-height:20px}
66582
66716
  .${terminalClass.listClose}{box-sizing:border-box;width:28px;height:28px;min-height:28px;padding:0;border:0;color:var(--dsw-alias-label-secondary);background:transparent;cursor:pointer;font:inherit;font-size:16px;line-height:20px;flex:none}
66583
66717
  .${terminalClass.listClose}:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}
66584
66718
  .${terminalClass.content}{box-sizing:border-box;width:100%;min-width:0;min-height:0;display:flex;flex:1 1 auto;overflow:hidden}