Merge remote-tracking branch 'origin/master' into worktree/web-theme-settings-integration-fde706

# Conflicts:
#	.agents/notes/implemented/architecture/2026-07-30-client-locale-full-rollout.i18n.yaml
#	.agents/notes/implemented/architecture/2026-07-30-client-locale-full-rollout.zh.md
#	.agents/notes/implemented/feature/2026-07-30-web-queue-steer-action.i18n.yaml
#	.agents/notes/implemented/feature/2026-07-30-web-queue-steer-action.zh.md
#	.agents/notes/implemented/feature/2026-07-31-browser-derived-initial-locale.i18n.yaml
#	.agents/notes/implemented/feature/2026-07-31-browser-derived-initial-locale.zh.md
#	.agents/notes/implemented/testing/2026-07-24-web-gui-browser-e2e-lane.i18n.yaml
#	apps/web/tests/scaffold.ts
#	docs/module-graph.md
#	packages/client/runtime/README.i18n.yaml
#	packages/client/runtime/package.json
#	packages/client/test-runtime/README.i18n.yaml
#	packages/client/test-runtime/README.zh.md
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-conversation/README.zh.md
#	packages/client/ui-conversation/package.json
#	packages/client/ui-conversation/src/client/apply.ts
#	packages/client/ui-theme/README.i18n.yaml
#	packages/client/ui-theme/README.md
#	packages/client/ui-theme/README.zh.md
#	packages/host/apiproxy/README.i18n.yaml
#	packages/host/apiproxy/README.zh.md
#	pnpm-lock.yaml
This commit is contained in:
Yichen Jiang
2026-08-10 12:50:43 +08:00
3485 changed files with 86192 additions and 25255 deletions

View File

@@ -2,6 +2,7 @@
import type {
ConversationSnapshot, ISession, SessionId, SessionSummary, WorkspaceListState,
} from '@deepseek-ai/dsh-client-runtime/client'
import { EMPTY_CHAT_SNAPSHOT } from '@deepseek-ai/dsh-client-runtime/client'
/**
* Fixture overrides for the session behavior face: any subset of the
@@ -45,6 +46,7 @@ export interface SessionFixture {
export function conversationSnapshot(sessionId: SessionId): ConversationSnapshot {
return {
sessionId,
chat: EMPTY_CHAT_SNAPSHOT,
nodes: [],
turnTimings: new Map(),
turnEnds: new Map(),

View File

@@ -22,7 +22,9 @@ import { act, render, within } from '@testing-library/react'
import type { RenderResult } from '@testing-library/react'
import type { queries } from '@testing-library/dom'
import type { BoundFunctions } from '@testing-library/dom'
import { SlotsService } from '@deepseek-ai/dsh-client-runtime/client'
import {
ConversationEventRegistry, ConversationViewRegistry, SlotsService,
} from '@deepseek-ai/dsh-client-runtime/client'
import { createSlotRenderer } from '@deepseek-ai/dsh-client-web-react'
import type {
ChildrenDecl, ComposedProps, OwnerOf, SlotComponent, SlotMap, SlotRendererHost, StoreInstanceLike,
@@ -42,7 +44,7 @@ export type { SessionBehaviorOverrides, SessionFixture, Stabilizer } from './fix
export { makeTranslate } from './translate.ts'
export { usePinnedBrowserLanguages } from './locale-env.ts'
/** Erased register face for the internal root call (the public declare seam holds the typing). */
/** Erased register face for the internal root call (the public declaration contract holds the typing). */
type ErasedRegister = (options: object, component: unknown) => () => void
/**
@@ -82,7 +84,7 @@ export interface FeatureHandle {
/**
* Owner-props cell behind the auto frame: one external store the frame
* subscribes to, so {@link SlotTestRuntime.renderSlot} and
* {@link SlotView.update} drive React through the standard uSES seam.
* {@link SlotView.update} drive React through the standard uSES boundary.
*/
class OwnerPropsCell {
private readonly owners = new Map<string, object>()
@@ -144,11 +146,11 @@ export class TestRoot {
*/
async declare<const D extends ChildrenDecl>(
children: D,
frame: SlotComponent<ComposedProps<'root', keyof NoInfer<D> & keyof SlotMap & string, undefined, object>>,
frame: SlotComponent<ComposedProps<'root', never, keyof NoInfer<D> & keyof SlotMap & string, undefined, object>>,
): Promise<void> {
await this.stabilize(() => {
// Erased hop (same pattern as SlotsService's own implementation arm);
// the declare signature above is the typed seam.
// the declaration signature above is the typed contract.
this.disposeEntry = (this.slots.register as unknown as ErasedRegister)({ name: 'root', children }, frame)
})
}
@@ -220,6 +222,8 @@ export class SlotTestRuntime {
const ctx = new Context()
const fiber = ctx.plugin(SlotsService)
await fiber.await()
await ctx.plugin(ConversationEventRegistry).await()
await ctx.plugin(ConversationViewRegistry).await()
return new SlotTestRuntime(ctx, ctx.get('slots') as SlotsService)
}
@@ -269,7 +273,7 @@ export class SlotTestRuntime {
/**
* Render the root slot tree through the ctx-level entry (the shell's own
* seam): `ctx.slots.renderSlot('root', {})` under Testing Library.
* entry point): `ctx.slots.renderSlot('root', {})` under Testing Library.
* @returns the Testing Library view.
*/
renderRoot(): RenderResult {

View File

@@ -368,7 +368,7 @@ export class TestSessions implements ISessions {
}
/**
* Read the session scope tag off a context (service-method seam mirror).
* Read the session scope tag off a context (service-method boundary mirror).
* @param ctx - any client context.
* @returns the session id, or undefined on root contexts.
*/
@@ -430,6 +430,14 @@ export class TestSessions implements ISessions {
return Promise.resolve()
}
/** Apply a confirmed preset switch into the fixture list, as production does. */
noteAgentPreset(sessionId: SessionId, agentPreset: string): void {
this.list.update((draft) => {
const summary = draft.byId[sessionId]
if (summary !== undefined) draft.byId[sessionId] = { ...summary, agentPreset }
})
}
/** Clear the current selection (recorded; the production no-session flow). */
clear(): void {
this.calls.push({ method: 'clear', args: [] })