refactor(picker): split the directory-picker faces into their own packages
The browse and native backends were dual-face packages: a Node backend plus a browser surface under one tsconfig that referenced Client packages. That put Client projects — and through them the Client runtime — inside the Host compiler aggregate, which builds before the generated Remote contributions exist. Each browser half moves to its own Client package, and both backends become Node-only. The interaction is still one choice: the adaptive chooser mounts the backend and its surface as a pair of Loader entries and tears both down in reverse, so a resolved kind still swaps both faces. Compositions that pin an interaction directly now pin the pair, and the chooser's runtime-string package list keeps naming everything a composing app must resolve.
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
/**
|
||||
* Adaptive chooser of the directory-picker seam: resolves the host's
|
||||
* situation once at boot (bind host, SSH launch, display session, Linux
|
||||
* chooser binary) and mounts the matching dual-face backend — `-native` or
|
||||
* `-browse` — as a real Loader entry in the in-memory root tree. Because the
|
||||
* backend arrives as an ordinary entry, its browser half is discovered
|
||||
* exactly as a config-row's would be, so the seam's one-row-swaps-both-faces
|
||||
* invariant holds for the resolved choice; pinning an interaction remains
|
||||
* composing that backend row directly instead of this one.
|
||||
* chooser binary) and mounts the matching interaction — `native` or `browse`
|
||||
* — as real Loader entries in the in-memory root tree. Each interaction is a
|
||||
* pair: the Host backend serving the seam capability and the client surface
|
||||
* occupying ui-workspace's directory-flow holes. Both arrive as ordinary
|
||||
* entries, so the surface is discovered exactly as a config-row's would be
|
||||
* and one resolved choice still swaps both faces; pinning an interaction
|
||||
* remains composing that pair directly instead of this row.
|
||||
* @module @deepseek-ai/dsh-host-directory-picker-auto
|
||||
*/
|
||||
|
||||
@@ -28,7 +29,7 @@ export const name = 'directory-picker-auto'
|
||||
export const inject = ['httpServer', 'loader']
|
||||
|
||||
/**
|
||||
* Backend package per resolved kind — fixed composition vocabulary, not a
|
||||
* Host backend package per resolved kind — fixed composition vocabulary, not a
|
||||
* tunable. Exported because the reference is a runtime string the static
|
||||
* config gate cannot see in a yml row: `verify-cordis-config` requires every
|
||||
* app composing this chooser to declare both values as dependencies.
|
||||
@@ -39,10 +40,20 @@ export const BACKEND_PACKAGES: Record<DirectoryPickerBackendKind, string> = {
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the backend from one boot-time sample and mount it as a Loader
|
||||
* entry; the effect's disposer removes the entry and joins the backend
|
||||
* fiber's teardown, so unloading this plugin returns only after both faces
|
||||
* of the mounted backend (and their dependents) quiesced.
|
||||
* Client surface package per resolved kind, mounted with its backend so one
|
||||
* resolved interaction still composes both faces. Declared as dependencies by
|
||||
* every composing app for the same reason as {@link BACKEND_PACKAGES}.
|
||||
*/
|
||||
export const SURFACE_PACKAGES: Record<DirectoryPickerBackendKind, string> = {
|
||||
native: '@deepseek-ai/dsh-client-ui-directory-picker-native',
|
||||
browse: '@deepseek-ai/dsh-client-ui-directory-picker',
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the interaction from one boot-time sample and mount its backend and
|
||||
* surface as Loader entries; the effect's disposer removes both entries and
|
||||
* joins their fibers' teardown, so unloading this plugin returns only after
|
||||
* both faces of the mounted interaction (and their dependents) quiesced.
|
||||
* @param ctx - cordis context carrying the injected `httpServer` and `loader`.
|
||||
*/
|
||||
export async function apply(ctx: Context): Promise<void> {
|
||||
@@ -54,16 +65,22 @@ export async function apply(ctx: Context): Promise<void> {
|
||||
})
|
||||
await ctx.effect(async () => {
|
||||
// Root-tree create: the Loader root is in-memory (write() is a no-op), so
|
||||
// the mounted row can never be persisted back into a config file.
|
||||
const id = await ctx.loader.create({ name: BACKEND_PACKAGES[backend] })
|
||||
return async () => {
|
||||
// Tree teardown (group.stop) can have removed the entry already;
|
||||
// nothing is left to unmount or await then.
|
||||
const entry = ctx.loader.store[id]
|
||||
if (entry === undefined) return
|
||||
// remove() disposes the entry transactionally, so the chooser's unload
|
||||
// signals completion only after the backend quiesced.
|
||||
await ctx.loader.remove(id)
|
||||
// the mounted rows can never be persisted back into a config file. The
|
||||
// backend lands first: the surface's browser half drives the capability
|
||||
// the backend registers.
|
||||
const ids: string[] = []
|
||||
for (const name of [BACKEND_PACKAGES[backend], SURFACE_PACKAGES[backend]]) {
|
||||
ids.push(await ctx.loader.create({ name }))
|
||||
}
|
||||
}, 'directory-picker-auto: backend entry')
|
||||
return async () => {
|
||||
for (const id of ids.reverse()) {
|
||||
// Tree teardown (group.stop) can have removed the entry already;
|
||||
// nothing is left to unmount or await then.
|
||||
if (ctx.loader.store[id] === undefined) continue
|
||||
// remove() disposes the entry transactionally, so the chooser's unload
|
||||
// signals completion only after that face quiesced.
|
||||
await ctx.loader.remove(id)
|
||||
}
|
||||
}
|
||||
}, 'directory-picker-auto: interaction entries')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user