refactor(client): remove compatibility imports

This commit is contained in:
imccyu 2026-08-23 22:50:42 +08:00
parent 3d1c0af60b
commit 997ad27a60
17 changed files with 57 additions and 60 deletions

View file

@ -76,7 +76,10 @@ export interface ISessions {
noteAgentPreset(sessionId: SessionId, agentPreset: string): void
/** Clear the current selection into the no-session view state. */
clear(): void
/** @returns completion of the current or newly started Session-list refresh. */
/**
* Refresh the Host-authoritative Session list.
* @returns completion of the current or newly started Session-list refresh.
*/
refresh(): Promise<void>
/**
* Search the Host's visible message-content index. Results stay

View file

@ -5,7 +5,6 @@ import type {} from '@deepseek-ai/dsh-agent/types'
import type { ConnectionHandle } from '@deepseek-ai/dsh-client-connection/client'
import { createSessionControlStream } from './transport.ts'
import { ClientSessions } from './sessions/service.ts'
import type { ISessions } from './contract/sessions.ts'
import type { SessionRemotes } from './sessions/remotes.ts'
import type {} from '../remote-events.ts'
@ -26,7 +25,7 @@ export type {
} from './transport.ts'
export { createScope, scopeOf } from './scope.ts'
export type { AgentContext, AgentScopeHandle } from './scope.ts'
export { SessionCreateError, SessionForkError, workspaceTitleOf } from './sessions/service.ts'
export { SessionCreateError, SessionForkError } from './sessions/service.ts'
export type { SessionBinding, SessionListState, SessionSummary } from './sessions/service.ts'
export type {
SessionListPhase,
@ -52,18 +51,8 @@ export type {
SessionSnapshot,
} from './contract/snapshot.ts'
export type { ClientFailure, ClientResult } from './contract/result.ts'
export { indexSubagentDescendants } from './sessions/subagent-lineage.ts'
export type { SubagentDescendantSummary } from './sessions/subagent-lineage.ts'
declare module '@deepseek-ai/cordis' {
interface Events {
/**
* A Host connection generation completed its readiness handshake.
* @mode emit
*/
'connection/reset'(): void
}
interface Context {
/** Client Session object layer and Agent scope owner. */
sessions: import('./contract/sessions.ts').ISessions
@ -79,17 +68,6 @@ export const inject = [
'remote.session',
]
/**
* Resolve the Client Session service from any Client Cordis context.
* @param ctx - Client root or Agent-scoped context.
* @returns the Client Session object layer.
*/
export function resolveClientSessions(ctx: Context): ISessions {
const sessions = ctx.get('sessions')
if (sessions === undefined) throw new Error('session-controller: Client sessions service unavailable')
return sessions
}
/**
* Install Client Session state and its reconnecting control stream.
* @param ctx - Client Cordis context.

View file

@ -87,7 +87,7 @@ async function mount(initialHost?: HostDescription): Promise<Bench> {
ctx.reflect.provide('remote.session', remote.session)
const fiber = ctx.plugin(SessionClient)
await fiber
const sessions = SessionClient.resolveClientSessions(ctx) as ClientSessions
const sessions = ctx.sessions as ClientSessions
return {
ctx,
api,
@ -108,14 +108,6 @@ async function flush(): Promise<void> {
}
describe('Session Controller Client apply', () => {
it('requires the installed Session service at the resolver boundary', () => {
const ctx = new Context()
contexts.add(ctx)
expect(() => SessionClient.resolveClientSessions(ctx))
.toThrow('session-controller: Client sessions service unavailable')
})
it('routes Session Remote Events and connection generations into the object layer', async () => {
const connected = vi.spyOn(ClientSessions.prototype, 'handleConnected')
const error = vi.spyOn(ClientSessions.prototype, 'handleSessionError')

View file

@ -3,7 +3,8 @@
import { Service, type Context } from '@deepseek-ai/cordis'
import type { SessionId } from '@deepseek-ai/dsh-session/types'
import type { RemoteFailure } from '@deepseek-ai/dsh-typert-protocol'
import type { WorkspaceId, WorkspaceView } from '../types.ts'
import type { WorkspaceId } from '@deepseek-ai/dsh-workspace/types'
import type { WorkspaceView } from '../types.ts'
import type { ClientWorkspaceModel, WorkspaceSnapshot } from './model.ts'
/** Structured create failure for callers that distinguish Host business errors. */

View file

@ -133,13 +133,29 @@ export interface InputTriggerController {
declare module '@deepseek-ai/cordis' {
interface Events {
/** @param request - command claim and span. @mode bail */
/**
* Claim a command token for the scoped input machine.
* @param request - command claim and span.
* @mode bail
*/
'slash/input-begin-command'(request: BeginCommandRequest): true | undefined
/** @param request - reference and span. @mode bail */
/**
* Insert a structured reference into the scoped input machine.
* @param request - reference and span.
* @mode bail
*/
'slash/input-insert-reference'(request: InsertReferenceRequest): true | undefined
/** @param request - token guard. @mode bail */
/**
* Consume a trigger token without inserting replacement content.
* @param request - token guard.
* @mode bail
*/
'slash/input-consume-token'(request: ConsumeTokenRequest): true | undefined
/** @param request - plain text and span. @mode bail */
/**
* Insert plain text into the scoped input machine.
* @param request - plain text and span.
* @mode bail
*/
'slash/input-insert-text'(request: InsertTextRequest): true | undefined
}
}

View file

@ -10,7 +10,7 @@ import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } fr
import type { ChangeEvent, KeyboardEvent, MouseEvent, ReactNode } from 'react'
import clsx from 'clsx'
import {
IconPlusOutline16, IconWarningOutline16, Toast, Tooltip,
IconPlusOutline16, IconWarningOutline16, ReferenceIcon, Toast, Tooltip,
} from '@deepseek-ai/dsh-client-ui-primitives'
// Type-only: the `plan` projection key merge (the TodoDock posture — the
// composer reads a host-computed value; the domain owns the key).
@ -24,7 +24,6 @@ import { deriveDecorations } from './decorations.ts'
import type { DraftDecorations } from './decorations.ts'
import type { EditRange } from '../contract/input.ts'
import { attachmentErrorText, imageSizeText } from '../image-labels.ts'
import { ReferenceIcon } from './ReferenceIcon.tsx'
import { ContextMeter } from './ContextMeter.tsx'
import { PermissionSelect } from './PermissionSelect.tsx'
import { isSafariBrowser, repairSafariTextareaLayout } from './safari.ts'

View file

@ -9,12 +9,15 @@
*/
import type { Context as ClientContext } from '@deepseek-ai/cordis'
import { createSnapshotStore, type SnapshotStore } from '@deepseek-ai/dsh-client-store'
import type {
ArbitrateKey, ArbitrateOutcome, PickOutcome,
} from '@deepseek-ai/dsh-client-ui-conversation/client'
import type { SessionId } from '@deepseek-ai/dsh-session/types'
import { detectTrigger } from '../core/detect.ts'
import { MENU_CLOSED, menuReduce, seedGroups } from '../core/menu.ts'
import type { MenuEvent, MenuState, TriggerHit } from '../core/contract.ts'
import type {
ArbitrateKey, ArbitrateOutcome, ClientSessionContext, PickOutcome, InputTriggerSource, SubmitEnvelope, TriggerChar, TriggerGuard,
ClientSessionContext, InputTriggerSource, SubmitEnvelope, TriggerChar, TriggerGuard,
} from '../types.ts'
/** Roster access the controller borrows from the root service (registration order preserved). */

View file

@ -7,7 +7,7 @@
// Type-only: pulls the locale plugin's Context merge (ctx.locale).
import type {} from '@deepseek-ai/dsh-client-locale/client'
import type { Context as ClientContext } from '@deepseek-ai/cordis'
import { resolveClientSessions } from '@deepseek-ai/dsh-api-session-controller/client'
import type {} from '@deepseek-ai/dsh-api-session-controller/client'
import type {} from '@deepseek-ai/dsh-client-ui-renderer/client'
import type {} from '@deepseek-ai/dsh-client-ui-session/client'
import { InputTriggerService } from './service.ts'
@ -60,7 +60,7 @@ export function apply(ctx: ClientContext): void {
ctx.effect(() => ctx.locale.register(MENU_NS, { zh, en }), 'ui-input-trigger: menu dictionaries')
ctx.inject(['slots', 'inputTriggers', 'sessions'], (scope: ClientContext) => {
const inputTriggers = scope.inputTriggers
const sessions = resolveClientSessions(scope)
const sessions = scope.sessions
scope.slots.inject('conversation.input.overlay', () => scope.slots.register({
name: 'conversation.input.overlay',
id: 'slash-menu',

View file

@ -4,7 +4,8 @@
* live in sibling modules annotated with these
* aliases; the service shell wires them to ctx.
*/
import type { InputTriggerCandidate, TokenSpan, TriggerChar, TriggerGuard, TriggerPosition } from '../types.ts'
import type { TokenSpan } from '@deepseek-ai/dsh-client-ui-conversation/client'
import type { InputTriggerCandidate, TriggerChar, TriggerGuard, TriggerPosition } from '../types.ts'
/** A detected trigger token under the caret. */
export interface TriggerHit {

View file

@ -7,9 +7,7 @@
import { Context } from '@deepseek-ai/cordis'
import { describe, expect, it } from 'vitest'
import { LocaleRuntime } from '@deepseek-ai/dsh-client-locale/client'
import {
createScope, resolveClientSessions, scopeOf,
} from '@deepseek-ai/dsh-api-session-controller/client'
import { createScope, scopeOf } from '@deepseek-ai/dsh-api-session-controller/client'
import { SlotRegistry } from '@deepseek-ai/dsh-client-ui-renderer/client'
import type { SessionId } from '@deepseek-ai/dsh-session/types'
import { apply, inject, InputTriggerService } from '@deepseek-ai/dsh-client-ui-input-trigger/client'
@ -80,7 +78,7 @@ describe('apply', () => {
const injectEntry = entries[0]!.inject as unknown as (sessionId: SessionId) => MenuViewInjected
const injected = injectEntry(sid('a'))
const controller = inputTriggers.sessionOf(
resolveClientSessions(ctx).scope(sid('a'))!,
ctx.sessions.scope(sid('a'))!,
)
expect(injected.menu).toBe(controller.menu)
// The pick face routes into the controller pipeline (closed menu → no-op).

View file

@ -13,7 +13,7 @@
*/
// Type-only: the carrier types, the forwarded Host-event face and the ctx.remote merge.
import type { ModelSelection, SessionModels } from '@deepseek-ai/dsh-api-session-controller/types'
import { resolveClientSessions } from '@deepseek-ai/dsh-api-session-controller/client'
import type {} from '@deepseek-ai/dsh-api-session-controller/client'
import type { Context as ClientContext } from '@deepseek-ai/cordis'
import type { CommandUiContract, SelectOption } from '@deepseek-ai/dsh-client-ui-commands/client'
// Type-only: pulls the ui-conversation SlotMap merge (the input.model seat).
@ -125,7 +125,7 @@ export function apply(ctx: ClientContext): void {
ctx.inject(['commandUi', 'modelDirectories'], (scope: ClientContext) => {
const command = scope.get('commandUi') as CommandUiContract
const models = scope.modelDirectories
const sessions = resolveClientSessions(scope)
const sessions = scope.sessions
scope.effect(() => command.register({
name: 'model',
description: t('command.description'),
@ -156,7 +156,7 @@ export function apply(ctx: ClientContext): void {
// Entry 2: the composer's named model seat over the SAME directory.
ctx.inject(['slots', 'modelDirectories'], (scope: ClientContext) => {
const models = scope.modelDirectories
const sessions = resolveClientSessions(scope)
const sessions = scope.sessions
scope.slots.inject('conversation.input.model', () => scope.slots.register({
name: 'conversation.input.model',
locale: NS,

View file

@ -14,7 +14,7 @@
*/
import { Service } from '@deepseek-ai/cordis'
import type { Context } from '@deepseek-ai/cordis'
import { resolveClientSessions } from '@deepseek-ai/dsh-api-session-controller/client'
import type {} from '@deepseek-ai/dsh-api-session-controller/client'
import type { SessionId } from '@deepseek-ai/dsh-session/types'
import { ModelDirectory } from './directory.ts'
@ -70,7 +70,7 @@ export class ModelDirectoryResolver extends Service {
const { live } = this
const existing = live.directories.get(sessionId)
if (existing !== undefined) return existing
const sessions = resolveClientSessions(this.ctx)
const sessions = this.ctx.sessions
const actx = sessions.scope(sessionId)
if (actx === undefined) throw new Error(`ui-model-selection: session "${String(sessionId)}" resolved no scope`)
const directory = new ModelDirectory(

View file

@ -15,7 +15,7 @@
*/
import type { Context as ClientContext } from '@deepseek-ai/cordis'
import type { ConnectionHandle } from '@deepseek-ai/dsh-api-remotes/client'
import { resolveClientSessions, type SessionFace } from '@deepseek-ai/dsh-api-session-controller/client'
import type { SessionFace } from '@deepseek-ai/dsh-api-session-controller/client'
// Type-only: pulls the locale plugin's Context merge (ctx.locale).
import type {} from '@deepseek-ai/dsh-client-locale/client'
// Type-only: the settings slot types (this package registers a General row).
@ -83,7 +83,7 @@ function optionsOf(value: PermissionSelect, t: (key: string) => string): SelectO
*/
export function apply(ctx: ClientContext): void {
const command = ctx.get('commandUi') as CommandUiContract
const sessions = resolveClientSessions(ctx)
const sessions = ctx.sessions
// This optional bundle and ui-conversation can load independently, so each
// owns the same safety copy under its own locale namespace.
/* jscpd:ignore-start */

View file

@ -32,7 +32,7 @@
// Type-only: the carrier types, the forwarded Host-event face and the ctx.remote merge.
import type { Context as ClientContext } from '@deepseek-ai/cordis'
import type { ConnectionHandle, SkillEntry } from '@deepseek-ai/dsh-api-remotes/client'
import { resolveClientSessions } from '@deepseek-ai/dsh-api-session-controller/client'
import type {} from '@deepseek-ai/dsh-api-session-controller/client'
import type { SessionId } from '@deepseek-ai/dsh-session/types'
import type { InputTriggerServiceContract, InputTriggerSource } from '@deepseek-ai/dsh-client-ui-input-trigger/client'
// Type-only: pulls the locale plugin's Context merge (ctx.locale).
@ -72,7 +72,7 @@ export function apply(ctx: ClientContext): void {
))
const skills = (ctx.get('connection') as ConnectionHandle).api.skills
const sessions = resolveClientSessions(ctx)
const sessions = ctx.sessions
// Session-keyed catalog cache; single-flight per key. Plugin-closure state:
// the fiber effect below is its teardown boundary.
const fetches = new Map<SessionId, CatalogFetch>()

View file

@ -14,8 +14,10 @@
* consumer merges keys in and the intersection is what keeps them string-typed.
* The rule fires on the empty-map view, not on real redundancy. */
import type { ReactNode } from 'react'
import type {
BoundActions, HandleOf, PropsStore, SnapshotSelectorHook, StoreDecl,
} from '@deepseek-ai/dsh-client-store'
import type { HostObservable } from './renderer.ts'
import type { BoundActions, HandleOf, PropsStore, SnapshotSelectorHook, StoreDecl } from './store.ts'
export * from './store.ts'
export * from './renderer.ts'

View file

@ -14,6 +14,7 @@
*/
import type { Context as ClientContext } from '@deepseek-ai/cordis'
import type {} from '@deepseek-ai/dsh-api-remotes/client'
import type { ISessions } from '@deepseek-ai/dsh-api-session-controller/client'
import type { ComposerChainProps } from '@deepseek-ai/dsh-client-ui-conversation/client'
import type {} from '@deepseek-ai/dsh-client-ui-renderer/client'
import type { PendingInteractionPublisher } from '@deepseek-ai/dsh-client-ui-session/client'
@ -56,7 +57,7 @@ async function answerQuestion(
next: ClientQuestionNext,
registerPendingInteraction: PendingInteractionPublisher<PendingQuestion>,
): Promise<ClientQuestionAnswer> {
const sessionId = ctx.sessions.scopeOf(owner)
const sessionId = (ctx.sessions as ISessions).scopeOf(owner)
if (sessionId === undefined) return next()
const pending = new PendingQuestion(sessionId, request.questions, request.signal)
const completed = Promise.withResolvers<void>()

View file

@ -31,7 +31,10 @@ export interface UiWorkspace {
* @param sessionId - Session to archive.
*/
archiveSession(sessionId: SessionId): Promise<void>
/** @returns the Host-native picked directory, or null when cancelled. */
/**
* Open the Host-native directory picker.
* @returns the selected directory, or null when cancelled.
*/
pickDirectory(): Promise<string | null>
/**
* List one Host directory level.