@crazx/dsh-client-ui-conversation 0.1.5-alpha.1.zw.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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.i18n.yaml +6 -0
  3. package/README.md +127 -0
  4. package/README.zh.md +127 -0
  5. package/lib/client.js +16935 -0
  6. package/lib/index.js +27 -0
  7. package/lib/types/client/apply.d.ts +25 -0
  8. package/lib/types/client/context-occupancy.d.ts +14 -0
  9. package/lib/types/client/contract/composer-blocks.d.ts +28 -0
  10. package/lib/types/client/contract/composer-submission.d.ts +8 -0
  11. package/lib/types/client/contract/context-provenance.d.ts +29 -0
  12. package/lib/types/client/contract/conversation.d.ts +256 -0
  13. package/lib/types/client/contract/input.d.ts +427 -0
  14. package/lib/types/client/contract/queue.d.ts +9 -0
  15. package/lib/types/client/contract/records.d.ts +272 -0
  16. package/lib/types/client/contract/request-inspection.d.ts +131 -0
  17. package/lib/types/client/contract/slots.d.ts +409 -0
  18. package/lib/types/client/contract/snapshot.d.ts +20 -0
  19. package/lib/types/client/contract/system-prompt.d.ts +35 -0
  20. package/lib/types/client/contract/views.d.ts +26 -0
  21. package/lib/types/client/conversation/assembler.d.ts +128 -0
  22. package/lib/types/client/conversation/assembly.d.ts +97 -0
  23. package/lib/types/client/conversation/definition-registry.d.ts +33 -0
  24. package/lib/types/client/conversation/event-registry.d.ts +24 -0
  25. package/lib/types/client/conversation/historical-images.d.ts +51 -0
  26. package/lib/types/client/conversation/location-index.d.ts +85 -0
  27. package/lib/types/client/conversation/view-registry.d.ts +12 -0
  28. package/lib/types/client/image-labels.d.ts +23 -0
  29. package/lib/types/client/index.d.ts +36 -0
  30. package/lib/types/client/input/blocks.d.ts +27 -0
  31. package/lib/types/client/input/decorations.d.ts +32 -0
  32. package/lib/types/client/input/editor/ComposerContentEditable.d.ts +16 -0
  33. package/lib/types/client/input/editor/DecoratorPortals.d.ts +14 -0
  34. package/lib/types/client/input/editor/ReferenceChip.d.ts +17 -0
  35. package/lib/types/client/input/editor/chip-node.d.ts +110 -0
  36. package/lib/types/client/input/editor/claim-decor.d.ts +23 -0
  37. package/lib/types/client/input/editor/keymap.d.ts +41 -0
  38. package/lib/types/client/input/editor/projection.d.ts +93 -0
  39. package/lib/types/client/input/editor/span-map.d.ts +38 -0
  40. package/lib/types/client/input/editor/text-ref.d.ts +60 -0
  41. package/lib/types/client/input/facade.d.ts +298 -0
  42. package/lib/types/client/input/hub.d.ts +88 -0
  43. package/lib/types/client/input/machine.d.ts +46 -0
  44. package/lib/types/client/input/queue-store.d.ts +20 -0
  45. package/lib/types/client/input/submission-policy.d.ts +52 -0
  46. package/lib/types/client/locales.d.ts +330 -0
  47. package/lib/types/client/queue/QueueDock.d.ts +26 -0
  48. package/lib/types/client/service.d.ts +185 -0
  49. package/lib/types/client/settings/EnterBehaviorRow.d.ts +21 -0
  50. package/lib/types/client/skeleton/ContextMeter.d.ts +14 -0
  51. package/lib/types/client/skeleton/ConversationRoot.d.ts +5 -0
  52. package/lib/types/client/skeleton/ConversationSession.d.ts +26 -0
  53. package/lib/types/client/skeleton/EmptyHero.d.ts +46 -0
  54. package/lib/types/client/skeleton/InputBar.d.ts +18 -0
  55. package/lib/types/client/skeleton/PermissionSelect.d.ts +11 -0
  56. package/lib/types/client/skeleton/TodoPanel.d.ts +21 -0
  57. package/lib/types/client/skeleton/safari.d.ts +18 -0
  58. package/lib/types/client/skeleton/toolbar-hosts.d.ts +17 -0
  59. package/lib/types/client/stores.d.ts +24 -0
  60. package/lib/types/client/view-selection.d.ts +9 -0
  61. package/lib/types/index.d.ts +9 -0
  62. package/lib/types/submission-settings.d.ts +20 -0
  63. package/package.json +103 -0
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Composer keymap over the Lexical command layer: menu arbitration
3
+ * (arrows/escape/enter), space adjudication, the Enter submit gesture, and
4
+ * paste routing. Registered at CRITICAL priority so it decides before
5
+ * @lexical/plain-text's own Enter/paste defaults; a handler returning false
6
+ * falls through to those defaults (Shift+Enter's line break, ordinary
7
+ * spaces, text paste the bar routes itself).
8
+ *
9
+ * IME guard: a composition-closing Enter/Space must not submit or adjudicate.
10
+ * KeyboardEvent.isComposing covers most engines; Safari delivers the closing
11
+ * keydown AFTER compositionend, so a root-element composition watch holds the
12
+ * guard for 10ms more (the old textarea's proven window); keyCode
13
+ * 229 is the legacy signal engines emit without isComposing.
14
+ */
15
+ import type { LexicalEditor } from 'lexical';
16
+ import type { ArbitrateKey, ArbitrateOutcome } from '../../contract/input.ts';
17
+ /** The bar-supplied behavior behind each intercepted gesture. */
18
+ export interface ComposerKeymapHandlers {
19
+ /** Keyboard arbitration while the menu is open ('pass' when no pipeline). */
20
+ arbitrate(key: ArbitrateKey, composing: boolean): ArbitrateOutcome;
21
+ /** Space adjudication; true = a claim was applied — the keystroke is consumed. */
22
+ space(): boolean;
23
+ /** Dismiss the popupSelect shell (Escape layering: an open overlay closes first). */
24
+ dismissPopup(): void;
25
+ /** Whether Enter may submit right now (locked/busy states refuse). */
26
+ canSubmit(): boolean;
27
+ /** The Enter gesture after every guard passed; `accelerated` = Ctrl/Cmd held. */
28
+ submit(accelerated: boolean): void;
29
+ /** Pasted files (image intake). */
30
+ intakeFiles(files: readonly File[]): void;
31
+ /** Pasted plain text (sanitized insertion through the shell). */
32
+ pasteText(text: string): void;
33
+ }
34
+ /**
35
+ * Register the composer keymap on one editor.
36
+ * @param editor - the shell-owned editor.
37
+ * @param handlers - bar-supplied behavior.
38
+ * @returns the unregister disposer.
39
+ */
40
+ export declare function registerComposerKeymap(editor: LexicalEditor, handlers: ComposerKeymapHandlers): () => void;
41
+ //# sourceMappingURL=keymap.d.ts.map
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Composer editor projections: one EditorState, three pure text views.
3
+ * detectText feeds trigger detection and TokenSpan coordinates (every chip
4
+ * counts as one U+FFFC — the opaque-reference invariant); clipboardText
5
+ * feeds persistence, the InputState draft, and submit-plane decisions
6
+ * (chips expand to their clipboard projection); the model form is not a
7
+ * text view here — submit serializes chip nodes through their owner codec.
8
+ * All $-functions must run inside `editor.read()` / `editor.update()`.
9
+ */
10
+ import type { LexicalNode, NodeKey, Point } from 'lexical';
11
+ import type { Occurrence } from '../../contract/input.ts';
12
+ /** The detect-projection stand-in for one chip (object replacement character). */
13
+ export declare const ATOMIC_CHAR = "\uFFFC";
14
+ /** One leaf (or gap) of the composer document in projection coordinates. */
15
+ export interface ComposerSegment {
16
+ /** text/linebreak carry a node; chip is atomic; gap is the newline between block elements. */
17
+ readonly kind: 'text' | 'chip' | 'linebreak' | 'gap';
18
+ /** The backing node; null only for gap. */
19
+ readonly node: LexicalNode | null;
20
+ readonly detectStart: number;
21
+ readonly detectLength: number;
22
+ readonly clipboardStart: number;
23
+ readonly clipboardLength: number;
24
+ /** gap only: the block elements this newline separates. */
25
+ readonly gapBetween?: {
26
+ readonly before: NodeKey;
27
+ readonly after: NodeKey;
28
+ };
29
+ }
30
+ /** One walk's product: segments plus the indexes point mapping needs. */
31
+ export interface ComposerLayout {
32
+ readonly segments: readonly ComposerSegment[];
33
+ readonly detectLength: number;
34
+ readonly detectText: string;
35
+ readonly clipboardText: string;
36
+ /** Leaf node key → its segment (text/chip/linebreak). */
37
+ readonly byKey: ReadonlyMap<NodeKey, ComposerSegment>;
38
+ /** Element key → ordered child keys (root and every block element). */
39
+ readonly children: ReadonlyMap<NodeKey, readonly NodeKey[]>;
40
+ /** Element key → detect bounds of its content (gaps excluded). */
41
+ readonly bounds: ReadonlyMap<NodeKey, {
42
+ readonly start: number;
43
+ readonly end: number;
44
+ }>;
45
+ }
46
+ /**
47
+ * Walk the composer document once, producing every projection segment in
48
+ * document order. Blocks (paragraphs) contribute a one-newline gap between
49
+ * one another in both text projections.
50
+ * @returns the layout for this EditorState.
51
+ */
52
+ export declare function $composerLayout(): ComposerLayout;
53
+ /**
54
+ * Fold one clipboard-projection offset to its detect-projection twin.
55
+ * Offsets inside a chip's clipboard expansion snap to the chip's trailing
56
+ * edge; callers only pass boundaries that were once a document end (submit
57
+ * snapshots), which never split a chip.
58
+ * @param layout - the current walk product.
59
+ * @param clipboardOffset - offset into the clipboard projection.
60
+ * @returns the detect offset covering the same document position.
61
+ */
62
+ export declare function detectOffsetOfClipboardOffset(layout: ComposerLayout, clipboardOffset: number): number;
63
+ /** The published projection product consumed by the shell every update. */
64
+ export interface EditorProjection {
65
+ /** Trigger/TokenSpan coordinate text (chip = one U+FFFC). */
66
+ readonly detectText: string;
67
+ /** Persistence/InputState draft text (chip = clipboardText). */
68
+ readonly clipboardText: string;
69
+ /** InputState-compatible occurrence view (clipboardText coordinates). */
70
+ readonly occurrences: readonly Occurrence[];
71
+ /** Range selection in detect coordinates (ordered); null while absent or non-range. */
72
+ readonly selection: {
73
+ readonly start: number;
74
+ readonly end: number;
75
+ } | null;
76
+ /** Collapsed caret in detect coordinates; null while the selection is absent or ranged. */
77
+ readonly caret: number | null;
78
+ }
79
+ /**
80
+ * Fold one selection point to a detect offset.
81
+ * @param layout - the current walk product.
82
+ * @param point - selection anchor/focus point.
83
+ * @returns detect offset, or null when the point references an unknown node.
84
+ */
85
+ export declare function $detectOffsetOfPoint(layout: ComposerLayout, point: Point): number | null;
86
+ /**
87
+ * Project the composer document and its caret.
88
+ * @param idOf - stable occurrence-id assignment per chip NodeKey (the shell
89
+ * owns the map so ids survive across projections of the same node).
90
+ * @returns the three-view projection product.
91
+ */
92
+ export declare function $projectComposer(idOf: (key: NodeKey) => number): EditorProjection;
93
+ //# sourceMappingURL=projection.d.ts.map
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Detect-coordinate span application: the one place that maps a TokenSpan's
3
+ * numeric [start, end) back onto Lexical points and applies an edit there.
4
+ * Every slash/input-* event (begin-command, insert-reference, insert-text,
5
+ * consume-token) lands through here; revision CAS stays with the caller —
6
+ * this module only maps and edits. All functions
7
+ * must run inside `editor.update()`.
8
+ */
9
+ import type { LexicalNode } from 'lexical';
10
+ /** Half-open [start, end) range in detect coordinates (TokenSpan's plane). */
11
+ export interface DetectSpan {
12
+ readonly start: number;
13
+ readonly end: number;
14
+ }
15
+ /**
16
+ * Select one detect span (collapsed spans place the caret). Exposed for the
17
+ * shell's caret placement and tests; the replace helpers below build on it.
18
+ * @param span - detect span to select.
19
+ * @returns whether both endpoints mapped.
20
+ */
21
+ export declare function $selectDetectSpan(span: DetectSpan): boolean;
22
+ /**
23
+ * Replace one detect span with plain text (empty text deletes the span).
24
+ * The caret lands after the insertion.
25
+ * @param span - detect span to replace.
26
+ * @param text - replacement text.
27
+ * @returns whether the span mapped and the edit applied.
28
+ */
29
+ export declare function $replaceDetectSpanWithText(span: DetectSpan, text: string): boolean;
30
+ /**
31
+ * Replace one detect span with nodes (chip insertion path). The caret lands
32
+ * after the last inserted node.
33
+ * @param span - detect span to replace.
34
+ * @param nodes - replacement nodes in order.
35
+ * @returns whether the span mapped and the edit applied.
36
+ */
37
+ export declare function $replaceDetectSpanWithNodes(span: DetectSpan, nodes: readonly LexicalNode[]): boolean;
38
+ //# sourceMappingURL=span-map.d.ts.map
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Plain-text reference decoration (the plain-text-reference decision;
3
+ * see .agents/notes/archived/architecture/2026-07-25-web-input-machine-and-slash-pipeline.md):
4
+ * a `/name` or `@name` token whose name is on the trigger's lexicon, and
5
+ * syntax-recognizable `@dir/` folder tokens, render in the chip family
6
+ * colors. Color only, no icon: a token still carrying its trigger character
7
+ * is editable text, not a settled chip — the domain icon marks exactly the
8
+ * settled state. Pure derivation as before — the entity transform converts
9
+ * matching text into TextRefNode and back as edits move it in and out of
10
+ * match shape; no occurrence identity exists.
11
+ */
12
+ import type { EditorConfig, LexicalEditor, SerializedTextNode } from 'lexical';
13
+ import { TextNode } from 'lexical';
14
+ /** JSON form of one text-ref node. */
15
+ export type SerializedTextRefNode = SerializedTextNode;
16
+ /** One matched plain-text reference as a styled, fully editable text node. */
17
+ export declare class TextRefNode extends TextNode {
18
+ /** Lexical node registry type tag. */
19
+ static getType(): string;
20
+ /**
21
+ * Clone with identity (Lexical writable-copy contract).
22
+ * @param node - node to clone.
23
+ * @returns a copy carrying the same NodeKey.
24
+ */
25
+ static clone(node: TextRefNode): TextRefNode;
26
+ /**
27
+ * Rebuild one text-ref from its JSON form.
28
+ * @param json - serialized node.
29
+ * @returns a fresh node.
30
+ */
31
+ static importJSON(json: SerializedTextRefNode): TextRefNode;
32
+ /** Serialize to the JSON node form. */
33
+ exportJSON(): SerializedTextRefNode;
34
+ /** Style the span the base TextNode mounts. */
35
+ createDOM(config: EditorConfig): HTMLElement;
36
+ /** Entity nodes never merge with plain siblings (the transform owns their bounds). */
37
+ isTextEntity(): true;
38
+ /** Editing continues inside; the transform re-evaluates match shape per edit. */
39
+ canInsertTextBefore(): boolean;
40
+ }
41
+ /**
42
+ * Register the plain-text reference entity transform. The claim decoration
43
+ * has precedence on the leading-token seat: while a command claim holds, the
44
+ * claimed token must stay a plain TextNode (transforms register per concrete
45
+ * node class, so a TextRefNode would never receive the TextNode claim
46
+ * transform and the warn color would be lost).
47
+ * @param editor - the shell-owned editor.
48
+ * @param lexiconOf - live per-trigger name-roll accessor (the controller's aggregated store).
49
+ * @param activeToken - live claim token accessor; null while unclaimed.
50
+ * @returns the unregister disposer.
51
+ */
52
+ export declare function registerTextRefDecoration(editor: LexicalEditor, lexiconOf: () => ReadonlyMap<'/' | '@', readonly string[]>, activeToken: () => string | null): () => void;
53
+ /**
54
+ * Force a re-scan of the whole document (transforms only visit dirty nodes;
55
+ * a lexicon roll change dirties nothing on its own). Queued, not discrete —
56
+ * the caller may sit inside an update listener.
57
+ * @param editor - the shell-owned editor.
58
+ */
59
+ export declare function rescanTextRefs(editor: LexicalEditor): void;
60
+ //# sourceMappingURL=text-ref.d.ts.map
@@ -0,0 +1,298 @@
1
+ /**
2
+ * SessionInput shell: owns the per-session Lexical editor (text + chip
3
+ * truth) and the pure SubmitMachine (phase/claim/attempt), and choreographs
4
+ * everything between them — projections and InputState publication, the
5
+ * scoped-event application verbs, the submit transaction plumbing
6
+ * (adjudicate via the session's InputTriggerController; claim.submit; default
7
+ * sink), the notice channel, and the draft persistence mirror.
8
+ * Package-private; the hub alone constructs it and wires the scoped event
9
+ * listeners onto it.
10
+ */
11
+ import type { Context } from '@deepseek-ai/cordis';
12
+ import { type ObservableSnapshot, type SnapshotStore } from '@deepseek-ai/dsh-client-store';
13
+ import type { LexicalEditor } from 'lexical';
14
+ import type { ArbitrateKey, ArbitrateOutcome, CommandClaim, ConsumeTokenRequest, DraftAttachmentId, InputActions, InputNotice, InputState, InputTriggerController, QueuedMessage, ReferenceInsert, SessionInput, SubmitAttachment, SubmitOutcome, TokenSpan } from '../contract/input.ts';
15
+ import type { InputSubmitMode } from '../contract/composer-submission.ts';
16
+ /** Popup face the shell needs (dismissal only; typed structurally to avoid a value import). */
17
+ export interface PopupDismissFace {
18
+ dismiss(): void;
19
+ }
20
+ /**
21
+ * Construction dependencies of one facade. The slash/popup faces are THUNKS: the
22
+ * shell is created inside the sessions provide materialization (before the
23
+ * scope record is queryable), where `slash.sessionOf`/`command.popupFor`
24
+ * cannot resolve yet — resolution defers to first interactive use.
25
+ */
26
+ export interface SessionInputDeps {
27
+ /** Session-scope ctx handed to claim.submit transactions. */
28
+ actx: Context;
29
+ /** Enter adjudication face resolver; absent/undefined answer = every '/' line falls to the default sink. */
30
+ inputTriggers?: (() => InputTriggerController | undefined) | undefined;
31
+ /** PopupSelect shell face resolver (dismissal on submit lock / escape). */
32
+ popup?: (() => PopupDismissFace | undefined) | undefined;
33
+ /** Queue read face; overlaid onto InputState.queue (absent = empty). */
34
+ queue?: ObservableSnapshot<readonly QueuedMessage[]> | undefined;
35
+ /**
36
+ * Steer every still-pending queued message into the running turn, in FIFO
37
+ * order (the empty-draft accelerated-Enter gesture); absent = unsupported.
38
+ */
39
+ steerQueue?: (() => void) | undefined;
40
+ /** The plain-message sink (send choreography / materialize fork — the hub owns it). */
41
+ defaultSink(text: string, attachmentIds: readonly DraftAttachmentId[], mode: InputSubmitMode, signal: AbortSignal): Promise<SubmitOutcome>;
42
+ /** Command-plane attachment plumbing (the hub owns the conversation face and the copy). */
43
+ commandAttachments: {
44
+ /** Resolve ordered draft ids to wire payloads without sending them; rejects when an id no longer resolves. */
45
+ serialize(ids: readonly DraftAttachmentId[]): Promise<readonly SubmitAttachment[]>;
46
+ /** Free consumed draft attachments after a successful command submit. */
47
+ release(ids: readonly DraftAttachmentId[]): void;
48
+ /** Localized composer notice for a claimed command that does not accept attachments. */
49
+ unsupportedNotice(token: string): string;
50
+ };
51
+ }
52
+ /**
53
+ * The per-session input facade: scoped-event application verbs +
54
+ * setDraft/submit + the published InputState store, over a shell-owned
55
+ * Lexical editor.
56
+ */
57
+ export declare class SessionInputShell implements SessionInput {
58
+ private readonly deps;
59
+ /** Published editor projection + submit-plane state + queue overlay (the InputZone currency source). */
60
+ readonly state: SnapshotStore<InputState>;
61
+ /** Latest surfaced notice (null after clear); the bar renders errors as banners and information inline. */
62
+ readonly notices: SnapshotStore<InputNotice | null>;
63
+ /** The shell-owned editor (text + chip truth); the composer binds its contenteditable to it. */
64
+ readonly editor: LexicalEditor;
65
+ /** The public provide-channel action face (one stable identity per session). */
66
+ readonly actions: InputActions;
67
+ private readonly core;
68
+ private projection;
69
+ private rev;
70
+ /** Stable occurrence ids per chip NodeKey (undo restores keys, so ids survive it too). */
71
+ private readonly occurrenceIds;
72
+ private occurrenceSeq;
73
+ private readonly unregister;
74
+ private noticeSeq;
75
+ private lastMirroredDraft;
76
+ private attachmentIds;
77
+ private disposed;
78
+ /** Draft persistence mirror (Conversation store write; receives the clipboard projection). */
79
+ private mirrorFn;
80
+ /** Live lexicon subscription disposer; undefined until the controller resolves. */
81
+ private lexiconOff;
82
+ /** Default sends retained until admission settles or scope disposal releases their attachments. */
83
+ private readonly detachedDrafts;
84
+ /** Failed default sends waiting to be restored together in submission order. */
85
+ private readonly failedDetached;
86
+ /** Revision of the last automatic failure restoration. */
87
+ private failedRestoreRev;
88
+ private restoringFailures;
89
+ private attachmentFlightSeq;
90
+ /** Attachment-only sends retained until admission settles or scope disposal releases their attachments. */
91
+ private readonly attachmentFlights;
92
+ constructor(deps: SessionInputDeps);
93
+ /**
94
+ * Run one editor edit whose result is observable on return. At the top
95
+ * level this is a discrete update. Inside this editor's own update —
96
+ * command handlers land here synchronously (space/enter picks, paste) —
97
+ * $-functions are already legal, and wrapping them in update() would DEFER
98
+ * them past the synchronous bail answer (and a nested discrete throws);
99
+ * the body runs directly and the outer update commits it.
100
+ * @param fn - the $-edit body.
101
+ */
102
+ private applyEdit;
103
+ /**
104
+ * Subscribe the text-ref re-scan to the controller's lexicon once the
105
+ * controller resolves. The deps thunk cannot resolve at construction (the
106
+ * shell is created inside the sessions provide materialization), so the
107
+ * first interactive updates retry until it can.
108
+ */
109
+ private ensureLexiconSubscription;
110
+ /** Re-project, run the claim watch, publish, and feed trigger tracking after every editor commit. */
111
+ private onEditorUpdate;
112
+ private occurrenceIdOf;
113
+ /**
114
+ * Replace the whole draft (persisted-draft seed and programmatic writes).
115
+ * Placeholder-sanitized; newlines split paragraphs; the caret lands at the
116
+ * end. Merged into history so a seed is not an undoable step of its own.
117
+ * @param text - the full next draft.
118
+ */
119
+ setDraft(text: string): void;
120
+ /** Append ordered attachment ids unless an admission transaction is locked. */
121
+ addAttachments(ids: readonly DraftAttachmentId[]): boolean;
122
+ /**
123
+ * Remove one attachment id from this draft. Busy admission phases refuse, like
124
+ * {@link addAttachments}: a removal landing while a command submit serializes
125
+ * would otherwise vanish from the rail yet still ride the in-flight send.
126
+ */
127
+ removeAttachment(id: DraftAttachmentId): boolean;
128
+ /**
129
+ * Keep only ids that still resolve in the browser attachment registry.
130
+ * @param available - live registry ids.
131
+ */
132
+ pruneAttachments(available: readonly DraftAttachmentId[]): void;
133
+ /**
134
+ * Clear the draft as a successful-send commit: the editor empties (no undo
135
+ * unit) and the undo history is cut, so Ctrl/Cmd-Z cannot resurrect sent
136
+ * content (the command path gets the same discipline from submit-settled).
137
+ * @param attachmentIds - admitted attachment ids to remove from this draft.
138
+ */
139
+ commitSend(attachmentIds: readonly DraftAttachmentId[]): void;
140
+ /**
141
+ * Insert pasted plain text over the current editor selection
142
+ * (placeholder-sanitized). The paste event's own default is suppressed by
143
+ * the caller; PASTE_TAG makes the paste its own history boundary, so one
144
+ * undo never removes both the paste and typing inside the merge window.
145
+ * @param text - pasted plain text.
146
+ */
147
+ paste(text: string): void;
148
+ /**
149
+ * Enter adjudication + submit transaction + default sink. Effects fan out
150
+ * from the machine; this method only feeds the event. Lock entry
151
+ * (adjudicating/submitting) force-closes the transient layers: the popup
152
+ * dismisses and the menu tracks frozen.
153
+ */
154
+ submit(mode?: InputSubmitMode): void;
155
+ /**
156
+ * Keyboard arbitration while the menu is open.
157
+ * @param key - the intercepted key.
158
+ * @param composing - IME composition guard state.
159
+ * @returns the menu's verdict; 'pass' when no pipeline is mounted.
160
+ */
161
+ arbitrate(key: ArbitrateKey, composing: boolean): ArbitrateOutcome;
162
+ /**
163
+ * Steer every still-pending queued message into the running turn (the
164
+ * empty-draft accelerated-Enter gesture). Execution belongs to the hub's
165
+ * queue choreography; absent dep = the gesture falls back to the machine's
166
+ * empty-draft no-op.
167
+ */
168
+ steerQueue(): void;
169
+ /**
170
+ * Space adjudication over the controller's hot state.
171
+ * @returns true = a claim/insert was applied — the caller preventDefaults.
172
+ */
173
+ space(): boolean;
174
+ /** Dismiss the popupSelect shell (any interaction outside the box). */
175
+ dismissPopup(): void;
176
+ /**
177
+ * The live selection as a detect-coordinate span (menu-launcher synthetic
178
+ * hits replace it on pick); an absent selection answers a collapsed span at
179
+ * the document end.
180
+ * @returns the ordered [start, end) span in detect coordinates.
181
+ */
182
+ caretSpan(): {
183
+ start: number;
184
+ end: number;
185
+ };
186
+ /**
187
+ * Hot plain-text reference lexicon source for the decoration scan:
188
+ * delegates to the controller's aggregated store. Stable
189
+ * identity per shell; without a pipeline the snapshot is the empty Map and
190
+ * subscribers never fire.
191
+ */
192
+ readonly lexicon: ObservableSnapshot<ReadonlyMap<'/' | '@', readonly string[]>>;
193
+ /**
194
+ * Apply one command claim (scoped begin-command event listener body): the
195
+ * editor replaces [0, span.end) with the claim token, then the machine
196
+ * enters claimed.
197
+ * @param claim - the command claim from the pick path.
198
+ * @param span - pick-time span snapshot (detect coordinates).
199
+ * @returns whether the edit applied (phase, span CAS, and leading guard passed).
200
+ */
201
+ beginCommand(claim: CommandClaim, span: TokenSpan): boolean;
202
+ /**
203
+ * Apply one reference insertion (scoped insert-reference event listener
204
+ * body): the editor replaces the span with one chip node, followed by a
205
+ * separating space unless one is already next.
206
+ * @param ref - the reference insertion from the pick path.
207
+ * @param span - pick-time span snapshot (detect coordinates).
208
+ * @returns whether the edit applied.
209
+ */
210
+ insertReference(ref: ReferenceInsert, span: TokenSpan): boolean;
211
+ /**
212
+ * Consume one command token after business success (scoped consume-token
213
+ * event listener body). Span guard: revision CAS then splice; bare-token
214
+ * guard: trimmed-draft equality then clear.
215
+ * @param guard - exact span or bare-token guard.
216
+ * @returns whether the token was consumed.
217
+ */
218
+ consumeToken(guard: ConsumeTokenRequest['guard']): boolean;
219
+ /**
220
+ * Insert plain reference text over the pick-time span (scoped insert-text
221
+ * event listener body; the plain-text reference path). The editor gains
222
+ * ordinary characters — no chip node; the chip look is a scan-derived
223
+ * decoration, never state.
224
+ * @param text - the plain reference text to splice in (e.g. `/name `).
225
+ * @param span - pick-time span snapshot (detect coordinates).
226
+ * @param keepCompleting - contract passenger; completion re-opening is
227
+ * automatic here (the update listener re-tracks at the settled caret, so an
228
+ * open token — a directory pick's trailing slash — reopens the menu without
229
+ * an explicit re-track).
230
+ * @returns whether the text was applied.
231
+ */
232
+ insertText(text: string, span: TokenSpan, keepCompleting?: boolean): boolean;
233
+ /**
234
+ * Surface a notice from outside the machine (detached command results).
235
+ * @param level - severity tier.
236
+ * @param text - notice body.
237
+ */
238
+ notify(level: 'info' | 'error', text: string): void;
239
+ /**
240
+ * Teardown the shell and return every browser-owned attachment still retained by
241
+ * the draft or an unsettled default send.
242
+ * @returns attachment ids the scope disposer must release.
243
+ */
244
+ dispose(): readonly DraftAttachmentId[];
245
+ /** Read the live input state (guard derivation reads here). */
246
+ get snapshot(): InputState;
247
+ /**
248
+ * Bind the draft persistence mirror (Conversation store write). Adopt-on-bind: the
249
+ * store draft may hold a persisted value from a previous mount; the caller
250
+ * seeds it via setDraft BEFORE binding, and afterwards every editor-adopted
251
+ * draft mirrors out.
252
+ * @param write - store draft write.
253
+ * @returns the unbind disposer.
254
+ */
255
+ bindMirror(write: (text: string) => void): () => void;
256
+ /** The claim token the decoration transform styles; null while unclaimed. */
257
+ private activeClaimToken;
258
+ /** Dispatch + execute, refreshing the claim decoration when the styled token flips. */
259
+ private dispatchRun;
260
+ private run;
261
+ private execute;
262
+ /**
263
+ * Execute the commit-draft effect: clear the committed content (retaining
264
+ * a pure typed-during-flight suffix when the snapshot allows) and cut the
265
+ * undo history so sent content cannot resurrect.
266
+ */
267
+ private commitDraft;
268
+ /**
269
+ * Prompt serialization before the sink: expand each chip occurrence to its
270
+ * owner's model form via the session controller's codec routing. Owner
271
+ * missing or serialization failure rejects the detached send and restores
272
+ * its editor snapshot. Chip-free drafts skip the async detour.
273
+ */
274
+ private sinkSerialized;
275
+ /** Settle one detached default send independently of other sends. */
276
+ private settleSink;
277
+ /** Restore one failed detached send without overwriting text entered after a restoration. */
278
+ private settleDetachedFailure;
279
+ /** Rebuild all currently failed snapshots in submission order. */
280
+ private restoreFailedDrafts;
281
+ /** Return failed-send attachments to the head of the rail; release happens only after success. */
282
+ private restoreAttachments;
283
+ /** Enter adjudication: poll the session controller; failure = notice + draft retained (never a silent downgrade). */
284
+ private adjudicate;
285
+ /**
286
+ * The submit transaction: claim.submit against the session scope; ok maps
287
+ * from the outcome kind. An accepting claim receives the serialized draft
288
+ * attachments, which are cleared and released only on a success outcome; a
289
+ * failure (serialize, transport, or handler error) keeps draft and attachments
290
+ * for correction.
291
+ */
292
+ private beginSubmit;
293
+ /** Late-settlement guard: superseded attempts and disposed facades drop silently. */
294
+ private dead;
295
+ private compose;
296
+ private publish;
297
+ }
298
+ //# sourceMappingURL=facade.d.ts.map
@@ -0,0 +1,88 @@
1
+ /**
2
+ * InputHub: the SessionInputResolver implementation (`ctx.conversation.input`) — one
3
+ * SessionInputShell per session, created inside the uiSession provide
4
+ * materialization (the 'input' standard-kit entry IS the
5
+ * creation trigger) and torn down by the scope disposer (instance-and-scope
6
+ * share one lifecycle). The hub registers the scoped input-mutation
7
+ * listeners on each Session context and owns the default-sink choreography: every session is a
8
+ * real host entity, so the sink is one unconditional prompt path.
9
+ */
10
+ import type { Context } from '@deepseek-ai/cordis';
11
+ import type { SessionBinding } from '@deepseek-ai/dsh-api-session-controller/client';
12
+ import type { SessionId } from '@deepseek-ai/dsh-session/types';
13
+ import type { TranslateNS } from '@deepseek-ai/dsh-client-locale/client';
14
+ import type { ComposerKeyboard, InputTriggerController, SessionInputResolver, SessionInput } from '../contract/input.ts';
15
+ import { SessionInputShell } from './facade.ts';
16
+ /** Session-addressed input facade registry (SessionInputResolver face + composer-layer extras). */
17
+ export declare class InputHub implements SessionInputResolver {
18
+ private readonly rootCtx;
19
+ private readonly t;
20
+ private readonly shells;
21
+ /**
22
+ * @param ctx - client root context (services resolved lazily per call — boot order stays free).
23
+ * @param t - conversation-namespace translate thunk (reads the active locale at call time).
24
+ */
25
+ constructor(rootCtx: Context, t: TranslateNS<'conversation'>);
26
+ /**
27
+ * Resolve the facade for one session-scope ctx (SessionInputResolver face).
28
+ * @param actx - session-scope context.
29
+ * @returns the resident per-session facade.
30
+ */
31
+ for(actx: Context): SessionInput;
32
+ /**
33
+ * Resident shell for one session binding — the provide-channel entry
34
+ * (called during scope materialization, BEFORE the scope record is
35
+ * queryable, hence binding-fed and hence the thunked slash/popup deps).
36
+ * Wires the scoped event listeners + teardown into the session scope.
37
+ * @param binding - session assembly handle.
38
+ * @returns the shell.
39
+ */
40
+ shellFor(binding: SessionBinding): SessionInputShell;
41
+ /**
42
+ * Resident shell by session id (service-face path; the provide channel has
43
+ * normally created it already — this covers direct id-addressed access).
44
+ * @param id - session id.
45
+ * @returns the shell.
46
+ */
47
+ shell(id: SessionId): SessionInputShell;
48
+ /**
49
+ * The InputBar-exclusive keyboard command face: the shell
50
+ * satisfies it structurally; package-internal — handed through the
51
+ * composer-bar entry's inject, never across a plugin boundary.
52
+ * @param id - session id.
53
+ * @returns the shell as the keyboard face.
54
+ */
55
+ keyboard(id: SessionId): ComposerKeyboard;
56
+ /**
57
+ * Resolve the optional slash controller for composer chrome that launches
58
+ * the shared candidate menu without typing a trigger.
59
+ * @param id - session id.
60
+ * @returns the resident controller, or undefined when no trigger provider is installed.
61
+ */
62
+ inputTriggers(id: SessionId): InputTriggerController | undefined;
63
+ /**
64
+ * Default sink: optimistic clear + prompt. The session is always a real
65
+ * host entity (materialized when its workspace was picked), so there is
66
+ * exactly one path; a failed first prompt is an ordinary prompt failure
67
+ * (banner via promptError, draft restored only while untouched).
68
+ */
69
+ private sink;
70
+ /**
71
+ * Submit every still-pending queued message through QueueDock Steer, in FIFO
72
+ * request order — the same operation as the queue dock's per-row button.
73
+ * An Agent stopping before a command (`session/steer-unavailable`) or a row already
74
+ * claimed by the agent (`session/queue-item-not-found`) converges silently, while a
75
+ * genuine failure surfaces as one composer notice. Repeated triggers
76
+ * (e.g. two rapid empty-draft chords) rely on that `session/queue-item-not-found`
77
+ * convergence: the snapshot may still list a row the host already steered,
78
+ * and the duplicate Steer is a silent no-op.
79
+ * @param session - the addressed host session.
80
+ * @param shell - the resident shell (notice outlet).
81
+ */
82
+ private steerQueue;
83
+ private controller;
84
+ private popup;
85
+ private sessions;
86
+ private conversation;
87
+ }
88
+ //# sourceMappingURL=hub.d.ts.map
@@ -0,0 +1,46 @@
1
+ import type { InputEffect, InputEvent, InputState } from '../contract/input.ts';
2
+ /** The submit-plane slice of the published InputState. */
3
+ export interface SubmitSnapshot {
4
+ readonly phase: InputState['phase'];
5
+ readonly claim?: InputState['claim'];
6
+ }
7
+ /** Pure phase, claim, and attempt owner for one Session input. */
8
+ export declare class SubmitMachine {
9
+ private phase;
10
+ private claim;
11
+ private seq;
12
+ private inflight;
13
+ /** Ordinary sends detached from the editor, retained for settlement validation and cancellation. */
14
+ private readonly detached;
15
+ /** Read-only snapshot of the submit-plane state. */
16
+ get state(): SubmitSnapshot;
17
+ /**
18
+ * Feed one event through the machine.
19
+ * @param ev - submit-plane event.
20
+ * @returns effects for the SessionInput shell, in execution order.
21
+ */
22
+ dispatch(ev: InputEvent): readonly InputEffect[];
23
+ /** Claimed integrity watch: a draft that breaks the token prefix releases the claim. */
24
+ private onDraftChanged;
25
+ /** The editor applied a claim-token replacement; busy phases refuse another claim. */
26
+ private onClaim;
27
+ /** Mint an attempt and controller without assigning its lifecycle owner. */
28
+ private mintAttempt;
29
+ /** Mint the frozen command/adjudication attempt. */
30
+ private beginAttempt;
31
+ /** Mint an ordinary send that leaves the phase plain. */
32
+ private beginDetached;
33
+ /** Default-send effects capture the sink input before the editor commit. */
34
+ private detachedEffects;
35
+ private onEnter;
36
+ private onAdjudicated;
37
+ private onAdjudicationFailed;
38
+ /** Claimed command settlement retains the frozen transaction semantics. */
39
+ private onSubmitSettled;
40
+ /** Settle one ordinary send independently of current phase and other detached sends. */
41
+ private onSinkSettled;
42
+ /** Clear after an accepted attachment-only send; it has no text suffix to retain. */
43
+ private onSendCommitted;
44
+ private onRelease;
45
+ }
46
+ //# sourceMappingURL=machine.d.ts.map