@deepseek-ai/dsh-client-ui-conversation 0.0.1-rc.1
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.
- package/LICENSE +28 -0
- package/README.i18n.yaml +6 -0
- package/README.md +65 -0
- package/README.zh.md +65 -0
- package/lib/client.js +9612 -0
- package/lib/index.js +28 -0
- package/lib/invariant.js +25 -0
- package/lib/types/client/apply.d.ts +16 -0
- package/lib/types/client/chat/AssistantMarkdown.d.ts +19 -0
- package/lib/types/client/chat/AssistantNodeView.d.ts +4 -0
- package/lib/types/client/chat/ChatNodeSeat.d.ts +11 -0
- package/lib/types/client/chat/ChatView.d.ts +7 -0
- package/lib/types/client/chat/CommandNodeView.d.ts +9 -0
- package/lib/types/client/chat/CompactionCommandCard.d.ts +8 -0
- package/lib/types/client/chat/CompactionItem.d.ts +19 -0
- package/lib/types/client/chat/ContextBody.d.ts +130 -0
- package/lib/types/client/chat/ContextInjectionRow.d.ts +26 -0
- package/lib/types/client/chat/GenericCommandCard.d.ts +9 -0
- package/lib/types/client/chat/MessageIconActions.d.ts +30 -0
- package/lib/types/client/chat/MessageImage.d.ts +20 -0
- package/lib/types/client/chat/MessageItem.d.ts +27 -0
- package/lib/types/client/chat/ReasoningRow.d.ts +14 -0
- package/lib/types/client/chat/StatsLine.d.ts +83 -0
- package/lib/types/client/chat/TurnTailNodeView.d.ts +7 -0
- package/lib/types/client/chat/message-chrome.d.ts +49 -0
- package/lib/types/client/chat/register-node-renderers.d.ts +7 -0
- package/lib/types/client/chat/tool-node-reader.d.ts +16 -0
- package/lib/types/client/chat/turn-assistant.d.ts +8 -0
- package/lib/types/client/chat/turn-metrics.d.ts +38 -0
- package/lib/types/client/chat/use-calendar-day.d.ts +6 -0
- package/lib/types/client/chat/use-throttled-visual-update.d.ts +8 -0
- package/lib/types/client/contract/chat-nodes.d.ts +68 -0
- package/lib/types/client/contract/composer-submission.d.ts +8 -0
- package/lib/types/client/contract/queue.d.ts +9 -0
- package/lib/types/client/contract/slots.d.ts +614 -0
- package/lib/types/client/contract/views.d.ts +39 -0
- package/lib/types/client/conversation-nodes/assistant.d.ts +35 -0
- package/lib/types/client/conversation-nodes/chat-snapshot-builder.d.ts +28 -0
- package/lib/types/client/conversation-nodes/command.d.ts +54 -0
- package/lib/types/client/conversation-nodes/common.d.ts +37 -0
- package/lib/types/client/conversation-nodes/compaction.d.ts +21 -0
- package/lib/types/client/conversation-nodes/fallback.d.ts +16 -0
- package/lib/types/client/conversation-nodes/inbox.d.ts +21 -0
- package/lib/types/client/conversation-nodes/message.d.ts +22 -0
- package/lib/types/client/conversation-nodes/register.d.ts +7 -0
- package/lib/types/client/conversation-nodes/retry.d.ts +23 -0
- package/lib/types/client/conversation-nodes/tool.d.ts +23 -0
- package/lib/types/client/conversation-nodes/turn-error.d.ts +27 -0
- package/lib/types/client/conversation-nodes/turn-tail.d.ts +28 -0
- package/lib/types/client/index.d.ts +29 -0
- package/lib/types/client/input/blocks.d.ts +57 -0
- package/lib/types/client/input/contract.d.ts +333 -0
- package/lib/types/client/input/decorations.d.ts +63 -0
- package/lib/types/client/input/facade.d.ts +219 -0
- package/lib/types/client/input/hub.d.ts +88 -0
- package/lib/types/client/input/machine.d.ts +114 -0
- package/lib/types/client/input/submission-policy.d.ts +46 -0
- package/lib/types/client/locales.d.ts +312 -0
- package/lib/types/client/queue/QueueDock.d.ts +29 -0
- package/lib/types/client/queue/store.d.ts +19 -0
- package/lib/types/client/service.d.ts +148 -0
- package/lib/types/client/settings/EnterBehaviorRow.d.ts +21 -0
- package/lib/types/client/skeleton/ApprovalPanel.d.ts +13 -0
- package/lib/types/client/skeleton/ContextMeter.d.ts +14 -0
- package/lib/types/client/skeleton/ConversationRoot.d.ts +5 -0
- package/lib/types/client/skeleton/ConversationSession.d.ts +20 -0
- package/lib/types/client/skeleton/DetailsPanel.d.ts +5 -0
- package/lib/types/client/skeleton/EmptyHero.d.ts +55 -0
- package/lib/types/client/skeleton/ImageLightbox.d.ts +9 -0
- package/lib/types/client/skeleton/InputBar.d.ts +16 -0
- package/lib/types/client/skeleton/PermissionSelect.d.ts +11 -0
- package/lib/types/client/skeleton/TodoPanel.d.ts +28 -0
- package/lib/types/client/stores.d.ts +22 -0
- package/lib/types/index.d.ts +9 -0
- package/lib/types/invariant.d.ts +16 -0
- package/lib/types/submission-settings.d.ts +20 -0
- package/package.json +105 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frozen input-machine contract. Types
|
|
3
|
+
* only. Three-tier visibility: business packages see InputState via the
|
|
4
|
+
* InputZone currency; the scoped input events carry the mutation verbs; the
|
|
5
|
+
* conversation wiring layer alone sees the full SessionInput. InputMachine
|
|
6
|
+
* (machine.ts) is package-private and never exported.
|
|
7
|
+
*/
|
|
8
|
+
import type { ClientContext, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client';
|
|
9
|
+
import type { Branded } from '@deepseek-ai/dsh-brand';
|
|
10
|
+
import type { ArbitrateKey, ArbitrateOutcome, CommandClaim, ConsumeTokenRequest, PickOutcome, ReferenceInsert, SubmitOutcome, TokenSpan } from '@deepseek-ai/dsh-client-ui-slash/client';
|
|
11
|
+
import type { QueueRow } from '../contract/queue.ts';
|
|
12
|
+
import type { InputSubmitMode } from '../contract/composer-submission.ts';
|
|
13
|
+
/** Browser-runtime identity of one unsent image draft. */
|
|
14
|
+
export type DraftAttachmentId = Branded<'DraftAttachmentId'>;
|
|
15
|
+
/**
|
|
16
|
+
* The scoped-event application verbs: the hub's bail listeners call these,
|
|
17
|
+
* and the boolean answer IS the event's bail value (true ⟺ the machine
|
|
18
|
+
* accepted after phase and span/bare-token guards).
|
|
19
|
+
*/
|
|
20
|
+
export interface InputTarget {
|
|
21
|
+
/** Replace the trigger span with claim.token and enter claimed (span-CAS'd). */
|
|
22
|
+
beginCommand(claim: CommandClaim, span: TokenSpan): boolean;
|
|
23
|
+
/** Replace the trigger span with one reference occurrence (span-CAS'd). */
|
|
24
|
+
insertReference(ref: ReferenceInsert, span: TokenSpan): boolean;
|
|
25
|
+
}
|
|
26
|
+
/** Per-session input facade owned by the conversation wiring layer. */
|
|
27
|
+
export interface SessionInput extends InputTarget {
|
|
28
|
+
/** Single write path for draft text (all mutation rides machine events). */
|
|
29
|
+
setDraft(text: string): void;
|
|
30
|
+
/** Append ordered browser-owned image ids; busy admission phases refuse. */
|
|
31
|
+
addImages(ids: readonly DraftAttachmentId[]): boolean;
|
|
32
|
+
/** Remove one browser-owned image id. */
|
|
33
|
+
removeImage(id: DraftAttachmentId): void;
|
|
34
|
+
/** Drop ids whose browser-owned objects no longer exist. */
|
|
35
|
+
pruneImages(ids: readonly DraftAttachmentId[]): void;
|
|
36
|
+
/**
|
|
37
|
+
* THE complexity sink: enter adjudication, submit transaction, and the default sink live inside.
|
|
38
|
+
* @param mode - delivery intent retained through asynchronous adjudication and serialization.
|
|
39
|
+
*/
|
|
40
|
+
submit(mode?: InputSubmitMode): void;
|
|
41
|
+
/**
|
|
42
|
+
* Surface a notice outside the machine's own effect stream: detached
|
|
43
|
+
* command results and business notifications render through here.
|
|
44
|
+
* Session-routed — resolving the facade via InputService.for(actx) lands
|
|
45
|
+
* the notice on that session's composer, so a result arriving after a
|
|
46
|
+
* session switch still reaches its own session.
|
|
47
|
+
* @param level - severity tier.
|
|
48
|
+
* @param text - notice body.
|
|
49
|
+
*/
|
|
50
|
+
notify(level: 'info' | 'error', text: string): void;
|
|
51
|
+
/** Input state store (InputZone currency + decorations read here). */
|
|
52
|
+
readonly state: SnapshotStore<InputState>;
|
|
53
|
+
}
|
|
54
|
+
/** Session-addressed access to the per-session input facade. */
|
|
55
|
+
export interface InputService {
|
|
56
|
+
/** Resolve the facade for one session-scope ctx. */
|
|
57
|
+
for(actx: ClientContext): SessionInput;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The public input action face provided to every session-scope slot
|
|
61
|
+
* component: two stable-identity void callbacks, mirroring the
|
|
62
|
+
* useStore+actions convention. Command-style handles (track/arbitrate/space/
|
|
63
|
+
* undo/paste/…) stay InputBar-private and never ride this face.
|
|
64
|
+
*/
|
|
65
|
+
export interface InputActions {
|
|
66
|
+
/** Single public draft write path (full next draft; occurrence math via diff scan). */
|
|
67
|
+
setDraft(text: string): void;
|
|
68
|
+
/** Append ordered browser-owned image ids; busy admission phases refuse. */
|
|
69
|
+
addImages(ids: readonly DraftAttachmentId[]): boolean;
|
|
70
|
+
/** Remove one browser-owned image id. */
|
|
71
|
+
removeImage(id: DraftAttachmentId): void;
|
|
72
|
+
/** Drop ids whose browser-owned objects no longer exist. */
|
|
73
|
+
pruneImages(ids: readonly DraftAttachmentId[]): void;
|
|
74
|
+
/** Enter submission (adjudication / claim transaction / default sink inside). */
|
|
75
|
+
submit(): void;
|
|
76
|
+
}
|
|
77
|
+
/** One surfaced notice (command results, adjudication failures). seq keys re-render of repeats. */
|
|
78
|
+
export interface InputNotice {
|
|
79
|
+
readonly level: 'info' | 'error';
|
|
80
|
+
readonly text: string;
|
|
81
|
+
readonly seq: number;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The InputBar-exclusive keyboard/DOM command face: synchronous
|
|
85
|
+
* returns and event-handler semantics that must not enter the public provide
|
|
86
|
+
* channel. Handed to the composer-bar entry through its own inject —
|
|
87
|
+
* package-internal, never across a plugin boundary. The session shell
|
|
88
|
+
* satisfies it structurally.
|
|
89
|
+
*/
|
|
90
|
+
export interface ComposerKeyboard {
|
|
91
|
+
/** Live machine state for event-handler reads (render reads go through useInput). */
|
|
92
|
+
readonly snapshot: InputState;
|
|
93
|
+
/** Draft write with the DOM-observed edit shape (narrows occurrence math). */
|
|
94
|
+
setDraft(text: string, editRange?: EditRange): void;
|
|
95
|
+
/** Submit with an explicit delivery mode resolved by the keyboard policy. */
|
|
96
|
+
submit(mode: InputSubmitMode): void;
|
|
97
|
+
/**
|
|
98
|
+
* Steer every still-pending queued message into the running turn (the
|
|
99
|
+
* empty-draft accelerated-Enter gesture; the queue dock's per-row steer
|
|
100
|
+
* button is the same operation applied to the whole queue).
|
|
101
|
+
*/
|
|
102
|
+
steerQueue(): void;
|
|
103
|
+
undo(): void;
|
|
104
|
+
redo(): void;
|
|
105
|
+
/** Paste over the selection (sync components ride the same transaction). */
|
|
106
|
+
pasteBegin(text: string, selection: EditSelection, components?: readonly PasteComponent[], generation?: number): void;
|
|
107
|
+
/** Caret/selection gestures the machine cannot observe end the paste attempt. */
|
|
108
|
+
invalidatePaste(): void;
|
|
109
|
+
/** Feed a draft/caret change through trigger detection (guard derived from phase). */
|
|
110
|
+
track(draft: string, caret: number): void;
|
|
111
|
+
/** Keyboard arbitration while the menu is open ('pass' when no pipeline). */
|
|
112
|
+
arbitrate(key: ArbitrateKey, composing: boolean): ArbitrateOutcome;
|
|
113
|
+
/** Space adjudication; true = the input applied a claim — caller preventDefaults. */
|
|
114
|
+
space(): boolean;
|
|
115
|
+
/** Dismiss the popupSelect shell (any interaction outside the box). */
|
|
116
|
+
dismissPopup(): void;
|
|
117
|
+
}
|
|
118
|
+
/** One independently addressable row projected from the transient queue snapshot. */
|
|
119
|
+
export type QueuedMessage = QueueRow;
|
|
120
|
+
/** Guard union of the scoped consume-token event, checked by the machine. */
|
|
121
|
+
export type ConsumeTokenGuard = ConsumeTokenRequest['guard'];
|
|
122
|
+
/** Half-open [start, end) range/selection in draft character coordinates. */
|
|
123
|
+
export interface EditSelection {
|
|
124
|
+
readonly start: number;
|
|
125
|
+
readonly end: number;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* One edit applied to the previous draft: [start, end) in the PREVIOUS
|
|
129
|
+
* draft's coordinates was replaced by insertedLength characters. Supplied by
|
|
130
|
+
* the wiring layer when the DOM event exposes the edit shape; absent, the
|
|
131
|
+
* machine recovers it with a prefix/suffix common-scan diff.
|
|
132
|
+
*/
|
|
133
|
+
export interface EditRange extends EditSelection {
|
|
134
|
+
readonly insertedLength: number;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* One reference chip occurrence, backing exactly one U+FFFC placeholder in
|
|
138
|
+
* the draft. Identity is occurrenceId — same-named
|
|
139
|
+
* references stay independently addressable. label/clipboardText are the
|
|
140
|
+
* owner's insert-time projections, cached so the chip survives owner loss
|
|
141
|
+
* (invalid flips instead of dropping the occurrence).
|
|
142
|
+
*/
|
|
143
|
+
export interface Occurrence {
|
|
144
|
+
/** Machine-minted stable identity (monotonic per machine). */
|
|
145
|
+
readonly occurrenceId: number;
|
|
146
|
+
/** Owning source name (serializer routing key). */
|
|
147
|
+
readonly source: string;
|
|
148
|
+
/** Owner-scoped reference id. */
|
|
149
|
+
readonly ref: string;
|
|
150
|
+
/** Placeholder offset in the draft; the occurrence occupies exactly [offset, offset+1). */
|
|
151
|
+
readonly offset: number;
|
|
152
|
+
/** Chip display label (insert-time cache). */
|
|
153
|
+
readonly label: string;
|
|
154
|
+
/** Clipboard / persistence projection, e.g. `/name` (insert-time cache, never the model form). */
|
|
155
|
+
readonly clipboardText: string;
|
|
156
|
+
/** Owner-resolution failure flag: chip renders invalid; serialization must fail. */
|
|
157
|
+
readonly invalid?: boolean;
|
|
158
|
+
}
|
|
159
|
+
/** One sync-matched paste component; start/end are relative to the pasted text. */
|
|
160
|
+
export interface PasteComponent extends EditSelection {
|
|
161
|
+
readonly reference: ReferenceInsert;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Live paste-match attempt published while async matching may still upgrade
|
|
165
|
+
* pasted tokens (the clipboard round-trip). Any non-paste transaction,
|
|
166
|
+
* submit start, invalidate-paste, or release ends it; a paste-upgrade keeps
|
|
167
|
+
* it current (later tokens re-CAS against the advanced draftRev).
|
|
168
|
+
*/
|
|
169
|
+
export interface PasteAttemptState {
|
|
170
|
+
/** Machine-minted attempt identity (paste-upgrade must match it). */
|
|
171
|
+
readonly attemptId: number;
|
|
172
|
+
/** Pasted range in the draft as of the paste transaction. */
|
|
173
|
+
readonly insertedRange: EditSelection;
|
|
174
|
+
/** Caller-supplied projection generation echoed back (the controller drops cross-generation results). */
|
|
175
|
+
readonly generation: number;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* InputMachine construction knobs. The machine never reads an ambient clock:
|
|
179
|
+
* `now` is the only time source, injected by the shell (tests inject a
|
|
180
|
+
* fake). The default clock is constant, i.e. consecutive single-char typing
|
|
181
|
+
* always coalesces until a non-typing transaction intervenes.
|
|
182
|
+
*/
|
|
183
|
+
export interface InputMachineOptions {
|
|
184
|
+
/** Single-char typing undo-merge window in ms (default 1000). */
|
|
185
|
+
readonly mergeWindowMs?: number;
|
|
186
|
+
/** Monotonic clock for typing-merge decisions (default: constant 0). */
|
|
187
|
+
readonly now?: () => number;
|
|
188
|
+
}
|
|
189
|
+
/** Published input state (the currency; per-session). */
|
|
190
|
+
export interface InputState {
|
|
191
|
+
readonly draft: string;
|
|
192
|
+
/** Ordered runtime-only image ids; bytes and URLs stay in ConversationService. */
|
|
193
|
+
readonly imageIds: readonly DraftAttachmentId[];
|
|
194
|
+
/** Monotonic draft revision (span CAS compares against this). */
|
|
195
|
+
readonly draftRev: number;
|
|
196
|
+
readonly phase: 'plain' | 'adjudicating' | 'claimed' | 'submitting';
|
|
197
|
+
/** Present exactly while claimed/submitting (claim snapshot during flight; submit closure withheld). */
|
|
198
|
+
readonly claim?: {
|
|
199
|
+
readonly token: string;
|
|
200
|
+
readonly hint?: string;
|
|
201
|
+
};
|
|
202
|
+
/** Chip occurrence table, sorted by offset (one U+FFFC per entry). */
|
|
203
|
+
readonly occurrences: readonly Occurrence[];
|
|
204
|
+
/** Live paste-match attempt (absent when no paste is matchable). */
|
|
205
|
+
readonly paste?: PasteAttemptState;
|
|
206
|
+
/** Read-only transient inbox projection (`session/queue`, including pending steering). */
|
|
207
|
+
readonly queue: readonly QueuedMessage[];
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* One in-flight submission attempt: the ONLY id concept in the submit plane.
|
|
211
|
+
* Created on enter; carried by adjudicated/submit-settled events; stale
|
|
212
|
+
* attempts are dropped (anti-backwash). release/session teardown aborts the
|
|
213
|
+
* current attempt, keeping the promise bounded.
|
|
214
|
+
*/
|
|
215
|
+
export interface SubmitAttempt {
|
|
216
|
+
readonly seq: number;
|
|
217
|
+
readonly signal: AbortSignal;
|
|
218
|
+
/** Draft at enter time; rollback restores it only while the live draft still equals it. */
|
|
219
|
+
readonly draftSnapshot: string;
|
|
220
|
+
/** Default-message delivery intent retained while slash adjudication is pending. */
|
|
221
|
+
readonly mode: InputSubmitMode;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* InputMachine input events (the machine's single write path). Every draft
|
|
225
|
+
* mutation is one transaction: draft edit, occurrence reconciliation, and
|
|
226
|
+
* undo-log push are atomic inside dispatch(). Events carrying `at` stamp the
|
|
227
|
+
* injected clock reading; only single-char typing coalescing reads it.
|
|
228
|
+
*/
|
|
229
|
+
export type InputEvent =
|
|
230
|
+
/** Full next draft from the textarea; editRange narrows the occurrence math (absent → diff scan). */
|
|
231
|
+
{
|
|
232
|
+
readonly type: 'draft-changed';
|
|
233
|
+
readonly draft: string;
|
|
234
|
+
readonly editRange?: EditRange;
|
|
235
|
+
} | {
|
|
236
|
+
readonly type: 'begin-command';
|
|
237
|
+
readonly claim: CommandClaim;
|
|
238
|
+
readonly span: TokenSpan;
|
|
239
|
+
}
|
|
240
|
+
/** Place one U+FFFC at the span and mint the occurrence (scoped insert-reference event payload). */
|
|
241
|
+
| {
|
|
242
|
+
readonly type: 'insert-ref';
|
|
243
|
+
readonly reference: ReferenceInsert;
|
|
244
|
+
readonly span: TokenSpan;
|
|
245
|
+
}
|
|
246
|
+
/** Delete a settled command token; success is observable as a draftRev advance. */
|
|
247
|
+
| {
|
|
248
|
+
readonly type: 'consume-token';
|
|
249
|
+
readonly guard: ConsumeTokenGuard;
|
|
250
|
+
}
|
|
251
|
+
/** Owner-resolution result: exactly the listed occurrences are invalid (style bit; not a transaction). */
|
|
252
|
+
| {
|
|
253
|
+
readonly type: 'set-invalid';
|
|
254
|
+
readonly invalidIds: readonly number[];
|
|
255
|
+
} | {
|
|
256
|
+
readonly type: 'undo';
|
|
257
|
+
} | {
|
|
258
|
+
readonly type: 'redo';
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Paste text replacing the selection, one transaction. Hot-snapshot sync
|
|
262
|
+
* matches ride in as components (chips minted inside the SAME transaction:
|
|
263
|
+
* one undo returns to pre-paste); a PasteMatchAttempt opens for the async
|
|
264
|
+
* remainder. Component ranges must be disjoint and inside the pasted text.
|
|
265
|
+
*/
|
|
266
|
+
| {
|
|
267
|
+
readonly type: 'paste-begin';
|
|
268
|
+
readonly text: string;
|
|
269
|
+
readonly selection: EditSelection;
|
|
270
|
+
readonly components?: readonly PasteComponent[];
|
|
271
|
+
readonly generation?: number;
|
|
272
|
+
}
|
|
273
|
+
/** Async match landed: upgrade one pasted token to a chip as an INDEPENDENT transaction (undo #1 → text, undo #2 → pre-paste). */
|
|
274
|
+
| {
|
|
275
|
+
readonly type: 'paste-upgrade';
|
|
276
|
+
readonly attemptId: number;
|
|
277
|
+
readonly span: TokenSpan;
|
|
278
|
+
readonly reference: ReferenceInsert;
|
|
279
|
+
}
|
|
280
|
+
/** Shell-observed attempt killers the machine cannot see itself (caret/selection ops, Slash interaction updates). */
|
|
281
|
+
| {
|
|
282
|
+
readonly type: 'invalidate-paste';
|
|
283
|
+
} | {
|
|
284
|
+
readonly type: 'enter';
|
|
285
|
+
readonly mode: InputSubmitMode;
|
|
286
|
+
} | {
|
|
287
|
+
readonly type: 'adjudicated';
|
|
288
|
+
readonly attempt: SubmitAttempt;
|
|
289
|
+
readonly outcome: PickOutcome;
|
|
290
|
+
} | {
|
|
291
|
+
readonly type: 'adjudication-failed';
|
|
292
|
+
readonly attempt: SubmitAttempt;
|
|
293
|
+
readonly message: string;
|
|
294
|
+
} | {
|
|
295
|
+
readonly type: 'submit-settled';
|
|
296
|
+
readonly attempt: SubmitAttempt;
|
|
297
|
+
readonly ok: boolean;
|
|
298
|
+
readonly outcome?: SubmitOutcome;
|
|
299
|
+
readonly message?: string;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* An ordinary (default-sink) send was accepted: clear the draft as a COMMIT —
|
|
303
|
+
* undo must not resurrect sent content (mirrors submit-settled's success arm).
|
|
304
|
+
*/
|
|
305
|
+
| {
|
|
306
|
+
readonly type: 'send-committed';
|
|
307
|
+
} | {
|
|
308
|
+
readonly type: 'release';
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* InputMachine output effects (executed by the SessionInput shell; the
|
|
312
|
+
* machine stays pure). Draft/occurrence mutations carry no effect — the
|
|
313
|
+
* shell publishes the state store after every dispatch.
|
|
314
|
+
*/
|
|
315
|
+
export type InputEffect = {
|
|
316
|
+
readonly type: 'adjudicate';
|
|
317
|
+
readonly attempt: SubmitAttempt;
|
|
318
|
+
readonly draft: string;
|
|
319
|
+
} | {
|
|
320
|
+
readonly type: 'begin-submit';
|
|
321
|
+
readonly attempt: SubmitAttempt;
|
|
322
|
+
readonly claim: CommandClaim;
|
|
323
|
+
readonly args: string;
|
|
324
|
+
} | {
|
|
325
|
+
readonly type: 'default-sink';
|
|
326
|
+
readonly draft: string;
|
|
327
|
+
readonly mode: InputSubmitMode;
|
|
328
|
+
} | {
|
|
329
|
+
readonly type: 'notice';
|
|
330
|
+
readonly level: 'info' | 'error';
|
|
331
|
+
readonly text: string;
|
|
332
|
+
};
|
|
333
|
+
//# sourceMappingURL=contract.d.ts.map
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Draft decoration pure core (chips render from the occurrence
|
|
3
|
+
* table at placeholder offsets; the claim token renders as a mirror-layer
|
|
4
|
+
* highlight, the claim hint as ghost text). Zero React — the skeleton renders
|
|
5
|
+
* the instructions; tests drive this directly.
|
|
6
|
+
*/
|
|
7
|
+
import type { InputState } from './contract.ts';
|
|
8
|
+
/** The claim-token highlight range (always draft-leading while the watch holds). */
|
|
9
|
+
export interface TokenRange {
|
|
10
|
+
readonly start: number;
|
|
11
|
+
readonly end: number;
|
|
12
|
+
}
|
|
13
|
+
/** One chip render instruction: the placeholder at `offset` draws as `label`. */
|
|
14
|
+
export interface ChipRender {
|
|
15
|
+
/** Stable render key (same-labeled chips stay independent). */
|
|
16
|
+
readonly occurrenceId: number;
|
|
17
|
+
/** Placeholder offset in the draft (the chip occupies [offset, offset+1)). */
|
|
18
|
+
readonly offset: number;
|
|
19
|
+
readonly label: string;
|
|
20
|
+
/** Owner-resolution failure styling bit. */
|
|
21
|
+
readonly invalid: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* One plain-text reference range (the plain-text-reference decision;
|
|
25
|
+
* see .agents/notes/implemented/architecture/2026-07-25-web-input-machine-and-slash-pipeline.md):
|
|
26
|
+
* a `/name` or `@name` token
|
|
27
|
+
* whose name is on the trigger's lexicon. Pure derivation — editing the text
|
|
28
|
+
* out of match shape simply drops the range next scan.
|
|
29
|
+
*/
|
|
30
|
+
export interface TextRefRange {
|
|
31
|
+
readonly start: number;
|
|
32
|
+
readonly end: number;
|
|
33
|
+
readonly trigger: '/' | '@';
|
|
34
|
+
}
|
|
35
|
+
/** Decoration product: claim token range + chip instructions + text-ref ranges + the ghost hint. */
|
|
36
|
+
export interface DraftDecorations {
|
|
37
|
+
/** Claim token range while claimed/submitting and the prefix watch holds; null otherwise. */
|
|
38
|
+
readonly token: TokenRange | null;
|
|
39
|
+
/** Chip render instructions in draft order (occurrence table is offset-sorted). */
|
|
40
|
+
readonly chips: readonly ChipRender[];
|
|
41
|
+
/** Scan-derived plain-text reference ranges (empty without a lexicon). */
|
|
42
|
+
readonly textRefs: readonly TextRefRange[];
|
|
43
|
+
/** Ghost hint shown while the claim's args are blank; null otherwise. */
|
|
44
|
+
readonly hint: string | null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Scan the draft for plain-text reference tokens against the hot lexicons.
|
|
48
|
+
* Word-boundary discipline: the trigger must sit at the draft
|
|
49
|
+
* start or after whitespace ('x/name' never matches); the name must be an
|
|
50
|
+
* exact lexicon member.
|
|
51
|
+
* @param draft - draft text.
|
|
52
|
+
* @param lexicon - per-trigger name lists (a missing trigger scans nothing).
|
|
53
|
+
* @returns matched ranges in draft order.
|
|
54
|
+
*/
|
|
55
|
+
export declare function scanTextRefs(draft: string, lexicon: ReadonlyMap<'/' | '@', readonly string[]>): TextRefRange[];
|
|
56
|
+
/**
|
|
57
|
+
* Derive the mirror-layer decorations from the input state.
|
|
58
|
+
* @param state - published input state.
|
|
59
|
+
* @param lexicon - optional per-trigger reference lexicons (plain-text-reference scan).
|
|
60
|
+
* @returns token range, chip instructions, text-ref ranges, and the ghost hint.
|
|
61
|
+
*/
|
|
62
|
+
export declare function deriveDecorations(state: InputState, lexicon?: ReadonlyMap<'/' | '@', readonly string[]>): DraftDecorations;
|
|
63
|
+
//# sourceMappingURL=decorations.d.ts.map
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionInput shell over the pure input machine: the sole machine caller
|
|
3
|
+
* and effect executor. Owns the InputState store (machine state + the queue
|
|
4
|
+
* overlay), the notice channel, and the submit transaction plumbing
|
|
5
|
+
* (adjudicate via the session's SlashController; claim.submit; default
|
|
6
|
+
* sink). Package-private; the hub alone constructs it and wires the scoped
|
|
7
|
+
* event listeners onto it.
|
|
8
|
+
*/
|
|
9
|
+
import type { ClientContext, ObservableSnapshot, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client';
|
|
10
|
+
import type { ArbitrateKey, ArbitrateOutcome, CommandClaim, ConsumeTokenRequest, ReferenceInsert, SlashController, TokenSpan } from '@deepseek-ai/dsh-client-ui-slash/client';
|
|
11
|
+
import type { DraftAttachmentId, EditRange, EditSelection, InputActions, InputNotice, InputState, PasteComponent, QueuedMessage, SessionInput } from './contract.ts';
|
|
12
|
+
import type { InputSubmitMode } from '../contract/composer-submission.ts';
|
|
13
|
+
/** Popup face the shell needs (dismissal only; typed structurally to avoid a value import). */
|
|
14
|
+
export interface PopupDismissFace {
|
|
15
|
+
dismiss(): void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Construction dependencies of one facade. The slash/popup faces are THUNKS: the
|
|
19
|
+
* shell is created inside the sessions provide materialization (before the
|
|
20
|
+
* scope record is queryable), where `slash.sessionOf`/`command.popupFor`
|
|
21
|
+
* cannot resolve yet — resolution defers to first interactive use.
|
|
22
|
+
*/
|
|
23
|
+
export interface SessionInputDeps {
|
|
24
|
+
/** Session-scope ctx handed to claim.submit transactions. */
|
|
25
|
+
actx: ClientContext;
|
|
26
|
+
/** Enter adjudication face resolver; absent/undefined answer = every '/' line falls to the default sink. */
|
|
27
|
+
slash?: (() => SlashController | undefined) | undefined;
|
|
28
|
+
/** PopupSelect shell face resolver (dismissal on submit lock / escape). */
|
|
29
|
+
popup?: (() => PopupDismissFace | undefined) | undefined;
|
|
30
|
+
/** Queue read face; overlaid onto InputState.queue (absent = empty). */
|
|
31
|
+
queue?: ObservableSnapshot<readonly QueuedMessage[]> | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Steer every still-pending queued message into the running turn, in FIFO
|
|
34
|
+
* order (the empty-draft accelerated-Enter gesture); absent = unsupported.
|
|
35
|
+
*/
|
|
36
|
+
steerQueue?: (() => void) | undefined;
|
|
37
|
+
/** The plain-message sink (send choreography / materialize fork — the hub owns it). */
|
|
38
|
+
defaultSink(text: string, imageIds: readonly DraftAttachmentId[], mode: InputSubmitMode): void;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The per-session input facade: scoped-event application verbs +
|
|
42
|
+
* setDraft/submit + the published InputState store.
|
|
43
|
+
*/
|
|
44
|
+
export declare class SessionInputShell implements SessionInput {
|
|
45
|
+
private readonly deps;
|
|
46
|
+
/** Published machine state + queue overlay (the InputZone currency source). */
|
|
47
|
+
readonly state: SnapshotStore<InputState>;
|
|
48
|
+
/** Latest surfaced notice (null after clear); the wiring renders it beside the error strip. */
|
|
49
|
+
readonly notices: SnapshotStore<InputNotice | null>;
|
|
50
|
+
/** The public provide-channel action face (one stable identity per session). */
|
|
51
|
+
readonly actions: InputActions;
|
|
52
|
+
private readonly core;
|
|
53
|
+
private noticeSeq;
|
|
54
|
+
private lastDraft;
|
|
55
|
+
private imageIds;
|
|
56
|
+
private disposed;
|
|
57
|
+
/** Draft persistence mirror (chat store write; receives the clipboard projection, never raw placeholders). */
|
|
58
|
+
private mirrorFn;
|
|
59
|
+
constructor(deps: SessionInputDeps);
|
|
60
|
+
/**
|
|
61
|
+
* Single draft write path (all mutation rides machine events).
|
|
62
|
+
* @param text - the full next draft.
|
|
63
|
+
* @param editRange - the DOM-observed edit shape, when the caller knows it
|
|
64
|
+
* (narrows the machine's occurrence math; absent → diff scan).
|
|
65
|
+
*/
|
|
66
|
+
setDraft(text: string, editRange?: EditRange): void;
|
|
67
|
+
/** Append ordered image ids unless an admission transaction is locked. */
|
|
68
|
+
addImages(ids: readonly DraftAttachmentId[]): boolean;
|
|
69
|
+
/** Remove one image id from this draft. */
|
|
70
|
+
removeImage(id: DraftAttachmentId): void;
|
|
71
|
+
/**
|
|
72
|
+
* Keep only image ids that still resolve in the browser attachment registry.
|
|
73
|
+
* @param available - live registry ids.
|
|
74
|
+
*/
|
|
75
|
+
pruneImages(available: readonly DraftAttachmentId[]): void;
|
|
76
|
+
/**
|
|
77
|
+
* Restore a failed attempt before any images added after its admission.
|
|
78
|
+
* @param ids - failed attempt image ids.
|
|
79
|
+
*/
|
|
80
|
+
restoreImages(ids: readonly DraftAttachmentId[]): void;
|
|
81
|
+
/**
|
|
82
|
+
* Clear the draft as a successful-send commit: no undo unit is recorded and
|
|
83
|
+
* the undo history is cut, so Ctrl/Cmd-Z cannot resurrect sent content
|
|
84
|
+
* (the command path gets the same discipline from submit-settled success).
|
|
85
|
+
* @param imageIds - admitted image ids to remove from this draft.
|
|
86
|
+
*/
|
|
87
|
+
commitSend(imageIds: readonly DraftAttachmentId[]): void;
|
|
88
|
+
/** Undo the latest transaction (InputBar intercepts the platform chord). */
|
|
89
|
+
undo(): void;
|
|
90
|
+
/** Redo the latest undone transaction. */
|
|
91
|
+
redo(): void;
|
|
92
|
+
/**
|
|
93
|
+
* Paste text over the selection in one transaction, with any hot-snapshot
|
|
94
|
+
* sync matches componentized inside it.
|
|
95
|
+
* @param text - pasted plain text.
|
|
96
|
+
* @param selection - replaced selection in draft coordinates.
|
|
97
|
+
* @param components - sync-matched reference components (disjoint, inside `text`).
|
|
98
|
+
* @param generation - projection generation for late async-upgrade guards.
|
|
99
|
+
*/
|
|
100
|
+
pasteBegin(text: string, selection: EditSelection, components?: readonly PasteComponent[], generation?: number): void;
|
|
101
|
+
/** End the live paste-match attempt (caret/selection ops and Slash updates the machine cannot see). */
|
|
102
|
+
invalidatePaste(): void;
|
|
103
|
+
/**
|
|
104
|
+
* Enter adjudication + submit transaction + default sink. Effects fan out
|
|
105
|
+
* from the machine; this method only feeds the event. Lock entry
|
|
106
|
+
* (adjudicating/submitting) force-closes the transient layers: the popup
|
|
107
|
+
* dismisses and the menu tracks frozen.
|
|
108
|
+
*/
|
|
109
|
+
submit(mode?: InputSubmitMode): void;
|
|
110
|
+
/**
|
|
111
|
+
* Feed a draft/caret change through trigger detection (guard derived from
|
|
112
|
+
* the machine phase).
|
|
113
|
+
* @param draft - live draft text.
|
|
114
|
+
* @param caret - caret position in draft coordinates.
|
|
115
|
+
*/
|
|
116
|
+
track(draft: string, caret: number): void;
|
|
117
|
+
/**
|
|
118
|
+
* Keyboard arbitration while the menu is open.
|
|
119
|
+
* @param key - the intercepted key.
|
|
120
|
+
* @param composing - IME composition guard state.
|
|
121
|
+
* @returns the menu's verdict; 'pass' when no pipeline is mounted.
|
|
122
|
+
*/
|
|
123
|
+
arbitrate(key: ArbitrateKey, composing: boolean): ArbitrateOutcome;
|
|
124
|
+
/**
|
|
125
|
+
* Steer every still-pending queued message into the running turn (the
|
|
126
|
+
* empty-draft accelerated-Enter gesture). Execution belongs to the hub's
|
|
127
|
+
* queue choreography; absent dep = the gesture falls back to the machine's
|
|
128
|
+
* empty-draft no-op.
|
|
129
|
+
*/
|
|
130
|
+
steerQueue(): void;
|
|
131
|
+
/**
|
|
132
|
+
* Space adjudication over the controller's hot state.
|
|
133
|
+
* @returns true = a claim/insert was applied — the caller preventDefaults.
|
|
134
|
+
*/
|
|
135
|
+
space(): boolean;
|
|
136
|
+
/** Dismiss the popupSelect shell (any interaction outside the box). */
|
|
137
|
+
dismissPopup(): void;
|
|
138
|
+
/**
|
|
139
|
+
* Hot plain-text reference lexicon source for the decoration scan
|
|
140
|
+
* (the plain-text-reference decision;
|
|
141
|
+
* see .agents/notes/implemented/architecture/2026-07-25-web-input-machine-and-slash-pipeline.md):
|
|
142
|
+
* delegates to the controller's aggregated store. Stable
|
|
143
|
+
* identity per shell; without a pipeline the snapshot is the empty Map and
|
|
144
|
+
* subscribers never fire.
|
|
145
|
+
*/
|
|
146
|
+
readonly lexicon: ObservableSnapshot<ReadonlyMap<'/' | '@', readonly string[]>>;
|
|
147
|
+
/**
|
|
148
|
+
* Apply one command claim (scoped begin-command event listener body).
|
|
149
|
+
* @param claim - the command claim from the pick path.
|
|
150
|
+
* @param span - pick-time span snapshot.
|
|
151
|
+
* @returns whether the machine accepted (phase + span CAS passed and the draft mutated).
|
|
152
|
+
*/
|
|
153
|
+
beginCommand(claim: CommandClaim, span: TokenSpan): boolean;
|
|
154
|
+
/**
|
|
155
|
+
* Apply one reference insertion (scoped insert-reference event listener body).
|
|
156
|
+
* @param ref - the reference insertion from the pick path.
|
|
157
|
+
* @param span - pick-time span snapshot.
|
|
158
|
+
* @returns whether the machine accepted.
|
|
159
|
+
*/
|
|
160
|
+
insertReference(ref: ReferenceInsert, span: TokenSpan): boolean;
|
|
161
|
+
/**
|
|
162
|
+
* Consume one command token after business success (scoped consume-token
|
|
163
|
+
* event listener body). Span guard: revision CAS then splice; bare-token
|
|
164
|
+
* guard: trimmed-draft equality then clear.
|
|
165
|
+
* @param guard - exact span or bare-token guard.
|
|
166
|
+
* @returns whether the token was consumed.
|
|
167
|
+
*/
|
|
168
|
+
consumeToken(guard: ConsumeTokenRequest['guard']): boolean;
|
|
169
|
+
/**
|
|
170
|
+
* Insert plain reference text over the pick-time span (scoped insert-text
|
|
171
|
+
* event listener body; plain-text-reference decision, web-input-machine
|
|
172
|
+
* note). Same CAS-then-splice shape as the
|
|
173
|
+
* consume-token span branch: the machine sees an ordinary draft-changed
|
|
174
|
+
* transaction (one undo step), no occurrence is minted — the chip look is
|
|
175
|
+
* a scan-derived decoration, never state.
|
|
176
|
+
* @param text - the plain reference text to splice in (e.g. `/name `).
|
|
177
|
+
* @param span - pick-time span snapshot (draftRev CAS).
|
|
178
|
+
* @returns whether the text was applied.
|
|
179
|
+
*/
|
|
180
|
+
insertText(text: string, span: TokenSpan): boolean;
|
|
181
|
+
/**
|
|
182
|
+
* Surface a notice from outside the machine (detached command results).
|
|
183
|
+
* @param level - severity tier.
|
|
184
|
+
* @param text - notice body.
|
|
185
|
+
*/
|
|
186
|
+
notify(level: 'info' | 'error', text: string): void;
|
|
187
|
+
/** Teardown: abort any in-flight attempt and stop accepting async settlements. */
|
|
188
|
+
dispose(): void;
|
|
189
|
+
/** Read the live machine state (guard derivation reads here). */
|
|
190
|
+
get snapshot(): InputState;
|
|
191
|
+
/**
|
|
192
|
+
* Bind the draft persistence mirror (chat store write). Adopt-on-bind: the
|
|
193
|
+
* store draft may hold a persisted value from a previous mount; the caller
|
|
194
|
+
* seeds it via setDraft BEFORE binding, and afterwards every machine-adopted
|
|
195
|
+
* draft mirrors out.
|
|
196
|
+
* @param write - store draft write.
|
|
197
|
+
* @returns the unbind disposer.
|
|
198
|
+
*/
|
|
199
|
+
bindMirror(write: (text: string) => void): () => void;
|
|
200
|
+
private run;
|
|
201
|
+
private execute;
|
|
202
|
+
/**
|
|
203
|
+
* Prompt serialization before the sink: expand each
|
|
204
|
+
* placeholder to its owner's model form via the session controller's
|
|
205
|
+
* codec routing. Owner missing / serialize failure / disposal blocks the
|
|
206
|
+
* send — notice + draft and chips retained, never a silent downgrade to
|
|
207
|
+
* the clipboard text. Chip-free drafts skip the async detour.
|
|
208
|
+
*/
|
|
209
|
+
private sinkSerialized;
|
|
210
|
+
/** Enter adjudication: poll the session controller; failure = notice + draft retained (never a silent downgrade). */
|
|
211
|
+
private adjudicate;
|
|
212
|
+
/** The submit transaction: claim.submit against the session scope; ok maps from the outcome kind. */
|
|
213
|
+
private beginSubmit;
|
|
214
|
+
/** Late-settlement guard: superseded attempts and disposed facades drop silently. */
|
|
215
|
+
private dead;
|
|
216
|
+
private compose;
|
|
217
|
+
private publish;
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=facade.d.ts.map
|