From a0efe02c0436870b45ef804b5230853bbc66b28c Mon Sep 17 00:00:00 2001 From: Pine Date: Fri, 14 Aug 2026 18:57:08 +0800 Subject: [PATCH] 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 --- .../src/client/PluginInventorySettingsTab.tsx | 6 +++--- .../src/client/index.ts | 8 ++++---- .../tests/components.client.spec.tsx | 10 +++++----- packages/host/plugin-inventory/src/index.ts | 4 ++-- .../host/plugin-inventory/tests/inventory.spec.ts | 14 +++++++------- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/client/ui-settings-plugin-inventory/src/client/PluginInventorySettingsTab.tsx b/packages/client/ui-settings-plugin-inventory/src/client/PluginInventorySettingsTab.tsx index a6cb3d90b8..bec0f7f1f1 100644 --- a/packages/client/ui-settings-plugin-inventory/src/client/PluginInventorySettingsTab.tsx +++ b/packages/client/ui-settings-plugin-inventory/src/client/PluginInventorySettingsTab.tsx @@ -22,7 +22,7 @@ export interface PluginInventorySettingsTabInjected { /** List the offline-installable optional bundles. */ availableBundles: () => Promise /** Install a bundle or registry plugin; the host persists the change. */ - install: (spec: InstallSpec) => Promise + installPlugin: (spec: InstallSpec) => Promise /** Un-compose an offline optional bundle. */ uninstall: (name: string) => Promise } @@ -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( () => { diff --git a/packages/client/ui-settings-plugin-inventory/src/client/index.ts b/packages/client/ui-settings-plugin-inventory/src/client/index.ts index 1e51421529..f1017bab52 100644 --- a/packages/client/ui-settings-plugin-inventory/src/client/index.ts +++ b/packages/client/ui-settings-plugin-inventory/src/client/index.ts @@ -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({ diff --git a/packages/client/ui-settings-plugin-inventory/tests/components.client.spec.tsx b/packages/client/ui-settings-plugin-inventory/tests/components.client.spec.tsx index 019177ed84..ba994494cb 100644 --- a/packages/client/ui-settings-plugin-inventory/tests/components.client.spec.tsx +++ b/packages/client/ui-settings-plugin-inventory/tests/components.client.spec.tsx @@ -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(async () => ({ ok: true, restartRequired: true })) + const installPlugin = vi.fn(async () => ({ ok: true, restartRequired: true })) const uninstall = vi.fn(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( SNAPSHOT, bundles, install, uninstall)} />) + render( 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. diff --git a/packages/host/plugin-inventory/src/index.ts b/packages/host/plugin-inventory/src/index.ts index db93423b18..dd151b8d0f 100644 --- a/packages/host/plugin-inventory/src/index.ts +++ b/packages/host/plugin-inventory/src/index.ts @@ -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) { diff --git a/packages/host/plugin-inventory/tests/inventory.spec.ts b/packages/host/plugin-inventory/tests/inventory.spec.ts index 6bb43e78d3..fcba1ca8b4 100644 --- a/packages/host/plugin-inventory/tests/inventory.spec.ts +++ b/packages/host/plugin-inventory/tests/inventory.spec.ts @@ -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 })