feat(schedule): add durable after reminders
This commit is contained in:
6
packages/client/ui-schedule/README.i18n.yaml
Normal file
6
packages/client/ui-schedule/README.i18n.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write packages/client/ui-schedule/README.md
|
||||
README.md: 7a37baf92c6e050e628d97d5926b08bae295137b
|
||||
README.zh.md: 8acc33cc397f8e0ac4bee016007d635d0021c309
|
||||
20
packages/client/ui-schedule/README.md
Normal file
20
packages/client/ui-schedule/README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# @deepseek-ai/dsh-client-ui-schedule
|
||||
|
||||
English | [中文](README.zh.md)
|
||||
|
||||
Browser-only renderer for durable Schedule reminder receipts. The plugin registers the `schedule/reminder` key in the conversation-owned `conversation.chat.eventview` slot. The generic runtime continues to carry the durable event identity and its Host-computed JSON sidecar; this package owns only the Schedule card.
|
||||
|
||||
The card displays the reminder prompt, Session-local Schedule ID, exact UTC occurrence, and the `session-local` delivery boundary. A malformed or incompatible sidecar remains visible as a contained unavailable receipt instead of crashing the conversation. Unloading the plugin removes only the keyed renderer; `ui-conversation` then shows its generic visible JSON fallback for the same durable event.
|
||||
|
||||
## Model Experience
|
||||
|
||||
None, as this browser-only renderer registers no model surface; Schedule tools and reminder framing belong to `@deepseek-ai/dsh-tool-schedule`.
|
||||
|
||||
#### KV Cache effect
|
||||
|
||||
None. The renderer consumes a browser-side presentation sidecar after the durable event is committed.
|
||||
|
||||
## Known Limitations and Deferred Work
|
||||
|
||||
- **Receipt-only UI** — creating, listing, and deleting reminders remains model-driven through the Schedule tools; this package does not add a management page.
|
||||
- **Session-local delivery** — the card records a receipt in the original Session. It does not imply a system, browser, email, or other external notification.
|
||||
20
packages/client/ui-schedule/README.zh.md
Normal file
20
packages/client/ui-schedule/README.zh.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# @deepseek-ai/dsh-client-ui-schedule
|
||||
|
||||
[English](README.md) | 中文
|
||||
|
||||
用于渲染持久 Schedule 提醒回执的纯浏览器插件。插件在会话拥有的 `conversation.chat.eventview` slot 中注册 `schedule/reminder` key。通用 runtime 继续携带持久事件身份与 Host 计算的 JSON sidecar;本包只拥有 Schedule 卡片。
|
||||
|
||||
卡片显示提醒原文、Session 内的 Schedule ID、精确 UTC 发生时刻,以及 `session-local` 交付边界。若 sidecar 损坏或版本不兼容,组件会显示受控的不可用回执,而不会让会话崩溃。卸载插件只会移除该键控 renderer;`ui-conversation` 随后仍会为同一个持久事件显示通用且可见的 JSON fallback。
|
||||
|
||||
## 模型体验
|
||||
|
||||
无,因为这个纯浏览器 renderer 不注册模型 surface;Schedule 工具与提醒 framing 由 `@deepseek-ai/dsh-tool-schedule` 拥有。
|
||||
|
||||
#### KV Cache 影响
|
||||
|
||||
无。renderer 只在持久事件提交后消费浏览器侧 presentation sidecar。
|
||||
|
||||
## 已知限制与暂缓事项
|
||||
|
||||
- **仅提供回执 UI**:创建、列出和删除提醒仍由模型通过 Schedule 工具完成;本包不增加管理页面。
|
||||
- **仅在 Session 内交付**:卡片记录的是原 Session 中的回执,并不表示系统、浏览器、邮件或其他外部通知。
|
||||
70
packages/client/ui-schedule/package.json
Normal file
70
packages/client/ui-schedule/package.json
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"name": "@deepseek-ai/dsh-client-ui-schedule",
|
||||
"description": "Web renderer for durable Schedule reminder receipts in the conversation flow",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/types/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./lib/types/index.d.ts",
|
||||
"default": "./lib/index.js"
|
||||
},
|
||||
"./invariant": {
|
||||
"types": "./lib/types/invariant.d.ts",
|
||||
"default": "./lib/invariant.js"
|
||||
},
|
||||
"./client": {
|
||||
"types": "./lib/types/client/index.d.ts",
|
||||
"default": "./lib/client.js"
|
||||
},
|
||||
"./src/*": "./src/*",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"dshClient": {
|
||||
"inject": [
|
||||
"@deepseek-ai/dsh-client-runtime",
|
||||
"@deepseek-ai/dsh-client-locale",
|
||||
"@deepseek-ai/dsh-client-ui-conversation"
|
||||
],
|
||||
"platform": "web"
|
||||
},
|
||||
"scripts": {
|
||||
"bundle": "tsdown",
|
||||
"watch": "tsdown --watch"
|
||||
},
|
||||
"license": "BSD-3-Clause",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-client-locale": "^0.0.1",
|
||||
"@deepseek-ai/dsh-client-runtime": "^0.0.1",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "^0.0.1",
|
||||
"@deepseek-ai/dsh-client-ui-primitives": "^0.0.1",
|
||||
"@deepseek-ai/dsh-client-ui-slots": "^0.0.1",
|
||||
"@deepseek-ai/dsh-invariants": "^0.0.1",
|
||||
"cordis": "^4.0.0-rc.7",
|
||||
"react": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-runtime": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-test-runtime": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-primitives": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-slots": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@testing-library/react": "^16.1.0",
|
||||
"@types/react": "~18.3.1",
|
||||
"cordis": "^4.0.0-rc.7",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"files": [
|
||||
"lib/index.js",
|
||||
"lib/invariant.js",
|
||||
"lib/client.js",
|
||||
"lib/types/**/*.d.ts",
|
||||
"lib/types/**/*.d.ts.map",
|
||||
"src"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
.root {
|
||||
display: grid;
|
||||
min-width: 0;
|
||||
gap: 8px;
|
||||
padding: 12px 14px;
|
||||
border: 1px solid var(--dsw-alias-border-l2);
|
||||
border-radius: 10px;
|
||||
background: var(--dsw-alias-bg-module-platform);
|
||||
color: var(--dsw-alias-label-primary);
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: inline-flex;
|
||||
flex: none;
|
||||
color: var(--dsw-alias-brand-text);
|
||||
}
|
||||
|
||||
.title {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
font: 600 13px/18px var(--ds-font-family);
|
||||
}
|
||||
|
||||
.delivery {
|
||||
flex: none;
|
||||
color: var(--dsw-alias-label-tertiary);
|
||||
font: 400 11px/16px var(--ds-font-family);
|
||||
}
|
||||
|
||||
.prompt {
|
||||
margin: 0;
|
||||
color: var(--dsw-alias-label-primary);
|
||||
font: 400 14px/21px var(--ds-font-family);
|
||||
overflow-wrap: anywhere;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.meta {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px 12px;
|
||||
color: var(--dsw-alias-label-tertiary);
|
||||
font: 400 11px/16px var(--ds-font-family);
|
||||
}
|
||||
|
||||
.id {
|
||||
font-family: var(--ds-font-family-code);
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
margin: 0;
|
||||
color: var(--dsw-alias-label-secondary);
|
||||
font: 400 13px/18px var(--ds-font-family);
|
||||
}
|
||||
61
packages/client/ui-schedule/src/client/ReminderRow.tsx
Normal file
61
packages/client/ui-schedule/src/client/ReminderRow.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import { IconSparkle16 } from '@deepseek-ai/dsh-client-ui-primitives'
|
||||
import type { EventRowProps } from '@deepseek-ai/dsh-client-ui-conversation/client'
|
||||
import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'
|
||||
import css from './ReminderRow.module.css'
|
||||
|
||||
interface ReminderPresentation {
|
||||
scheduleId: string
|
||||
prompt: string
|
||||
occurrenceAt: string
|
||||
deliveryMode: 'session-local'
|
||||
}
|
||||
|
||||
/** Full Schedule row props: event owner/runtime share plus the locale seat. */
|
||||
export type ReminderRowProps = EventRowProps & PropsLocale<'schedule'>
|
||||
|
||||
/** Narrow the domain-owned JSON sidecar without trusting its unknown carrier type. */
|
||||
function reminderPresentation(value: unknown): ReminderPresentation | null {
|
||||
if (typeof value !== 'object' || value === null || Array.isArray(value)) return null
|
||||
const record = value as Record<string, unknown>
|
||||
if (typeof record['scheduleId'] !== 'string' || record['scheduleId'].length === 0) return null
|
||||
if (typeof record['prompt'] !== 'string') return null
|
||||
if (typeof record['occurrenceAt'] !== 'string' || record['occurrenceAt'].length === 0) return null
|
||||
if (record['deliveryMode'] !== 'session-local') return null
|
||||
return {
|
||||
scheduleId: record['scheduleId'],
|
||||
prompt: record['prompt'],
|
||||
occurrenceAt: record['occurrenceAt'],
|
||||
deliveryMode: record['deliveryMode'],
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render one durable reminder dispatch carried by the generic event sidecar.
|
||||
* @param props - Keyed event owner payload and the Schedule translator.
|
||||
* @returns A visible reminder receipt, or a contained invalid-payload row.
|
||||
*/
|
||||
export function ReminderRow({ node, t }: ReminderRowProps) {
|
||||
const reminder = reminderPresentation(node.view)
|
||||
return (
|
||||
<section className={css.root} role="note" data-schedule-reminder>
|
||||
<header className={css.header}>
|
||||
<span className={css.icon} aria-hidden><IconSparkle16 size={14} /></span>
|
||||
<span className={css.title}>{t('reminder.title')}</span>
|
||||
{reminder !== null && <span className={css.delivery}>{t('reminder.delivery')}</span>}
|
||||
</header>
|
||||
{reminder === null
|
||||
? <p className={css.invalid}>{t('reminder.invalid')} · {node.presentationKey}</p>
|
||||
: (
|
||||
<>
|
||||
<p className={css.prompt}>{reminder.prompt}</p>
|
||||
<footer className={css.meta}>
|
||||
<span className={css.id}>{t('reminder.id', { id: reminder.scheduleId })}</span>
|
||||
<time dateTime={reminder.occurrenceAt}>
|
||||
{t('reminder.occurrence', { time: reminder.occurrenceAt })}
|
||||
</time>
|
||||
</footer>
|
||||
</>
|
||||
)}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
38
packages/client/ui-schedule/src/client/index.ts
Normal file
38
packages/client/ui-schedule/src/client/index.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
/** Register the Schedule durable-reminder renderer into the conversation event slot. */
|
||||
import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'
|
||||
// Type-only: pulls the locale plugin's Context merge (ctx.locale).
|
||||
import type {} from '@deepseek-ai/dsh-client-locale/client'
|
||||
import { ReminderRow } from './ReminderRow.tsx'
|
||||
import { en, NS, zh, type ScheduleKey } from './locales.ts'
|
||||
|
||||
export type { ReminderRowProps } from './ReminderRow.tsx'
|
||||
export type { ScheduleKey } from './locales.ts'
|
||||
|
||||
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
||||
interface LocaleNamespaceMap {
|
||||
/** Copy for durable Schedule reminder receipts. */
|
||||
schedule: ScheduleKey
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* `conversation` is an ordering edge: its service is published after the chat
|
||||
* entry has declared `conversation.chat.eventview`.
|
||||
*/
|
||||
export const inject = ['slots', 'conversation', 'locale']
|
||||
|
||||
/**
|
||||
* Register bilingual copy and the Schedule reminder keyed row.
|
||||
* @param ctx - Client root context.
|
||||
*/
|
||||
export function apply(ctx: ClientContext): void {
|
||||
ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'ui-schedule: dictionaries')
|
||||
ctx.effect(
|
||||
() => ctx.slots.register({
|
||||
name: 'conversation.chat.eventview',
|
||||
key: 'schedule/reminder',
|
||||
locale: NS,
|
||||
}, ReminderRow),
|
||||
'ui-schedule: reminder row registration',
|
||||
)
|
||||
}
|
||||
25
packages/client/ui-schedule/src/client/locales.ts
Normal file
25
packages/client/ui-schedule/src/client/locales.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
/** `schedule` namespace dictionaries. */
|
||||
|
||||
/** Dictionary namespace owned by this plugin. */
|
||||
export const NS = 'schedule'
|
||||
|
||||
/** Simplified Chinese dictionary (the key-set source of truth). */
|
||||
export const zh = {
|
||||
'reminder.title': '定时提醒',
|
||||
'reminder.delivery': '仅在当前会话中交付',
|
||||
'reminder.invalid': '提醒回执不可用',
|
||||
'reminder.id': '编号 {id}',
|
||||
'reminder.occurrence': '触发时间 {time}',
|
||||
} satisfies Record<string, string>
|
||||
|
||||
/** The Schedule namespace key union. */
|
||||
export type ScheduleKey = keyof typeof zh
|
||||
|
||||
/** English dictionary, checked complete against the Chinese key set. */
|
||||
export const en = {
|
||||
'reminder.title': 'Scheduled reminder',
|
||||
'reminder.delivery': 'Delivered in this session only',
|
||||
'reminder.invalid': 'Reminder receipt unavailable',
|
||||
'reminder.id': 'ID {id}',
|
||||
'reminder.occurrence': 'Due at {time}',
|
||||
} satisfies Record<ScheduleKey, string>
|
||||
4
packages/client/ui-schedule/src/css-modules.d.ts
vendored
Normal file
4
packages/client/ui-schedule/src/css-modules.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
declare module '*.module.css' {
|
||||
const classes: Readonly<Record<string, string>>
|
||||
export default classes
|
||||
}
|
||||
4
packages/client/ui-schedule/src/index.ts
Normal file
4
packages/client/ui-schedule/src/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
/** Host loader entry for the browser-only Schedule receipt renderer. */
|
||||
|
||||
/** Provides no host-side behavior. */
|
||||
export function apply(): void {}
|
||||
30
packages/client/ui-schedule/src/invariant.ts
Normal file
30
packages/client/ui-schedule/src/invariant.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Package-owned invariant companion for `@deepseek-ai/dsh-client-ui-schedule`.
|
||||
* @module @deepseek-ai/dsh-client-ui-schedule/invariant
|
||||
*/
|
||||
|
||||
/* jscpd:ignore-start */
|
||||
import type { Context } from 'cordis'
|
||||
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
|
||||
|
||||
const PACKAGE_NAME = '@deepseek-ai/dsh-client-ui-schedule'
|
||||
|
||||
/** Cordis companion plugin name. */
|
||||
export const name = 'client-ui-schedule-invariant'
|
||||
/** Service required before the companion can reserve package ownership. */
|
||||
export const inject = ['invariants']
|
||||
|
||||
/**
|
||||
* No runtime invariant: the keyed slot registry owns contribution lifecycle,
|
||||
* and the component has no state outside its immutable owner payload.
|
||||
*/
|
||||
const install: InvariantInstaller = () => {}
|
||||
|
||||
/**
|
||||
* Register this package's invariant companion.
|
||||
* @param ctx - Cordis context carrying the invariant service.
|
||||
* @returns The installed registration's disposer after setup succeeds.
|
||||
*/
|
||||
export const apply = (ctx: Context): Promise<() => void> =>
|
||||
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
|
||||
/* jscpd:ignore-end */
|
||||
75
packages/client/ui-schedule/tests/browser-plugin.spec.ts
Normal file
75
packages/client/ui-schedule/tests/browser-plugin.spec.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { Context } from 'cordis'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { LocaleService } from '@deepseek-ai/dsh-client-locale/client'
|
||||
import { apply, inject } from '../src/client/index.ts'
|
||||
import { ReminderRow } from '../src/client/ReminderRow.tsx'
|
||||
import { apply as nodeApply } from '../src/index.ts'
|
||||
import {
|
||||
apply as invariantApply,
|
||||
inject as invariantInject,
|
||||
name as invariantName,
|
||||
} from '../src/invariant.ts'
|
||||
|
||||
interface CapturedEntry {
|
||||
name: string
|
||||
key?: string
|
||||
locale?: string
|
||||
component: unknown
|
||||
}
|
||||
|
||||
function bench() {
|
||||
const ctx = new Context()
|
||||
let entry: CapturedEntry | undefined
|
||||
ctx.provide('slots', {
|
||||
register(options: Omit<CapturedEntry, 'component'>, component: unknown) {
|
||||
entry = { ...options, component }
|
||||
return () => { entry = undefined }
|
||||
},
|
||||
})
|
||||
ctx.provide('conversation', {})
|
||||
ctx.provide('locale', new LocaleService(ctx))
|
||||
const fiber = ctx.plugin({ inject: [...inject], apply })
|
||||
return { ctx, fiber, entry: () => entry }
|
||||
}
|
||||
|
||||
describe('ui-schedule browser plugin', () => {
|
||||
it('registers the keyed reminder renderer and unloads it with the fiber', async () => {
|
||||
const b = bench()
|
||||
await b.fiber.await()
|
||||
expect(b.entry()).toEqual({
|
||||
name: 'conversation.chat.eventview',
|
||||
key: 'schedule/reminder',
|
||||
locale: 'schedule',
|
||||
component: ReminderRow,
|
||||
})
|
||||
|
||||
await b.fiber.dispose()
|
||||
expect(b.entry()).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('ui-schedule node and invariant companions', () => {
|
||||
it('keeps the node half inert', () => {
|
||||
expect(() => { nodeApply() }).not.toThrow()
|
||||
})
|
||||
|
||||
it('registers exact package ownership and returns its disposer', async () => {
|
||||
const ctx = new Context()
|
||||
let owner: string | undefined
|
||||
let disposed = false
|
||||
ctx.provide('invariants', {
|
||||
register(packageName: string, install: unknown) {
|
||||
expect(install).toBeTypeOf('function')
|
||||
owner = packageName
|
||||
return () => { disposed = true }
|
||||
},
|
||||
})
|
||||
|
||||
expect(invariantName).toBe('client-ui-schedule-invariant')
|
||||
expect(invariantInject).toEqual(['invariants'])
|
||||
const dispose = await invariantApply(ctx)
|
||||
expect(owner).toBe('@deepseek-ai/dsh-client-ui-schedule')
|
||||
dispose()
|
||||
expect(disposed).toBe(true)
|
||||
})
|
||||
})
|
||||
55
packages/client/ui-schedule/tests/reminder-row.spec.tsx
Normal file
55
packages/client/ui-schedule/tests/reminder-row.spec.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { cleanup, render, screen } from '@testing-library/react'
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
import { makeTranslate } from '@deepseek-ai/dsh-client-test-runtime'
|
||||
import type { PresentedEventNode } from '@deepseek-ai/dsh-client-runtime/client'
|
||||
import { ReminderRow, type ReminderRowProps } from '../src/client/ReminderRow.tsx'
|
||||
import { zh } from '../src/client/locales.ts'
|
||||
|
||||
const t: ReminderRowProps['t'] = makeTranslate(zh)
|
||||
|
||||
afterEach(cleanup)
|
||||
|
||||
function props(view: unknown): ReminderRowProps {
|
||||
const node: PresentedEventNode = {
|
||||
kind: 'presented-event',
|
||||
seq: 4,
|
||||
time: Date.parse('2026-08-05T08:00:00.000Z'),
|
||||
presentationKey: 'schedule/reminder',
|
||||
view,
|
||||
}
|
||||
return { node, t } as ReminderRowProps
|
||||
}
|
||||
|
||||
describe('ReminderRow', () => {
|
||||
it('shows the durable reminder payload and its session-local boundary', () => {
|
||||
render(<ReminderRow {...props({
|
||||
scheduleId: 'schedule-7',
|
||||
prompt: 'Check the deploy',
|
||||
occurrenceAt: '2026-08-05T08:00:00.000Z',
|
||||
deliveryMode: 'session-local',
|
||||
})} />)
|
||||
|
||||
expect(screen.getByRole('note')).toBeTruthy()
|
||||
expect(screen.getByText('定时提醒')).toBeTruthy()
|
||||
expect(screen.getByText('仅在当前会话中交付')).toBeTruthy()
|
||||
expect(screen.getByText('Check the deploy')).toBeTruthy()
|
||||
expect(screen.getByText('编号 schedule-7')).toBeTruthy()
|
||||
const time = screen.getByText('触发时间 2026-08-05T08:00:00.000Z')
|
||||
expect(time.getAttribute('datetime')).toBe('2026-08-05T08:00:00.000Z')
|
||||
})
|
||||
|
||||
it('contains an incompatible sidecar as a visible unavailable receipt', () => {
|
||||
render(<ReminderRow {...props({
|
||||
scheduleId: '',
|
||||
prompt: 'not trusted',
|
||||
occurrenceAt: 123,
|
||||
deliveryMode: 'external',
|
||||
})} />)
|
||||
|
||||
expect(screen.getByText('提醒回执不可用 · schedule/reminder')).toBeTruthy()
|
||||
expect(screen.queryByText('not trusted')).toBeNull()
|
||||
expect(screen.queryByText('仅在当前会话中交付')).toBeNull()
|
||||
})
|
||||
})
|
||||
33
packages/client/ui-schedule/tsconfig.json
Normal file
33
packages/client/ui-schedule/tsconfig.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.base.client.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "lib/types"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../../vendor/cordis"
|
||||
},
|
||||
{
|
||||
"path": "../locale"
|
||||
},
|
||||
{
|
||||
"path": "../runtime"
|
||||
},
|
||||
{
|
||||
"path": "../ui-conversation"
|
||||
},
|
||||
{
|
||||
"path": "../ui-primitives"
|
||||
},
|
||||
{
|
||||
"path": "../ui-slots"
|
||||
},
|
||||
{
|
||||
"path": "../../support/invariants"
|
||||
}
|
||||
]
|
||||
}
|
||||
3
packages/client/ui-schedule/tsdown.config.ts
Normal file
3
packages/client/ui-schedule/tsdown.config.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-schedule', ['lib/types/index.js', 'lib/types/invariant.js'])
|
||||
Reference in New Issue
Block a user