Skip to content
源码版本47f9438 (dsh@0.1)

Loading and Discovery ​

Plugin loading happens in three layers:

  1. Loader (vendor/loader) service manages the entry tree + Node's built-in ModuleLoader (--expose-internals) for ESM/CJS imports
  2. Include plugin parses cordis.patch.yml (including !!js expressions)
  3. dsh plugin CLI reconciles pnpm package installation with the bundle layer

The Loader hooks onto the internal/plugin / internal/config / internal/update events, automatically handling fiber.entry binding, config interpolation, and reload write-back.

Loader Service ​

class Loader extends EntryTree at vendor/loader/src/index.ts:65-100:

  • internal = ModuleLoader.fromInternal() — get Node's internal ESM loader
  • builtins dict for builtin plugins
  • On construction it registers three internal/* hooks: config interpolation, update write-back, and plugin lifecycle logging

unwrapExports: Unifying Three Shapes ​

unwrapExports(exports) at vendor/loader/src/index.ts:192-199 handles the dual interop of default / __esModule, unifying ESM / CJS / default-export shapes into a single plugin object.

Node's Built-in ModuleLoader ​

dsh uses --expose-internals to get at Node's internal ESM loader — this is the prerequisite for fine-grained control over module loading, including HMR cache cleanup.

V1 vs V2 ​

vendor/loader/src/internal.ts:55-102 defines the ModuleLoaderV1 (Node 22/23) and ModuleLoaderV2 (Node 24+) interfaces, with field differences clearly annotated:
  • getModuleJobForImport → getOrCreateModuleJob
  • resolve becomes private
  • etc.

ModuleLoader.fromInternal() at vendor/loader/src/internal.ts:120-132: Node major ≥ 24 takes v2, ≥ 22 takes v1, obtaining the cascaded loader of internal/modules/esm/loader via --expose-internals or node-addon-require-builtin.

dsh plugin CLI: pnpm Reconciliation ​

Is It a Bundle Layer? ​

exportsPatch(packageName, profileDir) at apps/cli/src/plugin.ts:36-45:

  1. Resolves the bundle dir.
  2. Reads the manifest.
  3. Checks whether dsh.bundle.patch exists — i.e. "is it a bundle layer".

reconcilePlugins ​

reconcilePlugins(before, profileDir) at apps/cli/src/plugin.ts:59-91:

After pnpm finishes, diffs the before/after dependencies:

  • A new dependency that is a bundle → push into dsh.profile.bundles
  • A removed dependency, or a new version that no longer declares a bundle → splice out

Path Anchoring ​

anchorPathSpec(argument, cwd) at apps/cli/src/plugin.ts:104-112: rewrites . / .. / file: / link: relative specs against the caller's cwd, to avoid self-reference inside the profile directory.

The Entry Structure of patch.yml ​

packages/bundle/base/cordis.patch.yml:15-45 is the base bundle's insert list; each line:
yaml
- id: <stable>          # stable identity
  name: '<pkg or path>'  # module locator
  config: ...            # optional
  disabled: !!js ...     # optional; the only interpolated metadata field

Key Mechanisms ​

1. entry id Is a Stable Identity ​

A Loader entry's id is a stable identity: when the config file changes the loader diffs by id and only mounts / unmounts / reconfigures the changed lines; an entry without an id gets a fresh id on every read and is treated as "delete + add".

2. disabled: !!js Routing ​

disabled: !!js <expr> is the only interpolated metadata field; it is evaluated against the loader context on every mount decision, so platform / environment differences (e.g. process.platform === 'win32') are routed here.

3. internal/config Hook for Interpolation ​

The Loader internal/config hook does the interpolation: the config of tree carriers (Group / Include) stays literal, while the config of leaf entries goes through interpolate(ctx, config) to resolve !!js.

4. Loader.Intercept.await ​

Loader.Intercept.await keeps plugins that depend on the loader pending while the entry tree still has unfinished work — preventing plugins from seeing an incomplete registry early in boot.

5. Profile Is a Real pnpm Workspace ​

dsh plugin add is pnpm add; when pnpm ≥ 10 blocks the prepare script of a git dependency, the CLI prompts the user to add allowBuilds. Plugin management fully reuses pnpm's dependency graph.

Unofficial community learning site. Content based on the MIT-licensed deepseek-ai/deepseek-harness source. · Privacy · Terms · About