From fd8e3b80136c000af87ad0871c00a7880ec8d51e Mon Sep 17 00:00:00 2001 From: bowenliang123 Date: Mon, 12 Oct 2026 13:57:56 +0800 Subject: [PATCH] docs(compatibility): record dependency constraints invisible to static audit Documents the three non-obvious dependency rules that a source scan alone mis-reads: primitives publishes shiki/katex/mdast/micromark/ anser/clsx/diff/simple-icons as bare imports the plugin must declare; dsh-client-store + dsh-util-code-language (and zustand/immer behind them) are reached only through the primitives dist; and tailwindcss is deliberately not a direct dependency. --- docs/compatibility.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/compatibility.md b/docs/compatibility.md index 19ffb69..c539471 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -96,6 +96,14 @@ The session jump — a Context Insights session card or an Agent network node br The Context Insights page's DeepSeek balance capsule is an all-optional stack, so it arms nowhere it cannot: the host reaches the `settings` and `credentials` services only inside a deferred `ctx.inject` (and re-reads them per request, so a key added while the host runs is picked up on the next open), mounts `/api/dsh-context/balance` through the same Connection exact-route registry as the detail and backfill routes, and the outbound `/user/balance` read carries the key only inside the host process. The provider's settings row is read off the Config-form `describe()` projection — the row is the entry whose served value declares the top-level `apiKeyEnv` credential ref, preferred under the settings ids the generations have served it as (`llm-deepseek` on product profiles, `llm-deepseek-api-key` elsewhere). The capsule appears only on a live, well-formed answer; a deployment whose DeepSeek API-key provider is not composed (no settings row), whose credentials service cannot resolve the key, whose connection service lacks the exact-route registry, or whose platform read fails (network, non-2xx, malformed payload, a third-party endpoint that does not serve the balance path) answers a typed `null` and the browser renders nothing — no pill, no spinner, no error state. The `balance` probe pins the settings face and the provider row's sources per baseline. +## Dependency constraints tied to a dsh release + +Most of the plugin's dependencies are read directly from source, so an ordinary unused-dependency audit names them correctly. These are the exceptions: each looks dead to a static scan, and dropping it breaks the `client` vitest project (or the bundle) rather than the code that appears to use it. + +- **`@deepseek-ai/dsh-client-ui-primitives` publishes its heavy runtime libs as bare imports.** Its `lib/index.js` imports `shiki`, `@shikijs/langs/*` (every language), `katex`, the `mdast-util-*` / `micromark-*` markdown chain, `anser`, `clsx`, `diff`, and `simple-icons` by specifier even though it lists them as its own `devDependencies` — it inlines nothing. They are therefore **this plugin's** build- and test-time requirements, declared here so the primitives' `lib/` resolves under `vite`'s transform. The client bundle itself never carries them: `MarkdownText` and the other imported primitives are the only reachable surface, and `tsdown.config.ts` asserts the boundary with `deps.onlyBundle` (`@opencode-ai/models`, `@deepseek-ai/dsh-util-workspace-path`, `simple-icons`) plus the `dsh-client-bundle-purity` plugin. If a future primitives release starts inlining these, drop the matching entries here in the same change. +- **`@deepseek-ai/dsh-client-store` and `@deepseek-ai/dsh-util-code-language`** are imported by that same `lib/index.js`, which is why they are declared even though no plugin source names them. `dsh-client-store` in turn imports `zustand` and `immer` bare, so those two are declared for the same reason — they are the store's runtime, reached only through the primitives dist. +- **`tailwindcss` is deliberately NOT a direct dependency.** `@tailwindcss/node` depends on it at that same exact version, so the one-copy pin the native-binding rule requires (`src/client/styles/tailwind.css`) already holds. Adding a top-level entry would risk a second copy resolving in the build process, which is exactly what breaks the napi calls. + ## What each check means - **Automated seam matrix** — part of this repository's `pnpm test` (the `compat` vitest project). For every baseline tag it stages the harness's REAL sources at that tag, boots the plugin's built host entry into that tag's actual `SessionProjectionRegistry` on the cordis release the line vendors, and probes the tag's client seams (slots, finalized-nodes seat, image loader, history face/envelope, markdown chrome, platform module table, that generation's durable-event vocabulary, the right Sidebar tab seam, its guide-entry contract and its resource-navigation face, the session-jump seam, the preferences card seat and settings transport). Definitions live in `tests/baselines.ts` — the one source of truth for the supported baselines and their per-version seam faces; both workflows fetch the pinned baseline tags before testing, and the `compat` project fails rather than skips when they are absent. Retired seams are asserted ABSENT (`settings.register`, the settings `get(ns)` read, the sessions service's `open(id)`), so a resurrection names the seam instead of silently shadowing the current face. Every event family `src/host/fold.ts` switches on is read back out of that source and asserted to be declared by every baseline, so a new fold case cannot go unprobed. To add a future dsh release: add one `Baseline` entry (tag, vendored cordis, faces) to `tests/baselines.ts` and its tag to both workflows' fetch step, then run `pnpm test` and re-fit whichever seam a failing probe names. The `compat` project boots the BUILT plugin (`pnpm run build` first) against the ACTUAL harness sources at each baseline tag and needs a dsh checkout (env `DSH_REPO`, default `~/dev/deepseek-harness`).