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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/README.en.md +25 -14
  2. package/README.md +17 -15
  3. package/data/build/dist/client/bundle.js +198 -47
  4. package/data/build/dist/client/bundle.js.map +1 -1
  5. package/data/build/dist/client/locales/fileWorkspace.d.ts.map +1 -1
  6. package/data/build/dist/client/locales/fileWorkspace.js +4 -0
  7. package/data/build/dist/client/locales/fileWorkspace.js.map +1 -1
  8. package/data/build/dist/client/session-changed-files-view.d.ts.map +1 -1
  9. package/data/build/dist/client/session-changed-files-view.js +162 -58
  10. package/data/build/dist/client/session-changed-files-view.js.map +1 -1
  11. package/data/build/dist/host/cli-adapters/acp-cli-driver.d.ts +8 -3
  12. package/data/build/dist/host/cli-adapters/acp-cli-driver.d.ts.map +1 -1
  13. package/data/build/dist/host/cli-adapters/acp-cli-driver.js +99 -6
  14. package/data/build/dist/host/cli-adapters/acp-cli-driver.js.map +1 -1
  15. package/data/build/dist/host/cli-adapters/acp-elicitation.d.ts +31 -0
  16. package/data/build/dist/host/cli-adapters/acp-elicitation.d.ts.map +1 -0
  17. package/data/build/dist/host/cli-adapters/acp-elicitation.js +144 -0
  18. package/data/build/dist/host/cli-adapters/acp-elicitation.js.map +1 -0
  19. package/data/build/dist/host/cli-adapters/antigravity-driver.d.ts +2 -1
  20. package/data/build/dist/host/cli-adapters/antigravity-driver.d.ts.map +1 -1
  21. package/data/build/dist/host/cli-adapters/antigravity-driver.js +15 -2
  22. package/data/build/dist/host/cli-adapters/antigravity-driver.js.map +1 -1
  23. package/data/build/dist/host/cli-adapters/claude-driver.d.ts +10 -1
  24. package/data/build/dist/host/cli-adapters/claude-driver.d.ts.map +1 -1
  25. package/data/build/dist/host/cli-adapters/claude-driver.js +134 -2
  26. package/data/build/dist/host/cli-adapters/claude-driver.js.map +1 -1
  27. package/data/build/dist/host/cli-adapters/codebuddy-driver.d.ts +7 -1
  28. package/data/build/dist/host/cli-adapters/codebuddy-driver.d.ts.map +1 -1
  29. package/data/build/dist/host/cli-adapters/codebuddy-driver.js +143 -6
  30. package/data/build/dist/host/cli-adapters/codebuddy-driver.js.map +1 -1
  31. package/data/build/dist/host/cli-adapters/command-code-driver.d.ts.map +1 -1
  32. package/data/build/dist/host/cli-adapters/command-code-driver.js +20 -8
  33. package/data/build/dist/host/cli-adapters/command-code-driver.js.map +1 -1
  34. package/data/build/dist/host/cli-adapters/cursor-driver.d.ts +1 -1
  35. package/data/build/dist/host/cli-adapters/cursor-driver.js +2 -2
  36. package/data/build/dist/host/cli-adapters/cursor-driver.js.map +1 -1
  37. package/data/build/dist/host/cli-adapters/delegation-mention-rewrite.js +1 -1
  38. package/data/build/dist/host/cli-adapters/delegation-mention-rewrite.js.map +1 -1
  39. package/data/build/dist/host/cli-adapters/feature.d.ts.map +1 -1
  40. package/data/build/dist/host/cli-adapters/feature.js +4 -2
  41. package/data/build/dist/host/cli-adapters/feature.js.map +1 -1
  42. package/data/build/dist/host/cli-adapters/gemini-driver.d.ts +2 -1
  43. package/data/build/dist/host/cli-adapters/gemini-driver.d.ts.map +1 -1
  44. package/data/build/dist/host/cli-adapters/gemini-driver.js +66 -11
  45. package/data/build/dist/host/cli-adapters/gemini-driver.js.map +1 -1
  46. package/data/build/dist/host/cli-adapters/grok-driver.d.ts +3 -2
  47. package/data/build/dist/host/cli-adapters/grok-driver.d.ts.map +1 -1
  48. package/data/build/dist/host/cli-adapters/grok-driver.js +65 -14
  49. package/data/build/dist/host/cli-adapters/grok-driver.js.map +1 -1
  50. package/data/build/dist/host/cli-adapters/kiro-driver.js +1 -1
  51. package/data/build/dist/host/cli-adapters/kiro-driver.js.map +1 -1
  52. package/data/build/dist/host/cli-adapters/mcode-driver.d.ts +6 -2
  53. package/data/build/dist/host/cli-adapters/mcode-driver.d.ts.map +1 -1
  54. package/data/build/dist/host/cli-adapters/mcode-driver.js +93 -24
  55. package/data/build/dist/host/cli-adapters/mcode-driver.js.map +1 -1
  56. package/data/build/dist/host/cli-adapters/native-subagent-dispatch.d.ts +55 -1
  57. package/data/build/dist/host/cli-adapters/native-subagent-dispatch.d.ts.map +1 -1
  58. package/data/build/dist/host/cli-adapters/native-subagent-dispatch.js +148 -6
  59. package/data/build/dist/host/cli-adapters/native-subagent-dispatch.js.map +1 -1
  60. package/data/build/dist/host/cli-adapters/native-team-subagent.d.ts +7 -0
  61. package/data/build/dist/host/cli-adapters/native-team-subagent.d.ts.map +1 -1
  62. package/data/build/dist/host/cli-adapters/native-team-subagent.js.map +1 -1
  63. package/data/build/dist/host/cli-adapters/qoder-driver.d.ts +4 -4
  64. package/data/build/dist/host/cli-adapters/qoder-driver.d.ts.map +1 -1
  65. package/data/build/dist/host/cli-adapters/qoder-driver.js +31 -8
  66. package/data/build/dist/host/cli-adapters/qoder-driver.js.map +1 -1
  67. package/data/build/dist/host/cli-adapters/standard-stream-driver.js +3 -1
  68. package/data/build/dist/host/cli-adapters/standard-stream-driver.js.map +1 -1
  69. package/data/build/dist/host/cli-adapters/subagent-tool.d.ts.map +1 -1
  70. package/data/build/dist/host/cli-adapters/subagent-tool.js +40 -10
  71. package/data/build/dist/host/cli-adapters/subagent-tool.js.map +1 -1
  72. package/data/build/dist/host/cli-bridge/bridge-holder.d.ts +4 -1
  73. package/data/build/dist/host/cli-bridge/bridge-holder.d.ts.map +1 -1
  74. package/data/build/dist/host/cli-bridge/bridge-holder.js.map +1 -1
  75. package/data/build/dist/host/cli-bridge/bridge-server.d.ts +11 -3
  76. package/data/build/dist/host/cli-bridge/bridge-server.d.ts.map +1 -1
  77. package/data/build/dist/host/cli-bridge/bridge-server.js +8 -4
  78. package/data/build/dist/host/cli-bridge/bridge-server.js.map +1 -1
  79. package/data/build/dist/host/cli-bridge/command-code-mod.js +18 -2
  80. package/data/build/dist/host/cli-bridge/command-code-mod.js.map +1 -1
  81. package/data/build/dist/host/cli-bridge/dispatch.d.ts.map +1 -1
  82. package/data/build/dist/host/cli-bridge/dispatch.js +30 -5
  83. package/data/build/dist/host/cli-bridge/dispatch.js.map +1 -1
  84. package/data/build/dist/host/cli-bridge/injections.js +2 -2
  85. package/data/build/dist/host/cli-bridge/injections.js.map +1 -1
  86. package/data/build/dist/host/cli-bridge/mcp-stdio-entry.js +49 -7
  87. package/data/build/dist/host/cli-bridge/mcp-stdio-entry.js.map +1 -1
  88. package/data/build/dist/host/index.d.ts +1 -1
  89. package/data/build/dist/host/index.d.ts.map +1 -1
  90. package/data/build/dist/host/index.js +1 -1
  91. package/data/build/dist/host/index.js.map +1 -1
  92. package/data/build/dist/shared/contracts/version.d.ts +1 -1
  93. package/data/build/dist/shared/contracts/version.js +1 -1
  94. package/package.json +1 -1
  95. package/profile/README.md +2 -2
  96. package/profile/package.json +2 -2
  97. package/profile/version.json +1 -1
  98. 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.1`** · 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.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
15
15
 
16
16
  **[GitHub](https://github.com/jingyi0605/Codingns4DSH)** · **[npm](https://www.npmjs.com/package/@jingyi0605/codingns4dsh)** · **QQ group 1092985965**
17
17
 
@@ -74,21 +74,32 @@ Notes: the sidebar terminal exists as soon as the plugin is installed — **Term
74
74
 
75
75
  Detected on the Host by command name; version and models come from the CLI itself. Detected Agents are enabled by default and can be toggled individually. The built-in **DeepSeek Harness** Agent is always available.
76
76
 
77
- | Agent | id | Command | Protocol | Capabilities |
78
- | --- | --- | --- | --- | --- |
79
- | Command Code | `command-code` | `command-code`, `commandcode`, `cmdc` | single-shot CLI | models, streaming, resume, interrupt, tools, thinking, usage |
80
- | Claude Code | `claude-code` | `claude` | stream-json | models, streaming, resume, interrupt, tools, thinking, usage |
81
- | Kimi CLI | `kimi` | `kimi`, `kimi-cli` | stream-json | all of the above + approvals, questions, steering |
82
- | Gemini CLI | `gemini` | `gemini` | ACP | models, streaming, resume, interrupt, tools, thinking, usage, approvals |
83
- | Pi Agent | `pi` | `pi`, `pi-agent` | JSON-RPC | models, streaming, resume, interrupt, tools, thinking, usage, steering |
84
- | Codex | `codex` | `codex` | JSON-RPC (app-server) | all + approvals, questions, steering |
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 |
77
+ | Agent | id | Command | Protocol | Capabilities | Notes |
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 |
80
+ | Claude Code | `claude-code` | `claude` | stream-json | models, streaming, resume, interrupt, tools, thinking, usage, approvals, questions | `can_use_tool` approvals and `AskUserQuestion` |
81
+ | Kimi CLI | `kimi` | `kimi`, `kimi-cli` | stream-json | all of the above + approvals, questions, steering | — |
82
+ | Gemini CLI | `gemini` | `gemini` | ACP | models, streaming, resume, interrupt, tools, thinking, usage, approvals, questions | ACP permissions and form elicitation |
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 | — |
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 |
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
+ | ZCode | `zcode` | `zcode`, bundled desktop runtime | JSON-RPC bare envelope | models, streaming, resume, interrupt, usage | No verifiable DSH approval/question response wire |
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 |
90
+ | WorkBuddy | `workbuddy` | `codebuddy` bundled in the WorkBuddy desktop app | ACP (`--acp`) | models, streaming, resume, interrupt, tools, thinking, approvals, questions | Permissions and form elicitation use the HTTP ACP sidecar |
91
+ | Cursor CLI | `cursor-cli` | `cursor-agent`, `agent` | ACP (`acp`) | models, streaming, resume, interrupt, tools, thinking, approvals, questions | Standard ACP permissions and form elicitation |
92
+ | Kiro CLI | `kiro-cli` | `kiro-cli` | ACP (`acp --agent-engine v3 --auth-method cli`) | models, streaming, resume, interrupt, tools, thinking, approvals, questions | Standard ACP permissions and form elicitation |
93
+ | Qoder | `qoder` | `qoder`, `qodercli` | ACP (`--acp`) | models, streaming, resume, interrupt, tools, thinking, approvals, questions | Standard ACP permissions and form elicitation |
94
+ | Qoder CN | `qoder-cn` | `qodercn`, `qoderclicn` | ACP (`--acp`) | models, streaming, resume, interrupt, tools, thinking, approvals, questions | Standard ACP permissions and form elicitation |
95
+ | Antigravity | `antigravity` | `agy` | stream-json (stdin NDJSON) | models, streaming, resume, interrupt, tools, thinking | Permission state maps to CLI safety modes; no interactive approval/question wire |
87
96
 
88
97
  **models** model list · **streaming** live output · **resume** continue after restart · **interrupt** cancel a turn · **tools** tool calls in the conversation · **thinking** reasoning/effort · **usage** token or subscription limits · **approvals / questions** native DSH interactions · **steering** inject a message mid-turn.
89
98
 
90
99
  Unlisted capabilities are unsupported by that CLI or version. Install and log in to each Agent outside DSH; Codingns4DSH never stores Agent credentials.
91
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.
102
+
92
103
  ---
93
104
 
94
105
  ## Feature Details
@@ -223,7 +234,7 @@ The “access” line tells you whether you entered DSH Web locally, over the LA
223
234
  DSH automatically initializes the `web` profile on first use. You do not need to create a config file or run `--dump-config`:
224
235
 
225
236
  ```bash
226
- dsh plugin --profile web add @jingyi0605/codingns4dsh@0.2.1-beta.1
237
+ dsh plugin --profile web add @jingyi0605/codingns4dsh@0.2.1-beta.2
227
238
  dsh web
228
239
  ```
229
240
 
@@ -233,7 +244,7 @@ If you do not want to modify the built-in `web` profile, create a separate profi
233
244
 
234
245
  ```bash
235
246
  dsh codingns --from-default-profile web --dump-config
236
- dsh plugin --profile codingns add @jingyi0605/codingns4dsh@0.2.1-beta.1
247
+ dsh plugin --profile codingns add @jingyi0605/codingns4dsh@0.2.1-beta.2
237
248
  dsh codingns
238
249
  ```
239
250
 
@@ -254,7 +265,7 @@ dsh plugin --profile web remove @jingyi0605/codingns4dsh
254
265
  ```bash
255
266
  git clone https://github.com/jingyi0605/Codingns4DSH.git && cd Codingns4DSH
256
267
  pnpm install && pnpm build
257
- dsh plugin --profile web add "$PWD" # or: npm pack, then add ./jingyi0605-codingns4dsh-0.2.1-beta.1.tgz
268
+ dsh plugin --profile web add "$PWD" # or: npm pack, then add ./jingyi0605-codingns4dsh-0.2.1-beta.2.tgz
258
269
  dsh web
259
270
  ```
260
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.1`** · 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.2`** · 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,28 +76,30 @@ DSH 原生部分不会被替换:对话、会话列表、侧栏、设置、权
76
76
 
77
77
  | Agent | id | 命令 | 协议 | 能力 | 备注 |
78
78
  | --- | --- | --- | --- | --- | --- |
79
- | Command Code | `command-code` | `command-code`、`commandcode`、`cmdc` | 单轮 CLI | 模型、流式、恢复、打断、工具、思考、用量 | — |
80
- | Claude Code | `claude-code` | `claude` | stream-json | 模型、流式、恢复、打断、工具、思考、用量 | — |
79
+ | Command Code | `command-code` | `command-code`、`commandcode`、`cmdc` | 单轮 CLI | 模型、流式、恢复、打断、工具、思考、用量 | 权限按 DSH 状态映射为 CLI 安全模式;没有可回传的交互式权限/提问协议 |
80
+ | Claude Code | `claude-code` | `claude` | stream-json | 模型、流式、恢复、打断、工具、思考、用量、权限确认、提问 | `can_use_tool` 权限确认与 `AskUserQuestion` 提问 |
81
81
  | Kimi CLI | `kimi` | `kimi`、`kimi-cli` | stream-json | 上述全部 + 权限确认、提问、插话 | — |
82
- | Gemini CLI | `gemini` | `gemini` | ACP | 模型、流式、恢复、打断、工具、思考、用量、权限确认 | — |
83
- | Pi Agent | `pi` | `pi`、`pi-agent` | JSON-RPC | 模型、流式、恢复、打断、工具、思考、用量、插话 | — |
82
+ | Gemini CLI | `gemini` | `gemini` | ACP | 模型、流式、恢复、打断、工具、思考、用量、权限确认、提问 | ACP 权限与 form elicitation(表单式询问) |
83
+ | Pi Agent | `pi` | `pi`、`pi-agent` | JSON-RPC | 模型、流式、恢复、打断、工具、思考、用量、插话 | 当前协议没有可验证的 DSH 权限/提问回传 |
84
84
  | Codex | `codex` | `codex` | JSON-RPC(app-server) | 全部 + 权限确认、提问、插话 | — |
85
85
  | OpenCode | `opencode` | `opencode`,或 `OPENCODE_SERVER_URL`(默认 `http://127.0.0.1:4096`) | HTTP + SSE | 全部 + 权限确认、提问 | — |
86
- | Grok Build | `grok` | `grok`、`grok-build` | ACP | 模型、流式、工具、思考、用量、权限确认 | — |
87
- | MiniMax Code | `mcode` | `mcode` | ACP / stream-json | 模型、流式、恢复、打断、工具、思考、用量 | 上游贡献者:[chenjunyi000](https://github.com/chenjunyi000);提交 PR [#6](https://github.com/jingyi0605/Codingns4DSH/pull/6)、[#7](https://github.com/jingyi0605/Codingns4DSH/pull/7) |
86
+ | Grok Build | `grok` | `grok`、`grok-build` | ACP | 模型、流式、工具、思考、用量、权限确认、提问 | ACP 权限与 form elicitation(表单式询问) |
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
- | CodeBuddy(自动识别 CN/国际版) | `codebuddy` | `codebuddy`、`codebuddy-code`、`cbc` 及 Windows `.cmd` 入口;按环境变量与认证域名自动选择区域 | ACP(`--acp`) | 模型、流式、恢复、打断、工具、思考、用量 | CodexHost 上游贡献者:[mouzhi](https://github.com/mouzhi);首次适配 [f30b000](https://github.com/BytePioneer-AI/codex-host/commit/f30b000f88950c40844b071eec2f6f385c6bcb49) |
90
- | WorkBuddy | `workbuddy` | WorkBuddy 桌面应用内置 `codebuddy` | ACP(`--acp`) | 模型、流式、恢复、打断、工具、思考 | CodexHost 上游贡献者:[BytePioneer-AI(ChongWen)](https://github.com/BytePioneer-AI);首次适配 [6e9f365](https://github.com/BytePioneer-AI/codex-host/commit/6e9f365e2bf8ac61716f8250475530ae790f2d2f) |
91
- | Cursor CLI | `cursor-cli` | `cursor-agent`、`agent` | ACP(`acp`) | 模型、流式、恢复、打断、工具、思考 | CodexHost 上游贡献者:[mouzhi](https://github.com/mouzhi);首次适配 [ad6ba8e](https://github.com/BytePioneer-AI/codex-host/commit/ad6ba8e04d294c473d2dcad99880496ff39c1f7e) |
92
- | Kiro CLI | `kiro-cli` | `kiro-cli` | ACP(`acp --agent-engine v3 --auth-method cli`) | 模型、流式、恢复、打断、工具、思考 | CodexHost 上游贡献者:[gy212](https://github.com/gy212);首次适配 [79675cd](https://github.com/BytePioneer-AI/codex-host/commit/79675cdbfdc042eb37a849c3eb1539e9efc40a0d) |
93
- | Qoder | `qoder` | `qoder`、`qodercli` | ACP(`--acp`) | 模型、流式、恢复、打断、工具、思考、权限确认 | CodexHost 上游贡献者:[gy212](https://github.com/gy212)、[BytePioneer-AI(ChongWen)](https://github.com/BytePioneer-AI);PR #289 合并 [8926130](https://github.com/BytePioneer-AI/codex-host/commit/8926130af1426a467747b66d8d2dbf68f7764a7b) |
94
- | Qoder CN | `qoder-cn` | `qodercn`、`qoderclicn` | ACP(`--acp`) | 模型、流式、恢复、打断、工具、思考、权限确认 | CodexHost 上游贡献者:[gy212](https://github.com/gy212)、[BytePioneer-AI(ChongWen)](https://github.com/BytePioneer-AI);PR #289 合并 [8926130](https://github.com/BytePioneer-AI/codex-host/commit/8926130af1426a467747b66d8d2dbf68f7764a7b) |
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) |
90
+ | WorkBuddy | `workbuddy` | WorkBuddy 桌面应用内置 `codebuddy` | ACP(`--acp`) | 模型、流式、恢复、打断、工具、思考、权限确认、提问 | 通过 HTTP ACP sidecar(旁路服务)接入权限与 form elicitation(表单式询问);CodexHost 上游贡献者:[BytePioneer-AI(ChongWen)](https://github.com/BytePioneer-AI);首次适配 [6e9f365](https://github.com/BytePioneer-AI/codex-host/commit/6e9f365e2bf8ac61716f8250475530ae790f2d2f) |
91
+ | Cursor CLI | `cursor-cli` | `cursor-agent`、`agent` | ACP(`acp`) | 模型、流式、恢复、打断、工具、思考、权限确认、提问 | ACP 标准权限与 form elicitation(表单式询问);CodexHost 上游贡献者:[mouzhi](https://github.com/mouzhi);首次适配 [ad6ba8e](https://github.com/BytePioneer-AI/codex-host/commit/ad6ba8e04d294c473d2dcad99880496ff39c1f7e) |
92
+ | Kiro CLI | `kiro-cli` | `kiro-cli` | ACP(`acp --agent-engine v3 --auth-method cli`) | 模型、流式、恢复、打断、工具、思考、权限确认、提问 | ACP 标准权限与 form elicitation(表单式询问);CodexHost 上游贡献者:[gy212](https://github.com/gy212);首次适配 [79675cd](https://github.com/BytePioneer-AI/codex-host/commit/79675cdbfdc042eb37a849c3eb1539e9efc40a0d) |
93
+ | Qoder | `qoder` | `qoder`、`qodercli` | ACP(`--acp`) | 模型、流式、恢复、打断、工具、思考、权限确认、提问 | ACP 标准权限与 form elicitation(表单式询问);CodexHost 上游贡献者:[gy212](https://github.com/gy212)、[BytePioneer-AI(ChongWen)](https://github.com/BytePioneer-AI);PR #289 合并 [8926130](https://github.com/BytePioneer-AI/codex-host/commit/8926130af1426a467747b66d8d2dbf68f7764a7b) |
94
+ | Qoder CN | `qoder-cn` | `qodercn`、`qoderclicn` | ACP(`--acp`) | 模型、流式、恢复、打断、工具、思考、权限确认、提问 | ACP 标准权限与 form elicitation(表单式询问);CodexHost 上游贡献者:[gy212](https://github.com/gy212)、[BytePioneer-AI(ChongWen)](https://github.com/BytePioneer-AI);PR #289 合并 [8926130](https://github.com/BytePioneer-AI/codex-host/commit/8926130af1426a467747b66d8d2dbf68f7764a7b) |
95
95
  | Antigravity | `antigravity` | `agy` | stream-json(stdin NDJSON) | 模型、流式、恢复、打断、工具、思考 | CodexHost 上游贡献者:[gy212](https://github.com/gy212);首次适配 [ed4e785](https://github.com/BytePioneer-AI/codex-host/commit/ed4e785116642eafc08e4186e92e83f3816c7765) |
96
96
 
97
97
  **模型** 模型列表 · **流式** 实时输出 · **恢复** 重启后继续 · **打断** 取消当前回合 · **工具** 对话中渲染工具调用 · **思考** 推理/思考强度 · **用量** token 或订阅额度 · **权限确认 / 提问** 变成 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 安全模式。
102
+
101
103
  ---
102
104
 
103
105
  ## 功能详解
@@ -238,7 +240,7 @@ DSH 设置按钮旁的账户入口会显示登录状态、访问路径与延迟
238
240
  DSH 的 `web` Profile 会在首次使用时自动初始化,不需要手动创建配置文件,也不需要执行 `--dump-config`:
239
241
 
240
242
  ```bash
241
- dsh plugin --profile web add @jingyi0605/codingns4dsh@0.2.1-beta.1
243
+ dsh plugin --profile web add @jingyi0605/codingns4dsh@0.2.1-beta.2
242
244
  dsh web
243
245
  ```
244
246
 
@@ -248,7 +250,7 @@ dsh web
248
250
 
249
251
  ```bash
250
252
  dsh codingns --from-default-profile web --dump-config
251
- dsh plugin --profile codingns add @jingyi0605/codingns4dsh@0.2.1-beta.1
253
+ dsh plugin --profile codingns add @jingyi0605/codingns4dsh@0.2.1-beta.2
252
254
  dsh codingns
253
255
  ```
254
256
 
@@ -296,6 +296,8 @@ window.__ModuleLoader__.load({
296
296
  "sessionFiles.title": "Changed files",
297
297
  "sessionFiles.count": "{count} files",
298
298
  "sessionFiles.refresh": "Refresh",
299
+ "sessionFiles.close": "Close diff",
300
+ "sessionFiles.loadingDiff": "Reading diff…",
299
301
  "sessionFiles.stageAll": "Stage all",
300
302
  "sessionFiles.loading": "Reading session changes…",
301
303
  "sessionFiles.empty": "No changed files were detected in this session",
@@ -362,6 +364,8 @@ window.__ModuleLoader__.load({
362
364
  "sessionFiles.title": "修改文件",
363
365
  "sessionFiles.count": "{count} 个文件",
364
366
  "sessionFiles.refresh": "刷新",
367
+ "sessionFiles.close": "关闭 Diff",
368
+ "sessionFiles.loadingDiff": "正在读取 Diff…",
365
369
  "sessionFiles.stageAll": "全部暂存",
366
370
  "sessionFiles.loading": "正在读取会话修改…",
367
371
  "sessionFiles.empty": "本次会话没有已识别的修改文件",
@@ -2788,7 +2792,7 @@ window.__ModuleLoader__.load({
2788
2792
  return /^0\.1\.5(?:-|$)/u.test(version);
2789
2793
  }
2790
2794
  /** Codingns4DSH 插件自身的 npm 版本。 */
2791
- const CODINGNS_VERSION = "0.2.1-beta.1";
2795
+ const CODINGNS_VERSION = "0.2.1-beta.2";
2792
2796
  /** 判断宿主版本是否落在当前插件声明的 DSH 兼容范围内;范围省略上界时不校验上限。 */
2793
2797
  function isDshVersionCompatible(version) {
2794
2798
  const match = /^>=([^ ]+)(?: <=([^ ]+))?$/u.exec(DSH_COMPATIBILITY);
@@ -56021,8 +56025,11 @@ window.__ModuleLoader__.load({
56021
56025
  }
56022
56026
  //#endregion
56023
56027
  //#region src/client/session-changed-files-view.ts
56028
+ init_popup_dismiss();
56024
56029
  init_locale();
56025
56030
  const SESSION_CHANGED_FILES_VIEW_ID = "codingns4dsh/session-changed-files";
56031
+ /** 后台轮询只负责兜底发现外部文件变化,不能和页面交互争夺刷新节奏。 */
56032
+ const SESSION_CHANGED_FILES_BACKGROUND_REFRESH_MS = 3e4;
56026
56033
  /** 会话“修改文件”视图;数据只通过插件 RPC 和现有 Git RPC 读取。 */
56027
56034
  function SessionChangedFilesView(props) {
56028
56035
  const t = props.t;
@@ -56031,50 +56038,68 @@ window.__ModuleLoader__.load({
56031
56038
  const [changes, setChanges] = (0, react.useState)([]);
56032
56039
  const [selectedPath, setSelectedPath] = (0, react.useState)();
56033
56040
  const [diff, setDiff] = (0, react.useState)();
56041
+ const [diffLoading, setDiffLoading] = (0, react.useState)(false);
56042
+ const [mobileDiffOpen, setMobileDiffOpen] = (0, react.useState)(false);
56034
56043
  const [collapsed, setCollapsed] = (0, react.useState)(/* @__PURE__ */ new Set());
56035
56044
  const [hoveredPath, setHoveredPath] = (0, react.useState)();
56036
56045
  const [loading, setLoading] = (0, react.useState)(true);
56037
56046
  const [busy, setBusy] = (0, react.useState)(false);
56038
56047
  const [error, setError] = (0, react.useState)();
56039
56048
  const requestGeneration = (0, react.useRef)(0);
56040
- const load = async () => {
56049
+ const inFlightLoad = (0, react.useRef)();
56050
+ const load = (foreground = false) => {
56051
+ if (inFlightLoad.current !== void 0) return inFlightLoad.current;
56041
56052
  const generation = requestGeneration.current + 1;
56042
56053
  requestGeneration.current = generation;
56043
- setLoading(true);
56044
- setError(void 0);
56045
- try {
56046
- const resolved = await resolveGitWorkspaceId(props.remote, props.sessionId);
56047
- if (resolved === void 0) throw new Error("当前会话没有可用的工作区");
56048
- const [sessionFiles, status] = await Promise.all([call(props.rpc, "fileManagement/session-changes", {
56049
- sessionId: props.sessionId,
56050
- workspaceId: resolved
56051
- }), call(props.rpc, "git/status", { workspaceId: resolved })]);
56052
- if (generation !== requestGeneration.current) return;
56053
- const next = selectSessionChangedFiles(sessionFiles, status);
56054
- setWorkspaceId(resolved);
56055
- setChanges(next);
56056
- props.reportCount?.(props.sessionId, next.length);
56057
- setSelectedPath((current) => current !== void 0 && next.some((item) => item.path === current) ? current : next[0]?.path);
56058
- } catch (cause) {
56059
- if (generation !== requestGeneration.current) return;
56060
- setError(cause instanceof Error ? cause.message : String(cause));
56061
- setChanges([]);
56062
- setWorkspaceId(void 0);
56063
- props.reportCount?.(props.sessionId, 0);
56064
- } finally {
56065
- if (generation === requestGeneration.current) setLoading(false);
56054
+ if (foreground) {
56055
+ setLoading(true);
56056
+ setError(void 0);
56066
56057
  }
56058
+ const tracked = (async () => {
56059
+ try {
56060
+ const resolved = await resolveGitWorkspaceId(props.remote, props.sessionId);
56061
+ if (resolved === void 0) throw new Error("当前会话没有可用的工作区");
56062
+ const [sessionFiles, status] = await Promise.all([call(props.rpc, "fileManagement/session-changes", {
56063
+ sessionId: props.sessionId,
56064
+ workspaceId: resolved
56065
+ }), call(props.rpc, "git/status", { workspaceId: resolved })]);
56066
+ if (generation !== requestGeneration.current) return;
56067
+ const next = selectSessionChangedFiles(sessionFiles, status);
56068
+ setWorkspaceId((current) => current === resolved ? current : resolved);
56069
+ setChanges((current) => mergeChangedFiles(current, next));
56070
+ props.reportCount?.(props.sessionId, next.length);
56071
+ setSelectedPath((current) => current !== void 0 && next.some((item) => item.path === current) ? current : next[0]?.path);
56072
+ setError(void 0);
56073
+ } catch (cause) {
56074
+ if (generation !== requestGeneration.current) return;
56075
+ if (foreground) {
56076
+ setError(cause instanceof Error ? cause.message : String(cause));
56077
+ setChanges([]);
56078
+ setWorkspaceId(void 0);
56079
+ props.reportCount?.(props.sessionId, 0);
56080
+ } else setError(cause instanceof Error ? cause.message : String(cause));
56081
+ } finally {
56082
+ if (generation === requestGeneration.current && foreground) setLoading(false);
56083
+ }
56084
+ })().finally(() => {
56085
+ if (inFlightLoad.current === tracked) inFlightLoad.current = void 0;
56086
+ });
56087
+ inFlightLoad.current = tracked;
56088
+ return tracked;
56067
56089
  };
56068
56090
  (0, react.useEffect)(() => {
56069
56091
  setDiff(void 0);
56092
+ setDiffLoading(false);
56093
+ setMobileDiffOpen(false);
56070
56094
  setCollapsed(/* @__PURE__ */ new Set());
56071
56095
  setWorkspaceId(void 0);
56072
- load();
56096
+ load(true);
56073
56097
  const timer = globalThis.setInterval(() => {
56074
56098
  load();
56075
- }, 5e3);
56099
+ }, SESSION_CHANGED_FILES_BACKGROUND_REFRESH_MS);
56076
56100
  return () => {
56077
56101
  requestGeneration.current += 1;
56102
+ inFlightLoad.current = void 0;
56078
56103
  globalThis.clearInterval(timer);
56079
56104
  };
56080
56105
  }, [
@@ -56096,11 +56121,18 @@ window.__ModuleLoader__.load({
56096
56121
  (0, react.useEffect)(() => {
56097
56122
  if (workspaceId === void 0 || selectedPath === void 0) {
56098
56123
  setDiff(void 0);
56124
+ setDiffLoading(false);
56099
56125
  return;
56100
56126
  }
56101
56127
  const selected = changes.find((item) => item.path === selectedPath);
56102
- if (selected === void 0) return;
56128
+ if (selected === void 0) {
56129
+ setDiff(void 0);
56130
+ setDiffLoading(false);
56131
+ return;
56132
+ }
56103
56133
  let cancelled = false;
56134
+ setDiff(void 0);
56135
+ setDiffLoading(true);
56104
56136
  call(props.rpc, "git/diff", {
56105
56137
  workspaceId,
56106
56138
  path: selected.path,
@@ -56109,6 +56141,8 @@ window.__ModuleLoader__.load({
56109
56141
  if (!cancelled) setDiff(value);
56110
56142
  }).catch((cause) => {
56111
56143
  if (!cancelled) setError(cause instanceof Error ? cause.message : String(cause));
56144
+ }).finally(() => {
56145
+ if (!cancelled) setDiffLoading(false);
56112
56146
  });
56113
56147
  return () => {
56114
56148
  cancelled = true;
@@ -56119,6 +56153,14 @@ window.__ModuleLoader__.load({
56119
56153
  selectedPath,
56120
56154
  workspaceId
56121
56155
  ]);
56156
+ (0, react.useEffect)(() => {
56157
+ if (!compactLayout) setMobileDiffOpen(false);
56158
+ if (selectedPath === void 0 || !changes.some((item) => item.path === selectedPath)) setMobileDiffOpen(false);
56159
+ }, [
56160
+ changes,
56161
+ compactLayout,
56162
+ selectedPath
56163
+ ]);
56122
56164
  const tree = (0, react.useMemo)(() => buildTree(changes), [changes]);
56123
56165
  const unstaged = changes.filter((item) => !item.staged);
56124
56166
  const stageTargets = async (targets, action) => {
@@ -56130,7 +56172,7 @@ window.__ModuleLoader__.load({
56130
56172
  targets
56131
56173
  });
56132
56174
  notifyGitWorkspaceChanged(workspaceId);
56133
- await load();
56175
+ await load(true);
56134
56176
  } catch (cause) {
56135
56177
  setError(cause instanceof Error ? cause.message : String(cause));
56136
56178
  } finally {
@@ -56146,6 +56188,11 @@ window.__ModuleLoader__.load({
56146
56188
  });
56147
56189
  };
56148
56190
  const hasChanges = changes.length > 0;
56191
+ const selectedChange = selectedPath === void 0 ? void 0 : changes.find((item) => item.path === selectedPath);
56192
+ const selectPath = (path) => {
56193
+ setSelectedPath(path);
56194
+ if (compactLayout) setMobileDiffOpen(true);
56195
+ };
56149
56196
  const viewRootStyle = {
56150
56197
  ...rootStyle,
56151
56198
  padding: compactLayout ? "0 16px" : rootStyle.padding
@@ -56167,7 +56214,7 @@ window.__ModuleLoader__.load({
56167
56214
  return (0, react.createElement)("div", { style: viewRootStyle }, (0, react.createElement)("div", { style: viewToolbarStyle }, (0, react.createElement)("strong", { style: { fontSize: 15 } }, t("sessionFiles.title")), (0, react.createElement)("span", { style: countStyle }, t("sessionFiles.count", { count: changes.length })), (0, react.createElement)("span", { style: { flex: 1 } }), (0, react.createElement)("button", {
56168
56215
  type: "button",
56169
56216
  disabled: loading || busy,
56170
- onClick: () => void load(),
56217
+ onClick: () => void load(true),
56171
56218
  style: toolbarRefreshButtonStyle,
56172
56219
  title: t("sessionFiles.refresh"),
56173
56220
  "aria-label": t("sessionFiles.refresh")
@@ -56181,7 +56228,24 @@ window.__ModuleLoader__.load({
56181
56228
  }, (0, react.createElement)(StageIcon))), error === void 0 ? null : (0, react.createElement)("div", {
56182
56229
  role: "alert",
56183
56230
  style: errorStyle
56184
- }, error), (0, react.createElement)("div", { style: viewContentStyle }, (0, react.createElement)("div", { style: viewTreePaneStyle }, loading ? (0, react.createElement)("div", { style: emptyStyle }, t("sessionFiles.loading")) : changes.length === 0 ? (0, react.createElement)("div", { style: emptyStyle }, t("sessionFiles.empty")) : tree.map((node) => renderNode(node, 0, collapsed, hoveredPath, selectedPath, toggle, setSelectedPath, setHoveredPath, stageTargets, t))), hasChanges ? (0, react.createElement)("div", { style: diffPaneStyle }, selectedPath === void 0 ? (0, react.createElement)("div", { style: emptyStyle }, t("sessionFiles.selectFile")) : diff?.content ? (0, react.createElement)("pre", { style: diffStyle }, renderDiff(diff.content)) : (0, react.createElement)("div", { style: emptyStyle }, t("sessionFiles.noDiff"))) : null));
56231
+ }, error), (0, react.createElement)("div", { style: viewContentStyle }, (0, react.createElement)("div", { style: viewTreePaneStyle }, loading ? (0, react.createElement)("div", { style: emptyStyle }, t("sessionFiles.loading")) : changes.length === 0 ? (0, react.createElement)("div", { style: emptyStyle }, t("sessionFiles.empty")) : tree.map((node) => renderNode(node, 0, collapsed, hoveredPath, selectedPath, toggle, selectPath, setHoveredPath, stageTargets, t))), !compactLayout && hasChanges ? (0, react.createElement)("div", { style: diffPaneStyle }, selectedPath === void 0 ? (0, react.createElement)("div", { style: emptyStyle }, t("sessionFiles.selectFile")) : diffLoading ? (0, react.createElement)("div", { style: emptyStyle }, t("sessionFiles.loadingDiff")) : diff?.content ? (0, react.createElement)("pre", { style: diffStyle }, renderDiff(diff.content)) : (0, react.createElement)("div", { style: emptyStyle }, t("sessionFiles.noDiff"))) : null), compactLayout && mobileDiffOpen && selectedPath !== void 0 ? (0, react.createElement)("div", {
56232
+ style: mobileDiffOverlayStyle,
56233
+ onPointerDown: backdropPointerDownHandler(() => setMobileDiffOpen(false))
56234
+ }, (0, react.createElement)("section", {
56235
+ role: "dialog",
56236
+ "aria-modal": true,
56237
+ "aria-label": selectedChange?.path ?? t("sessionFiles.title"),
56238
+ style: mobileDiffModalStyle
56239
+ }, (0, react.createElement)("header", { style: mobileDiffHeaderStyle }, (0, react.createElement)("strong", {
56240
+ style: mobileDiffTitleStyle,
56241
+ title: selectedChange?.path
56242
+ }, selectedChange?.path ?? t("sessionFiles.title")), (0, react.createElement)("button", {
56243
+ type: "button",
56244
+ onClick: () => setMobileDiffOpen(false),
56245
+ style: mobileDiffCloseStyle,
56246
+ title: t("sessionFiles.close"),
56247
+ "aria-label": t("sessionFiles.close")
56248
+ }, "×")), (0, react.createElement)("div", { style: mobileDiffBodyStyle }, diffLoading ? (0, react.createElement)("div", { style: emptyStyle }, t("sessionFiles.loadingDiff")) : diff?.content ? (0, react.createElement)("pre", { style: diffStyle }, renderDiff(diff.content)) : (0, react.createElement)("div", { style: emptyStyle }, t("sessionFiles.noDiff"))))) : null);
56185
56249
  }
56186
56250
  /** 注册 DSH 原生 conversation.view Slot;标签由 DSH 根据 Slot 的 id/label 自动投影。 */
56187
56251
  function registerSessionChangedFilesView(ctx, rpc, remote, locale) {
@@ -56264,37 +56328,51 @@ window.__ModuleLoader__.load({
56264
56328
  (0, react.useEffect)(() => {
56265
56329
  let disposed = false;
56266
56330
  let generation = 0;
56331
+ let hasSuccessfulLoad = false;
56332
+ let subscribedWorkspaceId;
56333
+ let inFlight;
56267
56334
  let disposeWorkspaceSubscription;
56268
56335
  const updateWorkspaceSubscription = (workspaceId) => {
56336
+ if (subscribedWorkspaceId === workspaceId) return;
56269
56337
  disposeWorkspaceSubscription?.();
56338
+ subscribedWorkspaceId = workspaceId;
56270
56339
  disposeWorkspaceSubscription = workspaceId === void 0 ? void 0 : subscribeGitWorkspaceChanged(workspaceId, () => {
56271
56340
  load();
56272
56341
  });
56273
56342
  };
56274
- const load = async () => {
56343
+ const load = () => {
56344
+ if (inFlight !== void 0) return inFlight;
56275
56345
  const currentGeneration = ++generation;
56276
- try {
56277
- const workspaceId = await resolveGitWorkspaceId(props.remote, props.sessionId);
56278
- if (workspaceId === void 0) throw new Error("当前会话没有可用的工作区");
56279
- const [sessionFiles, status] = await Promise.all([call(props.rpc, "fileManagement/session-changes", {
56280
- sessionId: props.sessionId,
56281
- workspaceId
56282
- }), call(props.rpc, "git/status", { workspaceId })]);
56283
- if (disposed || currentGeneration !== generation) return;
56284
- updateWorkspaceSubscription(workspaceId);
56285
- const count = selectSessionChangedFiles(sessionFiles, status).length;
56286
- props.reportCount(props.sessionId, count);
56287
- } catch {
56288
- if (!disposed && currentGeneration === generation) props.reportCount(props.sessionId, 0);
56289
- }
56346
+ const tracked = (async () => {
56347
+ try {
56348
+ const workspaceId = await resolveGitWorkspaceId(props.remote, props.sessionId);
56349
+ if (workspaceId === void 0) throw new Error("当前会话没有可用的工作区");
56350
+ const [sessionFiles, status] = await Promise.all([call(props.rpc, "fileManagement/session-changes", {
56351
+ sessionId: props.sessionId,
56352
+ workspaceId
56353
+ }), call(props.rpc, "git/status", { workspaceId })]);
56354
+ if (disposed || currentGeneration !== generation) return;
56355
+ updateWorkspaceSubscription(workspaceId);
56356
+ const count = selectSessionChangedFiles(sessionFiles, status).length;
56357
+ hasSuccessfulLoad = true;
56358
+ props.reportCount(props.sessionId, count);
56359
+ } catch {
56360
+ if (!disposed && currentGeneration === generation && !hasSuccessfulLoad) props.reportCount(props.sessionId, 0);
56361
+ }
56362
+ })().finally(() => {
56363
+ if (inFlight === tracked) inFlight = void 0;
56364
+ });
56365
+ inFlight = tracked;
56366
+ return tracked;
56290
56367
  };
56291
56368
  load();
56292
56369
  const timer = globalThis.setInterval(() => {
56293
56370
  load();
56294
- }, 5e3);
56371
+ }, SESSION_CHANGED_FILES_BACKGROUND_REFRESH_MS);
56295
56372
  return () => {
56296
56373
  disposed = true;
56297
56374
  generation += 1;
56375
+ inFlight = void 0;
56298
56376
  globalThis.clearInterval(timer);
56299
56377
  disposeWorkspaceSubscription?.();
56300
56378
  };
@@ -56313,6 +56391,19 @@ window.__ModuleLoader__.load({
56313
56391
  style: diffLineStyle(line)
56314
56392
  }, `${line}${index < lines.length - 1 ? "\n" : ""}`));
56315
56393
  }
56394
+ /** 只替换真正变化的行对象,后台刷新时保持未变化文件的引用和交互状态。 */
56395
+ function mergeChangedFiles(current, next) {
56396
+ if (current.length === next.length && current.every((item, index) => sameChange(item, next[index]))) return current;
56397
+ const previous = new Map(current.map((item) => [item.path, item]));
56398
+ return next.map((item) => {
56399
+ const old = previous.get(item.path);
56400
+ return old !== void 0 && sameChange(old, item) ? old : item;
56401
+ });
56402
+ }
56403
+ function sameChange(left, right) {
56404
+ if (left === void 0 || right === void 0) return left === right;
56405
+ return left.path === right.path && left.status === right.status && left.staged === right.staged && left.oldPath === right.oldPath && left.binary === right.binary && left.stagedStatus === right.stagedStatus && left.worktreeStatus === right.worktreeStatus;
56406
+ }
56316
56407
  /** 只显示当前 Git 状态中仍属于本会话触及范围的文件。 */
56317
56408
  function selectSessionChangedFiles(sessionFiles, status) {
56318
56409
  const touched = new Set(sessionFiles.paths.map(normalizePath));
@@ -56663,6 +56754,66 @@ window.__ModuleLoader__.load({
56663
56754
  wordBreak: "break-word",
56664
56755
  font: "12px/1.55 var(--dsw-font-mono,ui-monospace,monospace)"
56665
56756
  };
56757
+ const mobileDiffOverlayStyle = {
56758
+ position: "fixed",
56759
+ inset: 0,
56760
+ zIndex: 1e3,
56761
+ display: "flex",
56762
+ alignItems: "stretch",
56763
+ justifyContent: "center",
56764
+ padding: 10,
56765
+ boxSizing: "border-box",
56766
+ background: "rgba(0,0,0,.48)"
56767
+ };
56768
+ const mobileDiffModalStyle = {
56769
+ display: "flex",
56770
+ flexDirection: "column",
56771
+ width: "100%",
56772
+ maxWidth: 720,
56773
+ maxHeight: "100%",
56774
+ minHeight: 0,
56775
+ overflow: "hidden",
56776
+ borderRadius: 10,
56777
+ background: "var(--dsw-alias-bg-layer-1,#fff)",
56778
+ boxShadow: "0 12px 40px rgba(0,0,0,.3)"
56779
+ };
56780
+ const mobileDiffHeaderStyle = {
56781
+ display: "flex",
56782
+ alignItems: "center",
56783
+ gap: 8,
56784
+ minHeight: 46,
56785
+ padding: "0 12px",
56786
+ borderBottom: "1px solid var(--dsw-alias-border-l3,#ddd)",
56787
+ flex: "0 0 auto"
56788
+ };
56789
+ const mobileDiffTitleStyle = {
56790
+ minWidth: 0,
56791
+ flex: 1,
56792
+ overflow: "hidden",
56793
+ textOverflow: "ellipsis",
56794
+ whiteSpace: "nowrap",
56795
+ fontSize: 13
56796
+ };
56797
+ const mobileDiffCloseStyle = {
56798
+ display: "inline-flex",
56799
+ alignItems: "center",
56800
+ justifyContent: "center",
56801
+ width: 32,
56802
+ height: 32,
56803
+ border: 0,
56804
+ borderRadius: 6,
56805
+ padding: 0,
56806
+ background: "transparent",
56807
+ color: "var(--dsw-alias-label-secondary,#777)",
56808
+ cursor: "pointer",
56809
+ fontSize: 22,
56810
+ lineHeight: 1
56811
+ };
56812
+ const mobileDiffBodyStyle = {
56813
+ minHeight: 0,
56814
+ overflow: "auto",
56815
+ background: "var(--dsw-alias-bg-layer-1,transparent)"
56816
+ };
56666
56817
  const diffHeaderLineStyle = {
56667
56818
  display: "block",
56668
56819
  color: "var(--dsw-alias-label-tertiary,#777)"