English · 简体中文
为 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(`dsh`)Web UI 提供快捷键 —— 一个监听器,三个聚焦的快捷键,并且会根据当前实际存在的右侧面板选择原生路径或插件路径。
## 快捷键
| 按键 | 功能 |
|---|---|
| `Ctrl+Q` | 切换 DSH 原生左侧栏 |
| `Ctrl+E` | 切换右侧栏:安装了 [dsh-better-sidebar](https://github.com/omdsh-dev/DSH-better-sidebar) 时控制 Files / git / terminal / browser 等插件面板,否则控制原生会话详情栏 |
| `Ctrl+S` | 打开 / 关闭设置面板 |
### 行为边界
- **只匹配严格组合键**:必须是单独的 `Ctrl`,带 `Cmd` / `Shift` / `Alt` 时不触发;`Cmd` 组合保留给浏览器或操作系统。
- **不抢页面事件**:IME 输入、按键自动重复、已经被其他监听器消费的事件都会让路。
- **`Ctrl+S` 让给 better-sidebar 编辑器**:焦点位于插件面板内时,交给它自己的 `Ctrl/Cmd+S` 保存逻辑。
- **`Ctrl+E` 需要已选中会话**:插件面板和原生详情栏都是会话级界面。
## 安装
默认是 `Ctrl+Q` / `Ctrl+E` / `Ctrl+S`。物理键码可在 profile 补丁里覆盖,见下方「快捷键配置」。
```sh
dsh plugin --profile web add github:Aafff623/dsh-keyboard-manager
```
安装后硬刷新浏览器(`Ctrl+Shift+R`)。`dsh.bundle.patch` 会把插件加入 profile bundle,不需要改 profile 文件。
`lib/` 是有意提交入库的:git 安装无需构建。改 `src/` 后执行 `npm run build`,并把刷新后的 `lib/` 一起提交;CI 会检查是否过期。
## 它是怎么工作的
DSH 的 layout service 提供了动作,但不提供状态读取;设置模态框的开关状态也只存在于组件内部。因此插件使用**稳定的 DOM 标记和界面自身的按钮**,不碰 React 内部状态,也不依赖哈希 CSS 类名。标记不存在时会静默 no-op,不会误触发。
- **`Ctrl+Q`**:直接调用 `ctx.layout.toggleSidebar()`。
- **`Ctrl+E`**:检测到 dsh-better-sidebar 时,点击 `[data-dsh-toggle-cluster]` 里的右侧栏开关(优先 `aria-label` / `data-panel` 含 `right` 的按钮,否则用最后一个);没有插件时,调用 `ctx.layout.openDetails()/closeDetails()`,并通过 `[data-shell-overlay]` 读取 `data-details-collapsed` 判断方向。
- **`Ctrl+S`**:打开时点击侧栏设置按钮;关闭时派发带 `code: Escape` 的 document 级别 `Escape`,复用设置面板自己的关闭路径。
### 快捷键配置
默认绑定为 `KeyQ`、`KeyE`、`KeyS`。三个物理键码都可通过插件配置覆盖:
```yaml
# ~/.dsh/profiles/web/cordis.patch.yml(profile 自己的补丁层)
- id: dsh-keyboard-manager
config:
sidebar: KeyQ
rightPanel: KeyE
settings: KeyS
```
配置会校验键码格式(`/^[A-Z][A-Za-z0-9]+$/`),并拒绝重复键码;无效配置回落到默认值。改完重启 `dsh` 并刷新页面生效。
**配置如何到达浏览器**:DSH 的 web 启动流程挂载客户端半区时不传插件配置(`loader.create({ name })`),浏览器端 `apply` 的第二个参数永远是 `undefined`。因此 node 半边把配置以 JSON 形式挂在 `/plugin-config/dsh-keyboard-manager` 路由上,浏览器半边激活后拉取一次并热更新绑定;拉取失败或无头 profile 下保持默认键位,不影响使用。
### DOM 合约
插件只依赖以下集中登记的稳定标记(均已对照 `dsh-client-ui-layout` 与 `dsh-better-sidebar` 源码核实):
| 标记 | 来源 | 用途 |
|---|---|---|
| `[data-dsh-toggle-cluster]` | dsh-better-sidebar | 右侧栏按钮组 |
| `[data-dsh-panel-host]` | dsh-better-sidebar | Ctrl+S 让路给编辑器的范围 |
| `[data-shell-overlay]` | dsh-client-ui-layout | 原生 AppFrame 锚点 |
| `data-details-collapsed` | dsh-client-ui-layout | 原生详情栏当前折叠状态 |
| `button[aria-haspopup="dialog"]` | dsh-client-ui-settings-general | 设置按钮 |
## 开发
```sh
npm install
npm run typecheck # tsc --noEmit
npm run build # esbuild → lib/index.js + lib/client.js(ModuleLoader wrapper)
npm test # node:test,vm 隔离的 fake-DOM 测试
```
插件采用 DSH 标准双半结构:
- `src/index.ts`:node / host 半边(把插件配置挂成 JSON 路由,供浏览器半边拉取)
- `src/client/index.ts`:浏览器半边(全部快捷键逻辑)
- `lib/client.js`:包在 `window.__ModuleLoader__.load()` 工厂形态里的浏览器产物
- `cordis.patch.yml`:把插件插入 bundle 的配置
不安装到 profile,直接用当前 checkout 做开发覆盖:
```sh
dsh web --patch D:/code/dsh-plugin/dsh-keyboard-manager/cordis.dev.yml
```
## 兼容性
- 需要 DSH Web UI 和 `@deepseek-ai/cordis ^4.0.2`。
- `dsh-better-sidebar` 是**可选插件**:不安装时,Ctrl+E 自动回落到原生详情栏。
- `Ctrl+S` 的保存让路依赖 better-sidebar 编辑器;在其他界面中仍按全局设置快捷键处理。
## 许可证
[MIT](LICENSE)