Files
deepseek-harness/vendor
imccyu 2c85c484d3 build(release): reference workspace members through the workspace protocol
1504 hand-written ranges pointing at workspace members become workspace:^, so
pnpm pack substitutes each member's real version at publication: sibling
peerDependencies follow the family version instead of being pinned at ^0.0.1,
and a reference to a vendored package follows that package's own line. Without
this, publishing 0.0.2 ships peer ranges naming a version that does not exist,
and 0.0.1-rc.1 does not satisfy ^0.0.1 either.

It also retires ranges that had gone stale against the workspace: ^4.0.0-rc.6
for a 4.0.0-rc.7 checkout, ^3.17.0 for schemastery 3.18.0.

workspace:* stays where an exact published version is the point, which is how
the Landlock entry pins its platform packages.

A workspace constraint now requires the protocol, so a new package cannot
reintroduce a hand-written range. The same constraint caught packages/boot/cmdline
arriving on master without the publishable trio, which this change completes.
2026-08-11 00:17:09 +08:00
..

Vendored Packages

This directory contains source-vendored copies of the Cordis framework and its foundation libraries. They are copied into this monorepo instead of being depended on via npm, so that the harness fully owns its framework layer (auditable, patchable, pinned).

All vendored packages are renamed into the @deepseek-ai scope (cordis@deepseek-ai/cordis, @cordisjs/plugin-<x>@deepseek-ai/cordis-plugin-<x>): every harness package declares cordis as a peer dependency, so publishing the harness publishes this framework layer too, and a publication under the upstream names would squat them on the registry. Directory names and upstream version numbers are deliberately unchanged, so the manifest below still reads as an upstream snapshot. pnpm-workspace.yaml#linkWorkspacePackages makes those preserved semver ranges resolve these pinned workspaces, including imports from built lib/. The hygiene gate verify-vendored-links asserts every vendored name resolves to a workspace link: in pnpm-lock.yaml with no registry copy alongside. Schemastery's manifest additionally declares a conditional exports map (import → .mjs, require → .cjs): pnpm links the directory itself, so without exports Node's ESM resolver would fall back to main and load the CJS entry whose lazy require('@deepseek-ai/cosmokit') can race ESM loading of the same linked module under module-hook hosts (vitest). Upstream MIT LICENSE files are preserved in each package directory.

This file covers the manifest, the local-modification log, and the procedure for updating an existing vendored package. To add a new one, see the cookbook guide: docs/cookbook/adding-a-vendored-package.md.

Manifest

Upstream workspace: cordis-workspace (local checkout: ~/repos/cordis-workspace).

Directory npm name Upstream name Version Upstream repo Commit
cosmokit/ @deepseek-ai/cosmokit cosmokit 1.8.1 https://github.com/deepseek-harness/cosmokit 16f6fc058ade66e8ac5da0033d35a8d0f279f544
schemastery/ @deepseek-ai/schemastery schemastery 3.18.0 https://github.com/deepseek-harness/schemastery (packages/core) e67cee00ad725bd1534aee930a979ea3eec6f698
cordis/ @deepseek-ai/cordis cordis 4.0.0-rc.7 https://github.com/cordiverse/cordis (packages/core) 56b3d4f725681cf4556c1a8695a709cc3b6eed74
loader/ @deepseek-ai/cordis-plugin-loader @cordisjs/plugin-loader 1.0.0-rc.5 https://github.com/cordiverse/cordis (packages/loader) 56b3d4f725681cf4556c1a8695a709cc3b6eed74
include/ @deepseek-ai/cordis-plugin-include @cordisjs/plugin-include 1.0.4 https://github.com/deepseek-harness/cordis (packages/include) abb0a307cb1d3b0947f455d590cf5ba922d4caa4
group/ @deepseek-ai/cordis-plugin-group @cordisjs/plugin-group 1.0.0 https://github.com/deepseek-harness/cordis (packages/group) abb0a307cb1d3b0947f455d590cf5ba922d4caa4
timer/ @deepseek-ai/cordis-plugin-timer @cordisjs/plugin-timer 1.1.2 https://github.com/deepseek-harness/cordis (packages/timer) abb0a307cb1d3b0947f455d590cf5ba922d4caa4
hmr/ @deepseek-ai/cordis-plugin-hmr @cordisjs/plugin-hmr 1.0.15 https://github.com/deepseek-harness/cordis (packages/hmr) abb0a307cb1d3b0947f455d590cf5ba922d4caa4
logger-console/ @deepseek-ai/cordis-plugin-logger-console @cordisjs/plugin-logger-console 1.0.0 https://github.com/deepseek-harness/cordis (packages/logger-console) abb0a307cb1d3b0947f455d590cf5ba922d4caa4

Third-party dependencies of the vendored packages stay on npm: @standard-schema/spec, js-yaml, chokidar, picomatch, @babel/code-frame, supports-color, node-addon-require-builtin.

Intentionally not vendored (verified unused by this set): reggol, @cordisjs/utils, @cordisjs/element, @cordisjs/unyaml (dev-time YAML import hook only).

Local modifications

Keep this log exhaustive — every divergence from upstream must be listed.

  1. hmr/src/index.ts: removed the ./locales/en-US.yml / ./locales/zh-CN.yml imports, the .i18n({...}) call on the Config schema, and the src/locales/ directory. Rationale: those imports require a runtime YAML loader hook (@cordisjs/unyaml) that we do not vendor; the i18n texts only localize config descriptions.
  2. All package.json files: regenerated — added private: true, added precise files entries for bundled runtime files and lib/types/**/*.d.ts / .d.ts.map, preserved src in files only for packages whose previous file list already shipped it, added a ./src/* export where missing, pointed declaration metadata at lib/types, and removed upstream devDependencies/scripts/repository fields. Dependency and peer-dependency ranges are preserved except that hmr declares esbuild as a direct dev dependency because its source imports the BuildFailure type and pnpm's strict workspace resolution requires the owner package to name that dependency, and loader requires node-addon-require-builtin@^0.1.4 to match the runtime used by published app packages.
  3. All tsconfig.json files: regenerated to extend the repo-root tsconfig.base.json, emit TypeScript intermediates to lib/types, and declare project references.
  4. Vendored TypeScript source internal specifiers: changed local relative imports/exports from upstream's specifier shape to explicit .ts specifiers so TypeScript rewrites emitted JS to .js while declarations keep explicit, NodeNext-safe .ts specifiers. This includes loader/src/config/isolate.ts using declare module './entry.ts'.
  5. schemastery/tsdown.config.ts and logger-console/tsdown.config.ts: ours, not upstream files — per-package build-shape overrides (dual ESM+CJS output; separate node/browser entries) for the repo-root tsdown build. They read the JS emitted under lib/types and then write the publish runtime entries under lib/. Like the regenerated tsconfigs, they are not part of the upstream sync surface.
  6. cordis/src/fiber.ts lifecycle hardening: locally closes three reentrant disposal gaps. An effect's owner-list wrapper is registered before its setup body runs, so an unload begun from inside setup awaits setup and every collected cleanup; synchronous setup failure removes the wrapper and rolls back collected cleanup. Async cleanup stays owner-visible until quiescence, and Cordis's internal effect composition joins an already-running cleanup while repeated public disposer calls retain their upstream single-shot result. Effect creation is rejected while the owner is UNLOADING (while PENDING and LOADING remain legal), preventing cleanup-time registrations from escaping the unload snapshot. Child fibers register and receive their parent-owned disposer before internal/plugin publication, resolve dependency declarations added by that notification before activation, drain effects attached while pending, skip plugin execution when reentrant disposal invalidates the load epoch before its first checkpoint, and contain teardown-notification failures per observer so one callback cannot starve peers or interrupt ownership cleanup. Fiber.update() returns its internal/update waterfall result, allowing Loader callers to await a restart while preserving synchronous config validation.
  7. cordis/src/*.ts JSDoc enrichment: added @param/@returns tags and contract documentation (disposal semantics, waterfall veto, bail conditions, error cases) across the public plugin-author surface — Context (class, statics, and the Context interface properties incl. root), EventsService, Fiber, RegistryService, ReflectService, Service, LoggerService and their declare module './context.ts' overloads. Comment-only; no code changes. Motivation: the website API-reference generator renders these docs and hard-errors on undocumented members. Retire this entry when the enrichment is upstreamed to the fork.
  8. Transactional Loader/Include config reconciliation: Loader imports a changed entry name before disposal, awaits lifecycle settlement, and restores the previous plugin or config when candidate application fails. Loader settlement rechecks service-gated fibers after current tasks drain, rejects failures, and leaves fibers with absent dependencies pending. Group updates start candidates concurrently, await every outcome, contain sibling-start failures after their owning tree is disposed, undo changes and additions on live-update failure, await removal, preserve programmatic option identity, and persist direct or tree-level mutations only after success. Include reads and validates detached candidate content, applies patches to a clone, reconciles the tree, and only then commits its cached content/data; direct refresh failures propagate for the caller to contain. A non-array parse is invalid, patches re-apply on every file or Include-config update, an omitted patch list clears the overlay, and initial content falls back to initial only on ENOENT. Covered by packages/boot/app-boot/tests/config-reload.spec.ts and packages/host/webserver/tests/webserver.spec.ts.
  9. hmr/src/index.ts exact config watching: registerConfig() watches one absolute config path outside module roots, including a path under missing parents, serializes and coalesces refreshes, and returns an async disposer that closes the watcher and drains active work. Module watches realpath their existing base directory, attach change listeners before declaring the service ready, and use that spelling for Node module-cache identity; exact config watches realpath the deepest existing watch ancestor and restore the missing suffix. Those native paths prevent Windows short-name aliases from colliding with long-form libuv event paths while exact-config callbacks keep the requested filename. Refresh failures are normalized to Error, logged, and broadcast through the parallel hmr/config-update-failed event; observer failures are contained. Config-file changes discovered by the ordinary HMR watcher use the same serialized path. Covered by packages/boot/app-boot/tests/hmr-config.spec.ts.
  10. Vendored Node-compatible TypeScript: marked erased imports explicitly across cordis, loader, include, hmr, and schemastery so Node's native TypeScript transform does not request types as runtime exports. Schemastery's source uses an ESM default export and its package declares type: module; its built ESM/CJS entries retain explicit .mjs/.cjs extensions.
  11. include/src/index.ts patch-semantics export: extracted the private applyPatches body into the exported pure function applyEntryPatches(data, patches, warn) (the method delegates to it) and exported the !!js YAML dialect as entryListSchema, so dsh --dump-config composes and prints exactly what the include would mount without booting a tree. Behavior-preserving for mounting; the extraction exists because config tooling must never reimplement (and drift from) the patch algorithm. applyEntryPatches also indexes each inserted entry as it is added, so a later patch in the same list can configure or disable a row an earlier patch inserted; upstream built the id index once before the patch loop, leaving inserted rows silently unpatchable. That matters because dsh composes an empty profile root with each bundle's patch layer, the profile's and the home-level cordis.patch.yml, and any --patch overlays as sibling patch lists at one include level — patches never cross an include boundary, so surface-only rows would otherwise be unreachable from user config. Covered by packages/boot/app-boot/tests/config-reload.spec.ts.
  12. include/src/index.ts serialized child-tree mutation and hmr/src/index.ts main-watcher initial-scan suppression: every Include child-tree mutation (initial apply, refresh, internal/update patch re-application) runs through one per-Include queue, because the group's transactional update is not reentrant — two concurrent applies interleave create and rollback on the same entries and strand the Include fiber without ever settling. The HMR main watcher passes ignoreInitial: true: the initial scan re-announced files boot had just consumed, and its add for a config file refreshed an Include mid-initial-apply; once serialized, a failing initial apply's rollback disposed HMR, whose teardown drain waited on the queued refresh sitting behind that same apply — a deadlock that exited 13 with no diagnostic. registerConfig() keeps its own ignoreInitial: false watcher because a user patch layer present at registration must apply once. Covered by the patch-overlay boot-failure built-bin case in apps/cli/tests/built-bin.e2e.ts.
  13. include/src/index.ts writeTask type: widened the optional writeTask?: NodeJS.Timeout property to NodeJS.Timeout | undefined — the debounced writer assigns undefined on flush, which exactOptionalPropertyTypes rejects on a plain optional. Type-only; no behavior change.
  14. include/src/index.ts durable debounced writes: serialized and tracked config-file writes, retried transient EACCES/EBUSY/EPERM rename failures with a bounded backoff, observed asynchronous timer rejections, and drained the latest write during Include teardown. Windows can briefly retain a destination handle after a Loader child disposes; the upstream fire-and-forget rename escaped as an unhandled rejection and could lose the persisted disabled state. A terminal failure is logged by the asynchronous writer and remains on the queue so Include.stop() rethrows it instead of silently declaring persistence complete; Cordis's ordinary fiber teardown retains its separate error-containment contract. Covered by packages/host/directory-picker-auto/tests/loader-composition.spec.ts with injected transient and terminal rename failures.
  15. Lazy Loader config resolution across cordis/src/{events,fiber}.ts, loader/src/{index,config/entry}.ts, include/src/index.ts, and hmr/src/index.ts: ports cordiverse/cordis#41, retaining raw fiber config and resolving it through internal/config only after declared injections are active. Provider replacement re-resolves the raw expression, pending updates retain it, and HMR transfers it. Resolution applies only to the entry root, so child plugins mounted by a row keep caller-owned config identity. Include adds a static entry-config resolver so its own options interpolate while nested row !!js nodes remain deferred. Deferred failures retain the owning row diagnostic, and tree teardown does not persist failure-driven self-disposal. Covered by packages/boot/app-boot/tests/{app-boot,user-patches}.spec.ts, packages/boot/cmdline/tests/cmdline.spec.ts, apps/cli/tests/web-agent-presets.e2e.ts, and the built custom-profile cases in apps/cli/tests/built-bin.e2e.ts.
  16. In-memory Loader entry activation in loader/src/config/entry.ts: an invocation can activate a row shipped with disabled: true without mutating its serialized options. The override belongs to the mounted entry object, survives Include config reapplication, respects disabled ancestors, and disappears with the entry. Covered by packages/boot/cmdline/tests/cmdline.spec.ts and apps/web/tests/hmr-live.e2e.ts.
  17. @deepseek-ai rescope: every vendored manifest name, every internal dependency entry among the vendored set, and every module specifier that reaches them use the scoped names in the manifest table's npm name column. Directory names, version numbers, and dependency ranges are unchanged, and no upstream runtime identifier is renamed — Symbol.for('schemastery') and Schemastery's vendor: metadata field keep their upstream values. Re-apply with pnpm run rescope-vendor --apply after a sync; the table's two name columns are the mapping, restated for consumers in docs/rescope.md.

Sync procedure

To update a vendored package from upstream:

  1. In the upstream workspace, note git rev-parse HEAD of the relevant submodule.
  2. Copy the package's src/ (and bin.js, README.md, LICENSE if changed) over the vendored directory.
  3. Re-apply the local modifications listed above (or drop them if upstream made them unnecessary — update the log either way).
  4. Update the version and commit hash in the manifest table.
  5. Run pnpm install && pnpm run test && pnpm run build at the repo root.