/** * Structural types for the cordis services this plugin consumes, plus the * Context augmentation both halves share. A third-party plugin resolves * outside the DSH monorepo's single cordis instance, so the upstream * `declare module 'cordis'` augmentations do not reach this Context — and * the npm cordis package does not declare the DSH-vendored runtime members * (`ctx.effect`, service properties). The members below mirror the actual * runtime shapes this plugin touches: * - httpServer: @deepseek-ai/dsh-host-webserver * - sessions: host side @deepseek-ai/dsh-session (SessionStore), client * side the runtime ISessions list feed * - conversation: client side ui-conversation's IConversation (composer * draft), read lazily through `ctx.get` — cross-plugin service reads need * an inject declaration, so the direct property is never typed here * - loader: @cordisjs/plugin-loader (entry options) * - slots: the client runtime SlotsService * - effect: the DSH-vendored cordis lifecycle helper * Drift from upstream is contained to this file. */ import type { IncomingMessage, ServerResponse } from 'node:http' import type { Duplex } from 'node:stream' import type { Context } from 'cordis' /** One named webserver route (mirror of the host-webserver WebRoute). */ export interface SidebarWebRoute { kind: 'exact' | 'prefix' path: string handler: (req: IncomingMessage, res: ServerResponse) => void | Promise } /** One exact-path HTTP upgrade registration (mirror of WebUpgradeRoute). */ export interface SidebarWebUpgradeRoute { path: string handler: (req: IncomingMessage, socket: Duplex, head: Buffer) => void | Promise } /** The httpServer service face this plugin uses. */ export interface SidebarHttpServer { register(route: SidebarWebRoute): () => void registerUpgrade(route: SidebarWebUpgradeRoute): () => void } /** A published session's header slice the sidebar reads (authoritative cwd). */ export interface SidebarSessionHeader { cwd?: string } /** The host session store face (`ctx.sessions.get(id)` returns the live session). */ export interface SidebarSessionStore { get(id: string): { header: SidebarSessionHeader } | undefined } /** One loader entry's options slice (the connection row's resolved config). */ export interface SidebarLoaderEntry { options: { name: string; config?: unknown } } /** The loader face used to read the connection row's trustedHosts config. */ export interface SidebarLoader { entries(): Iterable } /** Registration options the sidebar passes to `ctx.slots.register` (subset of the real options). */ export interface SidebarSlotRegisterOptions { name: string key?: string id?: string order?: number label?: string | (() => string) /** Chain routing selector (returns the matched value, or null to pass on). */ select?: (owner: unknown) => unknown priority?: number locale?: string registrant?: string /** Business-face factory; args depend on the slot scope. */ inject?: (...args: any[]) => Record children?: Record } /** The client slots service face (register returns the disposer). */ export interface SidebarSlotsService { register(options: SidebarSlotRegisterOptions, component: unknown): () => void /** * Run a callback for each declaration lifetime of a slot (the runtime * SlotsService.inject): a no-op while the slot is undeclared, so the * settings section registration waits for the settings shell. */ inject(key: string, callback: () => () => void): () => void } /** The client session list row the sidebar reads (cwd for the explorer). */ export interface SidebarSessionSummary { cwd?: string displayTitle: string } /** The client session list snapshot the sidebar subscribes to. */ export interface SidebarSessionList { current: string | undefined byId: Record } /** The client sessions service face (only the list feed is needed). */ export interface SidebarSessionsService { list: { getSnapshot(): SidebarSessionList subscribe(fn: () => void): () => void } /** * Resolve an Agent-scoped context view for one session (mirror of the * runtime ISessions.scope) — the ticket `ctx.conversation.input.for` * requires to reach that session's composer. */ scope(id: string): Context | undefined } /** The composer draft face the sidebar reaches through `ctx.conversation.input`. */ export interface SidebarSessionInput { /** The live input store (draft read for append). */ state: { getSnapshot(): { draft: string } } /** Replace the draft text (the input machine's single public write path). */ setDraft(text: string): void } /** The composer draft face the sidebar reaches through `ctx.get('conversation')`. */ export interface SidebarConversation { input: { for(actx: Context): SidebarSessionInput } } /** * The invariant service face (mirror of @deepseek-ai/dsh-invariants' * InvariantService). The upstream augmentation does not reach this Context * (dual-cordis-instance resolution), so the register signature is restated * structurally, exactly like the other service faces above. */ export interface SidebarInvariantsService { /** Reserve one package's checks and install them in the service's child fiber. */ register( packageName: string, installer: (ctx: Context, fail: (message: string) => never) => void | Promise, ): () => void } /** The settings service face (mirror of @deepseek-ai/dsh-settings' Settings). */ export interface SidebarSettingsService { /** * Register one namespace schema (the resolved value layers schema defaults, * then the composition base, then the user document). */ register( ns: string, schema: unknown, options?: { base?: Partial; applies?: 'live' | 'restart' }, ): { get(): T watch(callback: (next: T, prev: T) => void | Promise): () => void update(patch: object): Promise replace(section: object): Promise } /** Redacted descriptors of every registered namespace (secrets stripped). */ describe(options?: { redactSecrets?: boolean }): Array<{ ns: string value?: unknown base?: unknown user?: unknown applies: 'live' | 'restart' revision: number }> /** Service-level merge write with the revision guard (a stale writer is refused). */ update(ns: string, patch: object, expectedRevision?: number): Promise } declare module 'cordis' { interface Context { httpServer: SidebarHttpServer sessions: SidebarSessionStore & SidebarSessionsService loader: SidebarLoader slots: SidebarSlotsService settings: SidebarSettingsService invariants: SidebarInvariantsService /** * Register a lifecycle callback (DSH-vendored cordis): runs at plugin * activation; its returned cleanup runs at disposal. */ effect(fn: () => void | (() => void), label?: string): void } } export type { Context }