Merge remote-tracking branch 'origin/master' into feat/web-message-feedback-ui

Adapt to two contract changes master introduced:

- The generated Remote face now wraps every business result in
  RemoteResult, folding carrier failures into an ok:false branch instead
  of rejecting. The controller reads that envelope at its three call
  sites and maps a carrier failure onto the same settled shape the
  controls already render; three specs cover the new branch.
- Client packages split their tsconfig into host and client halves, and
  the host aggregate now compiles any test not named *.client.spec.*.
  Rename this package's specs to the client convention and drop the
  ../connection project reference, which pointed at a solution file that
  no longer carries the client sources.

Keep master's mount loop with its rollback-on-failure in api-remotes and
add messageFeedbackRemote to it.
This commit is contained in:
Chinesezjc
2026-08-12 10:43:23 +08:00
parent 47f254a252
commit b462d5fd69
507 changed files with 3130 additions and 2238 deletions

View File

@@ -47,7 +47,7 @@ function sessionFakeFor() {
async function bench() {
const runtime = await SlotTestRuntime.create()
runtime.provide('connection', { api: { settings: {} }, isLoopback: false } as never)
runtime.provide('connection', { api: { settings: {} }, isLoopback: false })
// The plugin injects both; these specs exercise no settings path.
runtime.provide('remote', { $on: () => () => {} })
runtime.provide('settingsScope', { bind: () => stubSettingsScope().scope } as never)

View File

@@ -50,7 +50,7 @@ function WorkspaceProbe({ open }: EmptyWorkspaceOwnerProps) {
async function bench(opts?: { blank?: boolean }) {
const runtime = await SlotTestRuntime.create()
runtime.provide('connection', { api: { settings: {} }, isLoopback: false } as never)
runtime.provide('connection', { api: { settings: {} }, isLoopback: false })
// The plugin injects both; these specs exercise no settings path.
runtime.provide('remote', { $on: () => () => {} })
runtime.provide('settingsScope', { bind: () => stubSettingsScope().scope } as never)
@@ -78,7 +78,7 @@ async function bench(opts?: { blank?: boolean }) {
describe('resident composer', () => {
it('renders the locked view state while no session exists at all', async () => {
const runtime = await SlotTestRuntime.create()
runtime.provide('connection', { api: { settings: {} }, isLoopback: false } as never)
runtime.provide('connection', { api: { settings: {} }, isLoopback: false })
// The plugin injects both; these specs exercise no settings path.
runtime.provide('remote', { $on: () => () => {} })
runtime.provide('settingsScope', { bind: () => stubSettingsScope().scope } as never)
@@ -108,7 +108,7 @@ describe('resident composer', () => {
it('keeps the complete Hero tree mounted when the first Workspace session appears', async () => {
const runtime = await SlotTestRuntime.create()
runtime.provide('connection', { api: { settings: {} }, isLoopback: false } as never)
runtime.provide('connection', { api: { settings: {} }, isLoopback: false })
// The plugin injects both; these specs exercise no settings path.
runtime.provide('remote', { $on: () => () => {} })
runtime.provide('settingsScope', { bind: () => stubSettingsScope().scope } as never)
@@ -177,7 +177,7 @@ describe('resident composer', () => {
describe('prompt rejection through the assembled composer', () => {
it('renders the promptError alert strip and keeps the draft in the machine', async () => {
const runtime = await SlotTestRuntime.create()
runtime.provide('connection', { api: { settings: {} }, isLoopback: false } as never)
runtime.provide('connection', { api: { settings: {} }, isLoopback: false })
// The plugin injects both; these specs exercise no settings path.
runtime.provide('remote', { $on: () => () => {} })
runtime.provide('settingsScope', { bind: () => stubSettingsScope().scope } as never)

View File

@@ -21,7 +21,7 @@ const CHILD = 'child-1' as SessionId
async function bench() {
const runtime = await SlotTestRuntime.create()
runtime.provide('connection', { api: { settings: {} }, isLoopback: false } as never)
runtime.provide('connection', { api: { settings: {} }, isLoopback: false })
// The plugin injects both; these specs exercise no settings path.
runtime.provide('remote', { $on: () => () => {} })
runtime.provide('settingsScope', { bind: () => stubSettingsScope().scope } as never)

View File

@@ -24,7 +24,7 @@ import {
import { AssistantMarkdown } from '../src/client/chat/AssistantMarkdown.tsx'
import { StatsLine, type StatsLineProps } from '../src/client/chat/StatsLine.tsx'
import { zh } from '../src/client/locales.ts'
import { chatSnapshotFixture } from './chat-snapshot-fixture.ts'
import { chatSnapshotFixture } from './chat-snapshot-fixture.client.ts'
/** jsdom has no ResizeObserver; StatsLine watches its row for ellipsis truncation through one. */
class ResizeObserverStub {

View File

@@ -14,7 +14,7 @@ import { en as commonEn } from '@deepseek-ai/dsh-client-locale/src/locales/en.ts
import { zh as commonZh } from '@deepseek-ai/dsh-client-locale/src/locales/zh.ts'
import { StatsLine, contextOccupancy, deriveStats, formatDuration, formatTokens, type StatsLineProps } from '../src/client/chat/StatsLine.tsx'
import { en, zh } from '../src/client/locales.ts'
import { chatSnapshotFixture } from './chat-snapshot-fixture.ts'
import { chatSnapshotFixture } from './chat-snapshot-fixture.client.ts'
// Mirrors the real lookup chain (conversation namespace, then common).
const t: StatsLineProps['t'] = makeTranslate(zh, commonZh)

View File

@@ -32,7 +32,7 @@ import {
} from '../src/client/chat/MessageItem.tsx'
import { TurnTailNodeView } from '../src/client/chat/TurnTailNodeView.tsx'
import { formatRunDuration } from '../src/client/chat/message-chrome.ts'
import { chatSnapshotFixture } from './chat-snapshot-fixture.ts'
import { chatSnapshotFixture } from './chat-snapshot-fixture.client.ts'
afterEach(() => {
cleanup()

View File

@@ -17,7 +17,7 @@ import { AssistantMarkdown, type AssistantMarkdownProps } from '../src/client/ch
import { StatsLine } from '../src/client/chat/StatsLine.tsx'
import { DetailsPanel } from '../src/client/skeleton/DetailsPanel.tsx'
import { zh } from '../src/client/locales.ts'
import { chatSnapshotFixture } from './chat-snapshot-fixture.ts'
import { chatSnapshotFixture } from './chat-snapshot-fixture.client.ts'
// Mirrors the real lookup chain (conversation namespace, then common).
const t: AssistantMarkdownProps['t'] = makeTranslate(zh, commonZh)

View File

@@ -16,7 +16,7 @@ import {
} from '@deepseek-ai/dsh-client-runtime/client'
import { SlashService } from '@deepseek-ai/dsh-client-ui-slash/client'
import type { ClientSessionContext, CommandClaim, PickOutcome, SubmitOutcome } from '@deepseek-ai/dsh-client-ui-slash/client'
import { FakeApiClient, ok } from '../../runtime/tests/fake-api.ts'
import { FakeApiClient, fakeRemote, ok } from '../../runtime/tests/fake-api.client.ts'
import { makeTranslate } from '@deepseek-ai/dsh-client-test-runtime'
import { zh as commonZh } from '@deepseek-ai/dsh-client-locale/src/locales/zh.ts'
import { SessionInputShell } from '../src/client/input/facade.ts'
@@ -98,7 +98,7 @@ async function scopedBench(register?: (slash: SlashService) => void) {
api.onList = () => Promise.resolve(ok({
items: [{ sessionId, updatedAt: 1, running: false, blank: false, cwd: '/w/a' }],
}) as never)
const sessions = new SessionsService(ctx, api) // provides 'sessions' itself
const sessions = new SessionsService(ctx, api, fakeRemote()) // provides 'sessions' itself
await sessions.refresh()
await Promise.resolve() // manager notifier flush
await ctx.plugin(SlashService).await()

View File

@@ -17,9 +17,6 @@
{
"path": "../../../vendor/cordis"
},
{
"path": "../connection"
},
{
"path": "../ui-slots"
},