/**
 * Input-trigger provider contract. Types only — no runtime code. The
 * conversation input layer owns and exports the shared machine currency;
 * this module re-exports it for trigger providers.
 *
 * Providers receive a {@link ClientSessionContext} projection per call —
 * never a Cordis context or the mutable Session. RPC and service access go
 * through the provider plugin's own root context captured at registration.
 */
import type { PickOutcome, TokenSpan } from '@deepseek-ai/dsh-client-ui-conversation/client';
import type { SessionId } from '@deepseek-ai/dsh-session/types';
export type { ArbitrateKey, ArbitrateOutcome, BeginCommandRequest, CommandClaim, ConsumeTokenRequest, InsertReferenceRequest, InsertTextRequest, PickOutcome, ReferenceInsert, SubmitImageAttachment, SubmitOutcome, TokenSpan, } from '@deepseek-ai/dsh-client-ui-conversation/client';
/**
 * The provider-facing projection of one client session. It carries stable
 * identity alone; a source that calls Agent-bound RPCs must consult its own
 * service's capability state because an addressed persisted subagent may
 * have a client scope without a live Host Agent.
 */
export interface ClientSessionContext {
    readonly sessionId: SessionId;
}
/** Trigger character a source binds to. */
export type TriggerChar = '/' | '@';
/** Where the trigger token sits in the draft: leading (trimmed draft starts with it) or inline. */
export type TriggerPosition = 'leading' | 'inline';
/** Which of the three pick paths produced a pick. */
export type PickVia = 'menu' | 'space' | 'enter';
/** What a pick asks for: resolve the candidate, or drill into it in place. */
export type PickAction = 'pick' | 'drill';
/** Leading glyph token of one menu candidate, mapped to its SVG by the menu view. */
export type InputTriggerCandidateIcon = 'file' | 'folder' | 'session';
/** One menu candidate. Pure display data — zero behavior declaration. */
export interface InputTriggerCandidate {
    readonly name: string;
    readonly description?: string;
    readonly icon?: InputTriggerCandidateIcon;
    readonly hint?: string;
    /** Optional visual heading shared by adjacent candidates; sectioned groups omit their source-title row. */
    readonly section?: string;
    /** Opaque source-owned pick payload. */
    readonly value?: string;
    /**
     * The row offers a drill action beside the settling pick: Tab or the row's
     * chevron refines the query in place (directory descent) instead of
     * resolving the candidate.
     */
    readonly drill?: boolean;
}
/**
 * One crumb of a source's menu header. The pipeline treats `value` as opaque
 * and hands it straight back on pick, so a source names its own destinations.
 */
export interface InputTriggerCrumb {
    /** Rendered text of this step. */
    readonly label: string;
    /** Opaque source-owned pick payload, returned through `onPick`. */
    readonly value: string;
    /** The step the menu is currently showing; rendered as the trailing, unclickable crumb. */
    readonly current?: boolean;
}
/** What a source needs to decide the header of the open menu. */
export interface HeaderRequest {
    /** Text between the trigger char and the caret, live-filtered. */
    readonly query: string;
    /** Whether the active @file token is an open quoted path. */
    readonly quoted?: boolean;
    /**
     * True while this menu was opened or last re-scoped by a drill pick. It
     * survives further typing and clears when the menu closes, so a query typed
     * after a drill still reads as drilled. The pipeline owns the fact; what it
     * means for a header is the source's to decide.
     */
    readonly drilled: boolean;
}
/**
 * Non-text composer submission state visible to enter adjudication. The
 * composer owns the actual attachment payloads; adjudication only needs their
 * presence to accept or refuse a whole submission.
 */
export interface SubmitEnvelope {
    /** Number of image attachments accompanying the draft. */
    readonly images: number;
}
/** Candidate request passed to a source. The signal is superseded on query change / menu close. */
export interface CandidateRequest {
    readonly query: string;
    /** Whether the active @file token is an open quoted path. */
    readonly quoted?: boolean;
    readonly position: TriggerPosition;
    /** Whether this menu was opened or last re-scoped by a drill pick; see {@link HeaderRequest.drilled}. */
    readonly drilled: boolean;
    readonly signal: AbortSignal;
}
/** Everything a source receives on pick: candidate + session projection + the span snapshot for CAS. */
export interface InputTriggerPick {
    readonly candidate: InputTriggerCandidate;
    readonly session: ClientSessionContext;
    readonly position: TriggerPosition;
    readonly via: PickVia;
    /** Settling pick, or the candidate's drill action (Tab / row chevron). */
    readonly action: PickAction;
    readonly span: TokenSpan;
}
/**
 * Reference codec owned by a source that produces {@link ReferenceInsert}
 * outcomes: the clipboard projection for copy/cut/persistence, and the model
 * serialization invoked per occurrence by the submit attempt (async, abort
 * rides the attempt signal; failure blocks the send — never a silent
 * downgrade to the clipboard text).
 */
export interface ReferenceCodec {
    /** Clipboard / persistence projection of one reference (e.g. `/name`). */
    clipboardText(ref: string): string;
    /** Model serialization of one reference (e.g. `<skill>name</skill>`). */
    serialize(ref: string, signal: AbortSignal): Promise<string>;
}
/**
 * One trigger source. Every callback receives the session's
 * ClientSessionContext projection; sources keep no copy across calls.
 *
 * Space/enter adjudication rides the optional match hooks: implementing one
 * IS the participation claim — the pipeline polls each implementing source
 * with the leading token; the first non-undefined answer wins (registration
 * order); no claimant → default sink. The hooks split because their timing
 * budgets differ: space fires mid-keystroke and must answer synchronously
 * from hot state, while enter may await the source's own warmup.
 */
export interface InputTriggerSource {
    readonly trigger: TriggerChar;
    /** Menu group label; unique per trigger — duplicate registration throws. */
    readonly name: string;
    /** Menu group display order (lower = higher in the list; default 0). */
    readonly order?: number;
    /** Whether the menu renders the source-title row; defaults to true. */
    readonly showGroupTitle?: boolean;
    candidates(session: ClientSessionContext, req: CandidateRequest): Promise<readonly InputTriggerCandidate[]>;
    /**
     * Synchronous breadcrumb rendered above this source's group, re-polled on
     * every hit. Implementing IS the participation claim; `undefined` means
     * this request needs no header. A crumb pick routes back through
     * {@link InputTriggerSource.onPick} with `action: 'drill'` and the crumb's
     * `value` as the candidate value, so returning to a step and descending
     * into one are the same outcome.
     * @param session - stable session projection.
     * @param req - the live query and how the menu reached it.
     * @returns the crumbs to render, or undefined for no header.
     */
    header?(session: ClientSessionContext, req: HeaderRequest): readonly InputTriggerCrumb[] | undefined;
    /** Every pick lands here; claim/insert outcomes are executed by the pipeline via the scoped input events. */
    onPick(pick: InputTriggerPick): PickOutcome;
    /** Synchronous space-time adjudication over hot state only. `token` is the just-completed leading token (e.g. '/goal'). */
    matchSpace?(session: ClientSessionContext, token: string): PickOutcome;
    /**
     * Enter-time adjudication; may strong-wait the source's own warmup and
     * reject on warmup failure. `line` is the full trimmed draft: the source
     * parses it and applies its own kind policy — args-tolerant kinds claim
     * with trailing text present, bare-token-only kinds answer undefined
     * unless the line is exactly the token. `envelope` describes the rest of
     * the composer submission; a source that would consume the line but cannot
     * consume the whole envelope throws to surface the refusal and leave the
     * submission intact.
     */
    matchEnter?(session: ClientSessionContext, line: string, signal: AbortSignal, envelope: SubmitEnvelope): Promise<PickOutcome>;
    /**
     * Scope-birth prewarm hook (fire-and-forget): the per-session controller
     * calls it once when the session scope comes alive so sources can fetch
     * their backing data before the first interaction.
     */
    warm?(session: ClientSessionContext): void;
    /**
     * Synchronous hot-snapshot name roll for plain-text reference decoration.
     * Implementing IS the participation claim: the render side
     * scans the draft for `<trigger><name>` tokens and decorates exact matches.
     * `undefined` = backing data not warm yet — no decoration, never a fetch
     * (the render path must stay synchronous and side-effect free).
     */
    lexicon?(session: ClientSessionContext): readonly string[] | undefined;
    /**
     * Subscribe to changes of this source's {@link InputTriggerSource.lexicon} answer
     * for one session (backing data settled, invalidated, or refreshed). The
     * controller re-polls lexicon on each notification; a source whose roll
     * never changes after warm omits the hook.
     * @param session - stable session projection.
     * @param listener - invalidation callback.
     * @returns unsubscribe.
     */
    subscribeLexicon?(session: ClientSessionContext, listener: () => void): () => void;
    /** Reference codec; required for sources producing insert outcomes. */
    readonly codec?: ReferenceCodec;
}
/** Trigger availability tier, derived from the input phase by the wiring layer. */
export interface TriggerGuard {
    /** plain: '/' and '@' live; claimed: '/' suppressed, '@' live; frozen: none. */
    readonly tier: 'plain' | 'claimed' | 'frozen';
}
//# sourceMappingURL=types.d.ts.map