Skip to content
dsh.fish
Bundle

dsh-pip

Detach the DeepSeek Harness Web GUI into a Document Picture-in-Picture window: a floating button moves the whole app into an always-on-top window and back

Source
extension-hunter
stars
1 stars
License
MIT
Updated
Updated 5 days ago

Readme

# dsh-pip

<p align="center"><strong>One click detaches the DeepSeek Harness web GUI into an always-on-top Document Picture-in-Picture window — it floats beside your editor, and one more click puts it back.</strong></p>

<p align="center">
  <a href="https://www.npmjs.com/package/dsh-pip"><img src="https://img.shields.io/npm/v/dsh-pip?style=flat-square" alt="npm" /></a>
  <a href="https://github.com/extension-hunter/dsh-pip/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-2EA44F?style=flat-square" alt="License: MIT" /></a>
  <img src="https://img.shields.io/badge/browser-Chromium%20116%2B-4285F4?style=flat-square&logo=googlechrome&logoColor=white" alt="Chromium 116+" />
  <img src="https://img.shields.io/badge/config-zero--config-8A2BE2?style=flat-square" alt="Zero config" />
</p>

<p align="center">English · <a href="README.zh.md">中文</a></p>

## Why

The DSH web GUI lives in a browser tab — watching the agent while writing code means hopping between the editor and the tab. `dsh-pip` uses [Document Picture-in-Picture](https://developer.chrome.com/docs/web-platform/document-picture-in-picture) to move the **whole app** (not a screenshot) into a system-level always-on-top window:

- **One command to install.** The package ships a bundle patch (`dsh.bundle.patch`): `dsh plugin add` mounts the plugin row automatically — no file edits.
- **Zero config.** Restart `dsh web` and a floating "独立窗口" button appears in the corner of the UI. Click it, done.
- **Window matches the browser by default.** The detached window opens at the current tab's viewport size; pin it with two numbers if you prefer.
- **The whole app comes along.** On click, `#root` moves together with styles and theme — not a screencast, the app itself, fully interactive.
- **No-op where unsupported.** Safari / Firefox lack the Document PiP API; the script no-ops and no button ever appears.

<p align="center">
  <img src="assets/dsh-pip-overview.png" width="100%" alt="dsh-pip moves the live Harness Web UI from its browser tab into an always-on-top window beside the editor and back in one click." />
</p>

## dsh-pip vs DeepSeek Harness Desktop

These projects solve different layers of the same workflow. `dsh-pip` is a focused plugin for people who already run `dsh web` and only want the UI beside their editor; [DeepSeek Harness Desktop](https://github.com/anywhere-labs/deepseek-harness-desktop) is a packaged Electron distribution that owns the desktop app and local Harness service lifecycle.

| | `dsh-pip` | DeepSeek Harness Desktop |
|---|---|---|
| Primary job | Detach the existing Web UI into an always-on-top companion window | Package Harness as a standalone desktop app |
| Install | One `dsh plugin` command | Download and install a desktop build |
| Existing setup | Requires a working `dsh web` profile and Chromium 116+ | Bundles the runtime; no manual Node.js setup or CLI launch |
| Harness service | Reuses your existing service and configuration; does not start or manage it | Starts and manages the local Harness service |
| Window experience | One-click Document PiP detach / return; stays above the editor | Electron window, system tray, and desktop-specific UI adaptation |
| Harness UI and plugins | Moves the current official Web UI as-is; installed through the DSH plugin mechanism | Retains the official local Web UI and plugin capabilities inside the desktop distribution |
| Remote access and channels | None; this is a local window enhancement only | Advertises iOS / Android remote control plus WeChat, Feishu, Discord, and WhatsApp channels |
| Plugin discovery | Uses the standard DSH plugin CLI; no marketplace | A plugin marketplace and DSH-plugin delivery for Desktop are planned, not currently shipped |
| Platform scope | Chrome / Edge with Document PiP | macOS and Windows desktop builds |

**Choose `dsh-pip`** if your current Harness setup already works and you want the smallest change: keep your runtime, browser, profiles, and update flow, and add only a floating window. **Choose Desktop** if you want Harness packaged and managed as a desktop application without setting up Node.js or starting it from the command line.

## Quick start

```sh
dsh plugin --profile web add dsh-pip
```

Restart `dsh web` — done, zero config:

- the bundle patch mounts the plugin row and injects the browser script into every page response — purely additive, core rows untouched;
- open the web UI, click the floating "独立窗口" button to detach;
- close the window (or click its "返回标签页" button) and the app returns to the tab.

## How it works

On click the browser script calls `documentPictureInPicture.requestWindow()` during the click's transient activation, copies the opener's stylesheets and theme attributes into the new window, adopts the app root (`#root`) into it, and hides the opener button. The window's `pagehide` event — fired by the browser's built-in "back to tab" control or the script's "返回标签页" button — moves the root back and restores the button.

| Half | Where | What it does |
|---|---|---|
| Host plugin | `src/index.ts` | Registers the `/pip/client.js` route and injects the browser script + config into every index response. |
| Browser script | `src/client.js` | Draws the floating button and moves the app (`#root`) into / out of the PiP window. |

## Configuration

All optional — the defaults just work. Override them in the profile's `~/.dsh/profiles/web/cordis.patch.yml`:

| Field | Default | Meaning |
|---|---|---|
| `enabled` | `true` | Mount the plugin; `false` (or `disabled: true` on the row) turns it off |
| `width` | omitted | Detached-window width (CSS px); omitted = match the browser viewport |
| `height` | omitted | Detached-window height (CSS px); omitted = match the browser viewport |

```yaml
- id: pip
  config:
    enabled: true
    width: 1280   # pin the size with numbers
    height: 800
```

> `requestWindow` width/height are hints — Chromium clamps the window to the available screen, so a maximized browser may yield a slightly smaller window.

## Requirements

- **Chromium 116+** (Chrome, Edge). The Document Picture-in-Picture API does not exist in Safari or Firefox; the script no-ops and no button appears.
- The `webServer` service, which the `web` profile provides through its `@deepseek-ai/dsh-host-webserver` bundle.

## Install & lifecycle

### Install

```sh
dsh plugin --profile web add dsh-pip
```

To install an unpublished checkout (e.g. during development), pass a local path:

```sh
dsh plugin --profile web add file:/path/to/dsh-pip
```

### Disable / restore

```yaml
- id: pip
  disabled: true
```

Flip it back to `false` to restore.

### Update

```sh
dsh plugin --profile web update dsh-pip
```

### Remove

```sh
dsh plugin --profile web remove dsh-pip
```

Removes the dependency and the bundle layer; nothing is left behind.

## Known limitations

- **Chromium-only** — Safari and Firefox never show the button.
- **Portal surfaces stay in the tab** — the app renders menus, modals, toasts, and hover cards through `createPortal(..., document.body)`; those elements continue to target the original tab's body while detached, so they are invisible until the app returns. Detaching is best used for reading/steady state, not for opening menus in the floating window.
- **Window-scoped listeners stay home** — global `window`/`document` listeners (keyboard shortcuts, scroll tracking) keep firing in the original tab; only React-managed events on the moved root follow the window.

## Development

```sh
npm install
npm run typecheck   # tsc --noEmit
npm run build       # tsc → lib/ + copy src/client.js → lib/client.js
```

`prepack` (run by `npm pack` / `npm publish`) rebuilds before packaging so the published tarball always ships a current `lib/`.

## License

[MIT](LICENSE)

Install

dsh plugin --profile web add github:extension-hunter/dsh-pip

Profile: web

  • This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source