Development Guide

September 3, 2026 · View on GitHub

Target: dsh-v0.1.2-alpha.5. This guide explains the repository toolchain, structure and extension workflow.

1. Toolchain

toolrole
Node.js ≥ 20 / npmruntime & package manager
TypeScript ~5.7typecheck (three projects) and host build
esbuildbrowser bundle build
vitesttests (Node environment)
oxlintlint (.oxlintrc.json)

Commands:

npm ci                 # install pinned devDependencies
npm run typecheck      # host + client + tests type projects
npm run lint           # oxlint over src, tests, scripts
npm test               # vitest suite
npm run build          # lib/ (tsc) + client/client.js (esbuild)
npm run check          # lint + typecheck + build + test (CI entry)

2. Repository layout

src/index.ts                 host plugin entry (name / inject / apply)
src/host/errors.ts           stable error codes, SessionOpError, wire errors
src/host/session-id.ts       session-id validation (single clean path segment)
src/host/artifact.ts         guarded removal of the durable artifact
src/host/delete-session.ts   delete operation over official service faces
src/host/rename-session.ts   rename operation over the official controller
src/host/rpc.ts              /dsh-sess channel: install + endpoint dispatch
src/client/index.tsx         browser entry: dictionaries + Settings section
src/client/session-manager.tsx   manager UI (two tabs, inline confirm/rename)
src/client/model.ts          pure row projection & relative time (unit-tested)
src/client/rpc.ts            client RPC helpers & RpcBusinessError
src/client/locales.ts        zh/en copy (key sets enforced equal)
src/client/types.ts          structural client service faces
src/client/styles.ts         scoped stylesheet injection
tests/host/operations.spec.ts   host op/guard tests (fake services + temp dirs)
tests/client/model.spec.ts      locale parity + projection tests
cordis.patch.yml             profile bundle patch (mounts the plugin row)
scripts/build-client.mjs     esbuild client bundle (module-table externals)

3. Type projects

  • tsconfig.host.json — host sources; emits lib/ (declarations included). Relative imports use .ts extensions; rewriteRelativeImportExtensions rewrites them to .js on emit.
  • tsconfig.client.json — browser sources (DOM lib, react-jsx); typecheck only, no emit (the bundle is built by esbuild).
  • tsconfig.tests.json — test sources plus the host sources they import.

4. Adding or changing a host operation

  1. Add the operation as a pure function over a structural face (see delete-session.ts) — it receives exactly the official services it needs and nothing else. Import official types (e.g. SessionId, SessionHeader from @deepseek-ai/dsh-session/types) type-only.
  2. Throw SessionOpError(code, message, details) for every refusal; fold unexpected failures into internal.
  3. Register the endpoint in rpc.ts (Endpoints, dispatch case, payload field extraction).
  4. Add a unit test faking the face (and a temp directory when the filesystem is involved).

Constraints that keep the plugin aligned with the target version:

  • never require a harness core package at runtime — only official services from the host context (ctx.get / inject);
  • never write workspace domain state or session files outside the guarded artifact removal;
  • keep wire payloads lossless-JSON.

5. Changing the browser half

  • Runtime module imports must stay within the baseline platform words; the esbuild script (scripts/build-client.mjs) lists them as external. Keep that list in sync with src/client imports. The script compiles JSX with jsx: 'automatic' to match the sources' react-jsx tsconfig setting — do not switch back to transform mode, which would emit React.createElement calls without a React import and crash every rendered entry.
  • Type against the structural faces in types.ts (the client bundle may not import the full client packages at runtime). @deepseek-ai/dsh-client-ui-primitives is the one real UI dependency (baseline).
  • All user-visible copy lives in locales.ts; add keys to zh and en together (a test enforces identical key sets).
  • Data derivation belongs in pure model.ts functions so it stays testable without a DOM.

6. Code conventions

  • English doc-comments explaining why, JSDoc @param/@throws on public functions.
  • strict TypeScript, no implicit any, noUncheckedIndexedAccess honored.
  • Errors: stable codes over messages (see docs/api.en.md).
  • No TODO/placeholder markers, no version branches, no monkey patching.

7. Release

  1. Bump version in package.json; add a CHANGELOG.en.md / CHANGELOG.zh.md entry.
  2. Run npm run check.
  3. Tag v<version> and push; the release workflow (.github/workflows/release.yml) runs CI and publishes to npm from the tag.