# dsh-launcher

[![npm version](https://img.shields.io/npm/v/dsh-launcher)](https://www.npmjs.com/package/dsh-launcher) [![npm downloads](https://img.shields.io/npm/dm/dsh-launcher)](https://www.npmjs.com/package/dsh-launcher) [![license](https://img.shields.io/npm/l/dsh-launcher)](https://github.com/LvienOeria/dsh-launcher/blob/main/LICENSE) [![GitHub stars](https://img.shields.io/github/stars/LvienOeria/dsh-launcher)](https://github.com/LvienOeria/dsh-launcher)

[English](https://github.com/LvienOeria/dsh-launcher/blob/main/README.en.md) | **中文**


一个轻量的 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 插件：安装一个**终端命令，一个字启动 harness** —— 输入 `dsh-go`，自动启动 Web UI 并打开浏览器。Everything is a plugin，这个插件本身就是一个 bundle。

**轻量：** 零依赖，包体积约 9 KB。只碰终端侧 —— 不产生任何桌面图标、不捆绑应用。桌面双击版是独立的 [dsh-desktop-launcher](https://github.com/LvienOeria/dsh-desktop-launcher) 包，想要什么装什么，绝不捆绑。

## 它能做什么

以 bundle 方式加载后，插件的 `apply` 会在每次 harness 启动时**收敛**以下产物（幂等：配置没变就是快速空操作）：

| 产物 | 位置 | 说明 |
|---|---|---|
| 启动脚本 | `~/.dsh-launcher/dsh-start.command` | 启动 dsh → 轮询 Web UI 地址 → 就绪后自动打开浏览器 |
| 终端命令 | `~/.local/bin/dsh-go` | 终端里输入 `dsh-go` 就是这个效果 |

## 安装

前置条件：`dsh` CLI + **pnpm ≥ 9**（harness 固定 pnpm 11 —— 版本旧的话执行 `corepack enable`）。

从 npm 安装：

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

从 GitHub 安装 —— 纯 JS、**无构建步骤**，无需任何 allowlist：

```sh
dsh plugin --profile web add github:LvienOeria/dsh-launcher
```

本地路径安装也可以（零依赖）：

```sh
dsh plugin --profile web add ./dsh-launcher
```

然后启动一次 dsh，插件会自动生成启动器：

```sh
dsh --profile web      # 已安装 CLI
# 或
pnpm dsh web           # 源码目录（自动检测）
```

搞定。终端输入 `dsh-go` 即可启动 harness；关闭那个终端窗口即停止（Ctrl+C 也可以）。

## 自定义

编辑 profile 的 patch 层（`~/.dsh/profiles/<profile>/cordis.patch.yml`）—— 后层覆盖前层，patch 会整体替换某行的 `config`：

```yaml
- id: dsh-launcher
  config:
    command: dsh-go                      # 终端命令名（默认 dsh-go）
    url: http://127.0.0.1:3080           # Web UI 地址（轮询 + 打开）
    sourceDir: /path/to/deepseek-harness # 从源码目录执行 `pnpm dsh web`
    startCommand: ''                     # 完全自定义启动命令（单行）
    autoOpenBrowser: true
    ensurePath: true                     # 自动把 binDir 加入 shell 配置 PATH
```

### 启动命令的解析顺序

1. `startCommand`（显式指定）
2. `sourceDir` → `cd <目录> && pnpm dsh web`
3. 当前目录是带 `dsh` script 的源码检出
4. PATH 上已安装的 `dsh` CLI（排除我们自己的 binDir —— 防递归）
5. 回退 `dsh --profile web`（带警告）

## 安全性设计

- 每个生成文件都带 `# managed by dsh-launcher vX` 标记；**没有**该标记的已有文件会被先备份为 `<path>.bak` 再替换（绝不静默覆盖）。
- 配置未变 → 不重写任何文件（状态哈希存在 `~/.dsh-launcher/state.json`）。
- 非法配置（类型错误、`url` 非 http(s)、`startCommand` 含换行）会响亮失败并给出清晰报错。
- 安装失败只打日志，绝不会拖垮 harness —— dsh 照常启动。

## 卸载

```sh
dsh plugin --profile web remove dsh-launcher
rm -rf ~/.dsh-launcher ~/.local/bin/dsh
```

## 说明

- 终端命令默认是 **`dsh-go`** 而不是 `dsh` —— `dsh` 是 harness CLI 的命令名，启动器绝不抢占它。想改别的名字，用 `command` 配置即可。
- 想要桌面双击应用（带鲸鱼图标），而不是 / 或者同时要终端命令？安装 [dsh-desktop-launcher](https://github.com/LvienOeria/dsh-desktop-launcher)。
- 不支持 Windows（不会安装任何文件，只打一条警告）。

## License

MIT —— 见 [LICENSE](LICENSE)。
