diff --git a/packages/api/remotes/src/client/index.ts b/packages/api/remotes/src/client/index.ts index 2f077dfd75..026fd864f2 100644 --- a/packages/api/remotes/src/client/index.ts +++ b/packages/api/remotes/src/client/index.ts @@ -7,6 +7,7 @@ import pluginInventoryRemote from '@deepseek-ai/dsh-host-plugin-inventory/remote import type { TypeRTClientRemote } from '@deepseek-ai/dsh-type-meta' export type { TypeRTClientRemote as ClientRemote } from '@deepseek-ai/dsh-type-meta' +export type { PluginInventorySnapshot } from '@deepseek-ai/dsh-host-plugin-inventory/types' export type {} from '@deepseek-ai/dsh-commands/remote' export type {} from '@deepseek-ai/dsh-goal/remote' export type {} from '@deepseek-ai/dsh-host-plugin-inventory/remote' diff --git a/packages/client/ui-plugins/package.json b/packages/client/ui-plugins/package.json index cca1843929..07fb9d162c 100644 --- a/packages/client/ui-plugins/package.json +++ b/packages/client/ui-plugins/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-plugins", "description": "Read-only Cordis Loader plugin inventory in Web settings", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-plugins/src/client/PluginSettingsSection.tsx b/packages/client/ui-plugins/src/client/PluginSettingsSection.tsx index 6fdf058c02..87d6486000 100644 --- a/packages/client/ui-plugins/src/client/PluginSettingsSection.tsx +++ b/packages/client/ui-plugins/src/client/PluginSettingsSection.tsx @@ -1,5 +1,5 @@ import { useEffect, useId, useMemo, useState, type ReactNode } from 'react' -import type { ClientRemote } from '@deepseek-ai/dsh-api-remotes/client' +import type { PluginInventorySnapshot } from '@deepseek-ai/dsh-api-remotes/client' import { IconChevronDownOutline14, IconSearchOutline16, @@ -11,10 +11,9 @@ import css from './PluginSettingsSection.module.css' /** Registration-side Remote face used by the section. */ export interface PluginSettingsSectionInjected { /** Read a current Host inventory snapshot. */ - list: ClientRemote['pluginInventory']['list'] + list: () => Promise } -type PluginInventorySnapshot = Awaited> type PluginInventoryEntry = PluginInventorySnapshot['entries'][number] type PluginFiberPhase = PluginInventoryEntry['fiberPhase'] @@ -119,7 +118,7 @@ export function PluginSettingsSection({ list, t }: PluginSettingsSectionProps): value={query} placeholder={t('search')} aria-label={t('search')} - onChange={event => setQuery(event.currentTarget.value)} + onChange={(event) => { setQuery(event.currentTarget.value) }} />
diff --git a/packages/client/ui-plugins/src/client/index.ts b/packages/client/ui-plugins/src/client/index.ts index b3034a86f9..ccf12ab989 100644 --- a/packages/client/ui-plugins/src/client/index.ts +++ b/packages/client/ui-plugins/src/client/index.ts @@ -1,6 +1,5 @@ /** Read-only Host plugin inventory registered into Web Settings. */ -import type { ClientRemote } from '@deepseek-ai/dsh-api-remotes/client' import type {} from '@deepseek-ai/dsh-client-locale/client' import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client' import type {} from '@deepseek-ai/dsh-client-ui-settings/client' @@ -28,7 +27,13 @@ export function apply(ctx: ClientContext): void { ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'ui-plugins: dictionaries') const t = ctx.locale.bind(NS) - const list: ClientRemote['pluginInventory']['list'] = () => ctx.remote.pluginInventory.list() + const list: PluginSettingsSectionInjected['list'] = async () => { + const result = await ctx.remote.pluginInventory.list() + if (!result.ok) { + throw new Error(`pluginInventory.list failed: ${result.error.code}: ${result.error.message}`) + } + return result.value + } const injected = (): PluginSettingsSectionInjected => ({ list }) ctx.slots.inject('settings.section', () => ctx.slots.register({ diff --git a/packages/client/ui-plugins/tests/browser-plugin.spec.tsx b/packages/client/ui-plugins/tests/browser-plugin.client.spec.tsx similarity index 87% rename from packages/client/ui-plugins/tests/browser-plugin.spec.tsx rename to packages/client/ui-plugins/tests/browser-plugin.client.spec.tsx index c2e3c741fd..d9d8a43cd8 100644 --- a/packages/client/ui-plugins/tests/browser-plugin.spec.tsx +++ b/packages/client/ui-plugins/tests/browser-plugin.client.spec.tsx @@ -14,6 +14,9 @@ usePinnedBrowserLanguages('zh-CN') afterEach(cleanup) const EMPTY = { entries: [] } +type ListResult = + | { readonly ok: true; readonly value: typeof EMPTY } + | { readonly ok: false; readonly error: { readonly code: string; readonly message: string } } async function bench() { const ctx = new Context() @@ -26,7 +29,8 @@ async function bench() { } } new RemoteService(ctx) - const list = vi.fn(() => Promise.resolve(EMPTY)) + const list = vi.fn<() => Promise>() + .mockResolvedValue({ ok: true, value: EMPTY }) ctx.provide('remote.pluginInventory', { list }) return { ctx, slots: ctx.get('slots') as SlotsService, locale, list } } @@ -58,6 +62,8 @@ describe('ui-plugins browser plugin', () => { const injected = (entry.inject as unknown as () => PluginSettingsSectionInjected)() await expect(injected.list()).resolves.toEqual(EMPTY) expect(b.list).toHaveBeenCalledOnce() + b.list.mockResolvedValueOnce({ ok: false, error: { code: 'REMOTE_ERROR', message: 'unavailable' } }) + await expect(injected.list()).rejects.toThrow('pluginInventory.list failed: REMOTE_ERROR: unavailable') await b.ctx.fiber.dispose() }) diff --git a/packages/client/ui-plugins/tests/components.spec.tsx b/packages/client/ui-plugins/tests/components.client.spec.tsx similarity index 87% rename from packages/client/ui-plugins/tests/components.spec.tsx rename to packages/client/ui-plugins/tests/components.client.spec.tsx index 9e4fcbc5f3..9da8a79b0d 100644 --- a/packages/client/ui-plugins/tests/components.spec.tsx +++ b/packages/client/ui-plugins/tests/components.client.spec.tsx @@ -27,7 +27,7 @@ function props(list: PluginSettingsSectionInjected['list']): PluginSettingsSecti const SNAPSHOT = { entries: [ { entryId: '8a1b2c3d', moduleName: '@deepseek-ai/cordis-plugin-hmr', enabled: true, fiberPhase: 'active' }, - { entryId: 'pending', moduleName: '@fixture/pending-name', enabled: true, fiberPhase: 'pending' }, + { entryId: 'pending', moduleName: 'cordis:pending-name', enabled: true, fiberPhase: 'pending' }, { entryId: 'loading', moduleName: '@fixture/loading-name', enabled: true, fiberPhase: 'loading' }, { entryId: 'failed', moduleName: '@fixture/failed-name', enabled: true, fiberPhase: 'failed' }, { entryId: 'unloading', moduleName: '@fixture/unloading-name', enabled: true, fiberPhase: 'unloading' }, @@ -69,6 +69,14 @@ describe('PluginSettingsSection', () => { expect(screen.getByText(en.cordis)).toBeTruthy() fireEvent.click(active) expect(view.container.querySelector('[data-loader-entry]')).toBeNull() + + fireEvent.click(active) + fireEvent.change(screen.getByRole('searchbox', { name: en.search }), { + target: { value: 'disabled-entry' }, + }) + expect(view.container.querySelector('[data-loader-entry]')).toBeNull() + fireEvent.click(screen.getByRole('button', { name: 'directory-picker-native, Not mounted, Disabled' })) + expect(screen.getAllByText(en.disabledTag)).toHaveLength(2) }) it('filters by module name or Loader entry id', async () => { @@ -111,5 +119,10 @@ describe('PluginSettingsSection', () => { const pending = render( deferred.promise)} />) pending.unmount() await act(async () => { deferred.resolve(SNAPSHOT) }) + + const deferredFailure = Promise.withResolvers() + const pendingFailure = render( deferredFailure.promise)} />) + pendingFailure.unmount() + await act(async () => { deferredFailure.reject(new Error('late failure')) }) }) }) diff --git a/packages/client/ui-plugins/tests/invariant.spec.ts b/packages/client/ui-plugins/tests/invariant.client.spec.ts similarity index 100% rename from packages/client/ui-plugins/tests/invariant.spec.ts rename to packages/client/ui-plugins/tests/invariant.client.spec.ts diff --git a/packages/host/plugin-inventory/package.json b/packages/host/plugin-inventory/package.json index 4da1a61f06..ac51ce4aa8 100644 --- a/packages/host/plugin-inventory/package.json +++ b/packages/host/plugin-inventory/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-host-plugin-inventory", "description": "Read-only Remote projection of current Cordis Loader plugin state", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, @@ -45,9 +45,7 @@ "lib/typert.host.js", "lib/typert.host.d.ts", "lib/typert.remote-client.js", - "lib/typert.remote-client.d.ts", - "lib/typert.remote-client.d.ts.map", - "src" + "lib/typert.remote-client.d.ts" ], "license": "BSD-3-Clause", "dependencies": {