Lessons Learned

August 21, 2026 · View on GitHub

Durable lessons from shipping this plugin — read before touching the client bundle.

1. exports.inject (browser bundle) takes Cordis service names, not package names

Incident (2026-08-21): the first install of this plugin prevented DSH from booting: web boot: 1 entry did not activate dsh-plugin-proxy — the plugin sat permanently pending because its browser half declared

exports.inject = ["@deepseek-ai/dsh-client-runtime", ...] // WRONG — package names

The browser-side Cordis loader waits for services by name, so those packages could never resolve as services and the fiber never activated.

The two injects are different things:

LocationMeaningValues
package.jsondsh.client.injectmodule-graph edges (which bundles to load)package names (@deepseek-ai/dsh-client-*)
lib/client.jsexports.injectCordis service dependencies (which fibers to wait for)service names (slots, settingsScope, locale, connection, remote)

The correct value here is what apply() actually uses:

exports.inject = ["slots", "settingsScope"];

(settingsScope is provided by @deepseek-ai/dsh-client-ui-settings.)

Regression guard: test/client-shape.mjs executes lib/client.js in a vm and asserts exports.inject equals exactly ["slots", "settingsScope"]. Keep that test; extend it if the client starts using another service.

Reference trap: the original dsh-plugin-focus client bundle also wrote package names into exports.inject. Do not copy that line from it.

2. Node 24 test runner: use node --test test/*.mjs

node --test test/ fails on Node 24 (a directory is not a module). The package script is node --test test/*.mjs. Run individual files directly too when debugging.

3. dsh plugin add + --dump-config is not a boot acceptance test

It verifies the composition tree only. Client-fiber activation (and every exports.inject mistake) only shows up on a real service restart — restart DSH and check the page for did not activate / pending before declaring a client-bearing plugin done.

A profile-level drift of @deepseek-ai/dsh-tools (a nested old copy pulled in by another plugin) crashed DSH with Cannot read properties of undefined (reading 'prepare'). The fix on this machine is the profile pnpm-workspace.yaml override pinning @deepseek-ai/dsh-tools to the harness core link. When adding dependencies, re-check nested node_modules for stale @deepseek-ai/* copies.