@perrylink/dsh-plugin-kit — renamed to dsh-scaffold
This package is the old scoped name of dsh-scaffold. It stays installable for compatibility; new releases are published under the bare name.
dsh plugin --profile <profile> add dsh-scaffold
Source: https://github.com/PerryLink/dsh-scaffold · Docs: https://perrylink.github.io/dsh-plugins/packages/dsh-scaffold.html
dsh-scaffold
Renamed: previously @perrylink/dsh-plugin-kit; now dsh-scaffold. Old repo stays as a pointer/backup. New home: https://github.com/PerryLink/dsh-scaffold
Non-official companion tool. Part of the DSH standards family; not a certification, accreditation, security audit, or official endorsement. Standard: https://github.com/PerryLink/dsh-standards. The dsh.standards block is a not-run placeholder, not a pass.
dsh plugin --profile <name> add dsh-scaffold
Shared zero-runtime-dependency toolkit for the PerryLink DSH plugin repositories. The per-project audit found 20+ plugins hand-rolling the same Provider seam and duplicating the same sanitize/pricing/verdict shapes, so this package extracts all of it — the pluggable Provider seam, the fail-closed approval and adaptive session-event gates, the mechanical verify scripts, and the shared sanitize/pricing/judge pure modules — into one ESM + TypeScript package.
Package name. This project publishes to npm as dsh-scaffold. The bare npm name dsh-scaffold belongs to a different, unrelated project — installing it does not install this package.
- 1024 store channel:
npm i -g dsh1024 once, then dsh1024 plugin --profile web add dsh-scaffold (counts toward the deepseek1024.com install ranking).
DSH Market
English | 简体中文 | Español | Português | हिन्दी
Shared zero-runtime-dependency toolkit for the PerryLink DSH plugin
repositories. The per-project audit found 20+ plugins hand-rolling
the same Provider seam and duplicating the same sanitize/pricing/verdict
shapes, so this package extracts all of it — the pluggable Provider seam, the
fail-closed approval and adaptive session-event gates, the mechanical verify
scripts, and the shared sanitize/pricing/judge pure modules — into one
ESM + TypeScript package.
Install & uninstall
As a library, install is pnpm add (see Quick start). The package also ships an
intentionally empty dsh.bundle.patch layer (cordis.patch.yml), so it flows
through the harness bundle channel when a profile wants the kit mounted as a
package:
# npm channel (published releases)
dsh plugin --profile web add dsh-scaffold
# git channel (latest master)
dsh plugin --profile web add github:PerryLink/dsh-scaffold
Remove with:
pnpm remove dsh-scaffold
Nothing registers global state: uninstall is exactly the reverse of install.
What is dsh-scaffold?
Shared zero-runtime-dependency toolkit for the PerryLink DSH plugin repositories. The per-project audit found 20+ plugins hand-rolling the same Provider seam and duplicating the same sanitize/pricing/verdict shapes, so this package extracts all of it — the pluggable Provider seam, the fail-closed approval and adaptive session-event gates, the mechanical verify scripts, and the shared sanitize/pricing/judge pure modules — into one ESM + TypeScript package.
Workflow diagram for dsh-scaffold: call → plugin → result.
Workflow overview: call → plugin → result. The examples below use the real command surface.
Compatibility
- DSH harness: the kit imports nothing from
@deepseek-ai/* at runtime.
@deepseek-ai/cordis (^4.0.5-alpha.1), @deepseek-ai/schemastery
(^3.18.5-alpha.1), and the @deepseek-ai/dsh-* packages are optional
peer dependencies in the >=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0 || >=0.1.6-0 <0.2.0 || >=0.1.7-0 <0.2.0 || >=0.2.0-0 <0.3.0 || >=0.2.1-0 <0.3.0
band the PerryLink plugin repos share; they exist only for type
interop. Verified 2026-09-11 against the dsh-v0.1.7-alpha.1 master checkout
(full gate chain + profile install smoke), and re-verified 2026-10-05 against
the dsh-v0.2.1-alpha.1 checkout (full gate chain + profile install smoke).
- Node:
^22.19.0 || >=24.0.0, ESM only.
- Wire compatibility: names and shapes mirror
dsh-mask (sanitize),
dsh-budget (pricing), and dsh-auto-review (judge and the
fallbackPolicy vocabulary), so migration is mechanical.
What you get
- Zero runtime dependencies — the pure core (
seam, gates, shared)
is browser-safe.
- ESM + strict TypeScript — JSDoc contracts on every module;
strict,
noUncheckedIndexedAccess, exactOptionalPropertyTypes.
- Fail-closed and adaptive gates — approval never defaults to a grant;
session-event appends degrade gracefully on hosts that reject unknown event
types.
- A new-plugin skeleton —
template/ with cordis.yml, a three-role
src/index.ts (Service Definition / Provider / Consumer), a test, and the
shared Renovate preset.
Quick start
dsh plugin --profile web add github:PerryLink/dsh-scaffold
From npm:
pnpm add dsh-scaffold
From git (the prepare script builds lib/ using only production
dependencies):
pnpm add github:PerryLink/dsh-scaffold
Replace a hand-rolled registry in one step:
import { ProviderRegistry } from 'dsh-scaffold/seam'
const registry = new ProviderRegistry<Detector>({
default: { name: 'regex', impl: new RegexDetector() },
})
ctx.effect(() => registry.register('ner', new NerDetector()))
const active = registry.use('ner') ?? registry.use()
Examples
These are the plugin's real entry points; install once, then call one.
Detailed example
Command
import { createStripper } from 'dsh-scaffold/shared'
createStripper().strip('call 13800138000 or email a@b.com')
Output
call <PHONE_1> or email <EMAIL_1>
Observed from README.md:153 (shared sanitize); src/shared/sanitize.ts:268; test/sanitize.test.ts:8-19
Failure branch
Input
const r = new ProviderRegistry(); r.register('openai', impl); r.register('openai', impl) // second call
Output
Error: Provider "openai" is already registered
Observed from plugins/dsh-scaffold/lib/seam/provider.js:55-58; plugins/dsh-scaffold/test/seam.test.ts:27-30; plugins/dsh-scaffold/README.md:164
Brief examples
applyFailClosed
parseVerdict
Configuration
No runtime configuration: the gates and helpers are pure functions. The only
configuration surface is cordis.patch.yml, the bundle-patch layer shipped
for harness profile composition; it mounts no plugin row (the kit is a
library) and documents how consuming plugins add their own rows.
Tools & surfaces
| Subpath | Purpose |
|---|
seam | ProviderRegistry<T> — reversible, fail-loud named provider registry. |
gates | applyFailClosed; makeEventGate / maybeAppendSessionEvent / probeIgnorableAppend. |
shared | sanitize (Stripper, redactText, redactMapping, sanitizeText, sanitizeUrl), pricing (BUILTIN_PRICES, estimateUsageCost, tokenCarbon, latencyStats, formatMoney, formatTokens), judge (parseVerdict, VERDICT_SCHEMA, riskExceeds). |
verify | Mechanical CI gates (verify-license, verify-readme-languages, verify-seam) with a VerifyReport and a non-zero-exit CLI: node lib/verify/cli.js all . |
template/ | New-plugin skeleton (cordis.yml, three-role plugin, test, README, renovate.json5). |
| root barrel | Re-exports all of the above. |
Permissions & data
The kit performs no I/O, no network access, and no subprocess spawns on its
own. Stripper keeps placeholder→original mappings in memory only, and
stats()/redactMapping() never emit plaintext; a consumer that persists a
mapping owns that decision and its storage permissions.
Security boundaries
sanitize/redact* are display hygiene, not a security boundary: they
reduce leakage into logs and results, they do not authenticate or authorize.
- Approval gates are fail closed by default (
rejected); the only grant path
is an explicit allow-once opt-in.
- Session-event appends the host refuses are skipped, never retried in a way
that could break session resume.
- Report vulnerabilities via GitHub Security Advisories — see
SECURITY.md.
Known limitations
- Hosts whose
Session.append third argument is a SurfaceIntent
(0.1.2-rc.1) throw validateNext on the ignorable-envelope probe; the
gate degrades to skip-unknown, so audit events are dropped (fail closed)
rather than logged on those hosts.
- 0.1.2-rc.1 (adapted 2026-09-02): the session envelope keeps its ignorable field for stored-log read compatibility only - Session.append still cannot stamp it, so audit-gate behavior is unchanged.
- The kit ships no browser UI half; it is a library consumed by the Host (and
optionally Client) halves of other plugins.
Development
pnpm install
pnpm run typecheck # tsc --noEmit
pnpm run typecheck:ci # CI face: tsc -p tsconfig.ci.json --noEmit
pnpm test # vitest unit tests
pnpm run build # emit lib/ + declarations (also run by prepare)
pnpm run verify:self-contained
pnpm run verify:artifacts
Topics
This repository is also the maintenance hub for the ecosystem:
scripts/sync-peer-range.mjs re-pins the shared peer band across every repo in
the target directory in
one command, renovate/default.json5 is the shared Renovate preset every repo
extends, .github/workflows/npm-publish.yml is a reusable tag-triggered
publish workflow (needs only an NPM_TOKEN secret), and data/repos.json is
the ecosystem registry consumed by the portal. Read that file for the roster; the per-plugin READMEs carry the collapsed list. See
docs/ecosystem-tooling.md.
Keywords: dsh, dsh-plugin, deepseek-harness, deepseek, cordis, perrylink,
provider, seam, approval, sanitize, pricing, judge.
Contributors
Maintained by PerryLink with contributions
from the DSH plugin ecosystem.
PerryLink DSH Plugin Family
This project is part of the DeepSeek Harness plugin family from PerryLink. The roster stays collapsed below so every README keeps a short first screen; expand it to see every row and its status.
Expand all plugins
License
Apache-2.0 — see LICENSE.