refactor(client): carve outward interfaces for the session, workspace, layout, slash, and conversation services

Feature packages now reach these domains through interface types only:
ISession/SessionFace (identity + prompt/cancel/loadOlder + the useSession
snapshot source), ISessions, IWorkspaces, ILayout, IConversation, and the
existing SlashServiceContract now actually mounted on Context.slash. The
concrete services implement their face; wire-pump and assembly entry
points stay on the classes. The provide-channel materialization and
current-projection logic moves into SessionProvideChannel so the
production service and the client test runtime share one implementation.
The workspaces service consumes sessions through the narrow SessionsPort.
This commit is contained in:
imccyu
2026-07-28 23:03:56 +08:00
parent eb38a365dc
commit 0efc7f045e
19 changed files with 556 additions and 179 deletions

View File

@@ -9,10 +9,10 @@
import { Service } from 'cordis'
import type { Context } from 'cordis'
import type { ConnectionHandle, SessionId } from '@deepseek-ai/dsh-client-connection/client'
import type { ClientContext, SessionsService } from '@deepseek-ai/dsh-client-runtime/client'
import type { ClientContext, ISessions } from '@deepseek-ai/dsh-client-runtime/client'
import type {
CandidateRequest, ClientSessionContext, CommandClaim, PickOutcome, SlashCandidate, SlashPick,
SlashServiceContract, SubmitOutcome,
SubmitOutcome,
} from '@deepseek-ai/dsh-client-ui-slash/client'
import type { CommandContribution, CommandServiceContract } from './contract.ts'
import type { CommandDescriptor } from './directory.ts'
@@ -46,7 +46,7 @@ export class CommandService extends Service implements CommandServiceContract {
if (!result.ok) throw new Error(`command.list failed: ${result.error.code}: ${result.error.message}`)
return result.value.commands
})
const slash = ctx.get('slash') as SlashServiceContract | undefined
const slash = ctx.get('slash')
if (slash === undefined) throw new Error('ui-command: slash service unavailable')
ctx.effect(() => slash.registerSource({
trigger: '/',
@@ -292,7 +292,7 @@ export class CommandService extends Service implements CommandServiceContract {
return this.sessions().scope(id)
}
private sessions(): SessionsService {
private sessions(): ISessions {
const sessions = this.ctx.get('sessions')
if (sessions === undefined) throw new Error('ui-command: sessions service unavailable')
return sessions