mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
The registry scans mounted Loader entries' dshClient declarations and
composes __DSH_BOOT__ {rev, entries} — inject edges and the immediately
mark come from manifests, never hand-copied; malformed fields fail loud
at load. The composing app owns one flat roster plus the --dev switch
(hmr row and bundle watching are dev-graph decisions).
The rebuild signal is the webserver's own observation: in dev mode the
registry stat-polls each scanned bundle (fs.watchFile; polling because
network mounts deliver no inotify), re-hashes on change, and broadcasts
a rebuilt frame on the /plugins/events SSE channel only when the rev
actually changed. Watch membership follows the table across rescans;
dispose drops all watches; a torn read self-heals on the next tick.
The POST /plugins/rebuilt endpoint is gone — builders and the host
share zero protocol. dsh web --dev logs the watched bundle list and
each rebuilt id with its rev transition.
58 lines
2.8 KiB
TypeScript
58 lines
2.8 KiB
TypeScript
/**
|
|
* Web client plugin assembly: mounts @cordisjs/plugin-loader with an in-memory
|
|
* entry tree over the caller-supplied client plugin roster. The roster is a
|
|
* composition decision and lives in the composing app (apps/cli); this module
|
|
* only owns the mount/settle/fail-loud mechanics. The web plugin registry
|
|
* discovers fetch-arrival entries among the mounted packages by their
|
|
* package.json dshClient declarations; node halves are empty applies, so
|
|
* mounting them here costs nothing beyond Loader governance.
|
|
*/
|
|
import { createRequire } from 'node:module'
|
|
import type { Context } from 'cordis'
|
|
import Loader from '@cordisjs/plugin-loader'
|
|
|
|
/** What the shell hands the web plugin registry (loader view + module resolution seam). */
|
|
export interface MountedWebPlugins {
|
|
/** Entry enumeration surface of the mounted Loader (registry scan source). */
|
|
loader: { entries(): Iterable<{ options: { name: string }; fiber?: unknown; disabled: boolean }> }
|
|
/** Resolve a plugin package's package.json absolute path. */
|
|
resolvePkgJson: (name: string) => string
|
|
}
|
|
|
|
/**
|
|
* Mount the Loader (when absent) and create one in-memory entry per client
|
|
* plugin package, then wait for the tree to settle. A plugin whose import
|
|
* fails leaves its entry fiber-less — surfaced here as a loud throw listing
|
|
* the failures (misconfiguration must not silently drop a client plugin).
|
|
* @param ctx - host root context (bootHost product).
|
|
* @param plugins - client plugin package names to mount (the composition layer's roster).
|
|
* @param anchor - module URL anchoring bare-specifier resolution (the composing
|
|
* app's import.meta.url; the roster packages must be dependencies of that app).
|
|
* @returns the loader view and package.json resolver the registry consumes.
|
|
*/
|
|
export async function mountWebPlugins(
|
|
ctx: Context, plugins: readonly string[], anchor: string,
|
|
): Promise<MountedWebPlugins> {
|
|
// The Loader resolves bare specifiers against ctx.baseUrl; without one the
|
|
// import silently fails and every entry stays fiber-less. The composing app
|
|
// declares the roster packages as dependencies, so its URL is the right anchor.
|
|
ctx.baseUrl ??= anchor
|
|
if (ctx.get('loader') === undefined) await ctx.plugin(Loader)
|
|
const existing = new Set([...ctx.loader.entries()].map(entry => entry.options.name))
|
|
for (const name of plugins) {
|
|
if (!existing.has(name)) await ctx.loader.create({ name })
|
|
}
|
|
await ctx.loader.await()
|
|
const dead = [...ctx.loader.entries()]
|
|
.filter(entry => plugins.includes(entry.options.name))
|
|
.filter(entry => entry.fiber === undefined && !entry.disabled)
|
|
if (dead.length > 0) {
|
|
throw new Error(`web-plugins: client plugin(s) failed to load: ${dead.map(e => e.options.name).join(', ')}`)
|
|
}
|
|
const require = createRequire(anchor)
|
|
return {
|
|
loader: ctx.loader,
|
|
resolvePkgJson: name => require.resolve(`${name}/package.json`),
|
|
}
|
|
}
|