Răsfoiți Sursa

fix(ci): align plugin inventory with current contracts

ZiyaZhang 1 lună în urmă
părinte
comite
46c0e3dba7

+ 1 - 0
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'

+ 1 - 1
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"
   },

+ 3 - 4
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<PluginInventorySnapshot>
 }
 
-type PluginInventorySnapshot = Awaited<ReturnType<PluginSettingsSectionInjected['list']>>
 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) }}
             />
           </label>
           <div className={css.catalogHeading}>

+ 7 - 2
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({

+ 7 - 1
packages/client/ui-plugins/tests/browser-plugin.spec.tsx → 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<ListResult>>()
+    .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()
   })
 

+ 14 - 1
packages/client/ui-plugins/tests/components.spec.tsx → 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(<PluginSettingsSection {...props(() => deferred.promise)} />)
     pending.unmount()
     await act(async () => { deferred.resolve(SNAPSHOT) })
+
+    const deferredFailure = Promise.withResolvers<Snapshot>()
+    const pendingFailure = render(<PluginSettingsSection {...props(() => deferredFailure.promise)} />)
+    pendingFailure.unmount()
+    await act(async () => { deferredFailure.reject(new Error('late failure')) })
   })
 })

+ 0 - 0
packages/client/ui-plugins/tests/invariant.spec.ts → packages/client/ui-plugins/tests/invariant.client.spec.ts


+ 2 - 4
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": {