2026/10/21 2:16:30

[DeepSeek Harness深度拆解-04]完整的插件配置树如何构建?

[DeepSeek Harness深度拆解-04]完整的插件配置树如何构建? 通过前面两篇文章针对Profile的介绍Profile究竟是什么和创建一个新的Profile提供自定义插件我们知道了所谓的Profile本质上就是构建了一组用来提供插件的配置但是最终应用到Cordis上的插件不限于此它还有其他的来源。这篇文章就来补齐最后这张拼图。1. Profile提供的两层插件配置回顾一下前面的两篇文章总结一下它们主要提供的知识点最终的插件树是按照固有的顺序先后应用插件补丁文件构建而成每个补丁文件提供一组PatchOptions列表一个PatchOptions对象代表一个插件组插件补丁文件可以利用- insert在根节点或者在现有的插件组中添加一组插件组插入的插件组体现为一个EntryOptions对象PatchOptions和EntryOptions不仅可以指定作为标识的id和作为包名/模块的name还可以分别利用config、inject和intercept指定插件配置、注入的依赖服务列表和针对服务的配置基于利用isolate构建独立的隔离域本质上就是根据指定的名称调用isolate方法来创建子ContextProfile提供了两组PatchOptions列表分别以如下的两种方式构建利用package.json注册包提供的插件补丁文件构建而成利用自身的cordis.patch.yml补丁文件构建而成。2. 插件配置树的额外两层DSH被启动并完成初始化流程后除了通过指定Profile构建的两层插件配置还包括如下两层在DSH运行时目录通过环境变量DSH_HOME定义默认位置为~/.dsh或者%userprofile%.dsh下定义的补丁文件用户启动DSH以命令行参数--patch指定的补丁文件这个参数可以多次指定意味着可以指定一组补丁文件。上述两组补丁文件构建的PatchOptions会和Profile对象一起组成一个ComposedProfile对象该接口对应的定义如下interfaceComposedProfile{profile:Profile bundlePatches:PatchOptions[]homePatches:PatchOptions[]overlays:PatchOptions[]}四个字段成员说明如下profile 构建的Profile对象bundlePatches由注册到Profile的包提供的补丁文件构建的一组PatchOptions列表PatchOptions列表的列表被打平后的结构homePatches由在DSH运行时目录提供的补丁文件构建的PatchOptions列表overlays: 由命令行参数--patch提供的补丁文件构建的PatchOptions列表。上述作为四个来源的PatchOptions列表可以视为四个层次。在生成最终插件树时会按照既定的顺序提取每个PatchOptions并应用到当前构建的这颗树上。具体顺序如下ComposedProfile.bundlePatchesComposedProfile.profile.patchPathComposedProfile.homePatchesComposedProfile.overlays3. 注册homePatches创建一个新的Profile提供自定义插件中我们已经创建了一个用来提供自定义插件的Profile我们现在来看看如何我们补齐其他两种类型的补丁。为此我们在%userprofile%.dsh目录下创建一个补丁文件cordis.patch.yml并提供如下的内容-insert:-id:plugin7name:jaydenai/fooconfig:source:$DSH_HOME/cordis.patch.yml-id:group1insert:-id:plugin8name:jaydenai/barconfig:source:$DSH_HOME/cordis.patch.yml我们在这个补丁中提供了两个插件其中插件foo被置于根节点另一个插件bar被添加到现有的组group1中。为了能够在运行时确定插件的来源我们通过提供的配置将source指定为$DSH_HOME/cordis.patch.yml。接下来我们按照如下的方式执行命名npx tsx apps/cli/src/bin.ts --profile test以源码启动DSH并将profile设置为test。从输出可以看出多出了两个来源匹配的插件被执行输出的结构与与上面的定义相符。PS E:\dsh\deepseek-harness npx tsx apps/cli/src/bin.ts --profile test npm notice run deepseek-ai/dsh-root0.1.5-alpha.2 npx npm notice run tsx apps/cli/src/bin.ts --profile test LoaderIncludefoo[package.json] LoaderIncludefoo[cordis.patch.yml] LoaderIncludefoo[$DSH_HOME/cordis.patch.yml] LoaderIncludebar[package.json] LoaderIncludeGroupbar[cordis.patch.yml] LoaderIncludeGroupbar[$DSH_HOME/cordis.patch.yml] LoaderIncludeGroupbaz[package.json] LoaderIncludeGroupGroupqux[package.json] LoaderIncludeGroupGroupbaz[cordis.patch.yml]4. 注册overlays我们进一步来验证利用命令行参数--patch提供的补丁文件能否按照我们的预期参与到插件树的构建流程。为此我们定义了如下两个补丁文件分别命名为overlays1和overlays2。这两个补丁同样注册了foo和bar两个插件前者置于顶层的根节点后者分别添加到由ComposedProfile.bundlePatches创建的组group1和group2中。我们将这两个文件保存到d:\下。d:\overlays1:-insert:-id:plugin9name:jaydenai/fooconfig:source:overlays1-id:group1insert:-id:plugin10name:jaydenai/barconfig:source:overlays1d:\overlays1:-insert:-id:plugin11name:jaydenai/fooconfig:source:overlays2-id:group2insert:-id:plugin12name:jaydenai/barconfig:source:overlays2我们依然按照上面的方式启动DSH不过这次我们通过两次使用命令行参数--patch分别指定了上述两个补丁文件。由它们提供的四个插件同样出现在最终的输出结果中。PS E:\dsh\deepseek-harness npx tsx apps/cli/src/bin.ts --profile test --patch d:\overlays1.yml --patch d:\overlays2.yml npm notice run deepseek-ai/dsh-root0.1.5-alpha.2 npx npm notice run tsx apps/cli/src/bin.ts --profile test --patch d:\overlays1.yml --patch d:\overlays2.yml LoaderIncludefoo[package.json] LoaderIncludefoo[cordis.patch.yml] LoaderIncludefoo[$DSH_HOME/cordis.patch.yml] LoaderIncludefoo[overlays1] LoaderIncludefoo[overlays2] LoaderIncludebar[package.json] LoaderIncludeGroupbar[cordis.patch.yml] LoaderIncludeGroupbar[$DSH_HOME/cordis.patch.yml] LoaderIncludeGroupbar[overlays1] LoaderIncludeGroupbaz[package.json] LoaderIncludeGroupGroupbar[overlays2] LoaderIncludeGroupGroupqux[package.json] LoaderIncludeGroupGroupbaz[cordis.patch.yml]5. 包含文件的使用在定义补丁问文件的时候插件的节点被我们设置成包名插件组的名称被统一设置成预定义的cordis:group。其实我们还可以将节点名称设置为cordis:include将另一个补丁文件引进来。比如在d:\include.yml添加了针对foo和bar的两个插件。由于SDH针对包的解析会在该文件所在的目录进行所以我们直接使用定义插件的源文件。除此之外包含就隐含插入的意思所以不能在外面在套一层insert。我们通过配置插件将source设置成include以示来源。-id:plugin13name:file:///E:/dsh/deepseek-harness/packages/demo/foo/lib/index.jsconfig:source:include-id:plugin14name:file:///E:/dsh/deepseek-harness/packages/demo/bar/lib/index.jsconfig:source:include我们修改testProfile所在目录的补丁文件cordis.patch.yml并添加了一个id和name分别为include-extra-tools和cordis:include的节点在设置的配置中利用path字段只想上面这个include.yml文件DSH要求文件路径严格采用为file:///为前缀的模式。-insert:-id:plugin5name:jaydenai/fooconfig:source:cordis.patch.yml-id:include-extra-toolsname:cordis:includeconfig:path:file:///d:/include.yml-id:group1insert:-id:plugin6name:jaydenai/barconfig:source:cordis.patch.yml-id:group2insert:-id:plugin7name:jaydenai/bazconfig:source:cordis.patch.yml我们依然按照上面的方式启动DSH。会发现d:\include.yml包含的两个插件会出现在最终的输出结果中最后两个。PS E:\dsh\deepseek-harness npx tsx apps/cli/src/bin.ts --profile test --patch d:\overlays1.yml --patch d:\overlays2.yml npm notice run deepseek-ai/dsh-root0.1.5-alpha.2 npx npm notice run tsx apps/cli/src/bin.ts --profile test --patch d:\overlays1.yml --patch d:\overlays2.yml LoaderIncludefoo[package.json] LoaderIncludefoo[cordis.patch.yml] LoaderIncludefoo[$DSH_HOME/cordis.patch.yml] LoaderIncludefoo[overlays1] LoaderIncludefoo[overlays2] LoaderIncludebar[package.json] LoaderIncludeGroupbar[cordis.patch.yml] LoaderIncludeGroupbar[$DSH_HOME/cordis.patch.yml] LoaderIncludeGroupbar[overlays1] LoaderIncludeGroupbaz[package.json] LoaderIncludeGroupGroupbar[overlays2] LoaderIncludeGroupGroupqux[package.json] LoaderIncludeGroupGroupbaz[cordis.patch.yml] LoaderIncludeIncludefoo[include] LoaderIncludeIncludebar[include]