@lalternative/assistant 0.0.0-stage → 0.2.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.
@@ -0,0 +1,480 @@
1
+ /*
2
+ * Every colour reads a --lalt-assistant-* variable so the host maps its own
3
+ * theme onto the panel; the fallbacks render a neutral light theme.
4
+ */
5
+
6
+ .lalt-assistant {
7
+ --_bg: var(--lalt-assistant-bg, #ffffff);
8
+ --_surface: var(--lalt-assistant-surface, #fafaf9);
9
+ --_hover: var(--lalt-assistant-hover, rgba(11, 11, 11, 0.05));
10
+ --_border: var(--lalt-assistant-border, #e5e5e2);
11
+ --_text: var(--lalt-assistant-text, #1c1c1a);
12
+ --_muted: var(--lalt-assistant-muted, #77756f);
13
+ --_accent: var(--lalt-assistant-accent, #1c1c1a);
14
+ --_accent-text: var(--lalt-assistant-accent-text, #ffffff);
15
+ --_danger: var(--lalt-assistant-danger, #d03b3b);
16
+ --_radius: var(--lalt-assistant-radius, 12px);
17
+ --_font: var(--lalt-assistant-font, inherit);
18
+ color: var(--_text);
19
+ font-family: var(--_font);
20
+ font-size: 14px;
21
+ line-height: 1.45;
22
+ }
23
+
24
+ .lalt-assistant *,
25
+ .lalt-assistant *::before,
26
+ .lalt-assistant *::after {
27
+ box-sizing: border-box;
28
+ }
29
+
30
+ .lalt-assistant button {
31
+ font: inherit;
32
+ color: inherit;
33
+ cursor: pointer;
34
+ }
35
+
36
+ .lalt-assistant button:disabled {
37
+ cursor: default;
38
+ opacity: 0.45;
39
+ }
40
+
41
+ .lalt-assistant-launcher {
42
+ position: fixed;
43
+ right: 16px;
44
+ bottom: 16px;
45
+ z-index: 40;
46
+ display: flex;
47
+ gap: 8px;
48
+ }
49
+
50
+ .lalt-assistant-launch {
51
+ display: inline-flex;
52
+ align-items: center;
53
+ gap: 8px;
54
+ height: 40px;
55
+ padding: 0 16px;
56
+ border-radius: var(--_radius);
57
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.14);
58
+ }
59
+
60
+ .lalt-assistant-launch-secondary {
61
+ border: 1px solid var(--_border);
62
+ background: var(--_bg);
63
+ }
64
+
65
+ .lalt-assistant-launch-secondary:hover {
66
+ background: var(--_surface);
67
+ }
68
+
69
+ .lalt-assistant-launch-primary {
70
+ border: 0;
71
+ background: var(--_accent);
72
+ color: var(--_accent-text) !important;
73
+ }
74
+
75
+ .lalt-assistant-panel {
76
+ position: fixed;
77
+ top: 0;
78
+ right: 0;
79
+ bottom: 0;
80
+ z-index: 50;
81
+ display: flex;
82
+ flex-direction: column;
83
+ width: 100%;
84
+ border-left: 1px solid var(--_border);
85
+ background: var(--_bg);
86
+ box-shadow: -16px 0 48px rgba(0, 0, 0, 0.18);
87
+ }
88
+
89
+ @media (min-width: 640px) {
90
+ .lalt-assistant-panel {
91
+ width: var(--lalt-assistant-width, 520px);
92
+ }
93
+ }
94
+
95
+ .lalt-assistant-resize {
96
+ display: none;
97
+ position: absolute;
98
+ top: 0;
99
+ bottom: 0;
100
+ left: -4px;
101
+ width: 8px;
102
+ cursor: col-resize;
103
+ }
104
+
105
+ .lalt-assistant-resize:hover {
106
+ background: color-mix(in srgb, var(--_accent) 25%, transparent);
107
+ }
108
+
109
+ .lalt-assistant-wide-only {
110
+ display: none !important;
111
+ }
112
+
113
+ @media (min-width: 640px) {
114
+ .lalt-assistant-resize {
115
+ display: block;
116
+ }
117
+ .lalt-assistant-wide-only {
118
+ display: inline-flex !important;
119
+ }
120
+ }
121
+
122
+ .lalt-assistant-dropzone {
123
+ position: absolute;
124
+ inset: 8px;
125
+ z-index: 2;
126
+ display: flex;
127
+ align-items: center;
128
+ justify-content: center;
129
+ border: 2px dashed var(--_accent);
130
+ border-radius: var(--_radius);
131
+ background: color-mix(in srgb, var(--_bg) 88%, transparent);
132
+ font-weight: 500;
133
+ pointer-events: none;
134
+ }
135
+
136
+ .lalt-assistant-header {
137
+ display: flex;
138
+ align-items: center;
139
+ gap: 8px;
140
+ height: 56px;
141
+ padding: 0 16px;
142
+ border-bottom: 1px solid var(--_border);
143
+ flex-shrink: 0;
144
+ }
145
+
146
+ .lalt-assistant-menu {
147
+ position: relative;
148
+ }
149
+
150
+ .lalt-assistant-title {
151
+ display: inline-flex;
152
+ align-items: center;
153
+ gap: 6px;
154
+ border: 0;
155
+ background: none;
156
+ font-weight: 500;
157
+ }
158
+
159
+ .lalt-assistant-menu-content {
160
+ position: absolute;
161
+ top: calc(100% + 6px);
162
+ left: 0;
163
+ z-index: 3;
164
+ width: 288px;
165
+ padding: 4px;
166
+ border: 1px solid var(--_border);
167
+ border-radius: 10px;
168
+ background: var(--_bg);
169
+ box-shadow: 0 12px 32px rgba(0, 0, 0, 0.14);
170
+ }
171
+
172
+ .lalt-assistant-menu-content button {
173
+ display: flex;
174
+ align-items: center;
175
+ gap: 8px;
176
+ width: 100%;
177
+ padding: 6px 8px;
178
+ border: 0;
179
+ border-radius: 6px;
180
+ background: none;
181
+ text-align: left;
182
+ }
183
+
184
+ .lalt-assistant-menu-content button:hover {
185
+ background: var(--_hover);
186
+ }
187
+
188
+ .lalt-assistant-menu-label {
189
+ padding: 6px 8px 2px;
190
+ font-size: 12px;
191
+ color: var(--_muted);
192
+ }
193
+
194
+ .lalt-assistant-menu-separator {
195
+ height: 1px;
196
+ margin: 4px 0;
197
+ background: var(--_border);
198
+ }
199
+
200
+ .lalt-assistant-grow {
201
+ flex: 1;
202
+ min-width: 0;
203
+ }
204
+
205
+ .lalt-assistant-truncate {
206
+ overflow: hidden;
207
+ white-space: nowrap;
208
+ text-overflow: ellipsis;
209
+ }
210
+
211
+ .lalt-assistant-muted {
212
+ color: var(--_muted);
213
+ }
214
+
215
+ .lalt-assistant-small {
216
+ font-size: 12px;
217
+ }
218
+
219
+ .lalt-assistant-scope-label {
220
+ max-width: 160px;
221
+ }
222
+
223
+ .lalt-assistant-select {
224
+ height: 32px;
225
+ max-width: 160px;
226
+ padding: 0 8px;
227
+ border: 1px solid var(--_border);
228
+ border-radius: 8px;
229
+ background: var(--_bg);
230
+ color: inherit;
231
+ font: inherit;
232
+ font-size: 12px;
233
+ }
234
+
235
+ .lalt-assistant-icon-button {
236
+ display: inline-flex;
237
+ align-items: center;
238
+ justify-content: center;
239
+ padding: 6px;
240
+ border: 0;
241
+ border-radius: 6px;
242
+ background: none;
243
+ }
244
+
245
+ .lalt-assistant-icon-button:hover {
246
+ background: var(--_hover);
247
+ }
248
+
249
+ .lalt-assistant-body {
250
+ flex: 1;
251
+ min-height: 0;
252
+ overflow-y: auto;
253
+ padding: 16px;
254
+ }
255
+
256
+ .lalt-assistant-empty-title {
257
+ margin: 24px 0 4px;
258
+ font-size: 20px;
259
+ font-weight: 500;
260
+ text-align: center;
261
+ }
262
+
263
+ .lalt-assistant-intro {
264
+ margin: 0 0 24px;
265
+ font-size: 12px;
266
+ color: var(--_muted);
267
+ text-align: center;
268
+ }
269
+
270
+ .lalt-assistant-actions {
271
+ display: grid;
272
+ gap: 8px;
273
+ margin-top: 16px;
274
+ }
275
+
276
+ .lalt-assistant-action {
277
+ padding: 10px 12px;
278
+ border: 1px solid var(--_border);
279
+ border-radius: var(--_radius);
280
+ background: var(--_surface);
281
+ text-align: left;
282
+ }
283
+
284
+ .lalt-assistant-action:hover:not(:disabled) {
285
+ background: var(--_hover);
286
+ }
287
+
288
+ .lalt-assistant-action-label {
289
+ font-weight: 500;
290
+ }
291
+
292
+ .lalt-assistant-thread {
293
+ display: flex;
294
+ flex-direction: column;
295
+ gap: 12px;
296
+ }
297
+
298
+ .lalt-assistant-user {
299
+ align-self: flex-end;
300
+ max-width: 85%;
301
+ padding: 8px 12px;
302
+ border-radius: var(--_radius);
303
+ background: var(--_hover);
304
+ white-space: pre-wrap;
305
+ overflow-wrap: anywhere;
306
+ }
307
+
308
+ .lalt-assistant-sent-files {
309
+ display: flex;
310
+ flex-wrap: wrap;
311
+ gap: 4px;
312
+ margin-top: 6px;
313
+ }
314
+
315
+ .lalt-assistant-sent-file {
316
+ display: inline-flex;
317
+ align-items: center;
318
+ gap: 4px;
319
+ font-size: 12px;
320
+ color: var(--_muted);
321
+ }
322
+
323
+ .lalt-assistant-plain {
324
+ white-space: pre-wrap;
325
+ overflow-wrap: anywhere;
326
+ }
327
+
328
+ .lalt-assistant-status {
329
+ display: flex;
330
+ align-items: center;
331
+ gap: 8px;
332
+ }
333
+
334
+ .lalt-assistant-spinner {
335
+ display: inline-block;
336
+ width: 14px;
337
+ height: 14px;
338
+ flex-shrink: 0;
339
+ border: 2px solid var(--_border);
340
+ border-top-color: var(--_muted);
341
+ border-radius: 50%;
342
+ animation: lalt-assistant-spin 0.8s linear infinite;
343
+ }
344
+
345
+ @keyframes lalt-assistant-spin {
346
+ to {
347
+ transform: rotate(360deg);
348
+ }
349
+ }
350
+
351
+ .lalt-assistant-error {
352
+ margin: 8px 0 0;
353
+ font-size: 12px;
354
+ color: var(--_danger);
355
+ }
356
+
357
+ .lalt-assistant-history {
358
+ margin: 0;
359
+ padding: 0;
360
+ list-style: none;
361
+ }
362
+
363
+ .lalt-assistant-history button {
364
+ display: block;
365
+ width: 100%;
366
+ padding: 8px 12px;
367
+ border: 0;
368
+ border-radius: 8px;
369
+ background: none;
370
+ text-align: left;
371
+ }
372
+
373
+ .lalt-assistant-history button:hover {
374
+ background: var(--_hover);
375
+ }
376
+
377
+ .lalt-assistant-history-empty {
378
+ margin-top: 32px;
379
+ text-align: center;
380
+ }
381
+
382
+ .lalt-assistant-footer {
383
+ padding: 12px;
384
+ border-top: 1px solid var(--_border);
385
+ flex-shrink: 0;
386
+ }
387
+
388
+ .lalt-assistant-composer {
389
+ padding: 8px;
390
+ border: 1px solid var(--_border);
391
+ border-radius: var(--_radius);
392
+ background: var(--_surface);
393
+ }
394
+
395
+ .lalt-assistant-chips {
396
+ display: flex;
397
+ flex-wrap: wrap;
398
+ gap: 6px;
399
+ margin-bottom: 6px;
400
+ }
401
+
402
+ .lalt-assistant-chips .lalt-assistant-error {
403
+ flex-basis: 100%;
404
+ margin: 0;
405
+ }
406
+
407
+ .lalt-assistant-chip {
408
+ display: inline-flex;
409
+ align-items: center;
410
+ gap: 6px;
411
+ max-width: 240px;
412
+ padding: 4px 4px 4px 6px;
413
+ border: 1px solid var(--_border);
414
+ border-radius: 8px;
415
+ background: var(--_bg);
416
+ }
417
+
418
+ .lalt-assistant-chip[data-status="error"] {
419
+ border-color: var(--_danger);
420
+ }
421
+
422
+ .lalt-assistant-chip[data-status="error"] .lalt-assistant-muted {
423
+ color: var(--_danger);
424
+ }
425
+
426
+ .lalt-assistant-chip-preview {
427
+ width: 28px;
428
+ height: 28px;
429
+ object-fit: cover;
430
+ border-radius: 4px;
431
+ }
432
+
433
+ .lalt-assistant-chip-text {
434
+ display: flex;
435
+ flex-direction: column;
436
+ min-width: 0;
437
+ line-height: 1.2;
438
+ }
439
+
440
+ .lalt-assistant-chip-remove {
441
+ display: inline-flex;
442
+ padding: 4px;
443
+ border: 0;
444
+ border-radius: 4px;
445
+ background: none;
446
+ }
447
+
448
+ .lalt-assistant-chip-remove:hover {
449
+ background: var(--_hover);
450
+ }
451
+
452
+ .lalt-assistant-textarea {
453
+ display: block;
454
+ width: 100%;
455
+ padding: 0 4px;
456
+ border: 0;
457
+ outline: none;
458
+ resize: none;
459
+ background: transparent;
460
+ color: inherit;
461
+ font: inherit;
462
+ }
463
+
464
+ .lalt-assistant-composer-row {
465
+ display: flex;
466
+ align-items: center;
467
+ gap: 4px;
468
+ }
469
+
470
+ .lalt-assistant-send {
471
+ display: inline-flex;
472
+ align-items: center;
473
+ justify-content: center;
474
+ width: 32px;
475
+ height: 32px;
476
+ border: 0;
477
+ border-radius: 8px;
478
+ background: var(--_accent);
479
+ color: var(--_accent-text) !important;
480
+ }
@@ -0,0 +1,135 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ interface AssistantScope {
5
+ id: string;
6
+ label: string;
7
+ }
8
+ interface AssistantScopePicker {
9
+ scopes: AssistantScope[];
10
+ scopeId: string;
11
+ label: string;
12
+ onChange: (scopeId: string) => void;
13
+ }
14
+ interface AssistantQuickAction {
15
+ id: string;
16
+ label: string;
17
+ hint?: string;
18
+ prompt: string;
19
+ }
20
+ interface AssistantAttachment {
21
+ id: string;
22
+ filename: string;
23
+ mimeType: string;
24
+ sizeBytes: number;
25
+ }
26
+ interface AssistantMessage {
27
+ role: "user" | "assistant";
28
+ content: string;
29
+ attachments?: AssistantAttachment[];
30
+ meta?: unknown;
31
+ }
32
+ interface AssistantConversationSummary {
33
+ id: string;
34
+ title: string;
35
+ scopeId?: string;
36
+ updatedAt?: string;
37
+ }
38
+ interface AssistantConversation {
39
+ id: string;
40
+ scopeId?: string;
41
+ messages: AssistantMessage[];
42
+ }
43
+ interface AssistantScreen {
44
+ path: string;
45
+ title: string;
46
+ text: string;
47
+ }
48
+ interface AssistantSendInput {
49
+ scopeId: string;
50
+ conversationId?: string;
51
+ message: string;
52
+ attachmentIds: string[];
53
+ screen?: AssistantScreen;
54
+ }
55
+ interface AssistantSendResult {
56
+ conversationId: string;
57
+ answer: string;
58
+ meta?: unknown;
59
+ }
60
+ interface AttachmentLimits {
61
+ maxCount: number;
62
+ maxImageBytes: number;
63
+ maxFileBytes: number;
64
+ imageTypes: string[];
65
+ fileTypes: string[];
66
+ }
67
+ interface AssistantApi {
68
+ send(input: AssistantSendInput): Promise<AssistantSendResult>;
69
+ listConversations(): Promise<AssistantConversationSummary[]>;
70
+ getConversation(id: string): Promise<AssistantConversation>;
71
+ attach?(file: File, scopeId: string): Promise<AssistantAttachment>;
72
+ }
73
+ interface AssistantLabels {
74
+ launcher: string;
75
+ history: string;
76
+ newConversation: string;
77
+ recent: string;
78
+ allHistory: string;
79
+ emptyTitle: string;
80
+ intro: string;
81
+ noConversation: string;
82
+ placeholder: string;
83
+ send: string;
84
+ attach: string;
85
+ removeAttachment: string;
86
+ close: string;
87
+ expand: string;
88
+ collapse: string;
89
+ resize: string;
90
+ scope: string;
91
+ loading: string;
92
+ thinking: string;
93
+ dropHere: string;
94
+ uploading: string;
95
+ tooManyFiles: (max: number) => string;
96
+ fileTooLarge: (name: string, max: string) => string;
97
+ fileTypeRefused: (name: string) => string;
98
+ uploadFailed: string;
99
+ requestFailed: string;
100
+ }
101
+ interface AssistantPanelProps {
102
+ api: AssistantApi;
103
+ scopes: AssistantScope[];
104
+ scopeId: string;
105
+ onScopeChange?: (scopeId: string) => void;
106
+ scopeLocked?: boolean;
107
+ quickActions?: AssistantQuickAction[];
108
+ attachmentLimits?: AttachmentLimits;
109
+ pasteAsFileThreshold?: number;
110
+ labels?: Partial<AssistantLabels>;
111
+ renderMarkdown?: (text: string) => ReactNode;
112
+ renderScopePicker?: (picker: AssistantScopePicker) => ReactNode;
113
+ renderMessageFooter?: (message: AssistantMessage) => ReactNode;
114
+ readScreen?: () => AssistantScreen | undefined;
115
+ widthStorageKey?: string;
116
+ onClose: () => void;
117
+ initialHistory?: boolean;
118
+ }
119
+
120
+ type AssistantLauncherProps = Omit<AssistantPanelProps, "onClose" | "initialHistory">;
121
+ declare function AssistantLauncher(props: AssistantLauncherProps): react_jsx_runtime.JSX.Element;
122
+
123
+ declare function AssistantPanel({ api, scopes, scopeId, onScopeChange, scopeLocked, quickActions, attachmentLimits, pasteAsFileThreshold, labels: labelOverrides, renderMarkdown, renderScopePicker, renderMessageFooter, readScreen, widthStorageKey, onClose, initialHistory, }: AssistantPanelProps): react_jsx_runtime.JSX.Element;
124
+
125
+ declare const defaultLabels: AssistantLabels;
126
+
127
+ declare function relativeTime(iso: string | undefined, now?: number): string;
128
+ declare function formatSize(bytes: number): string;
129
+ declare function readMainScreen(): {
130
+ path: string;
131
+ title: string;
132
+ text: string;
133
+ } | undefined;
134
+
135
+ export { type AssistantApi, type AssistantAttachment, type AssistantConversation, type AssistantConversationSummary, type AssistantLabels, AssistantLauncher, type AssistantLauncherProps, type AssistantMessage, AssistantPanel, type AssistantPanelProps, type AssistantQuickAction, type AssistantScope, type AssistantScopePicker, type AssistantScreen, type AssistantSendInput, type AssistantSendResult, type AttachmentLimits, defaultLabels, formatSize, readMainScreen, relativeTime };