跑起来 + 读懂你机器上的插件树
把仓库跑起来,然后用 --dump-config 把「一切皆插件」这句话变成你屏幕上的一棵可读的树。
这一课只做一件事:把「一切皆插件」这句话,变成你屏幕上一棵可读的树。
做完你会有两样东西:一份你自己机器上的插件清单,以及一双能看懂 --dump-config 每一行来自哪一层的眼睛。后面四个 Lab 全都建立在这双眼睛上。
1 先跑起来
$ export DEEPSEEK_API_KEY=... $ npx @deepseek-ai/dsh web
默认在 http://127.0.0.1:3080 起 Web UI,并在本地启动时打开默认浏览器。走 SSH 的话它只打印 URL——因为转发地址是 SSH 客户端或编辑器在管。不想开浏览器就加 --no-open。
第一次跑发生了什么:web 和 headless 这两个 profile 会从出厂模板自动初始化,落在 $DSH_HOME/profiles/<name>($DSH_HOME 没设就是 ~/.dsh)。其它名字的 profile 必须用 dsh plugin 显式创建,否则会大声失败并提示你该跑哪条命令。
2 把插件树打印出来
这条命令不启动 agent,只打印生效的插件树:
$ dsh --profile web --dump-config
输出是一份可加载的 YAML 文档,每一段前面有一行 # == 注释,写明这一段来自哪个文件、被哪些 patch 层改过。大概长这样:
# == @deepseek-ai/dsh-base - id: web name: '@deepseek-ai/dsh-web' config: searchProvider: deepseek-official ← 记住这一行,Lab 2 要换它 - id: web-search-deepseek name: '@deepseek-ai/dsh-web-search-deepseek' config: apiKeyEnv: DEEPSEEK_API_KEY - id: tool-web name: '@deepseek-ai/dsh-tool-web' config: fetch: false # 抓取默认关掉,理由写在补丁文件里 searchTimeoutMs: 60000
这三行取自 packages/bundle/base/cordis.patch.yml 的真实内容(核对于 commit b150a55)。你机器上的顺序和字段可能不同。
3 读懂它:四个问题
拿着你的输出,回答这四个问题。能全部答上来,这一课的目的就达到了。
- agent loop 在哪一行?找找
agent-loop。它跟tool-bash、web排在同一层,没有任何特殊待遇——这就是「无特权核心」的字面意思。 - 哪些行来自
dsh-base,哪些来自dsh-web-app?看# ==注释。webprofile 的 bundle 列表是base + web-app。 - 有没有一行是被后面的层改过的?如果有,注释里会写出改它的每一个 overlay 的标签。
- 有没有带
disabled: !!js …的行?有的话你多半在看 shell 那一组——base bundle 用disabled: !!js process.platform === 'win32'把 bash 和 pwsh 两套按平台各挂一套。!!js在 dump 里是原样保留、不求值的。
4 对比两条 dump 命令
$ dsh --profile web --dump-default-config # 只有 bundle 层 $ dsh --profile web --dump-config # 再叠上 profile / home / --patch
刚装完的机器上这两份应该几乎一样——因为你还没写任何补丁。做完 Lab 2 再跑一次,差异就是你自己那一层。
它不是一个「大概是这样」的诊断工具。renderConfigDump 走的是 include 自己的解析器和 patch 算法(entryListSchema / applyEntryPatches),所以结果等同于 boot() 真正挂载的东西。另外它不会运行任何 app 命令行 provider,所以它显示的是「app 参数被解析之前」的组合树——反过来,一个带着 app 参数的 dump 调用会被拒绝。
5 顺手看一眼你的 profile 目录
$ ls -a ~/.dsh/profiles/web/ package.json cordis.patch.yml node_modules
package.json 里有两样东西:树外插件的 dependencies,和 profile manifest dsh.profile(里面是有序的 bundles 列表)。cordis.patch.yml 就是你的补丁层——现在多半是空的。
一个会咬人的细节:这个文件空着或者只有注释会抛错(它解析出来是「什么都没有」,而不是「一个空列表」)。要停用这一层,写 []。
同样这件事,在别家要几步?
待核对
待核对
Lab 2 · 零 fork 换掉一个 provider——把你刚认出来的那行 searchProvider: deepseek-official 换掉。20 分钟。