Merge remote-tracking branch 'origin/master' into worktree/schedule-conversational-after
# Conflicts: # docs/event-producer-consumer.i18n.yaml # docs/event-producer-consumer.md # docs/event-producer-consumer.zh.md
This commit is contained in:
@@ -27,7 +27,6 @@
|
||||
"@deepseek-ai/dsh-agent-tool-mode": "workspace:^",
|
||||
"@deepseek-ai/dsh-app-boot": "workspace:^",
|
||||
"@deepseek-ai/dsh-base": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-agent-preset": "workspace:^",
|
||||
"@deepseek-ai/dsh-command-compact": "workspace:^",
|
||||
"@deepseek-ai/dsh-command-goal": "workspace:^",
|
||||
"@deepseek-ai/dsh-compact-basic": "workspace:^",
|
||||
|
||||
@@ -70,51 +70,6 @@
|
||||
},
|
||||
{
|
||||
"path": "../../packages/bash/tool-bash"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/client/connection"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/client/hmr"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/client/runtime"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/client/ui-theme"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/client/ui-settings"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/client/ui-settings-general"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/client/ui-models"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/client/ui-permission"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/client/locale"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/client/ui-layout"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/client/ui-sidebar"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/client/ui-conversation"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/client/ui-plan"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/client/ui-trajectory"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/client/ui-question"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
6
apps/web/tests/README.i18n.yaml
Normal file
6
apps/web/tests/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 apps/web/tests/README.md
|
||||
README.md: 68e5db5af5f816cc982bacb7989d996c859be204
|
||||
README.zh.md: f366c28024dab89d0243a60d93a706f220fa8fb8
|
||||
46
apps/web/tests/README.md
Normal file
46
apps/web/tests/README.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# apps/web browser e2e
|
||||
|
||||
English | [中文](README.zh.md)
|
||||
|
||||
These tests boot the real web composition in-process and drive it with a real
|
||||
Chromium over real HTTP. The lane's mechanics — modes, fixtures, goldens, and
|
||||
the deliberate composition divergences from `dsh web` — are documented in
|
||||
[`scaffold.ts`](scaffold.ts) and the
|
||||
[browser e2e Agent Note](../../../.agents/notes/implemented/testing/2026-07-24-web-gui-browser-e2e-lane.md).
|
||||
|
||||
## These are Host-face tests
|
||||
|
||||
They type-check in the root `tsconfig.host.json`, not in the Client aggregate,
|
||||
because they read Host services directly: `ctx.apiProxy`, the Host
|
||||
`SessionStore`, `ctx.sessionProjectionCache`. Driving a browser at runtime does
|
||||
not make a file part of the Client program — the two faces merge cordis
|
||||
`Context` under the same keys with different services, so one program cannot see
|
||||
both. Moving these files into the Client aggregate makes every Host-service
|
||||
access fail to compile.
|
||||
|
||||
## Do not import `@deepseek-ai/dsh-client-*` here
|
||||
|
||||
Importing a Client package — a value or a type — pulls its whole TypeScript
|
||||
project, and every project it references, into the **Host build graph**. That has
|
||||
bitten this lane once already: four Client consumer packages reference
|
||||
`api/remotes`' Client face, which cannot compile until Host tsdown has generated
|
||||
`@deepseek-ai/dsh-goal/remote`, so the Host build phase ended up waiting on an
|
||||
artifact it produces itself.
|
||||
|
||||
When a scenario needs a Client-owned constant or pure function, mirror it here
|
||||
instead, next to the commented-out import that names the source module. A drift
|
||||
then surfaces as a missed selector or an unsuppressed notice — a loud failure,
|
||||
never a silent pass. `scaffold.ts` holds the mirrored welcome-notice values and
|
||||
exports them for the scenarios that assert on them.
|
||||
|
||||
Two kinds of Client import stand. `assembled-boot.ts` drives the shell itself, so
|
||||
it imports `AppWebEntry` from `@deepseek-ai/dsh-client-web` and the boot-manifest
|
||||
type from `@deepseek-ai/dsh-client-modules/client`: booting the real shell is what
|
||||
that harness is for, and both packages are already in the Host graph. Separately,
|
||||
the chat scenarios import `conversationContextKey` from
|
||||
`@deepseek-ai/dsh-client-runtime/client` because `client/runtime` is reachable
|
||||
through the unsplit `directory-picker` packages and pulls nothing further in.
|
||||
That reachability is incidental, not a guarantee — if it ever leaves the graph,
|
||||
mirror the helper like the rest.
|
||||
|
||||
Nothing mechanically enforces this rule; keep it in review.
|
||||
37
apps/web/tests/README.zh.md
Normal file
37
apps/web/tests/README.zh.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# apps/web 浏览器 e2e
|
||||
|
||||
[English](README.md) | 中文
|
||||
|
||||
这些测试在进程内启动真实的 web 组合,并用真实 Chromium 通过真实 HTTP 驱动它。该 lane
|
||||
的运行机制——模式、fixture、golden,以及与 `dsh web` 之间刻意保留的组合差异——记录在
|
||||
[`scaffold.ts`](scaffold.ts) 和
|
||||
[浏览器 e2e Agent Note](../../../.agents/notes/implemented/testing/2026-07-24-web-gui-browser-e2e-lane.md)中。
|
||||
|
||||
## 这些是 Host 面的测试
|
||||
|
||||
它们在根 `tsconfig.host.json` 中做类型检查,而不在 Client aggregate 中,因为它们直接读取
|
||||
Host 服务:`ctx.apiProxy`、Host 侧 `SessionStore`、`ctx.sessionProjectionCache`。运行时驱动
|
||||
浏览器并不使一个文件成为 Client 程序的一部分——两个 face 在相同的键上以不同服务合并 cordis
|
||||
`Context`,因此单个程序无法同时看见两者。把这些文件挪进 Client aggregate 会让每一处
|
||||
Host 服务访问都无法编译。
|
||||
|
||||
## 不要在此 import `@deepseek-ai/dsh-client-*`
|
||||
|
||||
import 一个 Client 包——无论值还是类型——都会把它整个 TypeScript 工程、以及它引用的每个工程
|
||||
拉进 **Host 构建图**。这已经坑过本 lane 一次:四个 Client 消费方包引用了 `api/remotes` 的
|
||||
Client face,而该 face 必须等 Host tsdown 生成 `@deepseek-ai/dsh-goal/remote` 之后才能编译,
|
||||
于是 Host 构建阶段变成在等一个由它自己产出的产物。
|
||||
|
||||
当某个场景需要 Client 持有的常量或纯函数时,改为在此处镜像一份,并紧挨着一条注释掉的
|
||||
import 点明源模块。这样漂移会表现为选择器未命中或提示未被抑制——是响亮的失败,绝不会是静默
|
||||
通过。`scaffold.ts` 持有镜像的 welcome-notice 取值,并导出给断言它们的场景使用。
|
||||
|
||||
有两类 Client import 是长期成立的。`assembled-boot.ts` 驱动 shell 本身,因此它从
|
||||
`@deepseek-ai/dsh-client-web` import `AppWebEntry`、从
|
||||
`@deepseek-ai/dsh-client-modules/client` import boot manifest 类型:启动真实 shell 正是该
|
||||
harness 的用途,且这两个包本来就在 Host 图中。另外,chat 场景从
|
||||
`@deepseek-ai/dsh-client-runtime/client` import `conversationContextKey`,因为
|
||||
`client/runtime` 经未拆分的 `directory-picker` 包可达,且不会再牵入别的东西。这种可达性是
|
||||
偶然而非保证——一旦它离开该图,就像其余情形那样镜像该 helper。
|
||||
|
||||
没有任何机制强制这条规则;靠 review 守住它。
|
||||
@@ -20,9 +20,13 @@ const PLUGINS: readonly (WebBootEntry & { bundlePath: string })[] = [
|
||||
{ id: '@deepseek-ai/dsh-client-connection', bundlePath: 'packages/client/connection/lib/client.js', url: '/plugins/connection.js', rev: 'fx', inject: [], immediately: true },
|
||||
{ id: '@deepseek-ai/dsh-api-gateway', bundlePath: 'packages/api/gateway/lib/client.js', url: '/plugins/api-gateway.js', rev: 'fx', inject: ['@deepseek-ai/dsh-typert-registry', '@deepseek-ai/dsh-client-connection'], immediately: true },
|
||||
{ id: '@deepseek-ai/dsh-api-remotes', bundlePath: 'packages/api/remotes/lib/client.js', url: '/plugins/api-remotes.js', rev: 'fx', inject: ['@deepseek-ai/dsh-api-gateway'], immediately: true },
|
||||
{ id: '@deepseek-ai/dsh-client-runtime', bundlePath: 'packages/client/runtime/lib/client.js', url: '/plugins/runtime.js', rev: 'fx', inject: ['@deepseek-ai/dsh-client-connection', '@deepseek-ai/dsh-typert-registry'], immediately: true },
|
||||
{ id: '@deepseek-ai/dsh-client-ui-theme', bundlePath: 'packages/client/ui-theme/lib/client.js', url: '/plugins/ui-theme.js', rev: 'fx', inject: [], immediately: true },
|
||||
{ id: '@deepseek-ai/dsh-client-locale', bundlePath: 'packages/client/locale/lib/client.js', url: '/plugins/locale.js', rev: 'fx', inject: [], immediately: true },
|
||||
// The settings domain base: the only provider of ctx.settingsScope, which the
|
||||
// locale and ui-theme rows below inject for their preference rows. Without it
|
||||
// both stay pending and ui-layout never activates, so nothing renders.
|
||||
{ id: '@deepseek-ai/dsh-client-ui-settings', bundlePath: 'packages/client/ui-settings/lib/client.js', url: '/plugins/ui-settings.js', rev: 'fx', inject: ['@deepseek-ai/dsh-client-connection', '@deepseek-ai/dsh-client-runtime', '@deepseek-ai/dsh-api-remotes'], immediately: true },
|
||||
{ id: '@deepseek-ai/dsh-client-runtime', bundlePath: 'packages/client/runtime/lib/client.js', url: '/plugins/runtime.js', rev: 'fx', inject: ['@deepseek-ai/dsh-client-connection', '@deepseek-ai/dsh-typert-registry', '@deepseek-ai/dsh-api-gateway'], immediately: true },
|
||||
{ id: '@deepseek-ai/dsh-client-ui-theme', bundlePath: 'packages/client/ui-theme/lib/client.js', url: '/plugins/ui-theme.js', rev: 'fx', inject: ['@deepseek-ai/dsh-client-connection', '@deepseek-ai/dsh-client-runtime', '@deepseek-ai/dsh-client-locale', '@deepseek-ai/dsh-client-ui-settings', '@deepseek-ai/dsh-api-remotes'], immediately: true },
|
||||
{ id: '@deepseek-ai/dsh-client-locale', bundlePath: 'packages/client/locale/lib/client.js', url: '/plugins/locale.js', rev: 'fx', inject: ['@deepseek-ai/dsh-client-connection', '@deepseek-ai/dsh-client-runtime', '@deepseek-ai/dsh-client-ui-settings', '@deepseek-ai/dsh-api-remotes'], immediately: true },
|
||||
{ id: '@deepseek-ai/dsh-client-ui-layout', bundlePath: 'packages/client/ui-layout/lib/client.js', url: '/plugins/ui-layout.js', rev: 'fx', inject: ['@deepseek-ai/dsh-client-runtime'] },
|
||||
{ id: '@deepseek-ai/dsh-client-ui-sidebar', bundlePath: 'packages/client/ui-sidebar/lib/client.js', url: '/plugins/ui-sidebar.js', rev: 'fx', inject: ['@deepseek-ai/dsh-client-ui-layout'] },
|
||||
{ id: '@deepseek-ai/dsh-client-ui-conversation', bundlePath: 'packages/client/ui-conversation/lib/client.js', url: '/plugins/ui-conversation.js', rev: 'fx', inject: ['@deepseek-ai/dsh-client-ui-layout'] },
|
||||
|
||||
@@ -10,14 +10,12 @@ import { chromium } from 'playwright'
|
||||
import { afterAll, beforeAll, describe, expect, it, onTestFailed } from 'vitest'
|
||||
import {
|
||||
acknowledgeReloadConnectionLoss, assertFixtureInventory, captureStableAria, compareOrRefreshGolden,
|
||||
WELCOME_NOTICE_SETTINGS_NAMESPACE, WELCOME_NOTICE_ACK_FIELD,
|
||||
WELCOME_NOTICE_VERSION, WELCOME_NOTICE_COPY,
|
||||
launchWebScaffold, watchConsole, webSnapshotMode, type WebScaffold,
|
||||
} from './scaffold.ts'
|
||||
import { ZH_BROWSER_LOCALE, connectFreshWorkspaceZh, saveFailureShot } from './support.ts'
|
||||
import { settingsNamespace } from '@deepseek-ai/dsh-settings'
|
||||
import {
|
||||
WELCOME_NOTICE_ACK_FIELD, WELCOME_NOTICE_COPY, WELCOME_NOTICE_SETTINGS_NAMESPACE,
|
||||
WELCOME_NOTICE_VERSION,
|
||||
} from '@deepseek-ai/dsh-client-ui-settings-general'
|
||||
|
||||
const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/onboarding-deepseek-config', import.meta.url))
|
||||
const WELCOME_EXPECTED = join(SNAPSHOT_DIR, 'welcome.expected.md')
|
||||
|
||||
@@ -5,10 +5,10 @@ import { chromium } from 'playwright'
|
||||
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
||||
import {
|
||||
acknowledgeReloadConnectionLoss, launchWebScaffold, watchConsole, webSnapshotMode,
|
||||
WELCOME_NOTICE_COPY,
|
||||
type WebScaffold,
|
||||
} from './scaffold.ts'
|
||||
import { ZH_BROWSER_LOCALE } from './support.ts'
|
||||
import { WELCOME_NOTICE_COPY } from '@deepseek-ai/dsh-client-ui-settings-general'
|
||||
|
||||
const MODE = webSnapshotMode()
|
||||
|
||||
|
||||
@@ -41,9 +41,19 @@ import {
|
||||
loadOverlayPatches,
|
||||
} from '@deepseek-ai/dsh-app-boot'
|
||||
import { dshHomePath } from '@deepseek-ai/dsh-paths'
|
||||
import {
|
||||
WELCOME_NOTICE_ACK_FIELD, WELCOME_NOTICE_SETTINGS_NAMESPACE, WELCOME_NOTICE_VERSION,
|
||||
} from '@deepseek-ai/dsh-client-ui-settings-general'
|
||||
// Client packages must not be imported here: these e2e type-check in the Host
|
||||
// aggregate, so a Client import pulls that package's whole project — and every
|
||||
// project it references — into the Host build graph. Mirrored from
|
||||
// packages/client/ui-settings-general/src/onboarding-copy.ts; a drift makes the
|
||||
// pre-acknowledgement stop suppressing the notice, which fails loudly.
|
||||
// import {
|
||||
// WELCOME_NOTICE_ACK_FIELD, WELCOME_NOTICE_SETTINGS_NAMESPACE, WELCOME_NOTICE_VERSION, WELCOME_NOTICE_COPY,
|
||||
// } from '@deepseek-ai/dsh-client-ui-settings-general'
|
||||
export const WELCOME_NOTICE_SETTINGS_NAMESPACE = 'ui-onboarding'
|
||||
export const WELCOME_NOTICE_ACK_FIELD = 'welcomeNoticeVersion'
|
||||
export const WELCOME_NOTICE_VERSION = '2026-07-30.7'
|
||||
export const WELCOME_NOTICE_COPY = { zh: { title: '内测声明', continueLabel: '继续' } } as const
|
||||
|
||||
import { settingsNamespace } from '@deepseek-ai/dsh-settings'
|
||||
import { LlmAdapter } from '@deepseek-ai/dsh-llm'
|
||||
import type {
|
||||
|
||||
Reference in New Issue
Block a user