dshseek

seek://guides/profiles-and-dsh-plugin

DSH Profile 与 dsh plugin 命令

2026年8月24日Intermediate← 全部教程

TL;DR

DSH「bundle / profile」两个名词与 dsh plugin 命令的实战指南。profile 是 $DSH_HOME/profiles/<name> 下的目录,列出它叠加的 bundle;dsh plugin 把参数转发给该目录下的 pnpm,所以 pnpm 的每个动词都能用。官方发行的 profile 是 web 与 headless;web 也可以用 dsh web 别名访问。

要点

  • 按上游 CLI 参考,`dsh --profile <name>` 启动 `$DSH_HOME/profiles/<name>` 处的 profile;`dsh web` 是 `--profile web` 的硬编码别名
  • 首次使用时自动从模板初始化的两个 profile:`web`(base + web-app)与 `headless`(base + headless);其他名字会直接报错并提示 `dsh plugin --profile <name> add <package>`
  • 按架构概述,profile 在 `dsh.profile.bundles` 中按顺序列出它叠加的 bundle,存放它在 pnpm 里安装的的所有外部插件,并保留用户自己的 `cordis.patch.yml`
  • 按 CLI 参考,`dsh plugin --profile <name> <args...>` 在 profile 缺失时初始化 profile,再把 `<args...>` 转发给 pnpm —— `add` / `remove` / `why` / `update` 以及 pnpm 的其他动词都直接可用;pnpm 必须位于 PATH 上
  • 按 CLI 参考,profile 的有效配置按以下顺序叠加到空 root:profile 列出的每个 bundle 的 patch(按 list 顺序)→ profile 自身的 `cordis.patch.yml` → home 层的 `$DSH_HOME/cordis.patch.yml` → argv 中每个 `--patch <path>` 覆盖;后一层按 row id 整体覆盖前一层
  • 按 CLI 参考,`dsh --profile web --dump-config`(与 `--dump-default-config`)只打印组合出的配置树、不实际启动 —— 用来检视某个 profile 会装什么
  • 按 CLI 参考,运行中的 profile 保留当前启动时的 bundle 集合 —— 对 profile 或 home 层 `cordis.patch.yml` 的常规编辑通过热重载即时生效;但新增、删除或升级 bundle 仍需要重启 profile

本篇拆解你在 dsh 日常使用里会遇到的两个名词 —— profile 与 bundle —— 以及把二者串起来的 dsh plugin 命令。下方每条断言都能溯源到抓取的上游文档:CLI 参考(apps/cli/reference/README.md)、架构概述(docs/architecture.md)、打包与发布插件教程(docs/user/develop/basic/publish.md)。

profile 是什么

按架构概述,profile 是 home 里一个有名有姓的组合。它住在 $DSH_HOME/profiles/<name>,身上挂着三件东西:

  • 它要叠加的 bundle(按顺序写在 dsh.profile.bundles 清单里)
  • 它在 pnpm 里安装的所有外部插件
  • 用户自己的 cordis.patch.yml —— 叠在每个 bundle 之上的覆盖

官方发行两个 profile,首次使用时自动从模板初始化:web(base + web-app)与 headless(base + headless)。其他名字会直接报错,并提示 dsh plugin --profile <name> add <package>。

dsh --profile <name> 的启动顺序

按 CLI 参考,dsh --profile <name> 会启动 $DSH_HOME/profiles/<name>。有效配置按以下顺序叠加到空 root:

  1. profile 清单 dsh.profile.bundles 列出的每个 bundle 的 patch(按 list 顺序)
  2. profile 自身的 cordis.patch.yml
  3. home 层 $DSH_HOME/cordis.patch.yml(机器级偏好跨 profile 共享,所以排在 profile 层之上)
  4. argv 中每个 --patch <path> 覆盖

后一层按 row id 整体替换前一层;patch 不深合并单 key。dsh web 是 --profile web 的硬编码别名;argv 之后的参数会被原样交给启动后的 profile 处理(ctx.cmdlineArgs)。

dsh plugin --profile <name> ... 管理 bundle

按 CLI 参考,dsh plugin --profile <name> <args...> 做两件事:

  • profile 缺失时先初始化(用发行模板,或对其他名字用 @deepseek-ai/dsh-base 起步)
  • 然后把 <args...> 转发给 pnpm,profile 目录作为工作目录

第二点是关键:pnpm 的每个动词都能用 —— add、remove、why、update,以及 pnpm 其他动词。规范动作是:

dsh plugin --profile <name> add @scope/pkg
dsh plugin --profile <name> remove @scope/pkg
dsh plugin --profile <name> update

dsh 不发明自己的子命令表;pnpm 不认识的动词这里也不可用。

两点必须知道的行为细节

按 CLI 参考:

  • bundle 成员关系需要重启 profile。 正在跑的 profile 保留当前启动时的 bundle 集合;对 profile 或 home 层 cordis.patch.yml 的常规编辑会被事务式热重载,但新增、删除、升级 bundle 仍是启动边界。
  • 从 Git 装 TypeScript 源码包会撞上 pnpm ≥10 的 allowBuilds 门禁。 Git 装只拉源码、不跑 build 脚本,所以 lib/ 不在;把 pnpm 给的包名加到 profile 的 pnpm-workspace.yaml 的 allowBuilds 下再重跑;或者直接发预编译产物到 npm / 用 pnpm pack 出 tarball。

不实际启动只检视

按 CLI 参考:

dsh --profile web --dump-default-config
dsh --profile web --patch ./extra.yml --dump-config

--dump-default-config 只打印 bundle 层;--dump-config 还会加上 profile 的 cordis.patch.yml、home 层的 patch、--patch 覆盖。两份输出都会按注释标出每行来自哪个文件;!!js 表达式不会被求值;dump 永远不会跑 app 命令行 provider,所以它展示的是 app 参数被解析之前的组合树。

与站内其他位置的关系

官方参考