omdsh-dev/fabric
一种类似MC Fabric的hook处理器
已收录
14
Dev
Bundle 已验证
预览
功能介绍
类似 MC Fabric 的 hook 处理器。
适合
- 需要类似 MC Fabric 的转换 Hook 和兼容门面、但不想维护宿主 Fork 的 DSH 扩展作者。
- 需要以单个自包含发布包部署 cordis-fabric、cordis-fabric-api 和 cordis-fabric-dsh 三件套的 Profile。
不适合
- 不需要宿主转换 Hook 或 Fabric 兼容层的普通插件。
- 期望安装后立即激活 Fabric 的部署;其 Profile 行默认禁用,并依赖兼容的启动器引导接线。
README
RFC: dsh-external-fabric — repository purpose, architecture, and decision record
| English | 中文 |
- Status: living document (each section records the decision and its history)
- Scope: this standalone Fabric extension workspace
- Upstream anchors: deepseek-harness snapshots
7b9644f2(0812) /9f9e2782a4(0813), fork tip65bcaf9902(feat-fabric)
This document explains why this repository is shaped the way it is. Every non-obvious arrangement below was reached through a concrete failure recorded in the commit history; the sections follow the repository’s evolution rather than its file layout.
1. Purpose: an external Fabric extension, not a fork
deepseek-harness is a private monorepo. The Fabric/Mixin extension layer lives there as three extension packages, but a consumer cannot install them from the registry. This repository externalizes exactly those three packages so they can be installed through the official plugin channel:
dsh plugin --profile <p> add https://github.com/omdsh-dev/fabric/releases/latest/download/pkg.tgz
Boundary (hard rule): the workspace ships exactly three complete packages —
cordis-fabric (pure transformation service), cordis-fabric-api (pure compat
facade), cordis-fabric-dsh (DSH-facing facades, invariant, profile
bootstrap). Anything else — the official @deepseek-ai/dsh-tool-cordis
toolset included — is never added as a fourth package; official packages remain upstream dependencies and are not republished here.
2. Host integration: launcher-provided wiring
The three packages install hooks and mount facades through the compiled launcher.
src/fabric-dsh.ts compiles to lib/fabric-dsh.js, while
src/fabric-dsh-preload.ts compiles to lib/fabric-dsh-preload.js; the launcher
injects that compiled preload before the official CLI loads. No host patch
checkout is required.
Everything the official channels already cover is deliberately excluded:
installing the trio (dsh plugin add), bundle roster rows and dependencies,
catalog generation, invariant/gate exemptions for trio-in-workspace, and all
documentation (README*, docs/, .agents/). What remains is what no channel
can provide: launcher bootstrap (apps/cli/src/profile-boot.ts calls
installFabricBootstrap before any target import and
checkFabricRequiredPatches after boot), the clientBundle source-transform
build seam (packages/client/tsdown.client.ts), catalog entries compiled into
the official tool-cordis package, their tests, and the pnpm-policy seams.
2.1 The disabled opt-in rows
The web-app bundle layer inserts cordis-fabric / cordis-fabric-dsh rows as
disabled opt-ins: the pure cordis-fabric package is a library with no
plugin apply, so an enabled row fails every boot (“invalid plugin”). A
profile opts in by enabling the rows; the bundle layer applies on every boot,
so pre-existing profiles are covered without edits.
2.2 The TSX dead end (recorded and reverted)
The dsh source launch (node --import tsx/esm apps/cli/src/bin.ts) once
appeared to need TSX_TSCONFIG_PATH or a register preload: FiberState (a
const enum, only in vendor/cordis/src) failed to resolve. Both workarounds
shipped and were then reverted — the real cause was a stale
TSX_TSCONFIG_PATH in the shell pointing at an old staging checkout. With a
clean environment tsx auto-discovers the entry’s tsconfig (extending the base)
and resolves the aliases to src. The official script runs unchanged; no
host-specific workaround is required.
3. Install model: self-contained release bundle
The root bundle records the published trio tarballs and ships the prebuilt trio
inside bundledDependencies:
https://github.com/omdsh-dev/fabric/releases/latest/download/cordis-fabric.tgz
https://github.com/omdsh-dev/fabric/releases/latest/download/cordis-fabric-api.tgz
https://github.com/omdsh-dev/fabric/releases/latest/download/cordis-fabric-dsh.tgz
This keeps the release installation to one package:
dsh plugin --profile web add https://github.com/omdsh-dev/fabric/releases/latest/download/pkg.tgz
pnpm does not need to resolve nested Git or URL packages. At launch, fabric-dsh asks DSH’s module-fallback healer to map the bundle’s own dependency closure into $DSH_HOME/profiles/node_modules, so the Profile and the bundled preload resolve the same trio copies.
- Host source installs declare the bundle in
apps/cli/package.json; run the harness workspace’spnpm installandpnpm run build, then install the release bundle through the plugin channel (joiningcordis-fabric-bundletodsh.profile.bundles) and enable thecordis-fabric-dshrow. Launches go through the compiledlib/fabric-dsh.js. - Consumer-side builds use the explicit root
buildscript. The trio and the launcher are built with tsdown before packing; no install-time prepare build is required.
3.1 pnpm 11 supply-chain seams
The self-contained bundle does not require blockExoticSubdeps: false, a Git
prepare allowlist, or dangerouslyAllowAllBuilds in the Profile. The workspace
still allows the native esbuild build and excludes the fast-moving DSH rc
train from minimum-release-age checks:
-
allowBuilds: esbuildin this workspace; -
minimumReleaseAgeExclude: ['@deepseek-ai/dsh-*']— the dsh-* rc train ships inside the 24h window and a name-only entry exempts all versions.
4. Registry dependency policy
The dsh-* host packages publish fast rc trains; this repository tracks them through registry ranges, and each lesson below came from a real breakage.
4.1 The dsh-compact trap
@deepseek-ai/dsh-client-runtime@0.0.1-rc.1 depended on
@deepseek-ai/dsh-compact, which was never published (upstream deleted the
package after publishing that runtime). The 0.1.0-rc.x series dropped the
dependency; verified installable end-to-end.
4.2 The missing rc.5
Upstream code is versioned 0.1.0-rc.5, but the registry jumps
rc.3 → rc.6 — rc.5 was never published. Ranges therefore read ^0.1.0-rc.0
(resolving the newest published rc, and rc.0 keeps stable releases in range
too). Peers use the same range, which the host workspace’s rc.5 satisfies —
host installs reuse workspace packages instead of registry copies.
4.3 Real host types, not a local contract
The trio once declared a host-contracts.ts facade plus a global
@deepseek-ai/cordis Events injection. That broke type-checking across host
packages and was deleted in favor of importing the real @deepseek-ai/dsh-*
types (declared as peers + devDeps) — exactly the upstream shape. ctx.slots
typing comes from dsh-client-runtime’s declaration, as upstream.
4.4 Runtime peers of the published libs
With autoInstallPeers: false, the published dsh-* libs’ load-time imports
(dsh-scope, dsh-llm, dsh-timeout, dsh-typert-protocol) must be listed
as devDependencies explicitly — each was added after a “Cannot find package”
at test load.
5. Browser client format: the closure factory
The web shell loads /plugins/<id>/client.js as a classic script and resolves
value imports through the loader module table (a synchronous require inside
the factory). Plain ESM bundles cannot load there at all. Consequently both
trio browser halves ship as closure factories:
window.__ModuleLoader__.load({ id: "cordis-fabric", factory: (require) => { ...; return module.exports; } })
with @deepseek-ai/cordis external (a platform seed) and everything else
inlined. cordis-fabric was converted first; cordis-fabric-dsh followed
(the same gap, fixed after the ex-setting install exposed the first one).
Upstream never notices this — its monorepo builds both through the shared
clientBundle() preset.
5.1 ex-setting’s three lessons (same contract, external repo)
The sibling omdsh-dev/ex-setting bundle hit the same contract three times:
- Its
dsh.clientmanifest must be nested ("dsh": { "client": ... }), not a top-leveldshClientfield — client-modules scans the nested form; - its consumer-side build must use the prepare config, not just the local one, or git installs serve the old artifact;
- cross-bundle value imports must not rely on a disabled row’s factory — ex-setting inlines/avoids what the module table cannot answer, and installs static styles directly instead of routing them through a Fabric publish the transform could not produce (browser-transform cannot match inside the closure artifact).
6. Test strategy
The upstream suite resolves src through tsconfig paths; this repository only
has registry lib artifacts, which drove the evolution below.
-
serve.spec uses a test-local
node:httpadapter for the hostwebServerservice, so exact/prefix routing and real HTTP responses stay covered without a DSH host-webserver test dependency. -
hmr-e2e-runner drives config HMR by toggling the row’s
disabledflag incordis.yml: the vendored fork’shmr.registerConfigand includeinternal/updateare fork-private and exist in no registry version (verified against latest 1.0.16/1.0.6). -
client specs originally faked
CommandUiRuntime/SlotRegistrybecause the runtime rc.1 tree was uninstallable and the bundles are closure factories. After rc.6 became installable the real reason remained the factory format, so the specs now mount the real services through a test module loader (packages/cordis-fabric-dsh/tests/browser/module-loader.ts): happy-dom provideswindow; the__ModuleLoader__sink installs at helper module load; platform seeds (cordis,ui-slots,react) preload as ESM namespaces (the factoryrequireis synchronous and node cannotrequireESM);ui-primitives— a render-only heavy package — is stubbed;materialize()executes a factory with the module-table require (recursing into other registered bundles, memoized,stripClientSuffixnormalizingpkg/client). LoaderbaseUrland fixture URLs are pinned to file paths because happy-dom’slocationishttp://localhost:3000.
7. Timeline (abridged)
| Commit | Decision |
|---|---|
1e04b1a..2a42254
|
externalization: standalone Fabric bundle, self-contained template |
4018661, 8ffaac4
|
port the upstream three-package split + full host patch; HMR e2e |
d9228c4, 40600d4
|
official plugin channel install; source-host install script |
1ba7077, 3331b80
|
web-app bundle composes the rows; rows become disabled opt-ins |
7b8e913, 3fd3106
|
patch rebases: 0812 baseline → 0813 baseline |
9158f5d |
delete host-contracts.ts; real @deepseek-ai/dsh-* types |
30ed5ff, b58c643
|
registry dependency policy (rc.5 peer, installable suites) |
58fbe75, 33955ef
|
both browser halves become closure factories |
aa58a52 |
publish publicly (upstream parity) |
62ced22 |
revert the TSX workarounds (environment misdiagnosis) |
3fd1a56 |
happy-dom + ModuleLoader materializer; real browser services in tests |
8. Future work
- If the registry ever publishes node-importable builds (plain ESM or the
srchalves), the test module loader disappears and the specs import packages directly. - Upstream promoting
createSnapshotStoreout ofdsh-client-runtimeshrinks the seed table. - Upstream publishing
hmr.registerConfig/internal/updatewould let the HMR runner mirror the in-tree config flow again.
常见问题常见问题
在启用了 DSH 的终端中执行已验证命令 dsh plugin --profile default add github:omdsh-dev/fabric。命令会解析公开 package 元数据,并保持插件与本页展示的目录身份一致。
兼容性以页面上展示的 bundle 与 profile 状态为准。如果某个 profile 尚未检测到,请先保持禁用,并在生产启用前阅读仓库文档。
GitHub 链接和 activity 元数据是 release 与维护状态的来源。新版本发布后重新查看本页,确认目录已经观察到最新版本。