# dsh-plugin-scaffold
[中文](./README.md) | English
## Overview
This is a minimal **out-of-tree DSH (DeepSeek Harness) plugin scaffold**. It modifies no upstream package and prepares the parts a DSH plugin genuinely needs but easily gets wrong:
- **Bundle skeleton**: a compatibility gate row, a host service row, and a browser client-graph anchor row, each with a distinct job;
- **Host/client split build**: tsdown emits the host ESM face and the browser closure factory, while tsc emits both declaration sets;
- **Compatibility as a code contract**: an exact-version allowlist, `unsupported` / `mixed` / `incomplete` verdicts, and an upgrade lane;
- **Complete verification chain**: typecheck, lint, unit tests, composition smoke, pack gate, documentation check;
- **Engineering conventions**: AGENTS.md, `.agent/`, the nine `docs/` sections, bilingual READMEs/CHANGELOG, and CI/release/upgrade/diag workflows.
The scaffold currently ships a **runnable skeleton**: `src/service.ts` exposes a placeholder service and `src/client/index.ts` has an empty `apply`. Replace those with your plugin's behavior; the rest of the infrastructure does not need rebuilding.
## Requirements
**Using the plugin**: one of the DSH releases below (exact match, not a range). `dsh plugin` handles installation; no local Node toolchain is needed.
| DSH line | Supported releases |
| --- | --- |
| `0.2.1` | `0.2.1-rc.2` |
**Developing from source**: Node.js `^22.19.0 || >=24`, pnpm `11.25.0` (enable via corepack); the development pin is DSH `0.2.1-rc.2`.
## Quick start
```sh
git clone https://github.com/cherrchen/dsh-plugin-scaffold.git my-dsh-plugin
cd my-dsh-plugin
export CI=true
pnpm install
pnpm verify:all
```
`pnpm verify:all` runs lint, typecheck, build, tests, the composition smoke, the pack gate, and the packed smoke in order. The first run needs access to the npm registry.
### Turning it into your plugin
Every identifier in the scaffold is concentrated in a small set of names. When deriving a new project, replace the following and rerun `pnpm verify:all`:
| Location | Current scaffold value | Replace with |
| --- | --- | --- |
| `package.json` `name` | `@dsh-electron/dsh-plugin-scaffold` | your package name |
| `package.json` `repository.url` | `git+https://github.com/cherrchen/dsh-plugin-scaffold.git` | your repository URL |
| `LICENSE` copyright line | `Copyright (c) 2026 Cherry Chen` | your name or organization |
| Package-name references (source/scripts/tests) | `@dsh-electron/dsh-plugin-scaffold` | your package name |
| Environment variable | `DSH_PLUGIN_SCAFFOLD_COMPAT` | `DSH__COMPAT` |
| Compatibility service key | `dshPluginScaffoldCompat` | your service key |
| Host service key | `dshPluginScaffold` | your service key |
| Connection channel | `/dsh-plugin-scaffold` | your channel |
| Patch row ids | `dsh-plugin-scaffold-compat` / `-service` / `-client` | your row ids |
| Documentation and plan filenames | the files containing `dsh-plugin-scaffold` | your document names |
Locate every place that needs changing:
```sh
grep -rn "dsh-plugin-scaffold\|dshPluginScaffold\|DSH_PLUGIN_SCAFFOLD" \
--exclude-dir=node_modules --exclude-dir=.git --exclude-dir=lib .
```
Then adjust `REQUIRED_CORE_PACKAGES`, `OPTIONAL_CORE_PACKAGES`, and `peerDependencies` in `src/compat/dsh-version.ts` to the packages your plugin actually couples to; `pnpm compat:check` fails when the two drift apart.
## Install and verify the composition
Install into a DSH runtime and inspect the composition:
```sh
dsh plugin --profile web add /path/to/repo
dsh --profile web --dump-config | grep -A4 'dsh-plugin-scaffold'
```
Expected output:
```text
# == @dsh-electron/dsh-plugin-scaffold
- id: dsh-plugin-scaffold-compat
name: '@dsh-electron/dsh-plugin-scaffold/compat'
- id: dsh-plugin-scaffold-service
name: '@dsh-electron/dsh-plugin-scaffold/service'
- id: dsh-plugin-scaffold-client
name: '@dsh-electron/dsh-plugin-scaffold'
```
`dsh-plugin-scaffold-compat` is the boot gate, `dsh-plugin-scaffold-service` is the host half (it injects `dshPluginScaffoldCompat`, so a refused gate means it never starts), and `dsh-plugin-scaffold-client` is mounted at the bare package name — the only anchor from which the web client graph reads this package's `dsh.client` declaration.
> [!TIP]
> When `dsh` is not on PATH (e.g. running DSH from a source checkout), replace `dsh` in the commands with `pnpm dsh`.
## Development commands
```sh
pnpm compat:check # allowlist / peers / dev pin / installed tree agree
pnpm lint # oxlint
pnpm typecheck # both host and client faces, noEmit
pnpm build # declarations + tsdown bundle (host ESM + browser client)
pnpm test # vitest; asserts the BUILT lib/ artifacts, so build first
pnpm smoke # smoke:compose — real dsh plugin add + --dump-config
pnpm pack:check # tarball members, exports targets, patch-referenced modules
pnpm smoke:packed # the composition smoke against the packed tarball
pnpm docs:check # documentation structure check
pnpm verify:all # the full chain above minus compat:check
```
## Project structure
```text
.
├── src/
│ ├── compat.ts the boot gate (version allowlist and mixed-install verdicts)
│ ├── compat/dsh-version.ts the compatibility contract itself: SUPPORTED_DSH_RELEASES, package lists, classification
│ ├── service.ts the host half (placeholder service; replace with your plugin behavior)
│ ├── client/ browser half (empty apply; replace with your slot contributions)
│ ├── contract.ts the Connection channel name shared by both halves
│ └── index.ts public-surface barrel; its no-op apply also backs the bare-name client-graph anchor row
├── tests/ compatibility verdicts, patch invariants, client-artifact shape
├── scripts/ smokes, compatibility check, pack gate, upgrade flow, lefthook installer
└── docs/ requirements, architecture, ADRs, plans, development, reference, troubleshooting
```
## Contributing
1. Read [`AGENTS.md`](./AGENTS.md) (repository rules) and the [development workflow](./docs/development/plugin-development-workflow.md) first.
2. Branch from `main`; commit messages follow conventional commits.
3. Before opening a PR, all of the following must pass locally: `pnpm verify:all`, `pnpm compat:check`, `pnpm docs:check`.
4. Changes that affect behavior must update the corresponding documents under `docs/` in the same change; keep the bilingual READMEs in sync; add an ADR for engineering decisions with trade-offs.
5. Hard constraint: **do not modify any package in the upstream repository (deepseek-harness)**.
## Known limitations
- The plugin behavior has not been implemented yet: `service.ts` provides only the `dshPluginScaffold` service key and the compatibility verdict, and the client `apply` is empty. That is the deliberate starting point, not a defect.
- The support matrix is an exact-version allowlist: when the host release is unlisted, or core packages mix releases, the gated service row **does not start** and the composition degrades to "plugin not installed" ([ADR-0001](./docs/decisions/ADR-0001-dsh-compat-contract.md)).
- Upstream seams make no semver promise: the upgrade lane supplies evidence about a candidate, and promoting the support matrix remains a human decision.
## Documentation
- [CHANGELOG](./CHANGELOG.md)
- [User guide](./docs/guide/README.md)
- [Scaffold requirements](./docs/requirements/dsh-plugin-scaffold.md)
- [DSH plugin bundle reference](./docs/reference/dsh-plugin-bundle.md)
- [Architecture Decision Records](./docs/decisions/README.md)
- [Plans](./docs/plans/README.md)
- [Development workflow](./docs/development/plugin-development-workflow.md)
- [Troubleshooting](./docs/troubleshooting/README.md)
Repository rules for Coding Agents are defined in [`AGENTS.md`](./AGENTS.md).
## License
[MIT](./LICENSE)