@meshmakers/shared-ui 3.4.1480 → 3.5.0

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 (56) hide show
  1. package/README.md +48 -0
  2. package/assets/octobot/lg/octo_blink.webp +0 -0
  3. package/assets/octobot/lg/octo_blink_still.png +0 -0
  4. package/assets/octobot/lg/octo_idle.webp +0 -0
  5. package/assets/octobot/lg/octo_idle_still.png +0 -0
  6. package/assets/octobot/lg/octo_look.webp +0 -0
  7. package/assets/octobot/lg/octo_look_still.png +0 -0
  8. package/assets/octobot/lg/octo_swim.webp +0 -0
  9. package/assets/octobot/lg/octo_swim_still.png +0 -0
  10. package/assets/octobot/lg/octo_thinking.webp +0 -0
  11. package/assets/octobot/lg/octo_thinking_still.png +0 -0
  12. package/assets/octobot/lg/octo_wave.webp +0 -0
  13. package/assets/octobot/lg/octo_wave_still.png +0 -0
  14. package/assets/octobot/md/octo_blink.webp +0 -0
  15. package/assets/octobot/md/octo_blink_still.png +0 -0
  16. package/assets/octobot/md/octo_idle.webp +0 -0
  17. package/assets/octobot/md/octo_idle_still.png +0 -0
  18. package/assets/octobot/md/octo_look.webp +0 -0
  19. package/assets/octobot/md/octo_look_still.png +0 -0
  20. package/assets/octobot/md/octo_swim.webp +0 -0
  21. package/assets/octobot/md/octo_swim_still.png +0 -0
  22. package/assets/octobot/md/octo_thinking.webp +0 -0
  23. package/assets/octobot/md/octo_thinking_still.png +0 -0
  24. package/assets/octobot/md/octo_wave.webp +0 -0
  25. package/assets/octobot/md/octo_wave_still.png +0 -0
  26. package/assets/octobot/sm/octo_blink.webp +0 -0
  27. package/assets/octobot/sm/octo_blink_still.png +0 -0
  28. package/assets/octobot/sm/octo_idle.webp +0 -0
  29. package/assets/octobot/sm/octo_idle_still.png +0 -0
  30. package/assets/octobot/sm/octo_look.webp +0 -0
  31. package/assets/octobot/sm/octo_look_still.png +0 -0
  32. package/assets/octobot/sm/octo_swim.webp +0 -0
  33. package/assets/octobot/sm/octo_swim_still.png +0 -0
  34. package/assets/octobot/sm/octo_thinking.webp +0 -0
  35. package/assets/octobot/sm/octo_thinking_still.png +0 -0
  36. package/assets/octobot/sm/octo_wave.webp +0 -0
  37. package/assets/octobot/sm/octo_wave_still.png +0 -0
  38. package/fesm2022/meshmakers-shared-ui-assistant-core.mjs +940 -0
  39. package/fesm2022/meshmakers-shared-ui-assistant-core.mjs.map +1 -0
  40. package/fesm2022/meshmakers-shared-ui-assistant.mjs +819 -0
  41. package/fesm2022/meshmakers-shared-ui-assistant.mjs.map +1 -0
  42. package/fesm2022/meshmakers-shared-ui-command-palette.mjs +817 -0
  43. package/fesm2022/meshmakers-shared-ui-command-palette.mjs.map +1 -0
  44. package/fesm2022/meshmakers-shared-ui-shell.mjs +1738 -0
  45. package/fesm2022/meshmakers-shared-ui-shell.mjs.map +1 -0
  46. package/fesm2022/meshmakers-shared-ui-testing.mjs +92 -0
  47. package/fesm2022/meshmakers-shared-ui-testing.mjs.map +1 -0
  48. package/fesm2022/meshmakers-shared-ui.mjs +1550 -203
  49. package/fesm2022/meshmakers-shared-ui.mjs.map +1 -1
  50. package/package.json +28 -2
  51. package/types/meshmakers-shared-ui-assistant-core.d.ts +732 -0
  52. package/types/meshmakers-shared-ui-assistant.d.ts +258 -0
  53. package/types/meshmakers-shared-ui-command-palette.d.ts +398 -0
  54. package/types/meshmakers-shared-ui-shell.d.ts +939 -0
  55. package/types/meshmakers-shared-ui-testing.d.ts +41 -0
  56. package/types/meshmakers-shared-ui.d.ts +1004 -154
@@ -0,0 +1,258 @@
1
+ import { AssistantService, AssistantMessages, AssistantPanelMode, AssistantSessionSummary, AssistantProposalDecision, AssistantAttachmentOptions, AssistantSlashCommand, AssistantThreadItem, AssistantProposal, AssistantProposalDecisionKind } from '@meshmakers/shared-ui/assistant-core';
2
+ export { ASSISTANT_ENABLED, ASSISTANT_MESSAGES, ASSISTANT_NOT_CONNECTED_MESSAGE, ASSISTANT_PAGE_CONTEXT, ASSISTANT_PANEL_OPTIONS, ASSISTANT_SLASH_COMMANDS, ASSISTANT_TOOL_CALL_COMPONENT, ASSISTANT_TRANSPORT, AssistantAsyncResult, AssistantAttachmentOptions, AssistantAttachmentRef, AssistantAttachmentSelection, AssistantContextChip, AssistantContextKind, AssistantContextSource, AssistantExplainDirective, AssistantExplainTarget, AssistantMessages, AssistantOpenRequest, AssistantPageContext, AssistantPanelMode, AssistantPanelOptions, AssistantProposal, AssistantProposalDecision, AssistantProposalDecisionKind, AssistantSendRequest, AssistantService, AssistantSessionSummary, AssistantSlashCommand, AssistantStarterQuestions, AssistantStreamEvent, AssistantThreadItem, AssistantToolCall, AssistantToolCallRowComponent, AssistantTransport, AssistantTransportStatus, DEFAULT_ASSISTANT_MESSAGES, DEFAULT_ASSISTANT_PANEL_MAX_WIDTH, DEFAULT_ASSISTANT_PANEL_MIN_WIDTH, DEFAULT_ASSISTANT_PANEL_STORAGE_KEY, DEFAULT_ASSISTANT_SLASH_COMMANDS, FakeAssistantTransport, IfAssistantDirective, NotConnectedAssistantTransport, assistantFileAccepted, assistantHotkey, deriveAssistantContext, formatAssistantFileSize, formatAssistantMessage, proposalDecisionLabel, resolveAssistantMessages, selectAssistantAttachments } from '@meshmakers/shared-ui/assistant-core';
3
+ import * as _angular_core from '@angular/core';
4
+ import { PipeTransform } from '@angular/core';
5
+ import * as _progress_kendo_svg_icons from '@progress/kendo-svg-icons';
6
+
7
+ /** Classifies a link target: external (http/https/mailto), relative (same origin) or unsafe. */
8
+ declare function classifyAssistantHref(href: string | null | undefined): 'external' | 'relative' | 'unsafe';
9
+ /** Renders untrusted assistant markdown to HTML with the rules above. */
10
+ declare function renderAssistantMarkdown(markdown: string): string;
11
+ /** `{{ text | assistantMarkdown }}` for `[innerHTML]` bindings. */
12
+ declare class AssistantMarkdownPipe implements PipeTransform {
13
+ transform(markdown: string): string;
14
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AssistantMarkdownPipe, never>;
15
+ static ɵpipe: _angular_core.ɵɵPipeDeclaration<AssistantMarkdownPipe, "assistantMarkdown", true>;
16
+ }
17
+
18
+ /**
19
+ * Right-side assistant panel (ui-concept §5.3, wireframe screen 6): header,
20
+ * removable context chips, thread, composer. Non-modal: the page stays usable.
21
+ * Opening focuses the composer, Esc closes and focus returns to where it was
22
+ * (AssistantService). Below 640 px it covers the screen under the top bar and
23
+ * becomes a modal dialog (`aria-modal`, Tab trapped) so the page behind is out
24
+ * of reach. Removing a context chip moves focus to the next chip, else the composer.
25
+ *
26
+ * Host it only while {@link AssistantService.enabled} is set and the panel is open
27
+ * (`@if (assistant.enabled && assistant.isOpen()) { <mm-assistant-panel /> }`); the thread
28
+ * lives in the service, so closing and navigating keep it.
29
+ *
30
+ * Optional transport capabilities (AB#5621) add UI only when the transport has them:
31
+ * - **sessions** — "New chat" and "Chats" in the header; the chat list replaces the thread
32
+ * (open a chat, delete with an inline confirmation; Esc returns to the chat);
33
+ * - **starter questions** — shown as buttons on an empty thread; clicking one sends it;
34
+ * - **attachments** — the composer's "Attach file" button (see `mm-assistant-composer`).
35
+ *
36
+ * Header actions ("New chat", "Chats", close) are icon buttons with tooltip and `aria-label` from
37
+ * the messages, so they never wrap in a narrow panel (AB#5621).
38
+ *
39
+ * **Layout (AB#5621)** — inputs, else {@link ASSISTANT_PANEL_OPTIONS}, else the defaults:
40
+ * - `resizable` (default `false`, so no handle and no extra tab stop; opt in per input or token):
41
+ * a handle on the left edge (`role="separator"`) changes the width by dragging or with ←/→
42
+ * (Shift: bigger steps), Home/End (min/max); a double click forgets the chosen width. The width
43
+ * stays within `minWidth`..`maxWidth` (320..720 px, and at least 240 px of the window stay free)
44
+ * and is kept in `localStorage` under `storageKey` (`mm-assistant-panel-width`; `null` = not
45
+ * kept). Without `resizable`, or until someone resizes it, the panel keeps its CSS width (400 px,
46
+ * 340 px ≤ 1180 px). Unavailable storage only means the width is not kept.
47
+ * - `mode`: `docked` (default, pushes the content) or `overlay` (floats over it, `position: fixed`
48
+ * at the right edge below `--mm-assistant-overlay-top`, default 48 px; stacking via
49
+ * `--mm-assistant-overlay-z-index`, default 20).
50
+ * On phones neither applies: the panel is the full-screen dialog.
51
+ */
52
+ declare class AssistantPanelComponent {
53
+ protected readonly assistant: AssistantService;
54
+ private readonly injector;
55
+ private readonly host;
56
+ private readonly composer;
57
+ /** Translations; members left out fall back to {@link ASSISTANT_MESSAGES}, then English. */
58
+ readonly messages: _angular_core.InputSignal<Partial<AssistantMessages> | null>;
59
+ protected readonly m: _angular_core.Signal<AssistantMessages>;
60
+ /** `docked` pushes the content, `overlay` floats over it (default: options token, else `docked`). */
61
+ readonly mode: _angular_core.InputSignal<AssistantPanelMode | null>;
62
+ /** Shows the resize handle (default: options token, else `false`). */
63
+ readonly resizable: _angular_core.InputSignal<boolean | null>;
64
+ /** Smallest width in px of the resize handle (default: options token, else 320). */
65
+ readonly minWidth: _angular_core.InputSignal<number | null>;
66
+ /** Largest width in px of the resize handle (default: options token, else 720). */
67
+ readonly maxWidth: _angular_core.InputSignal<number | null>;
68
+ /**
69
+ * `localStorage` key of the chosen width; `null` = not kept. Left out (`undefined`): options
70
+ * token, else `mm-assistant-panel-width`.
71
+ */
72
+ readonly storageKey: _angular_core.InputSignal<string | null | undefined>;
73
+ protected readonly xIcon: _progress_kendo_svg_icons.SVGIcon;
74
+ protected readonly plusIcon: _progress_kendo_svg_icons.SVGIcon;
75
+ protected readonly historyIcon: _progress_kendo_svg_icons.SVGIcon;
76
+ protected readonly trashIcon: _progress_kendo_svg_icons.SVGIcon;
77
+ private readonly options;
78
+ protected readonly effectiveMode: _angular_core.Signal<AssistantPanelMode>;
79
+ protected readonly overlay: _angular_core.Signal<boolean>;
80
+ private readonly effectiveStorageKey;
81
+ protected readonly effectiveMin: _angular_core.Signal<number>;
82
+ protected readonly effectiveMax: _angular_core.Signal<number>;
83
+ /** The handle is shown (never on phones). */
84
+ protected readonly canResize: _angular_core.Signal<boolean>;
85
+ /** Width chosen in this panel instance; `undefined` = not touched yet (stored width applies). */
86
+ private readonly chosenWidth;
87
+ private readonly storedWidth;
88
+ /** The inline width in px, or null for the CSS default. */
89
+ protected readonly appliedWidth: _angular_core.Signal<number | null>;
90
+ /** CSS width as rendered, for `aria-valuenow` before the first resize. */
91
+ private readonly measuredWidth;
92
+ protected readonly currentWidth: _angular_core.Signal<number>;
93
+ protected readonly resizing: _angular_core.WritableSignal<boolean>;
94
+ private stopDrag;
95
+ /** Phone layout (≤ 640 px, the shell's breakpoint): the panel is a modal dialog. */
96
+ protected readonly isPhone: _angular_core.WritableSignal<boolean>;
97
+ protected readonly connected: _angular_core.Signal<boolean>;
98
+ /** `chat` = thread + composer; `sessions` = the saved chats list (session-capable transports only). */
99
+ protected readonly view: _angular_core.WritableSignal<"chat" | "sessions">;
100
+ /** Session whose deletion waits for confirmation. */
101
+ protected readonly confirmingDelete: _angular_core.WritableSignal<string | null>;
102
+ /** Session being opened or deleted (its buttons are disabled meanwhile). */
103
+ protected readonly busySession: _angular_core.WritableSignal<string | null>;
104
+ /**
105
+ * Greeting of an empty chat (AB#3444): the OctoBot waves once, then rests on its still frame.
106
+ * Not shown while the assistant is unavailable (the panel says so instead).
107
+ */
108
+ protected readonly showGreeting: _angular_core.Signal<boolean>;
109
+ /** Starter questions on an empty thread (transports with `starterQuestions` only). */
110
+ protected readonly showStarters: _angular_core.Signal<boolean>;
111
+ constructor();
112
+ /** Pointer drag on the handle: the panel sits on the right, so moving left widens it. */
113
+ protected startResize(event: PointerEvent): void;
114
+ /** ←/→ resize (Shift: ×4), Home/End jump to min/max; the width is kept right away. */
115
+ protected onResizeKey(event: KeyboardEvent): void;
116
+ /** Double click on the handle: back to the default width, forgetting the kept one. */
117
+ protected resetWidth(): void;
118
+ private setWidth;
119
+ private clampWidth;
120
+ private measure;
121
+ protected onEscape(event: Event): void;
122
+ /** Shows the saved chats and reloads them. */
123
+ protected showSessions(): void;
124
+ protected backToChat(): void;
125
+ protected newChat(): void;
126
+ protected openSession(session: AssistantSessionSummary): Promise<void>;
127
+ protected askDelete(session: AssistantSessionSummary): void;
128
+ protected cancelDelete(): void;
129
+ protected confirmDelete(session: AssistantSessionSummary): Promise<void>;
130
+ protected sendStarter(question: string): void;
131
+ /** Locale date + time of a session, or '' when absent or unparsable. */
132
+ protected sessionDate(session: AssistantSessionSummary): string;
133
+ /** First chat of the list, else the back button. */
134
+ private focusSessionList;
135
+ private focusComposer;
136
+ /** Phone dialog: Tab and Shift+Tab cycle inside the panel. */
137
+ protected onTab(event: Event): void;
138
+ /** Drops a chip and keeps keyboard users in the row: next chip, else the composer. */
139
+ protected removeChip(id: string, index: number): void;
140
+ protected format(message: string, values: Record<string, string>): string;
141
+ protected onDecision(decision: AssistantProposalDecision): void;
142
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AssistantPanelComponent, never>;
143
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AssistantPanelComponent, "mm-assistant-panel", never, { "messages": { "alias": "messages"; "required": false; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "resizable": { "alias": "resizable"; "required": false; "isSignal": true; }; "minWidth": { "alias": "minWidth"; "required": false; "isSignal": true; }; "maxWidth": { "alias": "maxWidth"; "required": false; "isSignal": true; }; "storageKey": { "alias": "storageKey"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
144
+ }
145
+
146
+ /**
147
+ * Composer (ui-concept §5.3): multi-line, Enter sends, Shift+Enter is a newline,
148
+ * typing `/` at the start lists the slash commands (`ASSISTANT_SLASH_COMMANDS`, by default
149
+ * `/explain`, `/query`, `/summarise`, `/draft-pipeline`). The suggestion list follows the combobox
150
+ * pattern: focus stays in the textarea, ↑/↓ move, Enter/Tab pick, Esc closes the
151
+ * list (and only then lets Esc reach the panel).
152
+ *
153
+ * With {@link attachments} set (the transport accepts files, AB#5621) an "Attach file" button opens
154
+ * a file picker limited to `accept`; files are checked against `maxFiles` / `maxFileSizeBytes`,
155
+ * rejected ones are announced in an alert, attached ones are listed with a remove button, and a
156
+ * message may then be sent without text. Without it there is no attachment UI.
157
+ */
158
+ declare class AssistantComposerComponent {
159
+ /** The composer text (two-way). */
160
+ readonly text: _angular_core.ModelSignal<string>;
161
+ /** Whether Enter may send; false while the transport is not ready. */
162
+ readonly canSend: _angular_core.InputSignal<boolean>;
163
+ /** A turn is running: the send button becomes a stop button. */
164
+ readonly sending: _angular_core.InputSignal<boolean>;
165
+ /** Accepted attachments; `null` (default) = no attachment UI. */
166
+ readonly attachments: _angular_core.InputSignal<AssistantAttachmentOptions | null>;
167
+ /** The attached files (two-way); sent with the next message by the host. */
168
+ readonly files: _angular_core.ModelSignal<readonly File[]>;
169
+ readonly send: _angular_core.OutputEmitterRef<string>;
170
+ readonly stop: _angular_core.OutputEmitterRef<void>;
171
+ /** Translations; members left out fall back to {@link ASSISTANT_MESSAGES}, then English. */
172
+ readonly messages: _angular_core.InputSignal<Partial<AssistantMessages> | null>;
173
+ protected readonly m: _angular_core.Signal<AssistantMessages>;
174
+ private readonly textarea;
175
+ private readonly fileInput;
176
+ /** Messages about rejected files of the last pick. */
177
+ protected readonly attachmentErrors: _angular_core.WritableSignal<readonly string[]>;
178
+ /** Something to send: text, or (with attachments) at least one file. */
179
+ protected readonly hasContent: _angular_core.Signal<boolean>;
180
+ protected readonly multiple: _angular_core.Signal<boolean>;
181
+ protected readonly xIcon: _progress_kendo_svg_icons.SVGIcon;
182
+ protected readonly paperclipIcon: _progress_kendo_svg_icons.SVGIcon;
183
+ protected readonly commands: readonly AssistantSlashCommand[];
184
+ protected readonly listId: string;
185
+ protected readonly activeIndex: _angular_core.WritableSignal<number>;
186
+ private readonly dismissedFor;
187
+ /** Slash commands matching what was typed, while the text is a bare `/word`. */
188
+ protected readonly suggestions: _angular_core.Signal<readonly AssistantSlashCommand[]>;
189
+ protected readonly activeOptionId: _angular_core.Signal<string | null>;
190
+ /** Focuses the textarea with the caret at the end (entry points prefill it). */
191
+ focus(): void;
192
+ protected onInput(value: string): void;
193
+ protected onKeydown(event: KeyboardEvent): void;
194
+ protected pick(command: AssistantSlashCommand): void;
195
+ protected submit(): void;
196
+ protected openFilePicker(): void;
197
+ protected onFilesPicked(input: HTMLInputElement): void;
198
+ protected removeFile(index: number): void;
199
+ protected format(message: string, values: Record<string, string>): string;
200
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AssistantComposerComponent, never>;
201
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AssistantComposerComponent, "mm-assistant-composer", never, { "text": { "alias": "text"; "required": false; "isSignal": true; }; "canSend": { "alias": "canSend"; "required": false; "isSignal": true; }; "sending": { "alias": "sending"; "required": false; "isSignal": true; }; "attachments": { "alias": "attachments"; "required": false; "isSignal": true; }; "files": { "alias": "files"; "required": false; "isSignal": true; }; "messages": { "alias": "messages"; "required": false; "isSignal": true; }; }, { "text": "textChange"; "files": "filesChange"; "send": "send"; "stop": "stop"; }, never, never, true, never>;
202
+ }
203
+
204
+ /**
205
+ * The conversation (wireframe screen 6): user turns, assistant turns (markdown
206
+ * via `renderAssistantMarkdown`: no images, safe links only; violet edge), tool-call rows and proposal cards. Tool calls
207
+ * render with the `ASSISTANT_TOOL_CALL_COMPONENT` (an OctoMesh host passes `mm-ai-tool-call` from
208
+ * `@meshmakers/octo-ai-console`, ui-concept §5.1 "do not rebuild"); proposals are emitted, never executed.
209
+ *
210
+ * A user turn sent through a slash command's `expand` (AB#5621) shows the expanded prompt with the
211
+ * typed command (`slashCommand`) as a small label above it.
212
+ *
213
+ * While an assistant turn streams it shows the OctoBot `thinking` with "Thinking…" (AB#3444);
214
+ * once the reply is complete the newest assistant turn keeps the OctoBot as a still frame. The
215
+ * figure is decorative — the text carries the meaning — and appears at most once in the thread.
216
+ *
217
+ * The list is an `aria-live` log; it is `aria-busy` while a turn streams so a
218
+ * screen reader announces finished messages instead of every token. Nothing
219
+ * inside it carries its own live role, so each addition is announced once.
220
+ */
221
+ declare class AssistantThreadComponent {
222
+ private readonly host;
223
+ readonly items: _angular_core.InputSignal<AssistantThreadItem[]>;
224
+ readonly proposalDecision: _angular_core.OutputEmitterRef<AssistantProposalDecision>;
225
+ /** Translations; members left out fall back to {@link ASSISTANT_MESSAGES}, then English. */
226
+ readonly messages: _angular_core.InputSignal<Partial<AssistantMessages> | null>;
227
+ protected readonly m: _angular_core.Signal<AssistantMessages>;
228
+ protected readonly toolCallComponent: _angular_core.Type<unknown>;
229
+ /** Id of the newest assistant turn: the only one that shows the resting OctoBot. */
230
+ protected readonly lastAssistantId: _angular_core.Signal<string | null>;
231
+ protected readonly streaming: _angular_core.Signal<boolean>;
232
+ constructor();
233
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AssistantThreadComponent, never>;
234
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AssistantThreadComponent, "mm-assistant-thread", never, { "items": { "alias": "items"; "required": false; "isSignal": true; }; "messages": { "alias": "messages"; "required": false; "isSignal": true; }; }, { "proposalDecision": "proposalDecision"; }, never, never, true, never>;
235
+ }
236
+
237
+ /**
238
+ * A write the assistant proposes (ui-concept §5.3/§5.6, wireframe screen 6):
239
+ * violet card with a parameter table and Run / Edit / Discard. The buttons only
240
+ * emit — the card never executes anything; the host forwards the decision.
241
+ */
242
+ declare class AssistantProposalCardComponent {
243
+ readonly proposal: _angular_core.InputSignal<AssistantProposal>;
244
+ /** Set once the person ran or discarded the proposal; disables the buttons. */
245
+ readonly decision: _angular_core.InputSignal<AssistantProposalDecisionKind | null>;
246
+ readonly run: _angular_core.OutputEmitterRef<AssistantProposal>;
247
+ readonly edit: _angular_core.OutputEmitterRef<AssistantProposal>;
248
+ readonly discard: _angular_core.OutputEmitterRef<AssistantProposal>;
249
+ /** Translations; members left out fall back to {@link ASSISTANT_MESSAGES}, then English. */
250
+ readonly messages: _angular_core.InputSignal<Partial<AssistantMessages> | null>;
251
+ protected readonly m: _angular_core.Signal<AssistantMessages>;
252
+ protected readonly cardLabel: _angular_core.Signal<string>;
253
+ protected readonly decisionLabel: _angular_core.Signal<string | null>;
254
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AssistantProposalCardComponent, never>;
255
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AssistantProposalCardComponent, "mm-assistant-proposal-card", never, { "proposal": { "alias": "proposal"; "required": true; "isSignal": true; }; "decision": { "alias": "decision"; "required": false; "isSignal": true; }; "messages": { "alias": "messages"; "required": false; "isSignal": true; }; }, { "run": "run"; "edit": "edit"; "discard": "discard"; }, never, never, true, never>;
256
+ }
257
+
258
+ export { AssistantComposerComponent, AssistantMarkdownPipe, AssistantPanelComponent, AssistantProposalCardComponent, AssistantThreadComponent, classifyAssistantHref, renderAssistantMarkdown };
@@ -0,0 +1,398 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { InjectionToken, OnInit } from '@angular/core';
3
+ import { SVGIcon } from '@progress/kendo-svg-icons';
4
+ import { Observable } from 'rxjs';
5
+
6
+ /**
7
+ * Result groups of the command palette, in the vocabulary of
8
+ * `docs/concepts/ui-concept-ai-os.md` §4.1. The group decides the section
9
+ * header a result is listed under and which typed prefix scopes to it.
10
+ */
11
+ type PaletteGroup = 'recent' | 'page' | 'action' | 'entity' | 'board' | 'tenant' | 'ai';
12
+ /** How a result is opened: Enter opens in place, Cmd/Ctrl+Enter in a new browser tab. */
13
+ type PaletteRunMode = 'open' | 'newTab';
14
+ /**
15
+ * What the palette does after a result or action ran. By default it closes;
16
+ * an outcome with `query` keeps it open and replaces the query (e.g. "Switch
17
+ * tenant…" re-scopes the palette to `/`).
18
+ */
19
+ interface PaletteRunOutcome {
20
+ query: string;
21
+ }
22
+ type PaletteRunResult = PaletteRunOutcome | void;
23
+ /** One entry of a result's actions sub-menu (opened with Tab). */
24
+ interface PaletteAction {
25
+ id: string;
26
+ label: string;
27
+ /** Keyboard hint shown on the right, e.g. '↵'. */
28
+ hint?: string;
29
+ run(): Promise<PaletteRunResult>;
30
+ }
31
+ /** One row of the palette. Providers create them; the ranking orders them. */
32
+ interface PaletteResult {
33
+ /** Unique and stable across searches (prefix it with the provider id). */
34
+ id: string;
35
+ group: PaletteGroup;
36
+ label: string;
37
+ /** Secondary text on the right, e.g. "Adapter · Online". */
38
+ description?: string;
39
+ /** Where the result lives, e.g. ['Integration'] — rendered "Integration ›". */
40
+ path?: string[];
41
+ /** Technical id rendered in mono type, e.g. an rtId or ckTypeId. */
42
+ typeHint?: string;
43
+ icon?: SVGIcon;
44
+ /** One-character text icon used when there is no SVG icon. */
45
+ glyph?: string;
46
+ /** Extra search terms (matched one tier below the label). */
47
+ keywords?: string[];
48
+ /** Key into the recents store; results with a key get the frecency boost. */
49
+ recentKey?: string;
50
+ /** Set by entity providers when the query was this result's exact id: ranks first. */
51
+ exactMatch?: boolean;
52
+ /**
53
+ * Extra ranking weight 0…1 on top of the frecency, e.g. 1 for a pinned board, so pinned
54
+ * and recently used rows lead their group (only orders within a match tier).
55
+ */
56
+ rankBoost?: number;
57
+ /** Keep this row after ranking even without a text match (e.g. the assistant fallback). */
58
+ alwaysShow?: boolean;
59
+ run(mode: PaletteRunMode): Promise<PaletteRunResult>;
60
+ /** Sub-menu opened with Tab. */
61
+ actions?: PaletteAction[];
62
+ }
63
+ /** A parsed palette query: an optional scope from a typed prefix plus the search text. */
64
+ interface PaletteQuery {
65
+ /** The input exactly as typed. */
66
+ raw: string;
67
+ /** The prefix character when one was typed ('>', '@', '#', '/', '?'). */
68
+ prefix: string | null;
69
+ /** The group the prefix scopes to, or null for an unscoped search. */
70
+ scope: PaletteGroup | null;
71
+ /** The search text without the prefix, trimmed. */
72
+ text: string;
73
+ }
74
+ /**
75
+ * One async result source. The palette calls `search` for every query
76
+ * change; a new query unsubscribes the previous search (cancellation), and a
77
+ * provider with `debounceMs` is only asked once typing paused that long.
78
+ * A provider error drops that provider's rows only.
79
+ */
80
+ interface PaletteProvider {
81
+ /** Stable id, used to prefix result ids. */
82
+ readonly id: string;
83
+ /** Groups this provider produces; a scoped query skips providers without that group. */
84
+ readonly groups: readonly PaletteGroup[];
85
+ /** Remote providers debounce (§4.2: 150 ms); local ones answer immediately. */
86
+ readonly debounceMs?: number;
87
+ search(query: PaletteQuery): Observable<PaletteResult[]>;
88
+ /** Called whenever the palette opens: drop per-session caches (visibility gates, pages). */
89
+ reset?(): void;
90
+ }
91
+ /** Multi-provider token for the palette sources: `{ provide: PALETTE_PROVIDERS, useClass: MyProvider, multi: true }`. */
92
+ declare const PALETTE_PROVIDERS: InjectionToken<PaletteProvider[]>;
93
+ /**
94
+ * Where the palette reads the frecency of recently used results (the boost for rows with a
95
+ * `recentKey`). Optional: without a source every frecency is 0. Read once per palette session.
96
+ *
97
+ * ```ts
98
+ * { provide: PALETTE_RECENT_ITEMS_SOURCE, useFactory: () => {
99
+ * const recents = inject(RecentItemsService);
100
+ * return { frecencies: now => new Map(recents.items(now).map(i => [i.key, normalizedFrecency(i, now)])) };
101
+ * } }
102
+ * ```
103
+ */
104
+ interface PaletteRecentItemsSource {
105
+ /** Normalised frecency 0…1 per `recentKey` at `now` (ms since epoch). */
106
+ frecencies(now: number): ReadonlyMap<string, number>;
107
+ }
108
+ declare const PALETTE_RECENT_ITEMS_SOURCE: InjectionToken<PaletteRecentItemsSource>;
109
+
110
+ /**
111
+ * UI strings of the command palette (`mm-command-palette`) and of
112
+ * {@link PaletteNavigationService}'s clipboard notifications.
113
+ *
114
+ * Provide translations app wide with {@link COMMAND_PALETTE_MESSAGES} or per instance with the
115
+ * component's `messages` input (wins over the token). Missing, `undefined` or `null` members keep
116
+ * the English default of {@link DEFAULT_COMMAND_PALETTE_MESSAGES}; `{name}` placeholders are
117
+ * filled with {@link formatCommandPaletteMessage}.
118
+ */
119
+ interface CommandPaletteMessages {
120
+ /** `aria-label` of the dialog. */
121
+ dialogLabel: string;
122
+ /** `aria-label` of the search input. */
123
+ inputLabel: string;
124
+ placeholder: string;
125
+ /** Close button on phones. */
126
+ cancel: string;
127
+ /** `aria-label` of the result list. */
128
+ results: string;
129
+ /** `aria-label` of the actions sub-menu; `{label}` = result label. */
130
+ actionsFor: string;
131
+ /** Header of the actions sub-menu; `{label}` = result label. */
132
+ actionsHeader: string;
133
+ /** Tooltip of the Tab hint on rows with actions. */
134
+ tabForActions: string;
135
+ /** Live status with one result. */
136
+ oneResult: string;
137
+ /** Live status; `{count}` = number of results. */
138
+ manyResults: string;
139
+ /** Empty list with a search text; `{text}` = search text. */
140
+ noResultsFor: string;
141
+ /** Empty list without a search text. */
142
+ typeToSearch: string;
143
+ footerMove: string;
144
+ footerOpen: string;
145
+ footerNewTab: string;
146
+ footerActions: string;
147
+ prefixActions: string;
148
+ prefixEntities: string;
149
+ prefixBoards: string;
150
+ prefixTenants: string;
151
+ groupRecent: string;
152
+ groupPage: string;
153
+ groupAction: string;
154
+ groupEntity: string;
155
+ groupBoard: string;
156
+ groupTenant: string;
157
+ groupAi: string;
158
+ /** `{label}` = what was copied, e.g. "RtId". */
159
+ copied: string;
160
+ copyFailed: string;
161
+ }
162
+ declare const DEFAULT_COMMAND_PALETTE_MESSAGES: CommandPaletteMessages;
163
+ /** App-wide translations of the command palette (partial). */
164
+ declare const COMMAND_PALETTE_MESSAGES: InjectionToken<Partial<CommandPaletteMessages>>;
165
+ /** Merges overrides over {@link DEFAULT_COMMAND_PALETTE_MESSAGES}, later sources winning; null/undefined members are ignored. */
166
+ declare function resolveCommandPaletteMessages(...overrides: (Partial<CommandPaletteMessages> | null | undefined)[]): CommandPaletteMessages;
167
+ /** Replaces `{name}` placeholders; unknown placeholders stay as they are. */
168
+ declare function formatCommandPaletteMessage(message: string, values: Record<string, string | number>): string;
169
+ /** The group header of a result group. */
170
+ declare function paletteGroupLabel(group: PaletteGroup, messages: CommandPaletteMessages): string;
171
+
172
+ /** A request to show the palette with a query; a new object per call so effects re-run. */
173
+ interface PaletteOpenRequest {
174
+ query: string;
175
+ }
176
+ /**
177
+ * Opens and closes the command palette (Cmd/Ctrl+K). The host (AppComponent) renders
178
+ * the overlay and binds the global hotkey; anything else — the top bar's
179
+ * "Search ⌘K" trigger, a Home tile, an empty state — calls {@link open}.
180
+ *
181
+ * Focus returns to the element that had it when the palette opened.
182
+ */
183
+ declare class CommandPaletteService {
184
+ private readonly _isOpen;
185
+ private readonly _request;
186
+ private returnFocusTo;
187
+ /** Whether the palette is shown. */
188
+ readonly isOpen: _angular_core.Signal<boolean>;
189
+ /** The latest open request; the palette adopts its query (also while already open). */
190
+ readonly request: _angular_core.Signal<PaletteOpenRequest>;
191
+ /**
192
+ * Shows the palette. `initialQuery` pre-fills the input, e.g. `'>'` for
193
+ * actions or `'/'` for the tenant list. Calling it while open replaces the query.
194
+ */
195
+ open(initialQuery?: string): void;
196
+ /** Hides the palette and gives focus back to where it was. */
197
+ close(): void;
198
+ /** Opens when closed, closes when open. */
199
+ toggle(initialQuery?: string): void;
200
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<CommandPaletteService, never>;
201
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<CommandPaletteService>;
202
+ }
203
+ /** What a global keydown should do to the palette. */
204
+ type PaletteHotkeyAction = 'toggle' | 'open';
205
+ /**
206
+ * Maps a document keydown to a palette action (ui-concept §4.3):
207
+ *
208
+ * - Cmd+K (macOS) / Ctrl+K toggles — except inside a Monaco code editor,
209
+ * whose own Cmd+K chords (comment, format …) must keep working;
210
+ * - `/` opens when no text field, text role, grid or Kendo widget is focused;
211
+ * - everything else, and events another handler already consumed, is ignored.
212
+ */
213
+ declare function paletteHotkeyAction(event: KeyboardEvent, isOpen: boolean): PaletteHotkeyAction | null;
214
+
215
+ /**
216
+ * Navigation and clipboard helpers shared by the palette providers. All
217
+ * palette targets are absolute router URLs (`/<tenant>/…`), so a result
218
+ * behaves the same whichever page the palette was opened on.
219
+ */
220
+ declare class PaletteNavigationService {
221
+ private readonly router;
222
+ private readonly notifications;
223
+ private readonly messages;
224
+ /** The tenant of the current URL (first path segment), or null outside a tenant. */
225
+ currentTenantId(): string | null;
226
+ /**
227
+ * Turns a command link into an absolute URL: links starting with `/` are
228
+ * absolute already, all others are relative to the tenant (as the drawer
229
+ * resolves them via `navigateRelativeToRoute`).
230
+ */
231
+ tenantUrl(link: string): string;
232
+ /** Opens an absolute router URL in place or in a new browser tab. */
233
+ open(url: string, mode?: PaletteRunMode): Promise<void>;
234
+ /** Opens an external link (href) in a new tab, as the drawer does. */
235
+ openExternal(href: string, target?: string): void;
236
+ /** Copies a value and confirms it with a short notification. */
237
+ copy(value: string, label: string): Promise<void>;
238
+ private toHref;
239
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PaletteNavigationService, never>;
240
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<PaletteNavigationService>;
241
+ }
242
+
243
+ /** Typed prefixes that force a group (ui-concept §4.2 rule 4). */
244
+ declare const PALETTE_PREFIXES: Readonly<Record<string, PaletteGroup>>;
245
+ /**
246
+ * Splits the raw input into an optional scope and the search text:
247
+ * `"> theme"` → scope `action`, text `theme`; `"edge"` → no scope.
248
+ * Only the first non-blank character counts as a prefix.
249
+ */
250
+ declare function parsePaletteQuery(raw: string): PaletteQuery;
251
+ /** A runtime id: 24 hex characters (MongoDB ObjectId). */
252
+ declare function isRtId(text: string): boolean;
253
+
254
+ /**
255
+ * Runs every provider for every query and merges their rows.
256
+ *
257
+ * - A provider whose groups do not include the query's scope is skipped (its rows clear at once).
258
+ * - A new query cancels the provider's running search (`switchMap` unsubscribes).
259
+ * - Providers with `debounceMs` start only after the query stood still that long; until
260
+ * then their previous rows stay, so remote results do not flicker away while typing
261
+ * (the ranking drops rows that no longer match).
262
+ * - An error drops only that provider's rows.
263
+ *
264
+ * The output emits on every provider answer, so local rows show immediately
265
+ * and remote rows stream in.
266
+ */
267
+ declare function searchProviders(providers: readonly PaletteProvider[], query$: Observable<PaletteQuery>): Observable<PaletteResult[]>;
268
+
269
+ /** Match tiers: prefix > word-start > subsequence (ui-concept §4.2 rule 2). */
270
+ declare enum MatchTier {
271
+ None = 0,
272
+ Fuzzy = 1,
273
+ WordStart = 2,
274
+ Prefix = 3
275
+ }
276
+ /** How well `text` matches `query` (both compared case-insensitively). */
277
+ declare function matchTier(text: string | null | undefined, query: string): MatchTier;
278
+ /**
279
+ * Score of one result for a query: 0 means "does not match". `frecency` is
280
+ * the normalised (0…1) frecency of the result's recent key.
281
+ */
282
+ declare function scoreResult(result: PaletteResult, text: string, frecency?: number): number;
283
+ /** A section of the ranked palette list. */
284
+ interface RankedGroup {
285
+ group: PaletteGroup;
286
+ results: PaletteResult[];
287
+ }
288
+ /**
289
+ * Orders the rows of all providers into sections. Pure: the same input gives
290
+ * the same output, so the palette can re-rank whenever a provider streams in
291
+ * without the list jumping around for unchanged rows.
292
+ *
293
+ * - non-matching rows are dropped (except `alwaysShow`),
294
+ * - rows sort by score within their group, ties by label,
295
+ * - groups follow the short/long query order; a group holding an exact id match goes first,
296
+ * - the assistant row (group `ai`) always stays last.
297
+ */
298
+ declare function rankResults(results: readonly PaletteResult[], query: PaletteQuery, frecencyOf?: (key: string) => number): RankedGroup[];
299
+ /** Splits a label into plain and highlighted parts for the first case-insensitive occurrence of `text`. */
300
+ declare function highlightSegments(label: string, text: string): {
301
+ text: string;
302
+ match: boolean;
303
+ }[];
304
+ /**
305
+ * Keeps what the user already sees in place while results stream in for the
306
+ * SAME query (ui-concept §4.2 rule 5): groups already shown keep their
307
+ * position and new groups are appended below them (the assistant row stays
308
+ * last); inside a group, rows already shown keep their order and late rows
309
+ * are appended. Rows a provider no longer returns disappear. For a new query
310
+ * the fresh ranking is used as is.
311
+ */
312
+ declare function stabilizeRanking(previous: readonly RankedGroup[], next: readonly RankedGroup[]): RankedGroup[];
313
+
314
+ interface PaletteRow {
315
+ index: number;
316
+ result: PaletteResult;
317
+ segments: {
318
+ text: string;
319
+ match: boolean;
320
+ }[];
321
+ side: string;
322
+ }
323
+ interface PaletteSection {
324
+ group: PaletteGroup;
325
+ label: string;
326
+ rows: PaletteRow[];
327
+ }
328
+ /**
329
+ * The command palette overlay (Cmd/Ctrl+K, ui-concept §4). Render it only while
330
+ * {@link CommandPaletteService.isOpen} — one component instance is one palette session:
331
+ *
332
+ * ```html
333
+ * @if (commandPalette.isOpen()) { <mm-command-palette /> }
334
+ * ```
335
+ *
336
+ * Results come from the {@link PALETTE_PROVIDERS}; the frecency boost from the optional
337
+ * {@link PALETTE_RECENT_ITEMS_SOURCE}.
338
+ *
339
+ * Accessibility: modal dialog; the input is a combobox driving a listbox via
340
+ * `aria-activedescendant`, so focus never leaves the input (Tab is taken for
341
+ * the actions sub-menu, which keeps keyboard focus trapped in the dialog);
342
+ * focus goes back to the invoking element on close (the service does that).
343
+ */
344
+ declare class CommandPaletteComponent implements OnInit {
345
+ private readonly palette;
346
+ private readonly providers;
347
+ private readonly recents;
348
+ /** Translations; members left out fall back to {@link COMMAND_PALETTE_MESSAGES}, then English. */
349
+ readonly messages: _angular_core.InputSignal<Partial<CommandPaletteMessages> | null>;
350
+ protected readonly m: _angular_core.Signal<CommandPaletteMessages>;
351
+ private readonly destroyRef;
352
+ private readonly input;
353
+ protected readonly query: _angular_core.WritableSignal<string>;
354
+ private readonly query$;
355
+ private readonly ranked;
356
+ private readonly parsed;
357
+ private readonly results;
358
+ /** Id of the highlighted row; null means "the first row" (reset whenever the user types). */
359
+ private readonly activeId;
360
+ protected readonly activeIndex: _angular_core.Signal<number>;
361
+ /** The result whose actions sub-menu is open (Tab), or null. */
362
+ protected readonly actionsFor: _angular_core.WritableSignal<PaletteResult | null>;
363
+ protected readonly activeActionIndex: _angular_core.WritableSignal<number>;
364
+ protected readonly sections: _angular_core.Signal<PaletteSection[]>;
365
+ protected readonly activeDescendant: _angular_core.Signal<string | null>;
366
+ /** Whether a listbox with options is shown (bound to the combobox's aria-expanded). */
367
+ protected readonly expanded: _angular_core.Signal<boolean>;
368
+ protected readonly statusText: _angular_core.Signal<string>;
369
+ protected readonly emptyText: _angular_core.Signal<string>;
370
+ protected get modifierLabel(): string;
371
+ constructor();
372
+ ngOnInit(): void;
373
+ protected groupLabel(group: PaletteGroup): string;
374
+ protected format(message: string, values: Record<string, string>): string;
375
+ protected onInput(event: Event): void;
376
+ protected onKeydown(event: KeyboardEvent): void;
377
+ /** Clicks on the dialog's chrome (header, footer, group headers) must not take focus from the input. */
378
+ protected onDialogMouseDown(event: MouseEvent): void;
379
+ protected close(): void;
380
+ protected onScrimMouseDown(event: MouseEvent): void;
381
+ protected onOptionHover(result: PaletteResult): void;
382
+ protected onOptionClick(result: PaletteResult, event: MouseEvent): void;
383
+ /** Runs a result. The palette closes first; an outcome with a query reopens it with that query. */
384
+ protected execute(result: PaletteResult, mode: PaletteRunMode): Promise<void>;
385
+ protected runAction(action: PaletteAction): Promise<void>;
386
+ private finish;
387
+ private openActions;
388
+ private move;
389
+ private moveTo;
390
+ private setQuery;
391
+ private focusInput;
392
+ private scrollActiveIntoView;
393
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<CommandPaletteComponent, never>;
394
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<CommandPaletteComponent, "mm-command-palette", never, { "messages": { "alias": "messages"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
395
+ }
396
+
397
+ export { COMMAND_PALETTE_MESSAGES, CommandPaletteComponent, CommandPaletteService, DEFAULT_COMMAND_PALETTE_MESSAGES, MatchTier, PALETTE_PREFIXES, PALETTE_PROVIDERS, PALETTE_RECENT_ITEMS_SOURCE, PaletteNavigationService, formatCommandPaletteMessage, highlightSegments, isRtId, matchTier, paletteGroupLabel, paletteHotkeyAction, parsePaletteQuery, rankResults, resolveCommandPaletteMessages, scoreResult, searchProviders, stabilizeRanking };
398
+ export type { CommandPaletteMessages, PaletteAction, PaletteGroup, PaletteHotkeyAction, PaletteOpenRequest, PaletteProvider, PaletteQuery, PaletteRecentItemsSource, PaletteResult, PaletteRunMode, PaletteRunOutcome, PaletteRunResult, RankedGroup };