Skip to content
dsh.fish
Bundle

dsh-window-drag-probe

窗口拖动:窗口一加载就在顶部自动装好一条可拖拽带(本机 macOS 拖不动窗口的解法),并从插件页提供按钮打开面板读取 computed app-region、recall 标记与窗口位移(deepseek-harness discussion #9112)。

Source
adamcjm
License
MIT
Updated
Updated 7 days ago

Readme

# dsh-window-drag-probe

English | [中文](README.zh.md)

A [DSH](https://github.com/deepseek-ai/deepseek-harness) plugin that restores window dragging on macOS DSH Desktop and diagnoses why it broke — from inside the running window.

Upstream report: **[deepseek-ai/deepseek-harness discussion #9112](https://github.com/deepseek-ai/deepseek-harness/discussions/9112)**

---

## Why this exists

On macOS, DSH Desktop is a `hiddenInset` window with **no native title bar**, so dragging depends entirely on `-webkit-app-region: drag` boxes declared by the page. The shell marks its chrome rows with `data-window-drag`, and `ui-web`'s `base.css` turns that mark into the one drag rule.

In practice those rows are **not draggable**: the interactive `no-drag` selector in the same sheet matches thousands of boxes in the real DOM (buttons, `[tabindex]` focus containers, ARIA-role widgets), and any one of them that overlaps a chrome row *later in document order* subtracts that overlap. What is left of the chrome band is a sliver a few pixels tall, so pressing anywhere that looks like a title bar does nothing.

The plugin does **not** patch any official file. It adds:

1. **A 16 px drag band** across the top of the window, appended to `document.body` **last** with an inline `app-region: drag` — document order is what wins in Electron's composition, so the band cannot be subtracted by earlier `no-drag` boxes.
2. **A diagnostic panel** that reports the evidence from the live window: the platform marker, the computed `app-region` of the chrome rows, the recall mark, every app-region box, a draggability matrix, and window movement read from `window.screenX/screenY`.

---

## Requirements

Verified against **DSH Desktop 0.2.0-rc.2 / Electron 44.0.0** — see [Verified on](#verified-on).

The DSH client API is **not forward-compatible across host releases**: a client half built for a different API does not degrade gracefully, it crashes the view (the typical symptom is `TypeError: useConversation is not a function`). `0.7.1` is the first published release, so there is no older line to fall back to — if your host differs from the verified build above, check `dsh --version` first and open an issue with it before installing.

The plugin declares no hard service dependency (`inject: []`): it looks `slots` and `locale` up optionally and falls back to a plain DOM overlay with Chinese copy when either is missing, so it can never park the shell waiting for a service.

---

## Install

### A. From the plugin page (recommended on DSH Desktop)

DSH Desktop manages its own profile exclusively, so the CLI refuses it — install through the UI:

1. Sidebar → **Plugins** → **Add plugin** → open the arrow menu → **Install a third-party plugin**
2. Paste the repository address:

   ```
   https://github.com/adamcjm/dsh-window-drag-probe
   ```

3. Install, then choose **Enable now**
4. **Quit DSH Desktop completely (⌘Q) and reopen it** — the client bundle is assembled once at host boot, so a window close is not enough

### B. CLI — from npm (profiles managed from the command line)

```sh
dsh plugin --profile <profile> add dsh-window-drag-probe
```

Pin the exact release when you need reproducibility:

```sh
dsh plugin --profile <profile> add dsh-window-drag-probe@0.7.1
```

The GitHub track resolves the default-branch HEAD instead of a published version:

```sh
dsh plugin --profile <profile> add github:adamcjm/dsh-window-drag-probe
```

Then restart that host.

### C. Local checkout (development)

```sh
git clone https://github.com/adamcjm/dsh-window-drag-probe
dsh plugin --profile <profile> add "$PWD/dsh-window-drag-probe"
```

A local directory install is linked, not copied, so edits take effect on the next host restart.

---

## Usage

### Drag band

After the host restarts, the **top 16 px** of the window is the drag strip: fully transparent at rest, so the window shows through and nothing gets tinted. Press anywhere inside it and drag: the window moves.

- Invisible at rest; a faint blue cue appears only while the pointer is over those 16 px (a draggable region swallows pointer events, so no other affordance is available).
- Everything below the band behaves normally; the band does not intercept clicks outside its 16 px.
- Only one band exists per window; re-arming is idempotent.

### Diagnostic panel

Plugins → open **Window Drag** → press **Open the “Window Drag” panel** (the button this plugin registers on its own page, and only on that page).

The panel is draggable by its header, collapsible with `▾`, remembers its position, and reports:

> There is only ever one panel: pressing the opener again reuses the open one and flashes its outline, and any duplicates left by an older revision are collapsed on the next open.

> Panel copy follows the DSH language: a Chinese UI shows Chinese, an English UI shows English (an open panel is relabelled in place). The plugin name and description in the plugin list follow the language too (`locale/en.json` → Window Drag, `locale/zh.json` → 窗口拖动).

| Row | Meaning |
| --- | --- |
| `platform` | The `data-platform` marker. `darwin` is the only value where any drag rule exists. |
| `computed app-region · body / first row` | The raw computed values. `drag` on the row means the cascade is fine and the loss happens in composition. |
| `recall 标记当前` | Whether the shell's `data-window-drag-recall` pulse is stuck on. A stuck mark subtracts the whole surface. |
| `窗口位置` / `窗口移动记录` | Live `window.screenX/screenY` — the only in-page witness of a native window move. |
| `drag 行` | Every `[data-window-drag]` element with its box and computed value. |
| `app-region 盒子` | Every box whose computed `app-region` is not `none`, in document order. |
| `顶部可拖性矩阵` | A `■`/`·` matrix over the top band, decided by the project's own model (last containing box in document order wins). |
| `采样点命中链` | For each sample point, the boxes containing it and which one decides. |

Panel buttons: **重新采集** (re-collect), **插入/移除顶部拖拽带**, **复位位置**, **隐藏面板**.

---

## Uninstall

- **Plugin page**: open the plugin card → **卸载** (Uninstall).
- **CLI**: `dsh plugin --profile <profile> remove dsh-window-drag-probe`
- **Manual installs**: remove the `dsh-window-drag-probe` symlink from the profile's `node_modules`, then restore `package.json` / `cordis.patch.yml` from your backups.

Uninstalling removes the band; after a restart the window is back to its previous (undraggable) state.

---

## Verified on

| | |
| --- | --- |
| DSH Desktop | 0.2.0-rc.2 |
| Electron | 44.0.0 |
| macOS | 27.0.1 (26A434, Apple Silicon) |

The band is armed unconditionally, but the app-region rules it compensates for only exist under `html[data-platform='darwin']`. On other platforms the plugin still loads and the panel still reports, with `platform` showing the actual marker.

## Limits

- This is a **workaround plus a probe**, not an upstream fix. If the matrix shows `drag` at a point yet the window still does not move there, the cause is outside the page and only the upstream fix (see the discussion) will help.
- The plugin appends one `div` to `document.body` and registers one button in the plugin page. It reads DOM state and `screenX/screenY`; it sends nothing anywhere.
- The panel is intentionally a plain DOM overlay rather than a slot decoration: it must be positionable over the whole viewport, and the drag band must be last in document order.

## License

MIT

Install

dsh plugin --profile web add github:adamcjm/dsh-window-drag-probe

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source