DeepSeek Harness combination bundle and profile: two manifests
In previous chapters we used--patchThe overlay loads local plugins; starting from this article, we package them into installable bundles.
In this section, we will clarify the two most fundamental concepts:bundleandprofile, as well as their respective manifests.
Two concepts, two kinds of manifests
The installation mechanism is built on two concepts, both described by a single package.json.
They are indshThe kind of manifest carried under the key differs, and so do the questions it answers.
A bundle is an npm package with a configuration layer attached.
Its manifest declaresdsh.bundle, answers "what does this package contribute": a patch file that inserts or overrides plugin lines.
profile is located$DSH_HOME/profiles/<name>under, describing a directory of a bootable bundle.
Its manifest declaresdsh.profile, answers "which bundles make up this configuration and in what order".
bundleis something you write and distribute;profileis used by the user
dsh --profile <name>the thing to boot.Nothing is both at the same time.
| Concepts | manifest key | Questions answered | Who writes / who uses |
|---|---|---|---|
| bundle (combination package) | dsh.bundle | What this package contributes (a patch file) | Written by the plugin author, distributed with the package |
| profile | dsh.profile | Which bundles make up this configuration and in what order | bydsh pluginAutomatically created and maintained, launched by the user |
The profile is located outside the installation directory; the path template is$DSH_HOME/profiles/<name>。
Hands-on: Create the hello-plugin composite package
According to the official tutorial, first create the package directory.
Example
mkdir -p hello-plugin
The bundle directory structure is as follows, with three files in total.
Example
hello-plugin/ ├── package.json # 声明 dsh.bundle ├── cordis.patch.yml # profile 列出该 bundle 时应用的配置层 └── index.js # patch 行引用的插件模块
Createhello-plugin/package.json, declare the composite package manifest.
Example
"name": "dsh-hello-plugin",
"version": "0.1.0",
"type": "module",
"main": "index.js",
"files": ["index.js", "cordis.patch.yml"],
"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }
}
The meanings of the fields in package.json are as follows.
| Fields | Description |
|---|---|
name | Package name; Node module resolution uses it to locate installed code |
version | Version number |
type | "module"Indicates using the ESM module format |
main | Entry file |
files | The list of files included only when publishing |
dsh.bundle.patch | Bundle manifest: declares the path of the contributed patch file |
Createhello-plugin/index.js, written into the plugin entry.
Example
export const name = 'hello-plugin' // Plugin name, used for logging and diagnostics
export function apply() {
console.log('[hello-plugin] plugin loaded!') // Print a log line when loading
}
Createhello-plugin/cordis.patch.yml。
Example
# This patch, like the usual --patch overlay, is a YAML array of patch entries.
# Difference: plugin lines are referenced by package name rather than relative source path, so Node module resolution can find installed code
- insert:
- id: hello
name: dsh-hello-plugin
This patch and--patchThe overlay is completely isomorphic.
The key difference isnameField: here goes the package namedsh-hello-plugin, not the relative source path.
After installation, pnpm links the package into node_modules, so Node's module resolution can find the installed code by package name.
no
dsh.bundleThe declared package can still be installed, but only as a regular dependency.at this time
dsh pluginIt will print a warning and will not activate any layer.If a library is meant to be imported by plugin packages rather than enabled by users, use this package format.
profile manifest: never needs to be written by hand
The profile directory contains two files.
The first ispackage.json, contains the profile's out-of-tree plugin dependencies (managed by pnpm), plusdsh.profileThe manifest and its orderedbundlesList.
The second iscordis.patch.yml, is the user's own patch layer, applied after each bundle layer.
The profile manifest never needs to be written by hand.
dsh pluginis responsible for creating and maintaining it; the next article will show its real results when installing the plugin.
Advanced: let the surface bundle hold its own command line
A bundle that defines a runnable application can mount an ordinary provider plugin to hold its own command line.
This provider plugin exportsinject = ['cmdlineArgs'], invoke it with your own commander programparseCmdline, then provide the application's own services in the program's own action.
Example
- id: hello-startup
name: 'dsh-hello-plugin/startup'
Lines configured by these parameters will inject the provider service, and read it in their own!!jsoptions, while writing the deployment value alongside as a fallback.
Example
- id: my-app
name: '@example/my-app'
inject: [myAppStartup]
config:
port: !!js ctx.myAppStartup.port ?? 8080
The launcher passes the same immutable arguments after its own flags to each plugin, so adding app-specific flags requires no changes to the launcher, and multiple plugins can parse the same snapshot.
encounter--helpwhen , the provider will not publish the service, so these lines will not be activated.
The Loader mounts the composition only once, waits for each line's normal injection, and then evaluates the line's based on its injected context.!!jsConfiguration.
Summary and self-test
Combined package declarationdsh.bundleTo answer "what is contributed", the profile declaresdsh.profileAnswer "which bundles it consists of"; both are carried by a single package.json but have different manifests.
Self-test questions:
- Which key does the bundle's manifest declare, and what question does it answer?
- Which directory is the profile located in, and what question does its manifest answer?
- Why does hello-plugin's cordis.patch.yml use the package name instead of a relative source path?