Files
deepseek-harness/packages/cordis/repository-plugin
Tianyi Cui 0664b25cd9 fix(review): validate skill roots at mount and isolate provider default roots
ds-review-bot round 1 on the repository-plugin runtime:
- a manifest-declared skill root absent or non-directory in the installed
  package now fails the plugin load (skill-local treats a missing root as
  legitimately empty, which silently mounted a skill-less plugin)
- includeDefaultRoots: false no longer inherits $DSH_BUNDLED_SKILL_DIR, so
  isolated repository providers see only their explicit roots
- prepared wrapper baseUrl schema requires the file: scheme, failing hostile
  URLs at the declared validation boundary
- preparedPath reuses format.ts's isOutside; SERVER_NAME_PATTERN is exported
  and pinned equal to dsh-mcp-client's, with the restatement justified (the
  prepare bin keeps a zod-only module graph); the unexplained `as never`
  cast now carries its schemastery rationale
- the import-free wrapper assertion also rejects dynamic import(
- the headless fixture wrapper is regenerated by the real prepareDshPlugin
  and a drift test pins fixture == generator output
- prepareDshPlugin JSDoc states the non-atomic publish repair contract
2026-08-02 01:25:02 +08:00
..

@deepseek-ai/dsh-repository-plugin

English | 中文

Restricted repository Plugin format for DeepSeek Harness. A repository author declares static skill roots and an optional common .mcp.json in .dsh-plugin/package.json; the prepare helper copies those assets and emits a fixed import-free Cordis wrapper. The runtime wrapper can only delegate to this DSH-owned package, which composes dsh-skill-local and dsh-mcp-client. Design rationale: static repository Plugin format Agent Note.

Authoring format

Place an ordinary package in the repository's .dsh-plugin directory:

{
  "name": "humanize-dsh-plugin",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "prepare": "dsh-plugin-prepare"
  },
  "devDependencies": {
    "@deepseek-ai/dsh-repository-plugin": "^0.0.1"
  },
  "dsh": {
    "skills": ["../skills"],
    "mcpServers": "../.mcp.json"
  }
}

dsh.skills is an optional array of local skill roots. dsh.mcpServers is an optional path to one .mcp.json; at least one field is required. Paths are relative to .dsh-plugin, must stay under its parent source directory, and may therefore refer to existing repository assets such as ../skills. A repository containing several Plugins gives each one its own .dsh-plugin package under a different selectable subdirectory.

Preparation

dsh-plugin-prepare validates package.json#dsh, verifies skill-root types, parses the MCP file, copies assets under dsh-plugin-assets, and writes dsh-plugin.mjs. The wrapper contains only the normalized static manifest and fixed code that looks up the dsh-repository-plugin Loader builtin. It neither discovers nor compiles repository JavaScript, and the runtime never imports another repository entry point.

The containing package manager still runs the configured repository package's lifecycle scripts. This restriction defines the supported DSH contribution surface; it is not a security boundary for a repository that the user chose to install as executable package-manager source.

Runtime composition

Loading this package registers one effect-scoped Loader builtin. Each generated wrapper delegates to that builtin with its own module URL and prepared manifest. The runtime validates every declared skill root as an existing in-package directory before mounting — a package whose generated outputs were dropped (a files/.npmignore mistake, a damaged cache entry) fails the plugin load instead of silently mounting a skill-less plugin. Repository skill roots mount as a uniquely named dsh-skill-local provider with default project/user roots excluded and watching disabled; cached package generations are immutable. Wrapper disposal removes the provider and all composed MCP clients through normal Cordis child-fiber teardown.

Common MCP format

The .mcp.json root is { "mcpServers": { ... } }. A stdio entry accepts only type: "stdio" (optional), command, args, and env; an HTTP entry accepts only type: "http", url, and headers. String values support exact ${NAME} process-environment expansion at Plugin load, and a missing name fails that load. HTTP URLs become the existing MCP client's streamable-http transport; stdio entries use the prepared package directory as cwd.

Unknown fields reject, including OAuth and auth objects. There is no CLAUDE_PLUGIN_ROOT expansion or compatibility layer. After translation, the existing dsh-mcp-client exclusively owns transport creation, connection diagnostics, tool synchronization, calls, and disconnect lifecycle; a network or child-process connection failure retains that client's established log-and-no-tools behavior.

Export shape

Namespace Plugin: named exports name / inject / apply, preparation constants, and prepareDshPlugin; no default export. The package also exposes the dsh-plugin-prepare executable and an invariant companion.

Model Experience

Repository skills

What the model sees

Indirectly through dsh-tool-skill: prepared, model-invocable skills join its logged catalog and selected instruction-body surface under their declared names and descriptions. The exact consumer schema is in the generated skill tool catalog.

Token effect

Conditional and data-dependent: each visible repository skill adds one capped catalog row; loading one adds its full current instruction body and resource-base guidance to retained tool history.

KV Cache effect

A stable prepared Plugin set is prefix-stable. Adding, removing, or replacing a repository Plugin can append the consumer's replacement catalog and affect later request prefixes.

Repository MCP tools

What the model sees

Indirectly through dsh-mcp-client: every connected server contributes its server-qualified tool schemas, and calls retain that client's canonical MCP results and rendering.

Token effect

Conditional on successful connection and the remote tool list; schemas recur on requests in the active tool view, while calls and results remain in history until compaction.

KV Cache effect

Stable connected tool lists are prefix-stable. Plugin lifecycle or MCP tool-list changes can change later tool-schema prefixes from the first affected definition.

Known Limitations and Deferred Work

  • Skills and MCP only — commands, hooks, agents, apps, arbitrary Cordis code, marketplaces, and compatibility shims are intentionally outside this format.
  • No MCP authentication protocol — static headers may use environment expansion, but OAuth-bearing definitions reject and private-server login flows are not implemented here.
  • Generated assets are immutable runtime input — repository cache generations are not watched; source, ref, path, or configuration must select another prepared generation.