ARTICLE · 1343041
dsh 插件开发 02|认知:两条路径跑起来,先看第一棵插件树
摘要:上篇留的那条命令,这一篇真的跑一遍。npm 与源码两条启动路径、环境门槛,以及不用起服务就能打印的第一棵插件树。
第 01 章收尾留了一条命令:dsh --profile web --dump-config。当时拿它只为一件事,说明 dsh 打印出来的每一行都能被自己的 patch 换掉。patch 是一份只写要改的配置行的 YAML。清单长什么样,那篇没展开。
这一篇把命令真的跑一遍。
上篇写过「前两章不急着装环境」,条件是把 SAFETY.zh.md 读完。官方五条建议里,优先一次性虚拟机或容器、只给最小权限、运行前检查插件与配置,这一篇默认都照做。装在哪台机器上,比装哪个版本更该先定下来。
两条路
第一条从 npm 拿现成的包,装好 Node.js 就能执行:
npx @deepseek-ai/dsh webREADME 写得很具体:命令默认在 http://127.0.0.1:3080 起 Web UI,本地启动时会打开默认浏览器;SSH 里启动只打印 host URL,因为本地转发地址归 SSH 客户端或编辑器管。加 --no-open 就只起服务、不开浏览器。
--no-open 属于 Web 应用的参数,不是启动器的参数。官方 CLI 行为参考给了一条容易踩的边界:启动器只解析自己的 flag,遇到第一个认不出来的 token 就停手,后面全部原样交给所选 profile(一份可启动的命名组合)。所以 dsh --profile web --port 8080 里的 --port 归 Web 应用,dsh --help 打印启动器自己的帮助,dsh --profile web --help 打印的是 Web 应用的帮助,而且不会启动服务。按这条规则推,把应用参数写到 profile 前面就不再归启动器管了。
版本先确认,再动手。
-V / --version 在应用参数边界之前时打印启动器版本,官方还写明插件安装和 profile 启动会拿同一个值去比对 engines.dsh 兼容范围。用 npx 时可以让它把启动器参数透传过去,另外查一下注册表当前的发布版本:
npx @deepseek-ai/dsh --versionnpm view @deepseek-ai/dsh version后者是通用 npm 命令,查到的值和本机 --version 读到的可能不是一回事。npx 会复用本地缓存,预览期迭代又快,缓存里留着旧版的可能是存在的;这是本系列的提醒,不是官方结论。本篇不写任何版本号,以你现场读到的为准。
第二条从仓库源码构建:
git clone https://github.com/deepseek-ai/deepseek-harness.gitcd deepseek-harnesspnpm installpnpm run buildpnpm dsh webREADME 对最后两步的解释是:pnpm run build 准备仓库产物,pnpm dsh web 使用这些已构建的产物,不重新构建。CLI 参考把源码执行讲得更透:pnpm dsh 实际是 node --import tsx/esm 启动 apps/cli/src/bin.ts 并转发参数,脚本本身不构建;Typert Host 产物缺失时,profile 启动会报模块解析错误并提示先 build;启动器也不检查产物是不是最新,陈旧的前端组合包可能一直跑旧浏览器代码,直到重新构建。改过源码之后要不要重跑 pnpm run build,答案在这里,不用猜。
两条路别混着用。
npm 装的是打包后的产物,源码路径跑的是 TypeScript 入口(tsx 是这里的 TypeScript 运行器),模块解析方式不一样;同一台机器两边各装一份,很容易对着 A 的配置树改 B 的代码。这是本系列按两份官方文档推出来的提醒,第 17 章讲绝对路径时还会再遇到一次。
装之前
官方 docs/development.zh.md 的搭建教程列了完整前置条件,照抄比转述可靠:
Node.js 24.9 或更高,CI 覆盖 24.9、最新的 24 和 26 启用 Node.js 的 TypeScript 类型剥离。构建脚本用 tsdown 的 native 配置加载器读 tsdown.config.ts,NODE_OPTIONS里带--no-experimental-strip-types、或 Node 构建本身缺 TypeScript 支持时,pnpm run build会先检查这个条件并说明原因启用了 Corepack 的 pnpm。Corepack 是 Node 自带的包管理器版本调度器,仓库在 package.json里固定了 pnpm 版本,官方开发指南当前写的是pnpm@11.28.5,以仓库现场为准;pnpm --version解析不出来时先跑corepack enableGit 2.26 或更高 可选:一个 DeepSeek API key,用于 Web、headless、ACP 演示和真实 API 的 e2e 测试
新克隆之后先跑一次 pnpm run typecheck,成功退出就算搭建完成。Windows 可以原生开发,也可以用 WSL 2;官方要求把检出目录、装好的依赖和工具链放在同一操作系统环境里,跨文件系统访问会给 Git、依赖安装和构建这些 I/O 密集操作加开销。用 WSL 2 就把目录放在 Linux 文件系统,用 Windows 原生工具就放 Windows 文件系统。
这里没有一条要求你现在填 API Key。
启动服务、打印配置树都不需要凭据;密钥是「跑真实模型任务」时才用得上。
跑起来之后
官方《使用 Web UI》指南是从「服务器已经跑起来」开始写的,里面有两条第一次必经的操作。
dsh 进程把启动命令所在的目录当作默认文件系统位置。全新的 Web UI 不会替你选中任何工作区,得点「选择工作区」,把启动时所在的项目目录加进来并选中;选中之前,会话输入框不可用。想让模型真的干活,还要打开「设置 → 模型」填入 DeepSeek API 密钥并保存,官方说模型路由会立即可用,不需要重启服务器。
这两步和上篇的安全说明是同一件事。工作区目录就是这圈代码默认能读写的地方,所以第 01 章那句「别放在装着公司代码和凭据的工作机上」,落点就在这一步:先想清楚把哪个目录交给它。官方也写了,按当前权限策略某项操作需要审批时,Web UI 会先问你,审批不是自动放行。
还有一页设置值得第一次就翻一下。CLI 行为参考提到,DeepSeek 会话日志贡献器默认会随后续 DeepSeek 请求发送尚未确认接收的完整日志后缀,包括经已配置网关发送的请求;Web 的「设置 → 通用 → 在使用官方模型 API 时上传 Session Log」可以关掉它,也能把对应配置项的 enabled 设为 false。本篇不替你决定开关,只提醒这一页存在。
第一棵插件树
官方 CLI 行为参考里有一句,比第 01 章给人的印象省事得多:
可在不启动的情况下检查组合出的配置树。
看树不用起服务。
按架构文档的定义,运行中的 dsh 是一棵插件树,由启动时按序叠加的各层组合而成。profile 是放在 Harness home 里的具名组装,Harness home 指 dsh 存放 profile 与本机配置的目录;profile 列出自己叠放的组合包、树外插件,以及用户自己的 cordis.patch.yml。组合包是「配置行 + 挂载代码」的分发格式,所以下层插入的内容始终能被上层 patch。
三个 dump 命令的分工,CLI 参考写得很清楚:
dsh --profile web --dump-default-config | ||
dsh --profile web --dump-config | cordis.patch.yml、home 级 $DSH_HOME/cordis.patch.yml 与 --patch overlay | |
dsh --profile web --dump-config-schema |
overlay 就是后叠上去的覆盖层。前两个命令都会打印注释,标明每行由哪个文件提供、哪些 overlay 改过它;配置里的 !!js 表达式保持未求值,找不到目标的 patch 会报告到 stderr。dump 会初始化缺失的 profile 文件,但不运行应用参数提供方,调用里带应用参数会被拒绝。三个 dump flag 互斥,desktop 是保留名,CLI 会拒绝对它做配置 dump。dsh web --dump-config 是官方给过的简写,同样落在这些规则里。
随发行版交付的 profile 模板有五个:web、headless、sdk、sdk-minimal、acp。架构文档说前四个共享 dsh-base 作为第一层,各自再叠浏览器应用、不带服务器的一次性 runner、SDK 的 JSON-RPC 服务器、仅用于自动化的 ACP 服务器;sdk-minimal 是刻意保留的例外,一个组合包带着完整显式配置树,不套 base。CLI 参考补了一句:这五个首次使用时会自动从随附模板初始化。
本系列建议把两份输出都存下来,后面每改一次配置就 diff 一次。下面用的是通用 shell 重定向:
dsh --profile web --dump-default-config > tree-default.ymldsh --profile web --dump-config > tree-local.yml一份是发行版默认层,一份是叠了你本机 patch 的最终树。第 11 章做四层覆盖实验时,这两份文本就是对照基线。
这一章不解释任何一行。 看到成排的 id / name / config、认不出包名、!!js 看不懂,都正常。要记住的只有三件:架构文档原话「它打印出的任何条目,都可以由你自己的 patch 替换」;注释会告诉你一行来自哪个文件;这份清单说明的是组合了哪些层,不说明谁先谁后。第 09 章才按能力域逐行拆 base bundle,第 05 章会解释加载顺序为什么由服务可用性决定。
接下来四章
打印完这份树,多数人会问同一串问题:这些行是谁变成运行中的插件的?为什么换个顺序照样跑?某个服务没了,依赖它的插件会怎样?卸载之后,注册过的东西谁收回去?
这四个问题的答案都不在 dsh,在它底下的 Cordis。第 03 章把两者分工切开,第 04 章看 ctx 上的服务从哪来,第 05 章拆 Registry 与 Fiber 状态机,第 06 章讲 effect 和可逆注册。四章都在官方那个不需要密钥的单文件启动器里做,动手量不大,但后面凡是「插件没反应」,都要回到这四章找原因。
现在可以做的动作有三个:把 dsh --version 读到的值记进自己的笔记(别写进配置,预览期会变),按 SAFETY.zh.md 选好一个一次性环境,跑上面两条 dump 命令把两份树存下来。做完这些再决定要不要填 API Key。
下一篇是 dsh 插件开发 03|底座:Cordis 不知道 Agent,却管住所有插件。
本篇一手出处:github.com/deepseek-ai/deepseek-harness 的 README.md / README.zh.md、docs/development.zh.md、docs/architecture.zh.md、apps/cli/README.zh.md、apps/cli/reference/README.zh.md、docs/user/guide/index.zh.md(核实日期 2026-11-11,分支 master)。逐条硬事实与存疑项见同目录 2026-11-11-dsh-02-run-and-dump-facts.md。















































































