Back to home

dawsondx

dsh-web-open

DeepSeek Harness (dsh) bundle: when `dsh web` is ready, print the full GUI URL and open it in your default browser. Cross-platform, zero runtime deps, fail-safe.

Stars
2
Language
JavaScript
Created
Aug 14, 2026
Updated
Aug 14, 2026

Introduction

dsh-web-open: Auto-open browser when dsh web is ready

中文 | English

MIT version 0.1.2 Windows / macOS / Linux CI


中文

一句话:dsh web 启动完成 → 完整链接自动打印浏览器自动打开。 装一次,任何装了 dsh 的机器都能用;零依赖、跨平台、故障安全。

以前 vs 现在

以前(每次都要)现在(一次装好)
记一长串 npx @deepseek-ai/dsh webdsh web 即可(想更省事可自建快捷方式/别名)
启动后自己拼 http://127.0.0.1:3080/ 复制进浏览器链接自动打印,浏览器自动打开
每台机器手动配 PATH、建快捷方式dsh plugin --profile web add dsh-web-open 一行安装

效果长这样

$ dsh web
[web-open] Web GUI ready: http://127.0.0.1:3080/
# ↑ 完整链接自动打印,浏览器同时自动打开 —— 全程零手动操作

本仓库包含什么(安装前先看清楚)

部分内容安装方式平台
插件本体(核心)index.js / opener.js / cordis.patch.ymldsh web 就绪后打印链接并自动打开浏览器dsh plugin --profile web add dsh-web-open(或 GitHub 直装)Windows / macOS / Linux
可选:Windows 启动器contrib/windows/dsh-web.cmd:一键启动 + 自动检查官方新版自行复制到 PATH 目录,或为它建桌面快捷方式仅 Windows
可选:Windows 更新脚本contrib/windows/dsh-update.cmd:一键更新 harness同上仅 Windows
可选:Unix shell 函数contrib/unix/dsh-fn.shdsh = dsh web加入 ~/.bashrc / ~/.zshrcmacOS / Linux

插件本体不包含更新功能,也不包含桌面快捷方式——桌面快捷方式、PATH 配置属于每台机器自己的事,仓库不替你创建;可选的 Windows 脚本复制到 PATH 后即可使用。

为什么需要它

官方 dsh (0.1.0-rc.6) 目前只有 printUrl(把链接打印到日志里),没有"启动后自动打开浏览器"的能力;CLI 也没有 --open 参数。社区现有的 dsh-plugin-browser / @anweat/dsh-browser 是给模型用的无头浏览器工具(Playwright 抓网页),与本插件解决的问题不同——本插件打开的是你自己的浏览器来看 GUI。

这个插件解决一个问题:dsh web 启动完成后,打印 URL 并自动打开浏览器。跨平台、零运行时依赖、故障安全设计。

安装

前提条件:已安装 dsh、已初始化 profile(跑过一次 dsh web 即可),且 PATH 里有 pnpm

从 GitHub 安装(推荐)

dsh plugin --profile web add github:dawsondx/dsh-web-open

或从 npm 安装

dsh plugin --profile web add dsh-web-open

dsh plugin 会自动把包装进 profile 的 node_modules,并注册到 dsh.profile.bundles。无需手动配置。重启生效:

dsh web
# → [web-open] Web GUI ready: http://127.0.0.1:3080/
# → 浏览器自动打开

验证是否生效

dsh web --dump-config   # 输出里应能看到 "id: web-open"

工作原理

插件等待 Loader 就绪,轮询 webServer 获取绑定端口(最多重试 40×250ms),然后打印 URL 并启动默认浏览器。即使使用 dsh web --port 0(系统分配端口)也能正确打开。

配置

默认行为:打印 URL + 打开浏览器。可在 profile 的 cordis.patch.yml 里覆盖:

# ~/.dsh/profiles/web/cordis.patch.yml
- id: web-open
  config:
    open: false          # 只打印链接,不打开浏览器
    printUrl: true
    # url: http://x:8080/      # 覆盖默认 http://127.0.0.1:<port>/
    # retryAttempts: 40       # 等待服务绑定的重试次数(默认 40 × 250ms)
    # retryIntervalMs: 250

或用环境变量临时关闭:

DSH_OPEN_BROWSER=0 dsh web   # 只打印,不打开浏览器

兼容性与更新策略

这个插件故意只依赖稳定层:

依赖稳定性失效时会怎样
@deepseek-ai/cordis(peer,>=4.0.0稳定的插件核心,独立版本号插件无法加载 → dsh 有明确报错,移除插件即恢复
dsh 内部服务 loader / webServer0.1.0-rc 阶段可能改名降级为 no-op:只打一行 warning,dsh web 照常启动,只是不自动打开

防失效设计

  1. apply() 永不抛错。因为 cordis-plugin-loader 对"插件 apply 抛错"的处理是整个 boot 失败,所以本插件把所有步骤包进 try/catch——最坏情况 = 少一个功能,绝不是起不来。
  2. 缺服务就静默降级webServer 拿不到就不打开;API 改名只影响本插件,不影响别的。
  3. profile 锁版本。插件装进 ~/.dsh/profiles/web 后由 pnpm lockfile 固定,dsh 官方发新版不会自动升级你 profile 里的插件。
  4. 零 rc 依赖。没有依赖任何 0.1.0-rc.x 的内部包,只依赖稳定核心,降低被 rc 版本牵连的概率。

已知的真实风险(写清楚比藏着好)

  • 若 dsh 官方把 loader / webServer 服务改名(rc 阶段完全可能),本插件需要一次小更新(改两个服务名);期间表现为"不自动打开",不影响使用。
  • 若官方未来原生支持 --open,本插件可以退役(卸载即可);为了不撞车,本插件故意不用 CLI 参数,只用 profile 配置控制。
  • 恢复/卸载:dsh plugin --profile web remove dsh-web-open,或直接编辑 ~/.dsh/profiles/web/package.json 的 bundles 列表。

跨平台兼容性(第一性原理审查)

结论:可以跨平台安装并正确运行(Windows / macOS / Linux,含 WSL)。以下逐层对照 dsh 0.1.0-rc.6 实际源码验证过,不是想当然:

实际机制(源码依据)结论
安装dsh plugin --profile web add <包> → pnpm 装入 profile → 命令内 reconcile 把声明了 dsh.bundle 的包写进 dsh.profile.bundlesplugin-*.js需要 pnpm(dsh 官方要求);boot 不会自动 reconcile,所以必须走 dsh plugin add,手动 pnpm add 不生效
装载row 的 name 由 Node 内部加载器从 profile 目录解析(mountRootInclude / cordis-plugin-loader),与官方 @deepseek-ai/dsh-web-app 完全同路径任意 OS 一致;纯 Cordis 插件,无需 TYPERT 清单(无 ./typert 导出的包会被 typert 注册表静默跳过,不报错)
契约导出 name / apply / config;Cordis unwrapExports 兼容具名导出;Config 导出也可(只在有 Config 时才校验)与官方插件同款写法
错误语义cordis-plugin-loader任一插件 apply 抛错 = 整个 boot 失败loader entries failed to apply本插件 apply() 全 try/catch、永不抛错 → 任何情况下都不会拖垮 dsh web
服务读取ctx.get("loader").await() + ctx.get("webServer").port(官方 web-app 的 printUrl 同款)任意 OS 一致;拿不到就降级 no-op + 警告
打开浏览器win32 cmd start(走 SystemRoot\System32\cmd.exe 绝对路径,GUI 启动 PATH 被裁剪也不怕);darwin /usr/bin/open;linux xdg-opensensible-browsergoogle-chromechromiumfirefox 逐级回退v0.1.1 修复:spawn 挂 error 监听 + 启动前 PATH 探测,缺 xdg-open 的 Linux 也不会崩(只警告并打印链接)
编码插件文件全部 UTF-8(JS/YAML),Node 与 js-yaml 原生支持中/英/日文系统均无乱码问题

已知边界(不是 bug,是环境事实):

  • Linux 无图形环境(服务器 / 容器 / WSL 无 DISPLAY):浏览器打不开,但 dsh web 照常运行,链接照常打印——行为可预期;
  • headless / CI:用 DSH_OPEN_BROWSER=0 关掉自动打开;
  • 需要 pnpmdsh plugin 的管理命令本身要求 pnpm(没装会提示安装);
  • dsh 版本:在 0.1.0-rc.6 上验证。rc 系列内用的都是官方 web-app 同款机制,大概率兼容;若未来 rc 改动了 loader/webServer 服务名,本插件按设计自动降级为 no-op(不报错、不影响启动),等一次小更新即可。

如何更新(官方更新后)

先分清边界:插件本体(dsh-web-open)只负责"启动后打印链接 + 自动打开浏览器",不包含更新 harness 的功能——插件运行在 dsh 进程内部,无法更新正在运行的宿主。更新 harness 是终端/脚本层面的事:

场景命令 / 操作说明
更新 harness(任何系统)npm install -g @deepseek-ai/dsh@latest更新 launcher = 更新整个 harness:官方 bundle(dsh-base / dsh-web-app)按"安装优先"从 launcher 解析,重启即生效
更新 profile 里的插件dsh plugin --profile web update本插件发布到 npm 后用此命令升级;GitHub 直装版需重新 dsh plugin add
Windows 可选一键脚本contrib/windows/dsh-update.cmd 复制到 PATH 目录后执行 dsh-update,或自己为它建桌面快捷方式自动对比 registry → 执行上面两条
Windows 可选启动器自动检查contrib/windows/dsh-web.cmd 启动器时,每次打开会静默检查新版并提示;设 DSH_AUTO_UPDATE=1 自动更新后再启动,DSH_SKIP_UPDATE_CHECK=1 关闭同上,需先把脚本放入 PATH

注意:官方 npx @deepseek-ai/dsh web 不会自动更新——npx 复用本地缓存,只有显式 @latest 才会重新拉取。

可选的 shell 便利层

插件解决的是"启动后自动打开",跨平台一致。但"dsh 三个字母 = 启动 Web"属于 shell 层,插件做不到,需要每个用户自己的终端配置:

Windows:把 dsh-web.cmd 启动器放进 PATH(见 contrib/windows/),或自己为它创建桌面快捷方式(右键 → 发送到 → 桌面快捷方式)。

macOS / Linux:在 ~/.bashrc / ~/.zshrc 加:

dsh() {
  if [ $# -eq 0 ]; then command dsh web; else command dsh "$@"; fi
}

装了插件之后,这些便利层里"等待端口 + 打开浏览器"的逻辑都可以删掉(插件会做),只保留启动本身。

开发与测试

npm test    # 13 项单元测试:平台命令形状、URL 构建、apply 永不抛错、打开/抑制路径

真实的端到端验证(dsh web 启动后浏览器弹出)请在没有占用 3080 端口的环境里跑一次。

License

MIT


English

One line: when dsh web is ready → full URL printedbrowser opens automatically. Install once, works on any machine with dsh. Zero dependencies, cross-platform, fail-safe.

Before vs After

Before (every single time)After (one-time setup)
Memorize npx @deepseek-ai/dsh webRun dsh web (or configure an alias / shortcut)
Manually assemble http://127.0.0.1:3080/ and paste it into a browserURL printed automatically, browser opens itself
Configure PATH / shortcuts on every machinedsh plugin --profile web add dsh-web-open — one line

What it looks like

$ dsh web
[web-open] Web GUI ready: http://127.0.0.1:3080/
# ↑ full URL printed, browser opens automatically — zero manual steps

What's in this repo (read before installing)

PartContentsInstallPlatform
Plugin coreindex.js / opener.js / cordis.patch.yml: prints the URL and opens your browser when dsh web is readydsh plugin --profile web add dsh-web-open (or GitHub)Windows / macOS / Linux
Optional: Windows launchercontrib/windows/dsh-web.cmd: one-click start + checks for official updatesCopy it into a PATH dir yourself, or create a desktop shortcutWindows only
Optional: Windows updatercontrib/windows/dsh-update.cmd: one-click harness updateSame as aboveWindows only
Optional: Unix shell fncontrib/unix/dsh-fn.sh: dsh = dsh webAdd to ~/.bashrc / ~/.zshrcmacOS / Linux

The plugin core has no update feature and ships no desktop shortcuts — PATH placement and shortcuts are per-machine, user-owned. The optional Windows scripts work once you copy them into a PATH dir.

Why you need this

The official dsh (0.1.0-rc.6) only has printUrl to log the URL — it doesn't auto-open your browser when ready. There's no --open CLI flag either. Community plugins like dsh-plugin-browser / @anweat/dsh-browser are headless browser tools for the model (Playwright for web scraping), not for opening your own browser to view the GUI.

This plugin solves one problem: when dsh web is ready, print the URL and open it automatically. Cross-platform, zero runtime dependencies, fail-safe by design.

Installation

Requirements: dsh installed, profile initialized (run dsh web once), and pnpm in PATH.

Install from GitHub (recommended)

dsh plugin --profile web add github:dawsondx/dsh-web-open

Or from npm

dsh plugin --profile web add dsh-web-open

dsh plugin automatically adds the bundle to your profile's node_modules and registers it in dsh.profile.bundles. No manual configuration needed. Restart to activate:

dsh web
# → [web-open] Web GUI ready: http://127.0.0.1:3080/
# → Browser opens automatically

Verify it's active:

dsh web --dump-config   # Should show "id: web-open"

How it works

The plugin waits for the Loader to settle, polls webServer for the bound port (retries up to 40×250ms), then prints the URL and spawns your default browser. Works even with dsh web --port 0 (OS-assigned port).

Configuration

Default behavior: print URL + open browser. Override in your profile's cordis.patch.yml:

# ~/.dsh/profiles/web/cordis.patch.yml
- id: web-open
  config:
    open: false          # Only print URL, don't open browser
    printUrl: true
    # url: http://x:8080/      # Override default http://127.0.0.1:<port>/
    # retryAttempts: 40       # Wait attempts (default 40 × 250ms)
    # retryIntervalMs: 250

Or temporarily disable with environment variable:

DSH_OPEN_BROWSER=0 dsh web   # Print only, no browser

Compatibility & update strategy

This plugin deliberately depends only on stable layers:

DependencyStabilityIf it breaks
@deepseek-ai/cordis (peer, >=4.0.0)Stable plugin core, independent versioningPlugin won't load → dsh shows clear error, remove to recover
dsh internal services loader / webServerMay change during 0.1.0-rcDegrades gracefully: prints warning, dsh web starts normally, just won't auto-open

Fail-safe design

  1. apply() never throws. Since cordis-plugin-loader fails the entire boot on plugin errors, every step is wrapped in try/catch — worst case = one feature missing, never a startup failure.
  2. Missing services degrade silently. If webServer is unavailable, it warns and skips opening; other plugins unaffected.
  3. Profile locks versions. Plugins installed in ~/.dsh/profiles/web are pinned by pnpm lockfile; official dsh updates won't auto-upgrade your plugins.
  4. Zero rc dependencies. No internal 0.1.0-rc.x packages, only stable Cordis core — reduces breaking change risk.

Known risks (transparency)

  • If dsh renames loader / webServer services (possible during rc), this plugin needs a small update (change two service names); during that time it'll silently skip auto-open without breaking dsh.
  • If official dsh adds native --open, this plugin can be retired (just uninstall). To avoid conflicts, this plugin deliberately avoids CLI params and uses profile config only.
  • Uninstall: dsh plugin --profile web remove dsh-web-open or edit ~/.dsh/profiles/web/package.json bundles list.

Cross-platform compatibility (first-principles review)

Verified layer-by-layer against dsh 0.1.0-rc.6 source, not by assumption:

LayerActual mechanism (source basis)Result
Installdsh plugin --profile web add <pkg> → pnpm installs into profile → reconciles within the command, writing bundles that declare dsh.bundle into dsh.profile.bundlesRequires pnpm (official requirement); boot does NOT reconcile, so dsh plugin add is mandatory — manual pnpm add alone won't activate it
LoadRow name resolves via Node's internal loader from the profile dir (mountRootInclude / cordis-plugin-loader) — the exact path official @deepseek-ai/dsh-web-app usesSame on every OS; plain Cordis plugin, no TYPERT manifest needed (packages without a ./typert export are silently skipped by the typert registry)
ContractExports name / apply / config; Cordis unwrapExports handles named exports; Config export is optional (validated only when present)Same writing style as official plugins
Error semanticscordis-plugin-loader: one plugin throwing in apply fails the whole bootThis plugin's apply() is fully wrapped in try/catch and never throws → can never take down dsh web
Service readsctx.get("loader").await() + ctx.get("webServer").port (same pattern as the official web-app printUrl)Same on every OS; degrades to no-op + warning if unavailable
Opening the browserwin32 cmd start (absolute SystemRoot\System32\cmd.exe, safe even when PATH is stripped on GUI launch); darwin /usr/bin/open; linux xdg-opensensible-browsergoogle-chromechromiumfirefoxFixed in v0.1.1: spawn error listener + PATH probing before launch — a Linux without xdg-open warns and prints the link instead of crashing dsh
EncodingPlugin files are UTF-8 (JS/YAML); Node & js-yaml nativeNo mojibake on any locale

Known environment boundaries (not bugs):

  • Linux without a graphical session (server / container / WSL without DISPLAY): the browser won't open, but dsh web runs normally and the link is still printed — predictable behavior.
  • Headless / CI: disable auto-open with DSH_OPEN_BROWSER=0.
  • pnpm is required: dsh plugin itself requires pnpm (it prompts to install if missing).
  • dsh version: verified on 0.1.0-rc.6. Within the rc line this uses the same mechanism as the official web-app bundle, so compatibility is very likely; if a future rc renames loader / webServer, the plugin degrades to no-op by design (no error, no startup impact) until a small update.

How to update (after an official release)

Boundary first: the plugin core (dsh-web-open) only prints the URL and opens the browser — it has no harness-update feature, because a plugin running inside dsh cannot update its own host. Updating the harness is a terminal / script concern:

ScenarioCommand / actionNotes
Update the harness (any OS)npm install -g @deepseek-ai/dsh@latestUpdating the launcher = updating the whole harness: the official bundles (dsh-base / dsh-web-app) resolve installation-first from the launcher — effective on next start
Update profile pluginsdsh plugin --profile web updateBumps this plugin once published to npm; GitHub-installed copies need a fresh dsh plugin add
Optional Windows one-clickCopy contrib/windows/dsh-update.cmd into a PATH dir, then run dsh-update (or create a shortcut yourself)Compares against the registry → runs the two commands above
Optional Windows launcher checkUsing contrib/windows/dsh-web.cmd, each launch silently checks for a newer version and prints a notice; DSH_AUTO_UPDATE=1 updates first, DSH_SKIP_UPDATE_CHECK=1 disablesRequires the script in PATH first

Note: the official npx @deepseek-ai/dsh web does NOT auto-update — npx reuses its local cache; only an explicit @latest re-fetches.

Optional shell convenience layer

The plugin solves "auto-open after boot" cross-platform. But "type dsh = start web" is a shell-layer concern the plugin can't handle — each user configures their own terminal:

Windows: put dsh-web.cmd from contrib/windows/ in PATH, or create a desktop shortcut for it yourself (right-click → Send to → Desktop).

macOS / Linux: add to ~/.bashrc / ~/.zshrc:

dsh() {
  if [ $# -eq 0 ]; then command dsh web; else command dsh "$@"; fi
}

Once the plugin is installed, these shell shortcuts can drop their "wait for port + open browser" logic (the plugin handles it) and just invoke dsh.

Development & testing

npm test    # 13 unit tests: platform commands, URL construction, apply never throws, open/suppress paths

For real end-to-end verification (browser actually pops up after dsh web), test in an environment where port 3080 is free.

License

MIT