Files
deepseek-harness/docs/cookbook/adding-a-vendored-package.md
imccyu 62125c0dcb docs(ts): document the solution-root TypeScript project layout
New authoritative section docs/development.md#typescript-project-layout
(five files, three roles, the program-vs-resolution principle and its two
disciplines), two repo conventions in AGENTS.md, package tsconfig shape in
packages/AGENTS.md, cookbook touch-lists updated for the two aggregates,
test source-plane rule in docs/testing.md. Decision record: new Agent Note
2026-07-22-tsconfig-solution-root-two-aggregates; ts-build-config note
updated in place (tsc-first pipeline unchanged); the two GUI RFCs now name
tsconfig.host.json. All bilingual pairs re-recorded. Doc budget ceilings
raised: AGENTS.md 1680, docs/testing.md 1020, packages/AGENTS.md 660 (two
new one-line conventions and one new section on already-near-ceiling docs).
Mission spec for the code-side migration: missions/tsconfig-single-graph-migration.md.
2026-07-23 03:59:35 +08:00

4.0 KiB

Cookbook: adding a vendored package

English | 中文

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/types, 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/types",
    "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, point declaration metadata at lib/types, publish .d.ts and .d.ts.map declaration outputs, 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).

Local relative imports/exports in vendored TypeScript source use explicit .ts specifiers after copying. This is a repo-local build-shape divergence from upstream: rewriteRelativeImportExtensions emits .js runtime imports while declarations keep explicit .ts specifiers that NodeNext/Node16 TypeScript consumers can resolve.

2. Register it in the root configs

File Change
tsconfig.base.json add "<npm-name>": ["./vendor/<dir>/src"] to paths
tsconfig.host.json add { "path": "./vendor/<dir>" } to references (before the packages/* entries; vendored code enters the graph through the host aggregate only)
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); its entry should read the JS emitted under lib/types.

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
pnpm run build && pnpm run test && pnpm run constraints

The source paths map lives once in tsconfig.base.json and serves every graph. The important isolation boundary is the project-reference graph: vendored source must be referenced through its own vendor/<dir>/tsconfig.json, not pulled into an aggregate's strict program (layout).