5. Distribution and publishing

September 1, 2026 · View on GitHub

5.1 Bundle vs profile

DSH has two distribution concepts, both declared under the package.json dsh key:

// bundle: an npm package carrying a config layer.
{ "name": "dsh-hello-plugin", "type": "module", "main": "index.js",
  "dsh": { "bundle": { "patch": "./cordis.patch.yml" } } }

// profile: a runnable composition under $DSH_HOME/profiles/<name>.
{ "dsh": { "profile": { "bundles": ["@deepseek-ai/dsh-base", "dsh-hello-plugin"] } } }

cordis.patch.yml inserts your plugin row(s):

# `name` is a PACKAGE NAME (resolved through the profile's node_modules or the
# fallback $DSH_HOME/profiles/node_modules), NOT a relative path.
- insert:
    - id: spike-tool-time
      name: dsh-spike
    - id: spike-lifecycle-logger
      name: dsh-spike/lifecycle

Layer order (later overrides earlier, whole-row replace by id): each bundle's cordis.patch.yml (in profile.bundles order) → the profile's own cordis.patch.yml$DSH_HOME/cordis.patch.yml → each --patch <path> overlay (argv order).

5.2 The bundle package.json

{
  "name": "dsh-spike",
  "version": "0.1.0",
  "type": "module",
  "main": "./dist/tool-time.js",
  "exports": { ".": "./dist/tool-time.js", "./lifecycle": "./dist/lifecycle-logger.js" },
  "files": ["dist", "cordis.patch.yml"],
  "dsh": { "bundle": { "patch": "./cordis.patch.yml" } },
  "dependencies": { "@deepseek-ai/dsh-tools": "^0.1.0-rc.6" },
  "peerDependencies": { "@deepseek-ai/cordis": "^4.0.1" },
  "devDependencies": { "@deepseek-ai/cordis": "^4.0.1", "@deepseek-ai/dsh-session": "^0.1.0-rc.6", "typescript": "^5.6.0" }
}

5.3 Version pitfalls

  1. Pin @deepseek-ai/dsh-tools to the next-tag version. npm's latest tag is a stale 0.0.1-rc.1; the real line is next (0.1.0-rc.x). A bare npm i @deepseek-ai/dsh-tools installs the broken old line. create-dsh-plugin resolves the current next version at generation time and pins it exactly.
  2. Keep every @deepseek-ai/dsh-* on the same 0.1.0-rc.x line, so pnpm doesn't install two copies of dsh-tools.
  3. @deepseek-ai/cordis is a peerDependency — import type only; the host hands you ctx.
  4. Pure ESM ("type": "module"); tsc with module: esnext + moduleResolution: bundler keeps bare specifiers.
  5. Node ^22.19.0 || >=24.0.0 (older Node only warns EBADENGINE).

Prev: Debugging and verification workflow · Contents · Next: FAQ — the 14 pitfalls that bite