What plugin management does now lives in `dsh-plugin-manager`, a boot-group package beside `app-boot`: `PluginInstaller` runs pnpm, probes, and judges new packages over the profile on disk, and `PluginManager` adds every operation over the booted tree, each refusal a `PluginOperationError` with a `plugins/*` code and no Remote protocol attached. The manager reads the profile runtime, the preset roster, and the running-agent count through per-call readers, and the roster only as `PresetLayers`, so the package depends on neither the roster nor the agent registry. `dsh-host-plugin-manager` keeps `pluginManager` and the `plugins` Remote as a relay: one Remote method per manager method, and one exhaustive switch turning a failure into the Remote error of the same code (`plugins/bad-request` into `gateway/bad-request`). Its `./types` re-exports the manager's types, so `api-remotes` and the client import one vocabulary unchanged. `dsh plugin add` and `remove` now run the installer instead of a bare pnpm forwarder: every new package is probed, a package that declares neither a bundle nor a plugin module is removed again with its reason, and newly installed bundles are enabled as before. Other pnpm verbs still forward.
49 lines
1.9 KiB
TypeScript
49 lines
1.9 KiB
TypeScript
/**
|
|
* The failure a plugin operation raises: a code from the `plugins/*`
|
|
* vocabulary and details typed by that code, with no Remote protocol
|
|
* attached. The Web host's adapter turns one into a `RemoteError` of the same
|
|
* code; the `dsh plugin` command prints it.
|
|
* @module @deepseek-ai/dsh-plugin-manager/errors
|
|
*/
|
|
|
|
import type { PluginOperationCode, PluginOperationDetailsMap } from './types.ts'
|
|
|
|
/**
|
|
* One refused or failed plugin operation. Discriminate by `code`: the
|
|
* {@link PluginOperationFailure} union narrows `details` per code.
|
|
*/
|
|
export class PluginOperationError<Code extends PluginOperationCode = PluginOperationCode> extends Error {
|
|
/** The stable failure code declared in {@link PluginOperationDetailsMap}. */
|
|
readonly code: Code
|
|
|
|
/** The structured payload the code declares. */
|
|
readonly details: PluginOperationDetailsMap[Code]
|
|
|
|
/**
|
|
* @param code - the stable failure code.
|
|
* @param message - human diagnostic.
|
|
* @param details - structured payload typed by the code.
|
|
* @param options - standard Error options; `cause` keeps the underlying failure.
|
|
*/
|
|
constructor(code: Code, message: string, details: PluginOperationDetailsMap[Code], options?: ErrorOptions) {
|
|
super(message, options)
|
|
this.name = 'PluginOperationError'
|
|
this.code = code
|
|
this.details = details
|
|
}
|
|
}
|
|
|
|
/** A plugin operation failure as the code-discriminated union, so a `code` branch narrows `details`. */
|
|
export type PluginOperationFailure = {
|
|
[Code in PluginOperationCode]: PluginOperationError<Code>
|
|
}[PluginOperationCode]
|
|
|
|
/**
|
|
* Narrow a caught value to a plugin operation failure.
|
|
* @param value - a caught value.
|
|
* @returns the failure when `value` is one, otherwise undefined.
|
|
*/
|
|
export function pluginOperationFailureOf(value: unknown): PluginOperationFailure | undefined {
|
|
return value instanceof PluginOperationError ? value as PluginOperationFailure : undefined
|
|
}
|