@hydraharness/harness-client-ui-conversation 0.1.1-rc.6

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