feat(plugin-inventory): blacklist/whitelist toggle guard with a default-open default
Splits the enable/disable guard into two code-editable lists: REQUIRED_PLUGINS (the blacklist of load-bearing core that must never be disabled) and USER_TOGGLEABLE_PLUGINS (the whitelist, which overrides the blacklist for an explicitly toggleable plugin). A plugin on neither list is toggleable by default. isRequiredPlugin and isUserToggleable derive from the two lists. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,19 +1,25 @@
|
|||||||
/**
|
/**
|
||||||
* Which Loader plugins the running application requires and must not be toggled.
|
* Which Loader plugins the running application requires and must not be toggled,
|
||||||
|
* and which plugins a deployment explicitly allows the user to toggle.
|
||||||
*
|
*
|
||||||
* The guard is default-open: every plugin is toggleable unless it is explicitly
|
* The guard is default-open with two code-editable lists:
|
||||||
* listed as required. Only the few load-bearing core plugins that other plugins
|
* - {@link REQUIRED_PLUGINS} is the blacklist of load-bearing core plugins that
|
||||||
* inject and whose disable would tear the process or the management surface
|
* must never be disabled (disabling one tears the process or the management
|
||||||
* down are surfaced as `protected`. Add a module name to
|
* surface down).
|
||||||
* {@link REQUIRED_PLUGINS} when a plugin must never be disabled.
|
* - {@link USER_TOGGLEABLE_PLUGINS} is the whitelist of plugins a deployment
|
||||||
|
* explicitly permits the user to toggle; a whitelisted name overrides the
|
||||||
|
* blacklist for that plugin.
|
||||||
|
* A plugin on neither list is toggleable by default. Edit these lists (they are
|
||||||
|
* plain constants) to change what the plugin-inventory `protected` flag reports
|
||||||
|
* and what `setEnabled` refuses to disable.
|
||||||
* @module @deepseek-ai/dsh-plugin-inventory/required
|
* @module @deepseek-ai/dsh-plugin-inventory/required
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugin module names that are required by the application and must not be
|
* Blacklist: plugin module names required by the application and must not be
|
||||||
* toggled. Everything else is toggleable. Keep this to the true core: the entry
|
* toggled. Keep this to the true core: the entry tree, the Remote RPC spine
|
||||||
* tree, the Remote RPC spine every Remote depends on, and the session/agent
|
* every Remote depends on, and the session/agent spines. `cordis:required` is a
|
||||||
* spines. `cordis:required` is a test seam for the unit tests.
|
* test seam for the unit tests.
|
||||||
*/
|
*/
|
||||||
const REQUIRED_PLUGINS = new Set([
|
const REQUIRED_PLUGINS = new Set([
|
||||||
'@deepseek-ai/cordis-plugin-loader',
|
'@deepseek-ai/cordis-plugin-loader',
|
||||||
@@ -25,7 +31,35 @@ const REQUIRED_PLUGINS = new Set([
|
|||||||
'cordis:required',
|
'cordis:required',
|
||||||
])
|
])
|
||||||
|
|
||||||
/** Whether a Loader module is required by the application and must not be toggled. */
|
/**
|
||||||
|
* Whitelist: plugin module names a deployment explicitly permits the user to
|
||||||
|
* toggle. A name here overrides the blacklist, so a whitelisted plugin is never
|
||||||
|
* reported `protected` even if it is also required. Everything else is
|
||||||
|
* toggleable by default, so this is the place to force a specific plugin open.
|
||||||
|
*/
|
||||||
|
const USER_TOGGLEABLE_PLUGINS = new Set([
|
||||||
|
'@deepseek-ai/dsh-image-recognition',
|
||||||
|
'@deepseek-ai/dsh-image-recognition-http',
|
||||||
|
'@deepseek-ai/dsh-tool-image-recognition',
|
||||||
|
])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether a Loader module is required by the application and must not be toggled.
|
||||||
|
* The blacklist wins over the default-open stance unless the name is explicitly
|
||||||
|
* whitelisted.
|
||||||
|
* @param moduleName - the Loader module specifier.
|
||||||
|
* @returns true when the plugin is `protected` (cannot be disabled).
|
||||||
|
*/
|
||||||
export function isRequiredPlugin(moduleName: string): boolean {
|
export function isRequiredPlugin(moduleName: string): boolean {
|
||||||
return REQUIRED_PLUGINS.has(moduleName)
|
return REQUIRED_PLUGINS.has(moduleName) && !USER_TOGGLEABLE_PLUGINS.has(moduleName)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether a Loader module may be toggled by the user. Default-open: a plugin is
|
||||||
|
* toggleable unless the blacklist marks it required and it is not whitelisted.
|
||||||
|
* @param moduleName - the Loader module specifier.
|
||||||
|
* @returns true when the plugin can be enabled or disabled.
|
||||||
|
*/
|
||||||
|
export function isUserToggleable(moduleName: string): boolean {
|
||||||
|
return !isRequiredPlugin(moduleName)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { describe, expect, it } from 'vitest'
|
||||||
|
import { AVAILABLE_BUNDLES } from '../src/bundles.ts'
|
||||||
|
import { isRequiredPlugin, isUserToggleable } from '../src/required.ts'
|
||||||
|
|
||||||
|
describe('isRequiredPlugin (blacklist/whitelist, default-open)', () => {
|
||||||
|
it('marks the blacklist core as required', () => {
|
||||||
|
for (const name of ['@deepseek-ai/cordis-plugin-loader', '@deepseek-ai/dsh-session', 'cordis:required']) {
|
||||||
|
expect(isRequiredPlugin(name)).toBe(true)
|
||||||
|
expect(isUserToggleable(name)).toBe(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('defaults everything else to toggleable', () => {
|
||||||
|
for (const name of ['@deepseek-ai/dsh-hmr', '@deepseek-ai/dsh-tool-todo', 'cordis:user-toggleable']) {
|
||||||
|
expect(isRequiredPlugin(name)).toBe(false)
|
||||||
|
expect(isUserToggleable(name)).toBe(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('whitelist overrides the blacklist for an explicitly toggleable plugin', () => {
|
||||||
|
// image-recognition is on the whitelist, so it is never required.
|
||||||
|
for (const name of ['@deepseek-ai/dsh-image-recognition', '@deepseek-ai/dsh-image-recognition-http']) {
|
||||||
|
expect(isRequiredPlugin(name)).toBe(false)
|
||||||
|
expect(isUserToggleable(name)).toBe(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('AVAILABLE_BUNDLES', () => {
|
||||||
|
it('lists the offline-installable optional bundles', () => {
|
||||||
|
expect(AVAILABLE_BUNDLES).toContain('@deepseek-ai/dsh-image-recognition-bundle')
|
||||||
|
expect(new Set(AVAILABLE_BUNDLES).size).toBe(AVAILABLE_BUNDLES.length)
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user