Merge branch 'master' into xtr/node-pty-1.2-beta

This commit is contained in:
_Kerman
2026-08-13 18:39:17 +08:00
committed by GitHub
11 changed files with 45 additions and 28 deletions

View File

@@ -2,5 +2,5 @@
# 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 docs/user/develop/basic/publish.md
publish.md: 8283f9e7ff0c28580343975d67c5715d17c53074
publish.zh.md: 5a87901fe39aa00e94db81dc840e39a52e0cc88c
publish.md: 9548fe2f8e4636dd160c79cd0d50f01f8bdfd3d1
publish.zh.md: 2cff05edcca55bac5fde9d2e7d24ed9c8b48a6f5

View File

@@ -4,6 +4,8 @@ English | [中文](publish.zh.md)
The previous tutorials loaded a local plugin through a `--patch` overlay. This tutorial packages it as an installable **bundle**, installs it into a **profile** with `dsh plugin add`, and explains the layer order that determines the composed configuration. It assumes the `dsh` CLI is installed. Complete [plugin configuration](./config.md) first.
To use a fresh source checkout instead, complete the [run-from-source section](../../../../README.md#run-from-source), keep this tutorial's `hello-plugin` directory at the repository root, and run the remaining `dsh ...` commands from there as `pnpm dsh ...`. See [source execution](../../../../apps/cli/reference/README.md#source-execution) for build and launcher behavior.
## Two concepts, two manifests
Installation is built on two concepts. Both are described by a `package.json`, but they carry different kinds of manifest under the `dsh` key, and they answer different questions:

View File

@@ -4,6 +4,8 @@
前几篇教程通过 `--patch` overlay 加载本地插件。本教程把它打包成可安装的**组合包**bundle`dsh plugin add` 安装进一个 **profile**,并解释决定组合后配置的层顺序。本文假设 `dsh` CLI 已安装。请先完成[插件配置](./config.md)。
如果改用全新的源码 checkout请先按照[从源码运行章节](../../../../README.md#run-from-source)完成准备,将本教程的 `hello-plugin` 目录放在仓库根目录,并从该目录把下文的 `dsh ...` 命令改为 `pnpm dsh ...`。构建与启动器行为见[源码执行](../../../../apps/cli/reference/README.md#source-execution)。
## 两个概念,两种 manifest
安装机制建立在两个概念之上。二者都由一份 `package.json` 描述,但它们在 `dsh` 键下携带的 manifest元数据清单种类不同回答的问题也不同

View File

@@ -26,7 +26,7 @@ export function OnboardingModal({
useEffect(() => {
const appRoot = document.getElementById('root')
if (appRoot === null) return
const previous = appRoot.inert === true
const previous = appRoot.inert
appRoot.inert = true
return () => { appRoot.inert = previous }
}, [])
@@ -41,7 +41,7 @@ export function OnboardingModal({
title={title}
onClose={ignoreImplicitDismiss}
headless
className={css['dialog'] ?? ''}
className={css.dialog as string}
>
<div className={css.content}>
<h2 ref={titleRef} className={css.title} tabIndex={focusTitle ? -1 : undefined}>{title}</h2>

View File

@@ -103,7 +103,7 @@ export const en = {
export type ModelsKey = keyof typeof en
/** Chinese strings (same keys as {@link en}). */
export const zh: typeof en = {
export const zh: { [Key in keyof typeof en]: string } = {
nav: '模型',
title: '模型',
intro: '填入各提供方的 API 密钥即可使用其模型。',

View File

@@ -18,8 +18,8 @@ export const WELCOME_NOTICE_COPY = {
continueLabel: '继续',
},
en: {
title: '内测声明',
body: 'DeepSeek Harness 目前的 0.1 版本仍处在面向 Harness 开发者进行测试的阶段,还有许多地方需要持续改进和打磨,希望听取广大开发者的反馈建议。预计 DeepSeek Harness 的核心插件以及基础 API 都会在接下来的一段时间内快速迭代、持续演化。\n\n我们期待与全球开发者一起在开源、开放、可复用、可组合的基础设施之上共同探索智能上限。欢迎全球 Harness 开发者加入 DSH 插件生态。',
continueLabel: '继续',
title: 'Internal Testing Notice',
body: "DeepSeek Harness 0.1 remains in testing for Harness developers. Many areas need further improvement, and we welcome feedback from the developer community. DeepSeek Harness's core plugins and foundational APIs will continue to evolve rapidly over the coming months.\n\nWe look forward to exploring the limits of intelligence with developers around the world, building on open-source, open, reusable, and composable infrastructure. We welcome Harness developers everywhere to join the DSH plugin ecosystem.",
continueLabel: 'Continue',
},
} as const

View File

@@ -14,7 +14,7 @@ import { WelcomeNotice } from '../src/client/WelcomeNotice.tsx'
// the shipped Chinese copy, so they state the browser they assume.
usePinnedBrowserLanguages('zh-CN')
async function bench() {
async function bench(isLoopback = true) {
const ctx = new Context()
await ctx.plugin(SlotRegistry).await()
const locale = new LocaleRuntime(ctx)
@@ -24,7 +24,7 @@ async function bench() {
new TestRemote(ctx)
// The apply path only captures the wire face; no call leaves this fake
// until a section actually loads.
ctx.provide('connection', { api: {}, isLoopback: true } as never)
ctx.provide('connection', { api: {}, isLoopback } as never)
return { ctx, slots: ctx.get('slots') as SlotRegistry, locale }
}
@@ -142,6 +142,22 @@ describe('ui-settings-models apply', () => {
expect(() => b.locale.register('settings.models', 'zh', {})).not.toThrow()
expect(() => b.locale.register('settings.models', 'en', {})).not.toThrow()
})
it('keeps remote-browser acknowledgement in process memory', async () => {
const b = await bench(false)
declare(b.slots)
await b.ctx.plugin({ inject: [...inject], apply }).await()
const entry = b.slots.entries('settings.onboarding')
.find(candidate => candidate.options.id === 'welcome-notice')!
const injected = (
entry.inject as unknown as () => import('../src/client/WelcomeNotice.tsx').WelcomeNoticeInjected
)()
await injected.controller.load()
expect(injected.controller.store.getSnapshot()).toEqual({
status: 'ready', acknowledged: false, error: null,
})
})
})
describe('pushed invalidations', () => {

View File

@@ -146,6 +146,13 @@ function harness(options: {
}
describe('DeepSeekOnboardingDialog', () => {
it('renders when the shell root is absent', async () => {
const h = harness()
document.getElementById('root')!.remove()
render(<DeepSeekOnboardingDialog {...h.props} />)
expect(await screen.findByRole('dialog', { name: en.onboardingTitle })).toBeTruthy()
})
it('loads a credential-only modal, inerts the product, and focuses the key', async () => {
const h = harness()
render(<DeepSeekOnboardingDialog {...h.props} />)
@@ -185,22 +192,6 @@ describe('DeepSeekOnboardingDialog', () => {
expect(h.set).not.toHaveBeenCalled()
})
it('stores only the official credential, refreshes, and completes without opening Settings', async () => {
const h = harness()
render(<DeepSeekOnboardingDialog {...h.props} />)
await screen.findByRole('dialog')
fireEvent.change(screen.getByLabelText(en.keyInput), { target: { value: ' sk-live ' } })
fireEvent.click(screen.getByRole('button', { name: en.onboardingSave }))
await waitFor(() => {
expect(h.set).toHaveBeenCalledWith({ ref: 'DEEPSEEK_API_KEY', value: 'sk-live' })
})
expect(h.mutate).not.toHaveBeenCalled()
expect(h.openSection).not.toHaveBeenCalled()
await waitFor(() => { expect(h.complete).toHaveBeenCalledOnce() })
expect(screen.queryByRole('dialog')).toBeNull()
expect(document.getElementById('root')?.inert).toBe(false)
})
it('keeps the modal open and reports rejected and failed credential writes', async () => {
for (const [options, message] of [
[{ setFailure: 'credential was rejected' }, 'credential was rejected'],

View File

@@ -62,7 +62,11 @@ function mount(version?: string, mutateImpl: () => Promise<unknown> = () => Prom
describe('WelcomeNotice', () => {
it('uses the exact owner copy in both GUI locales', () => {
expect(WELCOME_NOTICE_COPY.en).toEqual(WELCOME_NOTICE_COPY.zh)
expect(WELCOME_NOTICE_COPY.en).toEqual({
title: 'Internal Testing Notice',
body: "DeepSeek Harness 0.1 remains in testing for Harness developers. Many areas need further improvement, and we welcome feedback from the developer community. DeepSeek Harness's core plugins and foundational APIs will continue to evolve rapidly over the coming months.\n\nWe look forward to exploring the limits of intelligence with developers around the world, building on open-source, open, reusable, and composable infrastructure. We welcome Harness developers everywhere to join the DSH plugin ecosystem.",
continueLabel: 'Continue',
})
expect(en.welcomeBody).toBe(WELCOME_NOTICE_COPY.en.body)
expect(zh.welcomeBody).toBe(WELCOME_NOTICE_COPY.zh.body)
})

View File

@@ -91,7 +91,7 @@ describe('WelcomeNoticeStore', () => {
const nonError = new WelcomeNoticeStore({
// Durable/wire failures are unknown; exercise containment of a non-Error rejection.
settings: { describe: () => Promise.reject('offline string') },
settings: { describe: () => Promise.reject(new Error('offline string')) },
} as never)
await nonError.load()
expect(nonError.store.getSnapshot().error).toBe('offline string')

View File

@@ -243,6 +243,8 @@ export default defineConfig({
'packages/client/ui-workspace/src/client/index.ts',
'packages/test-support/client-runtime/src/translate.ts',
'packages/client/ui-primitives/src/JsonTree.tsx',
'packages/client/ui-settings-models/src/client/DeepSeekOnboardingDialog.tsx',
'packages/client/ui-settings-models/src/client/welcome-store.ts',
'packages/extensions/*/src/**/*.ts',
'packages/extensions/*/src/**/*.tsx',
// Typert generator: correctness is pinned by its fixture suites and