Appearance
0.3 运行机制初探:profile 与配置树
本章概览:DSH 的"组合式运行"是如何发生的——Harness home、profile、组合包(bundle)、patch 层,以及如何用
--dump-config观察组合结果。这是后续理解一切扩展机制的基础。
从一条命令到一个插件树
dsh --profile web 这条命令,最终会启动一棵插件树:空配置根之上,按固定顺序叠加多个配置层,每层是一份 cordis.yml(或 YAML 数组),声明要挂载的插件及其配置。启动器(launcher,apps/cli)只做三件事:
- 解析自己的 flag;
- 定位并初始化 profile;
- 调用
dsh-app-boot的boot()把配置树挂载成 Cordis 上下文。
出处:
packages/boot/app-boot/README.md(deepseek-harness-src/packages/boot/app-boot/README.md)与apps/cli/README.md
Harness home 与 profile
Harness home
Harness home 是 DSH 的"用户机器上的家",通过 resolveDshHome 解析:优先 $DSH_HOME 环境变量,否则 ~/.dsh。它存放 profile、用户级 patch 层与机器级偏好。
profile 是什么
profile 是存放在 $DSH_HOME/profiles/<name> 下的具名组装,包含:
| 文件/目录 | 作用 |
|---|---|
package.json | 记录树外插件依赖(dependencies)+ profile manifest dsh.profile |
dsh.profile | 元数据清单,其中 bundles 是有序的组合包名称列表 |
cordis.patch.yml | 用户自己的 patch 层 |
node_modules/ | pnpm 安装的树外插件 |
web 与 headless 是随发行版交付的模板 profile,首次使用时自动初始化;其他名字必须通过 dsh plugin --profile <name> 创建。
组合包(bundle)
组合包是 Cordis 配置项及其挂载代码的分发格式:一个 npm 包,其 package.json 声明 "dsh": { "bundle": { "patch": "./cordis.patch.yml" } }。因为组合包的内容是可 patch 的配置项,其上方任何层都能覆盖它。
出处:
docs/architecture.md(deepseek-harness-src/docs/architecture.md)
三个内置组合包:
| 组合包 | 内容 |
|---|---|
dsh-base | 每个 profile 的第一层:模型适配器、工具、持久化、沙箱与审批策略、设置、凭据、遥测 |
dsh-web-app | 在 base 之上增加浏览器应用(webserver、API gateway、workspace、客户端插件) |
dsh-headless | 在 base 之上增加一次性运行器,完全不带服务器 |
配置层的叠加顺序
配置树以空根为起点,依次叠加:
1. dsh.profile.bundles 中各组合包的 patch(按 bundle 列表顺序)
2. profile 自身的 cordis.patch.yml
3. home 级 $DSH_HOME/cordis.patch.yml
4. --patch 指定的覆盖层一条 patch 按 id 定位某个条目并替换其整个 config,或插入新条目。注意:替换是整个 config 替换,没有深层合并——profile 覆盖一个条目时,必须重述该条目保留的所有字段。
出处:
packages/boot/app-boot/README.md#profiles(deepseek-harness-src/packages/boot/app-boot/README.md)与@deepseek-ai/dsh-base/README.md
解析锚点
dsh.profile.bundles 中列出的组合包,先从 dsh 安装目录解析(@deepseek-ai/dsh-base、dsh-web-app、dsh-headless),再从 profile 自身的 node_modules 解析;healProfilesModuleFallback 维护 $DSH_HOME/profiles/node_modules 平面目录(每包一个符号链接),使任何 profile 的裸插件名都能通过 Node 普通父级查找解析。
观察组合结果
不启动即可查看组合后的配置树:
sh
dsh --profile web --dump-config它打印出的任何条目都可以被你的 patch 替换。--dump-default-config 则打印默认配置。renderConfigDump 会为每段同源、同 patch 层的行组标注 # == 注释,标明来源文件与叠加的层,并保留 !!js 表达式原样输出。
出处:
packages/boot/app-boot/README.md(deepseek-harness-src/packages/boot/app-boot/README.md)
!!js 表达式:条件组合
配置条目中允许 !!js 表达式(永远不是 !js),用于求值型字段:
- 条目
config:在声明注入激活后、对插件上下文求值(ctx.serviceName); - 条目
disabled:在每次挂载决策时、对 loader 上下文求值。
典型例子(dsh-base 的 patch 用平台表达式选择 shell 栈):
yaml
# 示例语义:Windows 上禁用 bash 栈,POSIX 上禁用 pwsh 栈
- id: bash-sandbox
name: '@deepseek-ai/dsh-bash-sandbox'
disabled: !!js process.platform === 'win32'出处:
docs/cordis-primer.md#loader-configuration(deepseek-harness-src/docs/cordis-primer.md)与packages/bundle/base/cordis.patch.yml
启动失败行为(fail loud)
DSH 对配置错误采取响亮失败策略:无效命令、来自其他模式的选项、配置错误、启动失败都以非零状态退出。dsh-app-boot 的 assertEntriesLoaded / assertEntriesActivated 会审计:启用的条目若没有 fiber(插件解析失败)或激活失败,会在启动时以明确报错列出每个未解析插件或未满足服务;boot() 失败时先 dispose 部分上下文(让终端类表面先恢复终端)再以带标签的报错退出。
小结
profile + 组合包 + patch 层构成 DSH 的"组合机制":产品形态(web / headless / 自定义)由 profile 决定,能力集合由组合包决定,用户定制由 patch 层决定。下一部分将深入组合机制赖以运行的框架——Cordis(1.1 一切皆插件)。
参考资料
- packages/boot/app-boot/README.md — 启动与 profile 机制(
deepseek-harness-src/packages/boot/app-boot/README.md) - apps/cli/README.md — CLI 行为参考(
deepseek-harness-src/apps/cli/README.md) - docs/cordis-primer.md — Loader 配置与 !!js(
deepseek-harness-src/docs/cordis-primer.md) - packages/bundle/base/cordis.patch.yml — base 组合包 patch 示例