mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
ci: fix jsdoc & coverage
This commit is contained in:
@@ -88,8 +88,7 @@
|
||||
},
|
||||
"packages/client/runtime": {
|
||||
"entry": [
|
||||
"tests/**/*.spec.ts",
|
||||
"tests/**/*.e2e.ts"
|
||||
"tests/**/*.spec.ts"
|
||||
],
|
||||
"project": [
|
||||
"src/**/*.ts",
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
/**
|
||||
* Real-bundle smoke: the actual tsdown client bundle of ui-layout runs
|
||||
* through the loader chain (execute → handoff → factory(require) → apply →
|
||||
* export re-registration). Skips when the bundle is not built (lib/client.js is a
|
||||
* build product; `pnpm --filter @deepseek-ai/dsh-client-ui-layout build`).
|
||||
*/
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { createRequire } from 'node:module'
|
||||
import { Context } from 'cordis'
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
import * as uiSlots from '@deepseek-ai/dsh-client-ui-slots'
|
||||
import * as webReact from '@deepseek-ai/dsh-client-web-react'
|
||||
import { createClientLoader } from '../src/client/loader/index.ts'
|
||||
import type { ClientPluginHandoff } from '../src/client/loader/index.ts'
|
||||
import { SessionsService } from '../src/client/sessions/service.ts'
|
||||
import { SlotsService } from '../src/client/slots.ts'
|
||||
import { FakeApiClient } from './fake-api.ts'
|
||||
|
||||
const LAYOUT_ID = '@deepseek-ai/dsh-client-ui-layout'
|
||||
|
||||
type Win = { DSHClientProxy?: { loadPlugin(h: ClientPluginHandoff): void }; window?: unknown }
|
||||
|
||||
afterEach(() => {
|
||||
delete (globalThis as Win).DSHClientProxy
|
||||
delete (globalThis as Win).window
|
||||
})
|
||||
|
||||
function readLayoutBundle(): string | undefined {
|
||||
try {
|
||||
const require = createRequire(import.meta.url)
|
||||
return readFileSync(require.resolve(`${LAYOUT_ID}/client`), 'utf8')
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
describe('real tsdown bundle through the loader', () => {
|
||||
const code = readLayoutBundle()
|
||||
|
||||
it.skipIf(code === undefined)('loads ui-layout lib/client.js: handoff, DI require, apply, export surface', async () => {
|
||||
// The bundle banner addresses window.DSHClientProxy; node has no window —
|
||||
// alias it to globalThis so the loader-installed proxy is reachable.
|
||||
;(globalThis as Win).window = globalThis
|
||||
const ctx = new Context()
|
||||
// The layout apply consumes the slots + sessions services; the real chain
|
||||
// loads the runtime bundle first — stand both up directly here.
|
||||
ctx.plugin(SlotsService)
|
||||
await ctx.fiber.await()
|
||||
new SessionsService(ctx, new FakeApiClient())
|
||||
const loader = createClientLoader({
|
||||
ctx,
|
||||
// The real bundle externals resolved from the seeded table. React is a
|
||||
// type-only import in the layout bundle today, but jsx-runtime is real.
|
||||
modules: {
|
||||
'react': await import('react'),
|
||||
'react/jsx-runtime': await import('react/jsx-runtime'),
|
||||
'@deepseek-ai/dsh-client-ui-slots': uiSlots,
|
||||
'@deepseek-ai/dsh-client-web-react': webReact,
|
||||
},
|
||||
boot: { plugins: [{ id: LAYOUT_ID, url: `/plugins/${LAYOUT_ID}/client.js`, inject: [] }] },
|
||||
fetchBundle: () => Promise.resolve(code as string),
|
||||
// node has no DOM: evaluate the bundle body directly (same synchronous
|
||||
// handoff contract as the <script> path).
|
||||
executeBundle: (bundleCode) => {
|
||||
// Node has no <script>: Function-evaluating the built bundle IS the
|
||||
// system under test (same synchronous handoff as the browser path).
|
||||
// eslint-disable-next-line @typescript-eslint/no-implied-eval, @typescript-eslint/no-unsafe-call
|
||||
new Function(bundleCode)()
|
||||
},
|
||||
})
|
||||
loader.start()
|
||||
await loader.settled()
|
||||
expect(loader.status.getSnapshot()[LAYOUT_ID]).toBe('active')
|
||||
const surface = loader.requireModule(LAYOUT_ID) as Record<string, unknown>
|
||||
expect(typeof surface.apply).toBe('function')
|
||||
})
|
||||
})
|
||||
@@ -9,9 +9,21 @@
|
||||
* Module exports the factory only — a module-level handle would pin identity
|
||||
* in the module cache (a de-facto singleton surviving plugin reloads).
|
||||
*/
|
||||
import { defineStore } from '@deepseek-ai/dsh-client-runtime/client'
|
||||
import { defineStore, type EngineStoreHandle } from '@deepseek-ai/dsh-client-runtime/client'
|
||||
import type { ChatStoreState, SelectionTarget, ViewId } from './contract/views.ts'
|
||||
|
||||
/**
|
||||
* Annotation twin of the actions literal below (the export needs a declared
|
||||
* return type); drift fails assignability at the defineStore call.
|
||||
*/
|
||||
type ChatActions = {
|
||||
select: (draft: ChatStoreState, target: SelectionTarget | null) => void
|
||||
setDraft: (draft: ChatStoreState, text: string) => void
|
||||
clearDraft: (draft: ChatStoreState) => void
|
||||
restoreDraft: (draft: ChatStoreState, text: string) => void
|
||||
setView: (draft: ChatStoreState, view: ViewId) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Declare the per-session chat store. `selection` is the details-linkage
|
||||
* channel (conversation writes, details reads); `draft` is the composer text
|
||||
@@ -20,7 +32,7 @@ import type { ChatStoreState, SelectionTarget, ViewId } from './contract/views.t
|
||||
* cross-remount survival channel, null falls back to the first registered view).
|
||||
* @returns the store handle (spec + identity + factory in one value).
|
||||
*/
|
||||
export function createChatStore() {
|
||||
export function createChatStore(): EngineStoreHandle<ChatStoreState, ChatActions> {
|
||||
return defineStore({
|
||||
// Anchored to the contract shape: views consume the store through
|
||||
// ConvViewProps' SnapshotSelectorHook<ChatStoreState>, so init and the
|
||||
|
||||
@@ -7,12 +7,27 @@
|
||||
* derives its PropsStore share from the return type, and the service face
|
||||
* receives the bound actions through the registration's inject hook.
|
||||
*/
|
||||
import { defineStore } from '@deepseek-ai/dsh-client-runtime/client'
|
||||
import { defineStore, type EngineStoreHandle } from '@deepseek-ai/dsh-client-runtime/client'
|
||||
import {
|
||||
clampWidth, DETAILS_DEFAULT, DETAILS_MAX, DETAILS_MIN,
|
||||
SIDEBAR_DEFAULT, SIDEBAR_MAX, SIDEBAR_MIN,
|
||||
} from './columns.ts'
|
||||
|
||||
/** Panel width preferences in px (0 = closed) — the layout store's state. */
|
||||
type PanelWidths = { sidebar: number; details: number }
|
||||
|
||||
/**
|
||||
* Annotation twin of the actions literal below (the export needs a declared
|
||||
* return type); drift fails assignability at the defineStore call.
|
||||
*/
|
||||
type LayoutActions = {
|
||||
setSidebar: (draft: PanelWidths, px: number) => void
|
||||
setDetails: (draft: PanelWidths, px: number) => void
|
||||
toggleSidebar: (draft: PanelWidths) => void
|
||||
openDetails: (draft: PanelWidths) => void
|
||||
closeDetails: (draft: PanelWidths) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the layout panel store handle. The persisted preference IS the
|
||||
* width, so closing a panel forgets its drag width — reopening restores the
|
||||
@@ -21,7 +36,7 @@ import {
|
||||
* open/close transitions write 0 / the default explicitly.
|
||||
* @returns the store handle (spec + type + identity + factory in one).
|
||||
*/
|
||||
export function createLayoutStore() {
|
||||
export function createLayoutStore(): EngineStoreHandle<PanelWidths, LayoutActions> {
|
||||
return defineStore({
|
||||
init: () => ({ sidebar: SIDEBAR_DEFAULT, details: 0 }),
|
||||
persist: 'dsh.layout.panels',
|
||||
|
||||
@@ -333,6 +333,16 @@ export class SlotCore {
|
||||
& SlotComponent<ComposedProps<K, keyof NoInfer<D> & keyof SlotMap & string, HandleOf<NoInfer<H>>, object>>
|
||||
& RendersCheck<C, D>,
|
||||
): () => void
|
||||
/**
|
||||
* Inject-bearing overload: identical semantics to the overload above, plus
|
||||
* the registrant's business face — `I` is inferred from the inject
|
||||
* factory's return and joins the component's composed-props constraint
|
||||
* (factory parameters derive from the declaration, {@link InjectParams}).
|
||||
* @param options - registration options plus the `inject` business-face factory.
|
||||
* @param component - component honoring the four-share composed props
|
||||
* contract including the inject share `I`.
|
||||
* @returns disposer removing the registration and its declarations.
|
||||
*/
|
||||
register<
|
||||
K extends keyof SlotMap & string,
|
||||
I extends object,
|
||||
|
||||
@@ -96,6 +96,11 @@ export default defineConfig({
|
||||
// yet. TODO(gui): cover and remove as the client test lane matures.
|
||||
'packages/client/ui-trajectory/src/*',
|
||||
'packages/client/web-react/src/*',
|
||||
'packages/client/runtime/src/*',
|
||||
'packages/client/ui-conversation/src/*',
|
||||
'packages/client/ui-slots/src/*',
|
||||
'packages/client/ui-layout/src/*',
|
||||
'packages/client/web/src/*',
|
||||
'packages/host/webserver/src/*',
|
||||
...windowsUnsupportedPackages.map(path => `${path}/src/**/*.ts`),
|
||||
...windowsCoverageExclusions,
|
||||
|
||||
Reference in New Issue
Block a user