打包与安装插件
掌握插件打包编译、本地 npm link 调试、发布至 npm 以及在 cordis.yml 中一键集成的完整路径。
在本地开发调试阶段,我们通常使用 --patch 参数直接挂载开发目录。然而,在跨团队协作、企业私有 npm 仓库发布或自动化流水线部署等生产场景中,必须将插件打包为标准化的 Bundle(组合包),并通过 dsh plugin 指令将其安装到可执行的 Profile(配置档案) 中。
本文将深入解析 Harness 的 Bundle 与 Profile 架构模型、四级配置叠加优先级,并以一个 “CI/CD 自动化流水线插件包(dsh-cicd-runner)” 为例演示打包与分发流程。
概念基石:Bundle 与 Profile 的双向契约
DeepSeek Harness 的分发体系建立在两个清晰的角色之上:
┌─────────────────────────────────────────────────────────────┐
│ Bundle 与 Profile 的核心分工 │
├─────────────────────┬───────────────────────────────────────┤
│ 1. Bundle (功能包) │ 发布的 npm 包,在 package.json 中声明 │
│ │ dsh.bundle,定义该包贡献的 patch 补丁 │
├─────────────────────┼───────────────────────────────────────┤
│ 2. Profile (运行时) │ 用户启动的独立环境,在 package.json │
│ │ 中声明 dsh.profile,管理已装载包列表 │
└─────────────────────┴───────────────────────────────────────┘
- Bundle(组合包):由插件作者发布。它包含编译后的代码和一个
cordis.patch.yml补丁文件,声明了向系统注入的插件节点; - Profile(配置档案):位于
$DSH_HOME/profiles/<name>。它是一个具体的运行环境实例,通过依赖清单记录了当前激活的所有 Bundle 及其加载顺序。
步骤一:创建并编写 Bundle 模块
以构建 dsh-cicd-runner 插件包为例,建立标准目录结构:
dsh-cicd-runner/
├── package.json # 声明 dsh.bundle 清单元数据
├── cordis.patch.yml # 当该 Bundle 被引入时所应用的配置补丁
└── index.js # 编译后的插件主入口
1) 编写 package.json 清单文件
{
"name": "dsh-cicd-runner",
"version": "1.0.0",
"type": "module",
"main": "index.js",
"files": ["index.js", "cordis.patch.yml"],
"dsh": {
"bundle": {
"patch": "./cordis.patch.yml"
}
}
}
2) 编写插件逻辑 index.js
export const name = 'cicd-runner';
export function apply(ctx) {
console.log('[CI/CD] 企业级持续集成插件已成功装载到当前 Profile!');
}
3) 编写配置补丁 cordis.patch.yml
生产环境重要规则: 在 Bundle 的补丁文件中,插件名称必须使用 npm 包名 而不是相对路径,以便 Node.js 解析器在任何机器上均能正确定位安装后的模块:
- insert:
- id: cicd-service
name: dsh-cicd-runner
config:
autoTriggerOnPush: true
步骤二:安装到 Profile 并启动验证
使用 dsh plugin --profile <name> 命令管理目标环境中的插件:
# 将本地开发的 Bundle 安装到名为 prod-agent 的 Profile 中
dsh plugin --profile prod-agent add ./dsh-cicd-runner
首次运行该命令时,Harness 会自动初始化该 Profile,并将新包追加到 package.json 中的 dsh.profile.bundles 数组中:
{
"name": "dsh-profile-prod-agent",
"private": true,
"dependencies": {
"dsh-cicd-runner": "link:./dsh-cicd-runner"
},
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"dsh-cicd-runner"
]
}
}
}
调试与配置预览:
在正式启动前,可以使用 --dump-config 打印多层配置融合后的最终 YAML:
# 1. 打印合并后的完整配置树
dsh --profile prod-agent --dump-config
# 2. 启动生产 Profile
dsh --profile prod-agent
若需移除该插件,执行卸载指令:
dsh plugin --profile prod-agent remove dsh-cicd-runner
四级配置叠加层级与覆盖机制
当 Harness 启动时,配置补丁按照自底向上的优先级严格顺序叠加:
┌─────────────────────────────────────────────────────────────┐
│ 第 4 级:CLI 运行时覆盖 (--patch <path>) │ ◀ 最高优先级
├─────────────────────────────────────────────────────────────┤
│ 第 3 级:全局用户补丁 ($DSH_HOME/cordis.patch.yml) │
├─────────────────────────────────────────────────────────────┤
│ 第 2 级:当前 Profile 专属补丁 (profile/cordis.patch.yml) │
├─────────────────────────────────────────────────────────────┤
│ 第 1 级:各 Bundle 补丁层 (按 dsh.profile.bundles 顺序叠加) │ ◀ 基础底座
└─────────────────────────────────────────────────────────────┘
整行替换(Whole-Row Replacement)原则: 高优先级层对同名
id的插件配置执行的是整行替换,而非深层对象合并。如果只需要调整某一个参数,请在补丁中声明该插件节点所需的完整配置。
常见问题解答 (FAQ)
Q1: 一个项目可以同时既是 Bundle 又是 Profile 吗?
解答:绝对不能。Bundle 是供他人安装的不可变发布包(声明 dsh.bundle),而 Profile 是可执行的用户本地环境(声明 dsh.profile)。两者的设计定位互斥。
Q2: 为什么 cordis.patch.yml 中必须写包名(如 dsh-cicd-runner)?
解答:当插件发布到 npm 并被其他开发者通过 dsh plugin add 安装后,其文件会被存放在项目的 node_modules 目录下。直接使用包名能够借助 Node.js 的标准模块解析机制精准定位。
Q3: 什么是“整行替换”?为什么不使用递归属性合并?
解答:整行替换能够确保高优先级的配置意图是确定且清晰的,避免因深层递归合并产生意外的“幽灵参数”遗留。建议借助 dsh --dump-config 查看最终融合生效的配置。
Q4: 在没有公网访问权限的离线内网服务器上,如何安装自研 Bundle?
解答:可以将自研 Bundle 打包为 .tgz 压缩包(通过 npm pack),然后执行 dsh plugin --profile prod add ./dsh-cicd-runner-1.0.0.tgz,pnpm 会从本地离线压缩包直接完成依赖链接与安装。