dsh-desktop
界面增强 活跃维护

dsh-desktop

s3yf1337/dsh-desktop

Tauri框架构建,集成系统托盘、单实例运行、系统通知、仅提示更新、原生文件选择弹窗、拖拽操作支持等功能,开箱即用体验流畅。

1
Stars 标星
1
Forks 分支
1
Watchers 关注
0
Open Issues
JavaScript
主要语言
MIT
开源协议
2 MB
仓库大小
1 个月前
最后推送
一键安装扩展 / 插件指令
dsh plugin --profile web add github:s3yf1337/dsh-desktop
git clone https://github.com/s3yf1337/dsh-desktop.git
git clone git@github.com:s3yf1337/dsh-desktop.git
README.md main

dsh-desktop

DeepSeek Harness in a native desktop window — built the way the harness
itself is built: as a plugin, not a fork.

build
release
license
platform
dsh

dsh-desktop is a DeepSeek Harness
profile that composes the standard bundles (dsh-base + dsh-web-app) with a
small plugin — this repo's dsh-desktop-shell — which opens the harness web
surface in a native Tauri window: custom title bar, tray icon, native
notifications, a real file-manager panel, and one-click updates.

The idea: desktop as a plugin

DeepSeek Harness is built on the principle that everything is a plugin:
models, tools, sandboxes, session storage, the UI — even the agent loop
itself. The desktop experience should follow the same rule.

This project adds a native window without forking or repackaging the
harness
. The profile is plain composition:

dsh --profile desktop      →   dsh-base + dsh-web-app + dsh-desktop-shell

That one decision buys a lot:

  • Always in sync. The harness keeps updating; so do you. There is no fork
    to rebase and no bundled copy to refresh — upstream releases land in your
    profile exactly the way they always do.
  • Composable. The shell is one row in your profile's bundle list. Keep
    your other bundles, swap the web app, add plugins — the desktop layer stays
    a layer, not a replacement.
  • Small. The native client is a Tauri binary, not a bundled browser plus a
    full runtime. Your dsh stays your dsh.
  • Honest trade-off. The plugin approach assumes you already run dsh. If
    you want a single installer with zero prerequisites, a standalone app that
    bundles its own runtime is the better fit. If you want the desktop to be
    part of your harness — same config, same workspaces, same plugins — this
    is the one that fits.

Features

  • Native window with an app icon in the dock/taskbar and a custom title
    bar (drag region, minimize/maximize/close) drawn by the web surface,
    matching the app theme on every platform. The window title follows the
    chat open in the UI right now (DeepSeek Harness — <chat title>), not
    the last started agent.
  • Explorer panel — a real file manager. Browse any folder (not just the
    workspace) with breadcrumbs, back/forward, name filter and recursive
    search, sort by name/size/date. Right-click or keyboard (F2 rename, Del to
    trash, arrows) to create, rename, copy, cut, paste, delete, open
    externally. Files changed or created since your last look are marked live
    (auto-refresh). A Preview tab renders markdown with the app's own
    renderer (headings, tables, task lists, syntax-highlighted code with a
    copy button, math — and relative images resolved from the local disk),
    renders mermaid diagrams (bundled with the app, works offline) and
    CSV/TSV tables with line/bar charts, opens local .html pages in a
    sandboxed frame, shows images (click to zoom, dimensions),
    syntax-highlights source code files (shiki, the app's own highlighter),
    and falls back to a hex dump for binary files. A URL bar in the preview
    opens any web page (external links land in the system browser). Previews
    re-render automatically when the file changes on disk (text 1 MiB /
    images 8 MiB caps).
  • Wired into the harness. Right-click a file → Send path to agent
    inserts its workspace-relative path into the composer; images can be
    attached to a message — or just drag an image file into the window:
    it lands in the composer as a real attachment (any other file inserts its
    path). The workspace picker (hero + sidebar + settings) is the panel in
    "choose a folder" mode instead of an OS dialog.
  • Links that work. Every http(s)/mailto link in the chat and in
    markdown previews opens in your system browser — no more dead
    target="_blank" clicks inside the webview.
  • Chat search (Ctrl/Cmd+F). A quick-search bar over the conversation:
    live case-insensitive highlighting, Enter/↑/↓ to jump between matches,
    Esc to leave. Highlights are painted over the text without touching the
    message DOM, so streaming re-renders never corrupt the chat.
  • Tray + close-to-tray. Closing the window hides it; running agents keep
    working. The tray menu carries a live agent monitor: every running
    agent with a refreshable log tail and a Stop agent action, plus a
    badge on the tray icon when an agent finishes (cleared from the menu).
  • Native notifications on agent finish, error, and question events.
  • One-click updates. Download, apply, restart. Nothing is applied
    automatically; background checks are opt-in (off by default).
  • Workspace selection via the OS folder dialog, or drag-and-drop a folder
    into the window.
  • A dsh-desktop tab inside the harness Settings for desktop
    preferences.

Screenshot

dsh-desktop

DeepSeek Harness in a native window: the harness web surface with the
custom title bar and the explorer panel.

Install

Requires the dsh CLI. Rust is needed only for the first build from
source — prebuilt client binaries skip it.

Pre-built installers per platform — .deb (Linux), .dmg (macOS), NSIS
.exe (Windows) — are published on the
releases page. One
installer places the client binary and registers an app-menu entry; the
first launch bootstraps the desktop profile into dsh and opens the window.

From source (Linux/macOS dev path):

git clone https://github.com/s3yf1337/dsh-desktop && cd dsh-desktop
./install.sh              # full bootstrap (builds the client if needed)
./install.sh --no-build   # use an existing client binary, never build
./install.sh --rebuild    # force a client rebuild
dsh-desktop

The client binary itself is also a plugin installer:

dsh-desktop-shell install              # bootstrap the profile + install client/launcher
dsh-desktop-shell install --prefix /usr  # OS-package layout (menus under /usr/share)
dsh-desktop-shell                      # install, then boot the profile
dsh-desktop-shell --version

Runs on Linux, macOS, and Windows.


Technical details (for contributors) ### How it works ``` dsh --profile desktop (or the `dsh-desktop` menu launcher) └─ dsh-base + dsh-web-app the whole web surface: server, /api, SPA └─ dsh-desktop-shell this repo's plugin bundle: after the server binds, spawns dsh-desktop-shell and watches it └─ dsh-desktop-shell (native client, src-tauri/) opens a native WebView on http://127.0.0.1: window closed → exit 0 → plugin shuts the harness down ``` `dsh-desktop` is a **profile** for the DeepSeek Harness, composed from the standard bundles (`dsh-base` + `dsh-web-app`) plus this repo's `dsh-desktop-shell` plugin. The plugin spawns the native Tauri client on the served loopback URL; the WebView loads the exact same `127.0.0.1` origin a browser would, so the whole SPA works unchanged and same-origin. The client exposes `window.__TAURI__` to that origin (`withGlobalTauri`), and the plugin pipes agent-lifecycle notifications to the client over a stdin control channel (`{"event":"notify", ...}` JSON lines). The window title follows the chat open in the UI right now: the browser half reads the active session from the harness's sessions service and mirrors it into the native window and the custom title bar. #### Install options **One installer per platform** (from the [releases](https://github.com/s3yf1337/dsh-desktop/releases) page): `.deb` on Linux, `.dmg` on macOS, `.exe` (NSIS) on Windows. The installer places the client binary and registers an app-menu entry; the first launch of the installed app bootstraps the plugin profile into dsh and opens the window. The client binary is also a plugin installer: ```sh dsh-desktop-shell install # bootstrap the profile + install client/launcher dsh-desktop-shell install --prefix /usr # OS-package layout (menus under /usr/share) dsh-desktop-shell # same as install, then boot the profile dsh-desktop-shell --version ``` From source (Linux/macOS dev path), `install.sh` works as before: ```sh ./install.sh # full bootstrap (builds the client if needed) ./install.sh --no-build # use an existing client binary, never build ./install.sh --rebuild # force a client rebuild ``` `install.sh` creates `$DSH_HOME/profiles/desktop` (bundle copied and linked, no pnpm/registry needed), builds the client if missing, installs `dsh-desktop-shell` + the `dsh-desktop` launcher to `~/.local/bin`, installs the icon into the hicolor theme, and registers a desktop menu entry. Idempotent: re-running refreshes the bundle copy and never touches your profile's `cordis.patch.yml` user layer. The binary's own `install` mode is the cross-platform equivalent (it embeds the bundle, so one artifact installs everything). #### Release artifacts (CI-built) Every `v*` tag builds, bundles, and publishes per platform: - **Installers** — `DeepSeek Harness__amd64.deb` (Linux), `.dmg` + `.app` (macOS), NSIS `.exe` (Windows) - **Update tarballs** — `dsh-desktop--linux-x86_64.tar.gz`, `-macos-aarch64.tar.gz`, `-windows-x86_64.tar.gz` (client binary + `bundle/`) The in-app **one-click update** downloads its platform tarball, swaps the client binary, refreshes the plugin bundle, and restarts. Nothing is ever applied automatically; background checks are opt-in (off by default). #### Configuration The `dsh-desktop` launcher resolves the `dsh` CLI: `$DSH_DESKTOP_DSH` → `$DSH_BIN` → `dsh` on `PATH`. `DSH_HOME` is inherited (defaults to `$HOME/.dsh`). The native client honors: - `DSH_DESKTOP_NO_SINGLE_INSTANCE=1` — skip the single-instance guard so a second harness can run side by side (development/debugging) - `DSH_DESKTOP_BIN` — an explicit client binary path Client binary resolution in the bundle plugin: `config.bin` → `DSH_DESKTOP_BIN` → `$DSH_HOME/bin/dsh-desktop-shell` → `dsh-desktop-shell` on `PATH` → `~/.local/bin/dsh-desktop-shell`. With no binary found the harness still serves the web UI (degrades to browser use). The window is frameless; the web surface draws the title bar (drag region, minimize/maximize/close, resize edges) and the right-hand explorer panel (Files/Preview tabs). The shell exits with code 0 when the user is done and code 11 after a one-click update (the plugin relaunches the profile). #### Layout ``` bundle/ the dsh-desktop-shell plugin package (bundle contract) cordis.patch.yml inserts the desktop-shell row lib/index.js spawn/watcher plugin (webServer, appExit, stdin control, loopback-only /dshd-file route: local files for the preview panel — markdown images, .html pages, assets) lib/client.js browser half: title bar, explorer panel (markdown / web / image / hexdump previews), settings tab dist/ repo-root tauri frontendDist: dist/index.html loading page the WebView shows while it boots. Build-time/CI only — not part of the install.sh bundle, which ships bundle/ (lib/ + cordis.patch.yml), not dist/. dsh-desktop launcher wrapper: exec dsh --profile desktop install.sh one-command bootstrap (profile + client + icons + menu entry) src-tauri/ the native render client (the actual app) src/main.rs src/lib.rs arg dispatch (url | install | no-arg), frameless window, tray, close-to-tray, single-instance, stdin control src/install.rs plugin installer mode (embedded bundle, cross-platform) src/fs.rs explorer commands (list dir, read file, stat, hexdump, home, parent) src/commands.rs desktop_* commands the settings tab invokes src/settings.rs persisted desktop preferences (dsh-desktop.json) src/tray.rs tray icon + menu (show/hide, updates, quit) src/update.rs update orchestration (check, emit, notify, apply, restart) src/updater.rs GitHub releases API client (assets, suggest + one-click) src/log.rs file + stderr logging (dsh-desktop.log) Cargo.toml tauri.conf.json capabilities/default.json test/client-smoke.mjs renders client.js (title bar module + explorer + settings) and exercises the preview helpers (markdown image rewrite, TOC, URL normalization, path resolution) ``` The installed profile lives at `$DSH_HOME/profiles/desktop/`: ``` profiles/desktop/ package.json dsh.profile.bundles: base + web-app + dsh-desktop-shell cordis.patch.yml your patch layer packages/dsh-desktop-shell/ a copy of bundle/ (refreshed by install.sh) ```

License

MIT