Files
deepseek-harness/docs/cookbook/adding-a-vendored-package.md
Tianyi Cui 605587e79c docs(rfc): classify RFCs by kind via path-encoded subdirectories
Add a second axis to every RFC — its class (feature, bug-fix,
simplification, architecture, process, testing) — encoded in the path
as docs/rfc/{lifecycle}/{class}/file.md. The folder is the label, so
the closed set is enforced by structure rather than a parsed field.

Two new doc-sync gates back it:
- verify-rfc-classification: every RFC sits in a valid class folder and
  the README index lists it under the matching lifecycle→class heading.
- verify-doc-refs: every docs/*.md path cited in a packages|examples TS
  comment resolves — closes a drift class verify-md-links can't see, and
  catches the four comment refs this reorg moved.

The README gains a Classification section explaining the taxonomy and
per-class index sub-sections. A self-referential process RFC records why
the scheme is path-encoded and gated.
2026-06-20 22:29:45 +08:00

3.7 KiB

Cookbook: adding a vendored package

When the harness needs another upstream Cordis package (e.g. @cordisjs/plugin-http), it is vendored as pinned source under vendor/, not added as an npm dependency — see the vendoring decision for why. vendor/README.md covers updating an already-vendored package; this guide is the file-by-file checklist for adding a new one. (Verified against the existing vendored set; if it drifts, fix it here.)

1. Copy the source in

vendor/<dir>/
  package.json     # from upstream; set "private": true, keep name/exports/type
  tsconfig.json    # extends ../../tsconfig.base.json (see shape below)
  src/             # the upstream src/ verbatim
  README.md LICENSE # if upstream ships them

tsconfig.json mirrors the other vendored packages — rootDir: src, outDir: lib, the strictness relaxations upstream code needs, and a references entry for every other vendored package it imports:

{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "rootDir": "src", "outDir": "lib",
    "noUncheckedIndexedAccess": false, "exactOptionalPropertyTypes": false,
    "noImplicitOverride": false, "noUnusedLocals": false, "noUnusedParameters": false
  },
  "include": ["src"],
  "references": [{ "path": "../cordis" }, { "path": "../cosmokit" }]
}

package.json invariants: "private": true (vendored packages are never published), keep upstream's name/version/exports/type, and list its cordis deps in peerDependencies (matching the upstream manifest). Transitive upstream deps must themselves be vendored or already present — vendoring one package often means vendoring its dependency tree (e.g. @cordisjs/plugin-http pulls @cordisjs/fetch-file).

2. Register it in the root configs

File Change
tsconfig.base.json add "<npm-name>": ["./vendor/<dir>/src"] to paths
tsconfig.typecheck.json add "<npm-name>": ["./vendor/<dir>/lib"] — this file points at built declarations, not src. If the package's types entry isn't lib/index.d.ts, point at that built file instead (e.g. logger-console maps to ./vendor/logger-console/lib/shared, matching its "types": "lib/shared.d.ts").
tsconfig.build.json add { "path": "./vendor/<dir>" } to references (before the packages/* entries)
vendor/README.md add a manifest table row (dir, npm name, version, upstream repo, commit SHA) and log any local modifications
scripts/publint-all.ts only if the vendored package is itself published from here (vendored deps normally are not — skip)

Covered automatically by globs — no edits needed: root package.json workspaces (vendor/*), tsdown.config.ts, vitest.config.ts, eslint.config.mjs. A per-package vendor/<dir>/tsdown.config.ts is needed ONLY if the build shape diverges from the root default (dual ESM/CJS or multiple entries — see vendor/schemastery and vendor/logger-console).

3. Mind the manifest guard

scripts/check-vendor-manifest.sh (a pre-commit hook) fails if anything under vendor/*/src is staged without vendor/README.md also staged. Stage the manifest update alongside the source so the commit passes.

4. Verify

pnpm install        # registers the workspace
pnpm run typecheck  # the base→lib path split means: run once after a fresh add
pnpm run build && pnpm run test && pnpm run constraints

Note the tsconfig two-map split (called out in AGENTS.md § Secrets/.env): lint's type-aware rules resolve vendored packages through their built lib/ declarations, so run pnpm run typecheck (which builds them) once after adding the package or lint reports unresolved-type errors.