<p align="center">
  <img src="assets/banner.svg" width="900" alt="dsh-web-launcher — 一键直达，零摩擦">
</p>

<div align="center">

[![npm version](https://img.shields.io/npm/v/dsh-web-launcher?color=1d4ed8&label=npm)](https://www.npmjs.com/package/dsh-web-launcher)
[![GitHub Stars](https://img.shields.io/github/stars/hanwuji1/dsh-web-launcher?style=social)](https://github.com/hanwuji1/dsh-web-launcher/stargazers)
[![License](https://img.shields.io/github/license/hanwuji1/dsh-web-launcher?color=64748b)](LICENSE)
[![test](https://img.shields.io/github/actions/workflow/status/hanwuji1/dsh-web-launcher/test.yml?label=test)](https://github.com/hanwuji1/dsh-web-launcher/actions)

[English](README.md) · 中文

</div>

> **别敲命令，别输网址。双击鲸鱼，直接开干。**
>
> [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)（`dsh`）是 DeepSeek 开源的智能体框架。
> 它的 Web 界面离你的工作只差一条命令和一个网址——这个插件把这两步也删了。

---

## 🐋 概述

**好工具会消失。**

用老办法打开 DSH Web 界面，每次都要重复同样的仪式：

```
打开终端 → 输入 "dsh web" → 等它启动 → 打开浏览器 → 敲网址 → 回车
```

六步。十秒钟。每次都一样。一天开十次，**一个月就有一百分钟花在"抵达工具"上**——而不是做事。这种摩擦单次看微不足道，但它每次、永远地抽你的税。税是隐形的，所以从来没人质疑它。

**适合谁？** 每天不止一次使用 DSH Web 界面的 Windows 用户——无论是一般使用者还是重度 agent 玩家，只要不想每次手输 `http://127.0.0.1:3080`，想要"双击即达"的入口。

这个插件存在的意义，就是**删掉这套仪式**：

- 🖱️ **一键直达。** 双击鲸鱼。服务启动、浏览器就位，你已经在里面了。没有第二步。
- 🔁 **天生幂等。** 已经在运行？直接开浏览器。连点十下也不坏——没有端口冲突，没有重复实例。
- 🕳️ **复杂藏在暗处。** 启动脚本放在 `%LOCALAPPDATA%`，桌面上只有一个干净的应用图标。
- 🌍 **处处可用。** 启动器是纯 ASCII——GBK、UTF-8、任何 Windows 代码页都能正确解析。
- 🤖 **Agent 原生。** `web_launcher` 模型工具让 agent 自己就能安装、打开、检查入口——入口成为工作流的一部分，而不是绕路。

> *"最好的界面是没有界面，其次是一键。"*

## ✅ 兼容性

| | |
|---|---|
| dsh | 已在 `0.1.0-rc.6`（web profile）实测；走标准 `dsh plugin add` 安装流程（`dsh.bundle` 清单） |
| Node | `^22.19 \|\| >=24`（`engines` 声明） |
| 平台 | Windows 10/11 支持桌面快捷方式；`web_launcher` 工具的 `status` / `open` 动作全平台可用 |
| 最后验证 | 2026-08-15（dsh `0.1.0-rc.6`，插件安装 + 单元测试） |

## 📦 安装 / 升级 / 卸载

需要已有 dsh profile（如 `web`）。

**安装**

```sh
# 从 npm
dsh plugin --profile web add dsh-web-launcher

# 或直接从 GitHub
dsh plugin --profile web add github:hanwuji1/dsh-web-launcher
```

**升级**

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

**卸载**

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

然后清理残留：删除桌面的 `DeepSeek Harness Web.lnk` 快捷方式和 `%LOCALAPPDATA%\dsh-web-launcher` 目录。

**还没装 dsh？** 独立 PowerShell 安装：

```powershell
powershell -ExecutionPolicy Bypass -File install.ps1        # 默认端口 3080
powershell -ExecutionPolicy Bypass -File install.ps1 -Port 8080
```

## 🚀 快速开始

1. 安装插件（见上文）。
2. 重启一次 `dsh web`——插件在启动时激活，自动把 **DeepSeek Harness Web** 应用放到桌面。
3. 双击应用 → 服务启动、轮询就绪、浏览器自动打开。
4. 可复现验证：在任意会话里让 agent 调用 `web_launcher`，动作 `status`——应返回 `running: true` 与 `http://127.0.0.1:3080`。

最小配置（可选）——完整配置见下文。

## 🤖 web_launcher 工具

| 动作 | 效果 |
|---|---|
| `install` | （重新）创建启动器与鲸鱼图标应用快捷方式（Windows） |
| `open` | 用默认浏览器打开 Web 界面 |
| `status` | 检查 DSH Web 服务是否在运行 |

## ⚙️ 配置

在 profile 的 `cordis.patch.yml`（如 `~/.dsh/profiles/web/cordis.patch.yml`）中覆盖插件行。patch 会整体替换该行 config，请保留需要保留的键：

```yaml
- id: dsh-web-launcher
  config:
    autoInstall: true          # 激活时创建/刷新启动器（默认 true）
    createShortcut: true       # 同时创建/刷新应用快捷方式（默认 true）
    port: 3080                 # Web 端口（默认 3080）
    shortcutName: Start-DSH-Web.cmd              # 启动器文件名（默认）
    linkName: DeepSeek Harness Web.lnk           # 应用快捷方式名（默认）
    launcherDir: ""            # 启动器目录；留空 = %LOCALAPPDATA%\dsh-web-launcher
    desktopDir: ""             # 桌面目录；留空 = 自动检测
```

不涉及任何环境变量或敏感信息。

## 🔐 权限与数据

| 领域 | 插件做了什么 |
|---|---|
| 写入文件 | `%LOCALAPPDATA%\dsh-web-launcher\Start-DSH-Web.cmd`；桌面 `DeepSeek Harness Web.lnk` |
| 读取文件 | 不读你的任何数据——只读包内自带的模板与图标 |
| 进程 | 调用 `powershell.exe`（WScript.Shell）创建快捷方式；启动器以你的用户权限运行 `dsh web` |
| 网络 | 仅回环地址：`status` 探测 `http://127.0.0.1:<port>`；`open` 交给系统默认浏览器 |
| 凭据 | 无——从不读取、存储或发送凭据 |

## 🔧 工作原理

```
┌───────────────────────────┐   ┌───────────────────────────────┐
│  DeepSeek Harness Web     │──▶│  cmd /c Start-DSH-Web.cmd     │
│  （桌面 .lnk，鲸鱼图标）   │   │  （藏在 %LOCALAPPDATA%）      │
└───────────────────────────┘   └───────────────┬───────────────┘
                                                │
                        ┌───────────────────────┼───────────────────────┐
                        ▼                       ▼                       ▼
                 dsh 存在吗？            端口在监听吗？          启动 dsh web
                 （友好报错）           （直接开浏览器）        （轮询 → 开浏览器）
```

- **`cordis.patch.yml`** — 声明 `dsh.bundle` 清单；`dsh plugin add` 自动把它归入 profile 的 bundle 栈。
- **`lib/launcher.js`** — 模板渲染（纯 ASCII）、桌面/启动器目录解析、端口探测（`fetch` + 超时）、`WScript.Shell` 创建 `.lnk`。
- **`lib/index.js`** — Cordis 插件（`name` / `inject: ['tools']` / `Config` schema）+ 基于 `defineTool` 的 `web_launcher` 工具。
- **`tools/make-icon.mjs`** — 从官方 Harness favicon 轮廓再生成多尺寸 `whale.ico`（SVG → PNG → PNG-in-ICO）。
- **`tools/make-banner.mjs`** — 再生成 README 顶部 banner。

## 🩺 故障排查

| 症状 | 原因与解决 |
|---|---|
| `transport failure for /api/...: HTTP 403` | **浏览器信任围栏**拦截了跨源调用。打开 DevTools → Network → 失败请求 → 复制它的 `Origin` 头。如果不是 `http://127.0.0.1:3080`，说明有第三方在调用本地 API——浏览器扩展（本地模型/翻译类）、残留标签页或嵌入的 iframe。禁用扩展或关掉该页面即可。`--trusted-host` 参数**不会**放宽 Origin 校验。 |
| `EADDRINUSE` / 端口被占用 | 已有实例在运行——启动器检测到监听端口会直接打开浏览器。想换端口就在 `cordis.patch.yml` 里设置 `port`。 |
| 双击提示 `dsh` 未找到 | 先安装 CLI：`npm install -g @deepseek-ai/dsh` |
| 桌面图标丢失或变成通用图标 | 调用 `web_launcher` 的 `install` 动作重建快捷方式与图标 |
| 日志在哪里？ | 启动器控制台会显示 `dsh web` 输出；profile 状态在 `~/.dsh` 下 |

**回滚**：`dsh plugin --profile web remove dsh-web-launcher` 并删除卸载一节列出的两个文件——插件不会留下任何其他痕迹。

## 🛠️ 开发

- **无构建步骤** — `lib/` 是纯 ESM JavaScript；除 dsh 的 peer 依赖外零运行时依赖。
- **测试**：`npm test`（node:test——无需任何第三方依赖）。
- **再生成资源**：`node tools/make-icon.mjs` 与 `node tools/make-banner.mjs`（需要 `sharp`；本地未安装时设置 `SHARP_PATH` 指向其 `node_modules`）。
- **发布**：bump `package.json` 的 `version` → `npm publish` → `git push`。`dsh.bundle` 清单意味着 `dsh plugin update` 会自动激活新版本。
- **贡献**：欢迎 PR——较大的改动请先开 issue。

## ❓ 常见问题

**Q: 会以管理员权限运行命令吗？** 不会。启动器以你的普通用户权限运行 `dsh web`。

**Q: 会干扰正在运行的服务吗？** 不会。它检测到端口在监听就直接进浏览器。

**Q: 为什么用 `.cmd` 而不是 exe？** 零依赖、无构建链、可审计——60 行，运行前可以通读。

**Q: 非 Windows 系统？** 工具仍然注册（`status` / `open` 全平台可用）；桌面快捷方式按设计仅限 Windows。

## ⭐ 支持

如果这个插件每天帮你省下几秒钟，**点个 Star** —— 它能让更多人找到这个项目，也让维护者知道：这笔"摩擦税"删得值。

[![GitHub Stars](https://img.shields.io/github/stars/hanwuji1/dsh-web-launcher?style=social)](https://github.com/hanwuji1/dsh-web-launcher/stargazers)

发现 bug 或有新想法？[提 Issue](https://github.com/hanwuji1/dsh-web-launcher/issues) —— 欢迎 PR。

## 🗂️ 项目结构

```
dsh-web-launcher/
├── lib/                  # 插件代码（ESM，零运行时依赖）
│   ├── index.js          # Cordis 插件 + web_launcher 工具
│   ├── launcher.js       # 模板、快捷方式、状态、浏览器辅助
│   └── template.cmd.txt  # ASCII 启动器模板
├── icons/                # whale.ico + 多尺寸 PNG（生成物）
├── assets/               # banner.svg、favicon.whale.svg（图标源）
├── tools/                # 图标/banner 生成器（sharp）
├── tests/                # node:test 单元测试
└── install.ps1           # 独立安装（无需 dsh）
```

## 📜 许可证与安全

MIT —— 见 [LICENSE](LICENSE)。

如需**私下**报告安全问题，请使用仓库的 **Security** 标签页（GitHub Security Advisory），不要公开发 issue。
