fix(plugin-inventory): rename install Remote to installPlugin

The RemoteNamespaceService reserves `install` as its private registration
method, so a Remote method also named `install` collided at client-api boot
(`pluginInventory/install conflicts with its namespace service`). Rename the
plugin-install Remote to `installPlugin` across host, client, and tests.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Pine
2026-08-14 18:57:08 +08:00
parent 6cd7c5a590
commit a0efe02c04
5 changed files with 21 additions and 21 deletions
@@ -22,7 +22,7 @@ export interface PluginInventorySettingsTabInjected {
/** List the offline-installable optional bundles. */
availableBundles: () => Promise<AvailableBundlesSnapshot>
/** Install a bundle or registry plugin; the host persists the change. */
install: (spec: InstallSpec) => Promise<InstallResult>
installPlugin: (spec: InstallSpec) => Promise<InstallResult>
/** Un-compose an offline optional bundle. */
uninstall: (name: string) => Promise<InstallResult>
}
@@ -80,7 +80,7 @@ type BundleState =
/** Render the current Loader inventory with per-plugin enable/disable and install. */
export function PluginInventorySettingsTab({
list, setEnabled, availableBundles, install, uninstall, t,
list, setEnabled, availableBundles, installPlugin, uninstall, t,
}: PluginInventorySettingsTabProps): ReactNode {
const catalogId = useId()
const [request, setRequest] = useState(0)
@@ -126,7 +126,7 @@ export function PluginInventorySettingsTab({
setInstallBusy(name)
setInstallNote(null)
const action = mode === 'install'
? install({ type: 'bundle', name })
? installPlugin({ type: 'bundle', name })
: uninstall(name)
void action.then(
() => {
@@ -47,10 +47,10 @@ export function apply(ctx: ClientContext): void {
}
return result.value
}
const install: PluginInventorySettingsTabInjected['install'] = async (spec) => {
const result = await ctx.remote.pluginInventory.install(spec)
const installPlugin: PluginInventorySettingsTabInjected['installPlugin'] = async (spec) => {
const result = await ctx.remote.pluginInventory.installPlugin(spec)
if (!result.ok) {
throw new Error(`pluginInventory.install failed: ${result.error.code}: ${result.error.message}`)
throw new Error(`pluginInventory.installPlugin failed: ${result.error.code}: ${result.error.message}`)
}
return result.value
}
@@ -62,7 +62,7 @@ export function apply(ctx: ClientContext): void {
return result.value
}
const injected = (): PluginInventorySettingsTabInjected => ({
list, setEnabled, availableBundles, install, uninstall,
list, setEnabled, availableBundles, installPlugin, uninstall,
})
ctx.slots.inject('settings.plugins.tab', () => ctx.slots.register({
@@ -16,14 +16,14 @@ const t = ((key: PluginInventoryLocaleKey): string => en[key]) as PluginInventor
function props(
list: PluginInventorySettingsTabInjected['list'],
bundles: PluginInventorySettingsTabInjected['availableBundles'] = async () => ({ available: [] }),
install: PluginInventorySettingsTabInjected['install'] = async () => ({ ok: true as const, restartRequired: true }),
installPlugin: PluginInventorySettingsTabInjected['installPlugin'] = async () => ({ ok: true as const, restartRequired: true }),
uninstall: PluginInventorySettingsTabInjected['uninstall'] = async () => ({ ok: true as const, restartRequired: true }),
): PluginInventorySettingsTabProps {
return {
t,
list,
availableBundles: bundles,
install,
installPlugin,
uninstall,
} as PluginInventorySettingsTabProps
}
@@ -163,7 +163,7 @@ describe('PluginInventorySettingsTab', () => {
})
it('renders the installable bundles with install and uninstall actions', async () => {
const install = vi.fn<PluginInventorySettingsTabInjected['install']>(async () => ({ ok: true, restartRequired: true }))
const installPlugin = vi.fn<PluginInventorySettingsTabInjected['installPlugin']>(async () => ({ ok: true, restartRequired: true }))
const uninstall = vi.fn<PluginInventorySettingsTabInjected['uninstall']>(async () => ({ ok: true, restartRequired: true }))
const bundles: PluginInventorySettingsTabInjected['availableBundles'] = async () => ({
available: [
@@ -171,7 +171,7 @@ describe('PluginInventorySettingsTab', () => {
{ name: '@deepseek-ai/dsh-installed-bundle', installed: true },
],
})
render(<PluginInventorySettingsTab {...props(async () => SNAPSHOT, bundles, install, uninstall)} />)
render(<PluginInventorySettingsTab {...props(async () => SNAPSHOT, bundles, installPlugin, uninstall)} />)
expect(await screen.findByText(en.available)).toBeTruthy()
expect(screen.getByText('@deepseek-ai/dsh-new-bundle')).toBeTruthy()
@@ -179,7 +179,7 @@ describe('PluginInventorySettingsTab', () => {
// Install a not-installed bundle.
fireEvent.click(screen.getByRole('button', { name: en.install }))
expect(install).toHaveBeenCalledWith({ type: 'bundle', name: '@deepseek-ai/dsh-new-bundle' })
expect(installPlugin).toHaveBeenCalledWith({ type: 'bundle', name: '@deepseek-ai/dsh-new-bundle' })
expect(await screen.findByText(en.restartRequired)).toBeTruthy()
// Uninstall an installed bundle.
+2 -2
View File
@@ -138,8 +138,8 @@ export class PluginInventoryGateway extends TypertRemoteService {
* @param spec - the bundle name or registry package spec to install.
* @returns a confirmation; `restartRequired` tells the caller to restart.
*/
@Remote('install')
install(spec: InstallSpec): InstallResult {
@Remote('installPlugin')
installPlugin(spec: InstallSpec): InstallResult {
const profileDir = this.profileDir()
const anchor = this.ctx.get('dshInstallAnchor') as string | undefined
if (anchor === undefined) {
@@ -49,7 +49,7 @@ describe('PluginInventoryGateway', () => {
{ method: 'list', invocation: { kind: 'direct' } },
{ method: 'setEnabled', invocation: { kind: 'direct' } },
{ method: 'availableBundles', invocation: { kind: 'direct' } },
{ method: 'install', invocation: { kind: 'direct' } },
{ method: 'installPlugin', invocation: { kind: 'direct' } },
{ method: 'uninstall', invocation: { kind: 'direct' } },
])
})
@@ -151,9 +151,9 @@ describe('PluginInventoryGateway', () => {
ctx.baseUrl = pathToFileURL(dir + '/').href
writeFileSync(join(dir, 'package.json'), JSON.stringify({ name: 'dsh-profile-test', dsh: { profile: { bundles: [] } } }))
try {
expect(() => inventory.install({ type: 'bundle', name: 'x' })).toThrow(/install anchor is unavailable/)
expect(() => inventory.installPlugin({ type: 'bundle', name: 'x' })).toThrow(/install anchor is unavailable/)
ctx.provide('dshInstallAnchor', join(dir, 'package.json'))
expect(() => inventory.install({ type: 'registry', spec: 'x' })).toThrow(/not permitted/)
expect(() => inventory.installPlugin({ type: 'registry', spec: 'x' })).toThrow(/not permitted/)
} finally {
rmSync(dir, { recursive: true, force: true })
}
@@ -185,7 +185,7 @@ describe('PluginInventoryGateway', () => {
writeFileSync(join(dir, 'node_modules', 'b', 'cordis.patch.yml'), '[]\n')
ctx.provide('dshInstallAnchor', join(dir, 'package.json'))
try {
inventory.install({ type: 'bundle', name: 'b' })
inventory.installPlugin({ type: 'bundle', name: 'b' })
expect(readProfileManifest('dsh', dir).dsh?.profile?.bundles).toEqual(['b'])
} finally {
rmSync(dir, { recursive: true, force: true })
@@ -203,7 +203,7 @@ describe('PluginInventoryGateway', () => {
try {
ctx.provide('dshInstallAnchor', join(dir, 'package.json'))
ctx.provide('dshAllowPluginInstall', true)
expect(inventory.install({ type: 'registry', spec: 'some-pkg' }).restartRequired).toBe(true)
expect(inventory.installPlugin({ type: 'registry', spec: 'some-pkg' }).restartRequired).toBe(true)
} finally {
delete process.env.DSH_PNPM
rmSync(dir, { recursive: true, force: true })
@@ -260,7 +260,7 @@ describe('PluginInventoryGateway', () => {
try {
ctx.provide('dshInstallAnchor', join(dir, 'package.json'))
ctx.provide('dshAllowPluginInstall', true)
expect(() => inventory.install({ type: 'registry', spec: 'x' })).toThrow(/bundled pnpm is unavailable/)
expect(() => inventory.installPlugin({ type: 'registry', spec: 'x' })).toThrow(/bundled pnpm is unavailable/)
} finally {
rmSync(dir, { recursive: true, force: true })
}
@@ -276,7 +276,7 @@ describe('PluginInventoryGateway', () => {
try {
ctx.provide('dshInstallAnchor', join(dir, 'package.json'))
ctx.provide('dshAllowPluginInstall', true)
expect(() => inventory.install({ type: 'registry', spec: 'x' })).toThrow(/failed to read profile manifest/)
expect(() => inventory.installPlugin({ type: 'registry', spec: 'x' })).toThrow(/failed to read profile manifest/)
} finally {
delete process.env.DSH_PNPM
rmSync(dir, { recursive: true, force: true })