@qilin-agent/client-ui-input-trigger 0.0.0-stage → 3.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Input-trigger provider contract. Types only — no runtime code. The
3
+ * conversation input layer owns and exports the shared machine currency;
4
+ * this module re-exports it for trigger providers.
5
+ *
6
+ * Providers receive a {@link ClientSessionContext} projection per call —
7
+ * never a Cordis context or the mutable Session. RPC and service access go
8
+ * through the provider plugin's own root context captured at registration.
9
+ */
10
+ import type { ComponentType } from 'react';
11
+ import type { PickOutcome, ReferenceInsert, TokenSpan } from '@qilin-agent/client-ui-conversation/client';
12
+ import type { IconProps } from '@qilin-agent/client-ui-primitives';
13
+ import type { SessionId } from '@qilin-agent/session/types';
14
+ export type { ArbitrateKey, ArbitrateOutcome, BeginCommandRequest, CommandClaim, ConsumeTokenRequest, InsertReferenceRequest, InsertTextRequest, PickOutcome, ReferenceInsert, SubmitAttachment, SubmitOutcome, TokenSpan, } from '@qilin-agent/client-ui-conversation/client';
15
+ /**
16
+ * The provider-facing projection of one client session. It carries stable
17
+ * identity alone; a source that calls Agent-bound RPCs must consult its own
18
+ * service's capability state because an addressed persisted subagent may
19
+ * have a client scope without a live Host Agent.
20
+ */
21
+ export interface ClientSessionContext {
22
+ readonly sessionId: SessionId;
23
+ }
24
+ /** Trigger character a source binds to. */
25
+ export type TriggerChar = '/' | '@';
26
+ /** Where the trigger token sits in the draft: leading (trimmed draft starts with it) or inline. */
27
+ export type TriggerPosition = 'leading' | 'inline';
28
+ /** Which of the three pick paths produced a pick. */
29
+ export type PickVia = 'menu' | 'space' | 'enter';
30
+ /** What a pick asks for: resolve the candidate, or drill into it in place. */
31
+ export type PickAction = 'pick' | 'drill';
32
+ /** Leading glyph token of one menu candidate, mapped to its reference SVG by the menu view. */
33
+ export type InputTriggerCandidateIcon = 'file' | 'folder' | 'session';
34
+ /** One menu candidate. Pure display data — zero behavior declaration. */
35
+ export interface InputTriggerCandidate {
36
+ /** Identity: the pick payload, the exact-match key, and the first search key. */
37
+ readonly name: string;
38
+ /**
39
+ * Display title; the name itself when absent. A label that is not the
40
+ * name in another letter case renders with the name as a trailing alias,
41
+ * and every label is the second search key (a localized title stays
42
+ * findable by its command name).
43
+ */
44
+ readonly label?: string;
45
+ readonly description?: string;
46
+ /** Reference glyph token, or an icon component from the shared icon set. */
47
+ readonly icon?: InputTriggerCandidateIcon | ComponentType<IconProps>;
48
+ readonly hint?: string;
49
+ /** Optional visual heading shared by adjacent candidates; sectioned groups omit their source-title row. */
50
+ readonly section?: string;
51
+ /** Opaque source-owned pick payload. */
52
+ readonly value?: string;
53
+ /**
54
+ * The row offers a drill action beside the settling pick: Tab or the row's
55
+ * chevron refines the query in place (directory descent) instead of
56
+ * resolving the candidate.
57
+ */
58
+ readonly drill?: boolean;
59
+ }
60
+ /**
61
+ * One crumb of a source's menu header. The pipeline treats `value` as opaque
62
+ * and hands it straight back on pick, so a source names its own destinations.
63
+ */
64
+ export interface InputTriggerCrumb {
65
+ /** Rendered text of this step. */
66
+ readonly label: string;
67
+ /** Opaque source-owned pick payload, returned through `onPick`. */
68
+ readonly value: string;
69
+ /** The step the menu is currently showing; rendered as the trailing, unclickable crumb. */
70
+ readonly current?: boolean;
71
+ }
72
+ /** What a source needs to decide the header of the open menu. */
73
+ export interface HeaderRequest {
74
+ /** Text between the trigger char and the caret, live-filtered. */
75
+ readonly query: string;
76
+ /** Whether the active @file token is an open quoted path. */
77
+ readonly quoted?: boolean;
78
+ /**
79
+ * True while this menu was opened or last re-scoped by a drill pick. It
80
+ * survives further typing and clears when the menu closes, so a query typed
81
+ * after a drill still reads as drilled. The pipeline owns the fact; what it
82
+ * means for a header is the source's to decide.
83
+ */
84
+ readonly drilled: boolean;
85
+ }
86
+ /**
87
+ * Non-text composer submission state visible to enter adjudication. The
88
+ * composer owns the actual attachment payloads; adjudication only needs their
89
+ * presence to accept or refuse a whole submission.
90
+ */
91
+ export interface SubmitEnvelope {
92
+ /** Number of attachments accompanying the draft. */
93
+ readonly attachments: number;
94
+ }
95
+ /** Candidate request passed to a source. The signal is superseded on query change / menu close. */
96
+ export interface CandidateRequest {
97
+ readonly query: string;
98
+ /** Whether the active @file token is an open quoted path. */
99
+ readonly quoted?: boolean;
100
+ readonly position: TriggerPosition;
101
+ /** Whether this menu was opened or last re-scoped by a drill pick; see {@link HeaderRequest.drilled}. */
102
+ readonly drilled: boolean;
103
+ readonly signal: AbortSignal;
104
+ }
105
+ /** Everything a source receives on pick: candidate + session projection + the span snapshot for CAS. */
106
+ export interface InputTriggerPick {
107
+ readonly candidate: InputTriggerCandidate;
108
+ readonly session: ClientSessionContext;
109
+ readonly position: TriggerPosition;
110
+ readonly via: PickVia;
111
+ /** Settling pick, or the candidate's drill action (Tab / row chevron). */
112
+ readonly action: PickAction;
113
+ readonly span: TokenSpan;
114
+ }
115
+ /**
116
+ * Reference codec owned by a source that produces {@link ReferenceInsert}
117
+ * outcomes: the clipboard projection for copy/cut/persistence, and the model
118
+ * serialization invoked per occurrence by the submit attempt (async, abort
119
+ * rides the attempt signal; failure blocks the send — never a silent
120
+ * downgrade to the clipboard text).
121
+ */
122
+ export interface ReferenceCodec {
123
+ /** Clipboard / persistence projection of one reference (e.g. `/name`). */
124
+ clipboardText(ref: string): string;
125
+ /** Model serialization of one reference (e.g. `<skill>name</skill>`). */
126
+ serialize(ref: string, signal: AbortSignal): Promise<string>;
127
+ }
128
+ /**
129
+ * One trigger source. Every callback receives the session's
130
+ * ClientSessionContext projection; sources keep no copy across calls.
131
+ *
132
+ * Space/enter adjudication rides the optional match hooks: implementing one
133
+ * IS the participation claim — the pipeline polls each implementing source
134
+ * with the leading token; the first non-undefined answer wins (registration
135
+ * order); no claimant → default sink. The hooks split because their timing
136
+ * budgets differ: space fires mid-keystroke and must answer synchronously
137
+ * from hot state, while enter may await the source's own warmup.
138
+ */
139
+ export interface InputTriggerSource {
140
+ readonly trigger: TriggerChar;
141
+ /** Menu group label; unique per trigger — duplicate registration throws. */
142
+ readonly name: string;
143
+ /** Menu group display order (lower = higher in the list; default 0). */
144
+ readonly order?: number;
145
+ /** Whether the menu renders the source-title row; defaults to true. */
146
+ readonly showGroupTitle?: boolean;
147
+ candidates(session: ClientSessionContext, req: CandidateRequest): Promise<readonly InputTriggerCandidate[]>;
148
+ /**
149
+ * Synchronous breadcrumb rendered above this source's group, re-polled on
150
+ * every hit. Implementing IS the participation claim; `undefined` means
151
+ * this request needs no header. A crumb pick routes back through
152
+ * {@link InputTriggerSource.onPick} with `action: 'drill'` and the crumb's
153
+ * `value` as the candidate value, so returning to a step and descending
154
+ * into one are the same outcome.
155
+ * @param session - stable session projection.
156
+ * @param req - the live query and how the menu reached it.
157
+ * @returns the crumbs to render, or undefined for no header.
158
+ */
159
+ header?(session: ClientSessionContext, req: HeaderRequest): readonly InputTriggerCrumb[] | undefined;
160
+ /** Every pick lands here; claim/insert outcomes are executed by the pipeline via the scoped input events. */
161
+ onPick(pick: InputTriggerPick): PickOutcome;
162
+ /** Synchronous space-time adjudication over hot state only. `token` is the just-completed leading token (e.g. '/goal'). */
163
+ matchSpace?(session: ClientSessionContext, token: string): PickOutcome;
164
+ /**
165
+ * Enter-time adjudication; may strong-wait the source's own warmup and
166
+ * reject on warmup failure. `line` is the full trimmed draft: the source
167
+ * parses it and applies its own kind policy — args-tolerant kinds claim
168
+ * with trailing text present, bare-token-only kinds answer undefined
169
+ * unless the line is exactly the token. `envelope` describes the rest of
170
+ * the composer submission; a source that would consume the line but cannot
171
+ * consume the whole envelope throws to surface the refusal and leave the
172
+ * submission intact.
173
+ */
174
+ matchEnter?(session: ClientSessionContext, line: string, signal: AbortSignal, envelope: SubmitEnvelope): Promise<PickOutcome>;
175
+ /**
176
+ * Scope-birth prewarm hook (fire-and-forget): the per-session controller
177
+ * calls it once when the session scope comes alive so sources can fetch
178
+ * their backing data before the first interaction.
179
+ */
180
+ warm?(session: ClientSessionContext): void;
181
+ /**
182
+ * Synchronous hot-snapshot name roll for plain-text reference decoration.
183
+ * Implementing IS the participation claim: the render side
184
+ * scans the draft for `<trigger><name>` tokens and decorates exact matches.
185
+ * `undefined` = backing data not warm yet — no decoration, never a fetch
186
+ * (the render path must stay synchronous and side-effect free).
187
+ */
188
+ lexicon?(session: ClientSessionContext): readonly string[] | undefined;
189
+ /**
190
+ * Subscribe to changes of this source's {@link InputTriggerSource.lexicon} answer
191
+ * for one session (backing data settled, invalidated, or refreshed). The
192
+ * controller re-polls lexicon on each notification; a source whose roll
193
+ * never changes after warm omits the hook.
194
+ * @param session - stable session projection.
195
+ * @param listener - invalidation callback.
196
+ * @returns unsubscribe.
197
+ */
198
+ subscribeLexicon?(session: ClientSessionContext, listener: () => void): () => void;
199
+ /**
200
+ * Open a reference preview without changing or submitting the draft.
201
+ * @param session - session owning the composer.
202
+ * @param reference - source-owned id and optional chip glyph; text references retain their trigger.
203
+ * @returns whether this source accepted the preview, possibly awaiting its catalog; false leaves the editor gesture unchanged.
204
+ */
205
+ openReference?(session: ClientSessionContext, reference: Pick<ReferenceInsert, 'ref' | 'appearance'>): boolean;
206
+ /** Reference codec; required for sources producing insert outcomes. */
207
+ readonly codec?: ReferenceCodec;
208
+ }
209
+ /** Trigger availability tier, derived from the input phase by the wiring layer. */
210
+ export interface TriggerGuard {
211
+ /** plain: '/' and '@' live; claimed: '/' suppressed, '@' live; frozen: none. */
212
+ readonly tier: 'plain' | 'claimed' | 'frozen';
213
+ }
214
+ //# sourceMappingURL=types.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,73 @@
1
1
  {
2
2
  "name": "@qilin-agent/client-ui-input-trigger",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "description": "Input trigger pipeline: '/' and '@' detection, candidate menu, pick routing to registered sources",
4
+ "version": "3.1.3",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/kkutysllb/QiLin.git",
11
+ "directory": "packages/client/ui-input-trigger"
12
+ },
13
+ "engines": {
14
+ "node": "^22.19.0 || >=24.0.0"
15
+ },
16
+ "type": "module",
17
+ "main": "lib/index.js",
18
+ "types": "lib/types/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./lib/types/index.d.ts",
22
+ "default": "./lib/index.js"
23
+ },
24
+ "./client": {
25
+ "types": "./lib/types/client/index.d.ts",
26
+ "default": "./lib/client.js"
27
+ },
28
+ "./src/*": "./src/*",
29
+ "./package.json": "./package.json"
30
+ },
31
+ "qilin": {
32
+ "client": {
33
+ "inject": [
34
+ "@qilin-agent/api-session-controller",
35
+ "@qilin-agent/client-locale",
36
+ "@qilin-agent/client-ui-conversation",
37
+ "@qilin-agent/client-ui-renderer"
38
+ ],
39
+ "platform": "web"
40
+ }
41
+ },
42
+ "license": "MIT",
43
+ "peerDependencies": {
44
+ "@qilin-agent/kylin": "~4.0.3"
45
+ },
46
+ "devDependencies": {
47
+ "@types/react": "~18.3.1",
48
+ "react": "^18.2.0",
49
+ "clsx": "^2.0.0",
50
+ "@qilin-agent/client-locale": "3.1.3",
51
+ "@qilin-agent/client-ui-conversation": "3.1.3",
52
+ "@qilin-agent/client-ui-renderer": "3.1.3",
53
+ "@qilin-agent/client-test-runtime": "3.1.3",
54
+ "@qilin-agent/client-ui-primitives": "3.1.3",
55
+ "@qilin-agent/client-ui-slots": "3.1.3",
56
+ "@qilin-agent/kylin": "~4.0.3",
57
+ "@qilin-agent/file-reference": "3.1.3",
58
+ "@qilin-agent/api-session-controller": "3.1.3",
59
+ "@qilin-agent/util-values": "3.1.3",
60
+ "@qilin-agent/client-store": "3.1.3",
61
+ "@qilin-agent/client-ui-session": "3.1.3",
62
+ "@qilin-agent/session": "3.1.3"
63
+ },
64
+ "files": [
65
+ "lib/index.js",
66
+ "lib/client.js",
67
+ "lib/types/**/*.d.ts"
68
+ ],
69
+ "scripts": {
70
+ "bundle": "tsdown",
71
+ "watch": "tsdown --watch"
72
+ }
6
73
  }