90 lines
3.6 KiB
TypeScript
90 lines
3.6 KiB
TypeScript
/**
|
|
* Frozen contract of the client command surface. Types only. The
|
|
* CommandService (`ctx.command`) implements this face; business packages
|
|
* consume `register` alone.
|
|
*/
|
|
import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'
|
|
import type { ClientSessionContext } from '@deepseek-ai/dsh-client-ui-slash/client'
|
|
|
|
/** Copy for an option that must be acknowledged before onSelect can run. */
|
|
export interface SelectConfirmation {
|
|
readonly title: string
|
|
readonly description: string
|
|
readonly acknowledgeLabel: string
|
|
readonly cancelLabel: string
|
|
readonly confirmLabel: string
|
|
}
|
|
|
|
/** One option row of a popupSelect shell. */
|
|
export interface SelectOption {
|
|
readonly id: string
|
|
readonly label: string
|
|
readonly detail?: string
|
|
readonly active?: boolean
|
|
/** Optional in-page risk gate owned by the shared popup shell. */
|
|
readonly confirmation?: SelectConfirmation
|
|
}
|
|
|
|
/**
|
|
* Business registration for the popupSelect command kind. Data is
|
|
* self-served: options/onSelect use the business package's own protocol.
|
|
* The shell component is owned by ui-command; business never sees it. Both
|
|
* callbacks receive the ClientSessionContext captured at popup open.
|
|
*/
|
|
export type CommandUiSpec = {
|
|
readonly kind: 'popupSelect'
|
|
options(session: ClientSessionContext, signal: AbortSignal): Promise<readonly SelectOption[]>
|
|
onSelect(option: SelectOption, session: ClientSessionContext): void | Promise<void>
|
|
}
|
|
|
|
/**
|
|
* One client-owned command contribution: a slash-menu entry whose behavior
|
|
* lives entirely on the client (no host descriptor). Merged with the host
|
|
* catalog by name — a collision with a host command fails loud at candidate
|
|
* synthesis, never shadows.
|
|
*/
|
|
export interface CommandContribution {
|
|
/** Command name without the leading slash (unique across contributions). */
|
|
readonly name: string
|
|
/** Menu row description. */
|
|
readonly description: string
|
|
/** Capability filter, called with a fresh projection per candidate pass. */
|
|
available(session: ClientSessionContext): boolean
|
|
/** The command's UI behavior (this phase: popupSelect only). */
|
|
readonly ui: CommandUiSpec
|
|
}
|
|
|
|
/**
|
|
* A UI decoration hung on one HOST command: what its BARE invocation does on
|
|
* this client. Not a second command — the host command keeps its catalog
|
|
* row, its argument claim (space / argued enter), and its lifecycle logging;
|
|
* the decoration replaces only the bare menu-pick/enter with a popup whose
|
|
* onSelect typically submits a completed line back through command.execute.
|
|
* A decoration never manufactures a row: a name with no host catalog entry
|
|
* in the session's directory simply never reaches the decoration.
|
|
*/
|
|
export interface CommandDecoration {
|
|
/** The HOST command name this decorates (without the leading slash). */
|
|
readonly name: string
|
|
/** Capability filter, called with a fresh projection per bare invocation. */
|
|
available(session: ClientSessionContext): boolean
|
|
/** The bare-invocation UI (this phase: popupSelect only). */
|
|
readonly ui: CommandUiSpec
|
|
}
|
|
|
|
/** The `ctx.command` service face visible to business packages. */
|
|
export interface CommandServiceContract {
|
|
/**
|
|
* Register one client command contribution; effect disposer. Duplicate
|
|
* names throw at registration.
|
|
*/
|
|
register(contribution: CommandContribution): () => void
|
|
/**
|
|
* Hang a bare-invocation decoration on one host command; effect disposer.
|
|
* Duplicate names throw at registration.
|
|
*/
|
|
decorate(decoration: CommandDecoration): () => void
|
|
/** Resolve the per-session popup controller for one session scope (wiring/overlay layer). */
|
|
popupFor(actx: ClientContext): unknown
|
|
}
|