@skippr/live-agent-sdk 0.16.0 → 0.17.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.
@@ -1,6 +1,6 @@
1
1
  // src/components/LiveAgent.tsx
2
2
  import { LiveKitRoom, RoomAudioRenderer } from "@livekit/components-react";
3
- import { useCallback as useCallback7, useMemo as useMemo4, useState as useState7 } from "react";
3
+ import { useCallback as useCallback8, useEffect as useEffect8, useMemo as useMemo4, useState as useState8 } from "react";
4
4
 
5
5
  // src/context/LiveAgentContext.tsx
6
6
  import { createContext } from "react";
@@ -243,188 +243,9 @@ function useSession({ agentId, authToken, appKey, userToken }) {
243
243
  return { connection, shouldConnect, isStarting, error, startSession, disconnect };
244
244
  }
245
245
 
246
- // src/components/Sidebar.tsx
247
- import { useConnectionState } from "@livekit/components-react";
248
- import { ConnectionState } from "livekit-client";
249
- import { useEffect as useEffect7 } from "react";
250
-
251
- // src/hooks/useCombinedMessages.ts
252
- import { useVoiceAssistant } from "@livekit/components-react";
253
- import { useMemo as useMemo3 } from "react";
254
-
255
- // src/hooks/useChatMessages.ts
256
- import { useChat, useLocalParticipant } from "@livekit/components-react";
257
- import { useMemo } from "react";
258
-
259
- // src/lib/filterSystemMessages.ts
260
- var SYSTEM_MESSAGE_PATTERN = /^\[\w+\]$/;
261
- function filterSystemMessages(messages) {
262
- return messages.filter((m) => !SYSTEM_MESSAGE_PATTERN.test(m.content.trim()));
263
- }
264
-
265
- // src/hooks/useChatMessages.ts
266
- function useChatMessages() {
267
- const { chatMessages: rawMessages, send, isSending } = useChat();
268
- const { localParticipant } = useLocalParticipant();
269
- const localIdentity = localParticipant.identity;
270
- const chatMessages = useMemo(() => {
271
- const sortedMessages = rawMessages.map((msg) => ({
272
- id: msg.id,
273
- role: msg.from?.identity === localIdentity ? "user" : "assistant",
274
- content: msg.message,
275
- source: "chat",
276
- timestamp: msg.timestamp
277
- })).sort((a, b) => (a.timestamp ?? 0) - (b.timestamp ?? 0));
278
- return filterSystemMessages(sortedMessages);
279
- }, [rawMessages, localIdentity]);
280
- return { chatMessages, sendChatMessage: send, isSendingChat: isSending };
281
- }
282
-
283
- // src/hooks/useStreamingTranscript.ts
284
- import { useLocalParticipant as useLocalParticipant2, useTranscriptions } from "@livekit/components-react";
285
- import { useMemo as useMemo2 } from "react";
286
- function useStreamingTranscript() {
287
- const transcriptions = useTranscriptions();
288
- const { localParticipant } = useLocalParticipant2();
289
- const localIdentity = localParticipant.identity;
290
- const transcriptMessages = useMemo2(() => filterSystemMessages(transcriptions.filter((stream) => stream.text.trim().length > 0).map((stream) => ({
291
- id: stream.streamInfo.id,
292
- role: stream.participantInfo.identity === localIdentity ? "user" : "assistant",
293
- content: stream.text,
294
- source: "voice-transcript",
295
- timestamp: stream.streamInfo.timestamp
296
- }))), [transcriptions, localIdentity]);
297
- return { transcriptMessages };
298
- }
299
-
300
- // src/hooks/useCombinedMessages.ts
301
- function mergeChatsIntoTranscripts(transcripts, chats) {
302
- const merged = [];
303
- let chatIndex = 0;
304
- for (const transcript of transcripts) {
305
- while (chatIndex < chats.length && (chats[chatIndex].timestamp ?? 0) <= (transcript.timestamp ?? 0)) {
306
- merged.push(chats[chatIndex]);
307
- chatIndex++;
308
- }
309
- merged.push(transcript);
310
- }
311
- while (chatIndex < chats.length) {
312
- merged.push(chats[chatIndex]);
313
- chatIndex++;
314
- }
315
- return merged;
316
- }
317
- function useCombinedMessages() {
318
- const { transcriptMessages } = useStreamingTranscript();
319
- const { chatMessages, sendChatMessage, isSendingChat } = useChatMessages();
320
- const { state: agentState } = useVoiceAssistant();
321
- const allMessages = useMemo3(() => {
322
- if (chatMessages.length === 0)
323
- return transcriptMessages;
324
- if (transcriptMessages.length === 0)
325
- return chatMessages;
326
- return mergeChatsIntoTranscripts(transcriptMessages, chatMessages);
327
- }, [transcriptMessages, chatMessages]);
328
- return { allMessages, agentState, sendChatMessage, isSendingChat };
329
- }
330
-
331
- // src/hooks/useLiveAgent.ts
332
- import { use } from "react";
333
- function useLiveAgent() {
334
- const ctx = use(LiveAgentContext);
335
- if (!ctx) {
336
- throw new Error("useLiveAgent must be used within a <LiveAgent> provider");
337
- }
338
- const { connection, shouldConnect, ...publicValue } = ctx;
339
- return publicValue;
340
- }
341
-
342
- // src/hooks/usePhaseUpdates.ts
343
- import { useCallback as useCallback3 } from "react";
344
-
345
- // src/hooks/useAgentState.ts
346
- import { useRemoteParticipants } from "@livekit/components-react";
347
- import { useEffect as useEffect3, useState as useState3 } from "react";
348
- function useAgentState(attributeKey, parse, initial) {
349
- const [value, setValue] = useState3(initial);
350
- const remoteParticipants = useRemoteParticipants();
351
- useEffect3(() => {
352
- const agentParticipant = remoteParticipants.find((p) => p.attributes?.[attributeKey]);
353
- if (agentParticipant) {
354
- const attr = agentParticipant.attributes?.[attributeKey];
355
- if (attr) {
356
- const parsed = parse(attr);
357
- if (parsed)
358
- setValue(parsed);
359
- }
360
- }
361
- const handlers = new Map;
362
- for (const p of remoteParticipants) {
363
- const handler = (changedAttributes) => {
364
- if (changedAttributes[attributeKey]) {
365
- const parsed = parse(changedAttributes[attributeKey]);
366
- if (parsed)
367
- setValue(parsed);
368
- } else if (p.attributes?.[attributeKey]) {
369
- const parsed = parse(p.attributes[attributeKey]);
370
- if (parsed)
371
- setValue(parsed);
372
- }
373
- };
374
- handlers.set(p, handler);
375
- p.on("attributesChanged", handler);
376
- }
377
- return () => {
378
- for (const [p, handler] of handlers) {
379
- p.off("attributesChanged", handler);
380
- }
381
- };
382
- }, [remoteParticipants, attributeKey, parse]);
383
- return value;
384
- }
385
-
386
- // src/hooks/usePhaseUpdates.ts
387
- function parsePhases(json) {
388
- try {
389
- const data = JSON.parse(json);
390
- if (data.type === "phase_update" && Array.isArray(data.phases)) {
391
- return data.phases;
392
- }
393
- } catch {}
394
- return null;
395
- }
396
- function usePhaseUpdates() {
397
- const parse = useCallback3(parsePhases, []);
398
- const phases = useAgentState("phases", parse, []);
399
- return { phases };
400
- }
401
-
402
- // src/hooks/useQuestionUpdates.ts
403
- import { useCallback as useCallback4 } from "react";
404
- function parseQuestions(json) {
405
- try {
406
- const data = JSON.parse(json);
407
- if (data.type === "question_update" && Array.isArray(data.questions)) {
408
- return data.questions;
409
- }
410
- } catch {}
411
- return null;
412
- }
413
- function useQuestionUpdates() {
414
- const parse = useCallback4(parseQuestions, []);
415
- const questions = useAgentState("questions", parse, []);
416
- return { questions };
417
- }
418
-
419
- // src/lib/constants.ts
420
- var SIDEBAR_WIDTH = 600;
421
-
422
- // src/lib/utils.ts
423
- import { clsx } from "clsx";
424
- import { twMerge } from "tailwind-merge";
425
- function cn(...inputs) {
426
- return twMerge(clsx(inputs));
427
- }
246
+ // src/components/MinimizedBubble.tsx
247
+ import { useLocalParticipant, useVoiceAssistant } from "@livekit/components-react";
248
+ import { ScreenSharePresets } from "livekit-client";
428
249
  // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/createLucideIcon.js
429
250
  import { forwardRef as forwardRef2, createElement as createElement2 } from "react";
430
251
 
@@ -524,112 +345,471 @@ var __iconNode2 = [
524
345
  ["path", { d: "M12 17h.01", key: "p32p05" }]
525
346
  ];
526
347
  var MessageCircleQuestionMark = createLucideIcon("message-circle-question-mark", __iconNode2);
527
- // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/send-horizontal.js
348
+ // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/panel-left.js
528
349
  var __iconNode3 = [
350
+ ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
351
+ ["path", { d: "M9 3v18", key: "fh3hqa" }]
352
+ ];
353
+ var PanelLeft = createLucideIcon("panel-left", __iconNode3);
354
+ // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/send-horizontal.js
355
+ var __iconNode4 = [
529
356
  [
530
357
  "path",
531
358
  {
532
359
  d: "M3.714 3.048a.498.498 0 0 0-.683.627l2.843 7.627a2 2 0 0 1 0 1.396l-2.842 7.627a.498.498 0 0 0 .682.627l18-8.5a.5.5 0 0 0 0-.904z",
533
360
  key: "117uat"
534
361
  }
535
- ],
536
- ["path", { d: "M6 12h16", key: "s4cdu5" }]
537
- ];
538
- var SendHorizontal = createLucideIcon("send-horizontal", __iconNode3);
539
- // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/bot.js
540
- var __iconNode4 = [
541
- ["path", { d: "M12 8V4H8", key: "hb8ula" }],
542
- ["rect", { width: "16", height: "12", x: "4", y: "8", rx: "2", key: "enze0r" }],
543
- ["path", { d: "M2 14h2", key: "vft8re" }],
544
- ["path", { d: "M20 14h2", key: "4cs60a" }],
545
- ["path", { d: "M15 13v2", key: "1xurst" }],
546
- ["path", { d: "M9 13v2", key: "rq6x2g" }]
547
- ];
548
- var Bot = createLucideIcon("bot", __iconNode4);
549
- // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/check.js
550
- var __iconNode5 = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
551
- var Check = createLucideIcon("check", __iconNode5);
552
- // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/circle.js
553
- var __iconNode6 = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
554
- var Circle = createLucideIcon("circle", __iconNode6);
555
- // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mail.js
556
- var __iconNode7 = [
557
- ["path", { d: "m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7", key: "132q7q" }],
558
- ["rect", { x: "2", y: "4", width: "20", height: "16", rx: "2", key: "izxlao" }]
559
- ];
560
- var Mail = createLucideIcon("mail", __iconNode7);
561
- // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/message-circle.js
562
- var __iconNode8 = [
563
- [
564
- "path",
565
- {
566
- d: "M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719",
567
- key: "1sd12s"
362
+ ],
363
+ ["path", { d: "M6 12h16", key: "s4cdu5" }]
364
+ ];
365
+ var SendHorizontal = createLucideIcon("send-horizontal", __iconNode4);
366
+ // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/arrow-left.js
367
+ var __iconNode5 = [
368
+ ["path", { d: "m12 19-7-7 7-7", key: "1l729n" }],
369
+ ["path", { d: "M19 12H5", key: "x3x0zl" }]
370
+ ];
371
+ var ArrowLeft = createLucideIcon("arrow-left", __iconNode5);
372
+ // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/bot.js
373
+ var __iconNode6 = [
374
+ ["path", { d: "M12 8V4H8", key: "hb8ula" }],
375
+ ["rect", { width: "16", height: "12", x: "4", y: "8", rx: "2", key: "enze0r" }],
376
+ ["path", { d: "M2 14h2", key: "vft8re" }],
377
+ ["path", { d: "M20 14h2", key: "4cs60a" }],
378
+ ["path", { d: "M15 13v2", key: "1xurst" }],
379
+ ["path", { d: "M9 13v2", key: "rq6x2g" }]
380
+ ];
381
+ var Bot = createLucideIcon("bot", __iconNode6);
382
+ // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/check.js
383
+ var __iconNode7 = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
384
+ var Check = createLucideIcon("check", __iconNode7);
385
+ // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/circle.js
386
+ var __iconNode8 = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
387
+ var Circle = createLucideIcon("circle", __iconNode8);
388
+ // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mail.js
389
+ var __iconNode9 = [
390
+ ["path", { d: "m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7", key: "132q7q" }],
391
+ ["rect", { x: "2", y: "4", width: "20", height: "16", rx: "2", key: "izxlao" }]
392
+ ];
393
+ var Mail = createLucideIcon("mail", __iconNode9);
394
+ // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/message-circle.js
395
+ var __iconNode10 = [
396
+ [
397
+ "path",
398
+ {
399
+ d: "M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719",
400
+ key: "1sd12s"
401
+ }
402
+ ]
403
+ ];
404
+ var MessageCircle = createLucideIcon("message-circle", __iconNode10);
405
+ // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mic-off.js
406
+ var __iconNode11 = [
407
+ ["path", { d: "M12 19v3", key: "npa21l" }],
408
+ ["path", { d: "M15 9.34V5a3 3 0 0 0-5.68-1.33", key: "1gzdoj" }],
409
+ ["path", { d: "M16.95 16.95A7 7 0 0 1 5 12v-2", key: "cqa7eg" }],
410
+ ["path", { d: "M18.89 13.23A7 7 0 0 0 19 12v-2", key: "16hl24" }],
411
+ ["path", { d: "m2 2 20 20", key: "1ooewy" }],
412
+ ["path", { d: "M9 9v3a3 3 0 0 0 5.12 2.12", key: "r2i35w" }]
413
+ ];
414
+ var MicOff = createLucideIcon("mic-off", __iconNode11);
415
+ // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mic.js
416
+ var __iconNode12 = [
417
+ ["path", { d: "M12 19v3", key: "npa21l" }],
418
+ ["path", { d: "M19 10v2a7 7 0 0 1-14 0v-2", key: "1vc78b" }],
419
+ ["rect", { x: "9", y: "2", width: "6", height: "13", rx: "3", key: "s6n7sd" }]
420
+ ];
421
+ var Mic = createLucideIcon("mic", __iconNode12);
422
+ // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/minimize-2.js
423
+ var __iconNode13 = [
424
+ ["path", { d: "m14 10 7-7", key: "oa77jy" }],
425
+ ["path", { d: "M20 10h-6V4", key: "mjg0md" }],
426
+ ["path", { d: "m3 21 7-7", key: "tjx5ai" }],
427
+ ["path", { d: "M4 14h6v6", key: "rmj7iw" }]
428
+ ];
429
+ var Minimize2 = createLucideIcon("minimize-2", __iconNode13);
430
+ // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/monitor-off.js
431
+ var __iconNode14 = [
432
+ ["path", { d: "M12 17v4", key: "1riwvh" }],
433
+ ["path", { d: "M17 17H4a2 2 0 0 1-2-2V5a2 2 0 0 1 1.184-1.826", key: "cv7jms" }],
434
+ ["path", { d: "m2 2 20 20", key: "1ooewy" }],
435
+ ["path", { d: "M8 21h8", key: "1ev6f3" }],
436
+ ["path", { d: "M8.656 3H20a2 2 0 0 1 2 2v10a2 2 0 0 1-.293 1.042", key: "z8ni2w" }]
437
+ ];
438
+ var MonitorOff = createLucideIcon("monitor-off", __iconNode14);
439
+ // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/monitor.js
440
+ var __iconNode15 = [
441
+ ["rect", { width: "20", height: "14", x: "2", y: "3", rx: "2", key: "48i651" }],
442
+ ["line", { x1: "8", x2: "16", y1: "21", y2: "21", key: "1svkeh" }],
443
+ ["line", { x1: "12", x2: "12", y1: "17", y2: "21", key: "vw1qmm" }]
444
+ ];
445
+ var Monitor = createLucideIcon("monitor", __iconNode15);
446
+ // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/panel-right.js
447
+ var __iconNode16 = [
448
+ ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
449
+ ["path", { d: "M15 3v18", key: "14nvp0" }]
450
+ ];
451
+ var PanelRight = createLucideIcon("panel-right", __iconNode16);
452
+ // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/phone-off.js
453
+ var __iconNode17 = [
454
+ [
455
+ "path",
456
+ {
457
+ d: "M10.1 13.9a14 14 0 0 0 3.732 2.668 1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2 18 18 0 0 1-12.728-5.272",
458
+ key: "1wngk7"
459
+ }
460
+ ],
461
+ ["path", { d: "M22 2 2 22", key: "y4kqgn" }],
462
+ [
463
+ "path",
464
+ {
465
+ d: "M4.76 13.582A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 .244.473",
466
+ key: "10hv5p"
467
+ }
468
+ ]
469
+ ];
470
+ var PhoneOff = createLucideIcon("phone-off", __iconNode17);
471
+ // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/settings.js
472
+ var __iconNode18 = [
473
+ [
474
+ "path",
475
+ {
476
+ d: "M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915",
477
+ key: "1i5ecw"
478
+ }
479
+ ],
480
+ ["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
481
+ ];
482
+ var Settings = createLucideIcon("settings", __iconNode18);
483
+ // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/x.js
484
+ var __iconNode19 = [
485
+ ["path", { d: "M18 6 6 18", key: "1bl5f8" }],
486
+ ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
487
+ ];
488
+ var X = createLucideIcon("x", __iconNode19);
489
+ // src/components/MinimizedBubble.tsx
490
+ import { useCallback as useCallback3 } from "react";
491
+
492
+ // src/hooks/useLiveAgent.ts
493
+ import { use } from "react";
494
+ function useLiveAgent() {
495
+ const ctx = use(LiveAgentContext);
496
+ if (!ctx) {
497
+ throw new Error("useLiveAgent must be used within a <LiveAgent> provider");
498
+ }
499
+ const { connection, shouldConnect, ...publicValue } = ctx;
500
+ return publicValue;
501
+ }
502
+
503
+ // src/lib/utils.ts
504
+ import { clsx } from "clsx";
505
+ import { twMerge } from "tailwind-merge";
506
+ function cn(...inputs) {
507
+ return twMerge(clsx(inputs));
508
+ }
509
+
510
+ // src/components/MinimizedBubble.tsx
511
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
512
+ function AgentAvatar({ agentState }) {
513
+ if (agentState === "speaking") {
514
+ return /* @__PURE__ */ jsxs("div", {
515
+ className: "skippr:flex skippr:items-end skippr:justify-center skippr:gap-[3px] skippr:h-5",
516
+ children: [
517
+ /* @__PURE__ */ jsx("span", {
518
+ className: "skippr:w-[3px] skippr:h-full skippr:rounded-full skippr:bg-primary-foreground skippr:origin-bottom skippr:animate-skippr-bar-1"
519
+ }),
520
+ /* @__PURE__ */ jsx("span", {
521
+ className: "skippr:w-[3px] skippr:h-full skippr:rounded-full skippr:bg-primary-foreground skippr:origin-bottom skippr:animate-skippr-bar-2"
522
+ }),
523
+ /* @__PURE__ */ jsx("span", {
524
+ className: "skippr:w-[3px] skippr:h-full skippr:rounded-full skippr:bg-primary-foreground skippr:origin-bottom skippr:animate-skippr-bar-3"
525
+ }),
526
+ /* @__PURE__ */ jsx("span", {
527
+ className: "skippr:w-[3px] skippr:h-full skippr:rounded-full skippr:bg-primary-foreground skippr:origin-bottom skippr:animate-skippr-bar-4"
528
+ })
529
+ ]
530
+ });
531
+ }
532
+ if (agentState === "listening") {
533
+ return /* @__PURE__ */ jsx(Bot, {
534
+ className: "skippr:relative skippr:z-10 skippr:size-5 skippr:animate-skippr-breathe"
535
+ });
536
+ }
537
+ if (agentState === "thinking") {
538
+ return /* @__PURE__ */ jsx(Bot, {
539
+ className: "skippr:relative skippr:z-10 skippr:size-5 skippr:animate-pulse"
540
+ });
541
+ }
542
+ return /* @__PURE__ */ jsx(Bot, {
543
+ className: "skippr:relative skippr:z-10 skippr:size-5"
544
+ });
545
+ }
546
+ function MinimizedBubble() {
547
+ const { expandPanel, disconnect, position } = useLiveAgent();
548
+ const { state: agentState } = useVoiceAssistant();
549
+ const { localParticipant } = useLocalParticipant();
550
+ const isMuted = !localParticipant.isMicrophoneEnabled;
551
+ const isScreenSharing = localParticipant.isScreenShareEnabled;
552
+ const toggleMute = useCallback3(async () => {
553
+ try {
554
+ await localParticipant.setMicrophoneEnabled(isMuted);
555
+ } catch (e) {
556
+ console.error("Failed to toggle microphone:", e);
557
+ }
558
+ }, [localParticipant, isMuted]);
559
+ const toggleScreenShare = useCallback3(async () => {
560
+ try {
561
+ await localParticipant.setScreenShareEnabled(!isScreenSharing, {
562
+ video: { displaySurface: "browser" },
563
+ resolution: ScreenSharePresets.h720fps30.resolution,
564
+ contentHint: "detail"
565
+ });
566
+ } catch (e) {
567
+ console.error("Failed to toggle screen share:", e);
568
+ }
569
+ }, [localParticipant, isScreenSharing]);
570
+ const handleHangUp = useCallback3(async () => {
571
+ await disconnect();
572
+ }, [disconnect]);
573
+ const isSpeaking = agentState === "speaking";
574
+ const isListening = agentState === "listening";
575
+ return /* @__PURE__ */ jsxs("div", {
576
+ className: cn("skippr:fixed skippr:bottom-6 skippr:z-[9999]", "skippr:flex skippr:items-center skippr:gap-0", "skippr:rounded-full skippr:bg-card skippr:shadow-2xl", "skippr:border skippr:border-border", "skippr:p-1.5", position === "right" ? "skippr:right-6" : "skippr:left-6"),
577
+ children: [
578
+ /* @__PURE__ */ jsxs("button", {
579
+ type: "button",
580
+ onClick: expandPanel,
581
+ className: cn("skippr:relative skippr:size-11 skippr:rounded-full", "skippr:bg-primary skippr:text-primary-foreground", "skippr:flex skippr:items-center skippr:justify-center", "skippr:cursor-pointer skippr:transition-all skippr:duration-300", "skippr:hover:brightness-110", isListening && "skippr:animate-skippr-pulse-ring"),
582
+ "aria-label": "Expand meeting panel",
583
+ children: [
584
+ isSpeaking && /* @__PURE__ */ jsxs(Fragment, {
585
+ children: [
586
+ /* @__PURE__ */ jsx("span", {
587
+ className: "skippr:absolute skippr:inset-0 skippr:rounded-full skippr:bg-primary skippr:animate-skippr-speak-ripple"
588
+ }),
589
+ /* @__PURE__ */ jsx("span", {
590
+ className: "skippr:absolute skippr:inset-0 skippr:rounded-full skippr:bg-primary skippr:animate-skippr-speak-ripple-delayed"
591
+ })
592
+ ]
593
+ }),
594
+ /* @__PURE__ */ jsx(AgentAvatar, {
595
+ agentState
596
+ })
597
+ ]
598
+ }),
599
+ /* @__PURE__ */ jsx("div", {
600
+ className: "skippr:mx-1 skippr:h-6 skippr:w-px skippr:bg-border"
601
+ }),
602
+ /* @__PURE__ */ jsxs("div", {
603
+ className: "skippr:flex skippr:items-center skippr:gap-1",
604
+ children: [
605
+ /* @__PURE__ */ jsx("button", {
606
+ type: "button",
607
+ onClick: toggleMute,
608
+ className: cn("skippr:size-9 skippr:rounded-full skippr:flex skippr:items-center skippr:justify-center", "skippr:transition-colors skippr:cursor-pointer", isMuted ? "skippr:bg-destructive skippr:text-white" : "skippr:text-foreground skippr:hover:bg-accent"),
609
+ "aria-label": isMuted ? "Unmute" : "Mute",
610
+ children: isMuted ? /* @__PURE__ */ jsx(MicOff, {
611
+ className: "skippr:size-4"
612
+ }) : /* @__PURE__ */ jsx(Mic, {
613
+ className: "skippr:size-4"
614
+ })
615
+ }),
616
+ /* @__PURE__ */ jsx("button", {
617
+ type: "button",
618
+ onClick: toggleScreenShare,
619
+ className: cn("skippr:size-9 skippr:rounded-full skippr:flex skippr:items-center skippr:justify-center", "skippr:transition-colors skippr:cursor-pointer", isScreenSharing ? "skippr:text-foreground skippr:hover:bg-accent" : "skippr:bg-destructive skippr:text-white"),
620
+ "aria-label": isScreenSharing ? "Stop sharing" : "Share screen",
621
+ children: isScreenSharing ? /* @__PURE__ */ jsx(MonitorOff, {
622
+ className: "skippr:size-4"
623
+ }) : /* @__PURE__ */ jsx(Monitor, {
624
+ className: "skippr:size-4"
625
+ })
626
+ })
627
+ ]
628
+ }),
629
+ /* @__PURE__ */ jsx("div", {
630
+ className: "skippr:mx-1 skippr:h-6 skippr:w-px skippr:bg-border"
631
+ }),
632
+ /* @__PURE__ */ jsx("button", {
633
+ type: "button",
634
+ onClick: handleHangUp,
635
+ className: "skippr:size-9 skippr:rounded-full skippr:flex skippr:items-center skippr:justify-center skippr:bg-destructive skippr:text-white skippr:cursor-pointer skippr:transition-colors skippr:hover:bg-destructive/90",
636
+ "aria-label": "Hang up",
637
+ children: /* @__PURE__ */ jsx(PhoneOff, {
638
+ className: "skippr:size-4"
639
+ })
640
+ })
641
+ ]
642
+ });
643
+ }
644
+
645
+ // src/components/Sidebar.tsx
646
+ import { useConnectionState } from "@livekit/components-react";
647
+ import { ConnectionState } from "livekit-client";
648
+ import { useEffect as useEffect7, useState as useState7 } from "react";
649
+
650
+ // src/hooks/useCombinedMessages.ts
651
+ import { useVoiceAssistant as useVoiceAssistant2 } from "@livekit/components-react";
652
+ import { useMemo as useMemo3 } from "react";
653
+
654
+ // src/hooks/useChatMessages.ts
655
+ import { useChat, useLocalParticipant as useLocalParticipant2 } from "@livekit/components-react";
656
+ import { useMemo } from "react";
657
+
658
+ // src/lib/filterSystemMessages.ts
659
+ var SYSTEM_MESSAGE_PATTERN = /^\[\w+\]$/;
660
+ function filterSystemMessages(messages) {
661
+ return messages.filter((m) => !SYSTEM_MESSAGE_PATTERN.test(m.content.trim()));
662
+ }
663
+
664
+ // src/hooks/useChatMessages.ts
665
+ function useChatMessages() {
666
+ const { chatMessages: rawMessages, send, isSending } = useChat();
667
+ const { localParticipant } = useLocalParticipant2();
668
+ const localIdentity = localParticipant.identity;
669
+ const chatMessages = useMemo(() => {
670
+ const sortedMessages = rawMessages.map((msg) => ({
671
+ id: msg.id,
672
+ role: msg.from?.identity === localIdentity ? "user" : "assistant",
673
+ content: msg.message,
674
+ source: "chat",
675
+ timestamp: msg.timestamp
676
+ })).sort((a, b) => (a.timestamp ?? 0) - (b.timestamp ?? 0));
677
+ return filterSystemMessages(sortedMessages);
678
+ }, [rawMessages, localIdentity]);
679
+ return { chatMessages, sendChatMessage: send, isSendingChat: isSending };
680
+ }
681
+
682
+ // src/hooks/useStreamingTranscript.ts
683
+ import { useLocalParticipant as useLocalParticipant3, useTranscriptions } from "@livekit/components-react";
684
+ import { useMemo as useMemo2 } from "react";
685
+ function useStreamingTranscript() {
686
+ const transcriptions = useTranscriptions();
687
+ const { localParticipant } = useLocalParticipant3();
688
+ const localIdentity = localParticipant.identity;
689
+ const transcriptMessages = useMemo2(() => filterSystemMessages(transcriptions.filter((stream) => stream.text.trim().length > 0).map((stream) => ({
690
+ id: stream.streamInfo.id,
691
+ role: stream.participantInfo.identity === localIdentity ? "user" : "assistant",
692
+ content: stream.text,
693
+ source: "voice-transcript",
694
+ timestamp: stream.streamInfo.timestamp
695
+ }))), [transcriptions, localIdentity]);
696
+ return { transcriptMessages };
697
+ }
698
+
699
+ // src/hooks/useCombinedMessages.ts
700
+ function mergeChatsIntoTranscripts(transcripts, chats) {
701
+ const merged = [];
702
+ let chatIndex = 0;
703
+ for (const transcript of transcripts) {
704
+ while (chatIndex < chats.length && (chats[chatIndex].timestamp ?? 0) <= (transcript.timestamp ?? 0)) {
705
+ merged.push(chats[chatIndex]);
706
+ chatIndex++;
707
+ }
708
+ merged.push(transcript);
709
+ }
710
+ while (chatIndex < chats.length) {
711
+ merged.push(chats[chatIndex]);
712
+ chatIndex++;
713
+ }
714
+ return merged;
715
+ }
716
+ function useCombinedMessages() {
717
+ const { transcriptMessages } = useStreamingTranscript();
718
+ const { chatMessages, sendChatMessage, isSendingChat } = useChatMessages();
719
+ const { state: agentState } = useVoiceAssistant2();
720
+ const allMessages = useMemo3(() => {
721
+ if (chatMessages.length === 0)
722
+ return transcriptMessages;
723
+ if (transcriptMessages.length === 0)
724
+ return chatMessages;
725
+ return mergeChatsIntoTranscripts(transcriptMessages, chatMessages);
726
+ }, [transcriptMessages, chatMessages]);
727
+ return { allMessages, agentState, sendChatMessage, isSendingChat };
728
+ }
729
+
730
+ // src/hooks/usePhaseUpdates.ts
731
+ import { useCallback as useCallback4 } from "react";
732
+
733
+ // src/hooks/useAgentState.ts
734
+ import { useRemoteParticipants } from "@livekit/components-react";
735
+ import { useEffect as useEffect3, useState as useState3 } from "react";
736
+ function useAgentState(attributeKey, parse, initial) {
737
+ const [value, setValue] = useState3(initial);
738
+ const remoteParticipants = useRemoteParticipants();
739
+ useEffect3(() => {
740
+ const agentParticipant = remoteParticipants.find((p) => p.attributes?.[attributeKey]);
741
+ if (agentParticipant) {
742
+ const attr = agentParticipant.attributes?.[attributeKey];
743
+ if (attr) {
744
+ const parsed = parse(attr);
745
+ if (parsed)
746
+ setValue(parsed);
747
+ }
748
+ }
749
+ const handlers = new Map;
750
+ for (const p of remoteParticipants) {
751
+ const handler = (changedAttributes) => {
752
+ if (changedAttributes[attributeKey]) {
753
+ const parsed = parse(changedAttributes[attributeKey]);
754
+ if (parsed)
755
+ setValue(parsed);
756
+ } else if (p.attributes?.[attributeKey]) {
757
+ const parsed = parse(p.attributes[attributeKey]);
758
+ if (parsed)
759
+ setValue(parsed);
760
+ }
761
+ };
762
+ handlers.set(p, handler);
763
+ p.on("attributesChanged", handler);
568
764
  }
569
- ]
570
- ];
571
- var MessageCircle = createLucideIcon("message-circle", __iconNode8);
572
- // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mic-off.js
573
- var __iconNode9 = [
574
- ["path", { d: "M12 19v3", key: "npa21l" }],
575
- ["path", { d: "M15 9.34V5a3 3 0 0 0-5.68-1.33", key: "1gzdoj" }],
576
- ["path", { d: "M16.95 16.95A7 7 0 0 1 5 12v-2", key: "cqa7eg" }],
577
- ["path", { d: "M18.89 13.23A7 7 0 0 0 19 12v-2", key: "16hl24" }],
578
- ["path", { d: "m2 2 20 20", key: "1ooewy" }],
579
- ["path", { d: "M9 9v3a3 3 0 0 0 5.12 2.12", key: "r2i35w" }]
580
- ];
581
- var MicOff = createLucideIcon("mic-off", __iconNode9);
582
- // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mic.js
583
- var __iconNode10 = [
584
- ["path", { d: "M12 19v3", key: "npa21l" }],
585
- ["path", { d: "M19 10v2a7 7 0 0 1-14 0v-2", key: "1vc78b" }],
586
- ["rect", { x: "9", y: "2", width: "6", height: "13", rx: "3", key: "s6n7sd" }]
587
- ];
588
- var Mic = createLucideIcon("mic", __iconNode10);
589
- // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/monitor-off.js
590
- var __iconNode11 = [
591
- ["path", { d: "M12 17v4", key: "1riwvh" }],
592
- ["path", { d: "M17 17H4a2 2 0 0 1-2-2V5a2 2 0 0 1 1.184-1.826", key: "cv7jms" }],
593
- ["path", { d: "m2 2 20 20", key: "1ooewy" }],
594
- ["path", { d: "M8 21h8", key: "1ev6f3" }],
595
- ["path", { d: "M8.656 3H20a2 2 0 0 1 2 2v10a2 2 0 0 1-.293 1.042", key: "z8ni2w" }]
596
- ];
597
- var MonitorOff = createLucideIcon("monitor-off", __iconNode11);
598
- // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/monitor.js
599
- var __iconNode12 = [
600
- ["rect", { width: "20", height: "14", x: "2", y: "3", rx: "2", key: "48i651" }],
601
- ["line", { x1: "8", x2: "16", y1: "21", y2: "21", key: "1svkeh" }],
602
- ["line", { x1: "12", x2: "12", y1: "17", y2: "21", key: "vw1qmm" }]
603
- ];
604
- var Monitor = createLucideIcon("monitor", __iconNode12);
605
- // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/phone-off.js
606
- var __iconNode13 = [
607
- [
608
- "path",
609
- {
610
- d: "M10.1 13.9a14 14 0 0 0 3.732 2.668 1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2 18 18 0 0 1-12.728-5.272",
611
- key: "1wngk7"
765
+ return () => {
766
+ for (const [p, handler] of handlers) {
767
+ p.off("attributesChanged", handler);
768
+ }
769
+ };
770
+ }, [remoteParticipants, attributeKey, parse]);
771
+ return value;
772
+ }
773
+
774
+ // src/hooks/usePhaseUpdates.ts
775
+ function parsePhases(json) {
776
+ try {
777
+ const data = JSON.parse(json);
778
+ if (data.type === "phase_update" && Array.isArray(data.phases)) {
779
+ return data.phases;
612
780
  }
613
- ],
614
- ["path", { d: "M22 2 2 22", key: "y4kqgn" }],
615
- [
616
- "path",
617
- {
618
- d: "M4.76 13.582A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 .244.473",
619
- key: "10hv5p"
781
+ } catch {}
782
+ return null;
783
+ }
784
+ function usePhaseUpdates() {
785
+ const parse = useCallback4(parsePhases, []);
786
+ const phases = useAgentState("phases", parse, []);
787
+ return { phases };
788
+ }
789
+
790
+ // src/hooks/useQuestionUpdates.ts
791
+ import { useCallback as useCallback5 } from "react";
792
+ function parseQuestions(json) {
793
+ try {
794
+ const data = JSON.parse(json);
795
+ if (data.type === "question_update" && Array.isArray(data.questions)) {
796
+ return data.questions;
620
797
  }
621
- ]
622
- ];
623
- var PhoneOff = createLucideIcon("phone-off", __iconNode13);
624
- // ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/x.js
625
- var __iconNode14 = [
626
- ["path", { d: "M18 6 6 18", key: "1bl5f8" }],
627
- ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
628
- ];
629
- var X = createLucideIcon("x", __iconNode14);
798
+ } catch {}
799
+ return null;
800
+ }
801
+ function useQuestionUpdates() {
802
+ const parse = useCallback5(parseQuestions, []);
803
+ const questions = useAgentState("questions", parse, []);
804
+ return { questions };
805
+ }
806
+
807
+ // src/lib/constants.ts
808
+ var SIDEBAR_WIDTH = 480;
809
+
630
810
  // src/components/ui/button.tsx
631
811
  import { forwardRef as forwardRef3 } from "react";
632
- import { jsx } from "react/jsx-runtime";
812
+ import { jsx as jsx2 } from "react/jsx-runtime";
633
813
  var variantClasses = {
634
814
  default: "skippr:bg-primary skippr:text-primary-foreground skippr:hover:bg-primary/90",
635
815
  destructive: "skippr:bg-destructive skippr:text-white skippr:hover:bg-destructive/90",
@@ -648,7 +828,7 @@ var sizeClasses = {
648
828
  "icon-lg": "skippr:size-10"
649
829
  };
650
830
  var Button = forwardRef3(({ className, variant = "default", size = "default", ...props }, ref) => {
651
- return /* @__PURE__ */ jsx("button", {
831
+ return /* @__PURE__ */ jsx2("button", {
652
832
  className: cn("skippr:inline-flex skippr:items-center skippr:justify-center skippr:gap-2 skippr:whitespace-nowrap skippr:rounded-md skippr:text-sm skippr:font-medium skippr:ring-offset-background skippr:transition-all skippr:focus-visible:outline-none skippr:focus-visible:ring-2 skippr:focus-visible:ring-ring skippr:focus-visible:ring-offset-2 skippr:disabled:pointer-events-none skippr:disabled:opacity-50 skippr:shrink-0 skippr:[&_svg]:pointer-events-none skippr:[&_svg:not([class*='size-'])]:size-4 skippr:[&_svg]:shrink-0", variantClasses[variant], sizeClasses[size], className),
653
833
  ref,
654
834
  ...props
@@ -657,61 +837,88 @@ var Button = forwardRef3(({ className, variant = "default", size = "default", ..
657
837
  Button.displayName = "Button";
658
838
 
659
839
  // src/components/ChatHeader.tsx
660
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
661
- function ChatHeader({ onClose }) {
662
- return /* @__PURE__ */ jsxs("div", {
840
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
841
+ function ChatHeader({ onOpenSettings }) {
842
+ const { closePanel, minimizePanel, minimizable, isConnected } = useLiveAgent();
843
+ return /* @__PURE__ */ jsxs2("div", {
663
844
  className: "skippr:flex skippr:items-center skippr:gap-3 skippr:bg-primary skippr:px-4 skippr:py-3 skippr:text-primary-foreground",
664
845
  children: [
665
- /* @__PURE__ */ jsx2("div", {
846
+ /* @__PURE__ */ jsx3("div", {
666
847
  className: "skippr:flex skippr:size-6 skippr:items-center skippr:justify-center skippr:rounded-full skippr:bg-primary-foreground/20",
667
- children: /* @__PURE__ */ jsx2(Bot, {
848
+ children: /* @__PURE__ */ jsx3(Bot, {
668
849
  className: "skippr:size-3.5 skippr:text-primary-foreground"
669
850
  })
670
851
  }),
671
- /* @__PURE__ */ jsx2("div", {
852
+ /* @__PURE__ */ jsx3("div", {
672
853
  className: "skippr:flex-1",
673
- children: /* @__PURE__ */ jsx2("p", {
854
+ children: /* @__PURE__ */ jsx3("p", {
674
855
  className: "skippr:text-sm skippr:font-semibold skippr:leading-none",
675
856
  children: "AI Agent"
676
857
  })
677
858
  }),
678
- /* @__PURE__ */ jsx2(Button, {
679
- variant: "ghost",
680
- size: "icon-xs",
681
- onClick: onClose,
682
- className: "skippr:text-primary-foreground skippr:hover:bg-primary-foreground/20 skippr:hover:text-primary-foreground",
683
- children: /* @__PURE__ */ jsx2(X, {
684
- className: "skippr:size-4"
685
- })
859
+ /* @__PURE__ */ jsxs2("div", {
860
+ className: "skippr:flex skippr:items-center skippr:gap-1",
861
+ children: [
862
+ /* @__PURE__ */ jsx3(Button, {
863
+ variant: "ghost",
864
+ size: "icon-xs",
865
+ onClick: onOpenSettings,
866
+ className: "skippr:text-primary-foreground skippr:hover:bg-primary-foreground/20 skippr:hover:text-primary-foreground",
867
+ "aria-label": "Settings",
868
+ children: /* @__PURE__ */ jsx3(Settings, {
869
+ className: "skippr:size-4"
870
+ })
871
+ }),
872
+ minimizable && isConnected && /* @__PURE__ */ jsx3(Button, {
873
+ variant: "ghost",
874
+ size: "icon-xs",
875
+ onClick: minimizePanel,
876
+ className: "skippr:text-primary-foreground skippr:hover:bg-primary-foreground/20 skippr:hover:text-primary-foreground",
877
+ "aria-label": "Minimize",
878
+ children: /* @__PURE__ */ jsx3(Minimize2, {
879
+ className: "skippr:size-4"
880
+ })
881
+ }),
882
+ /* @__PURE__ */ jsx3(Button, {
883
+ variant: "ghost",
884
+ size: "icon-xs",
885
+ onClick: closePanel,
886
+ className: "skippr:text-primary-foreground skippr:hover:bg-primary-foreground/20 skippr:hover:text-primary-foreground",
887
+ "aria-label": "Close",
888
+ children: /* @__PURE__ */ jsx3(X, {
889
+ className: "skippr:size-4"
890
+ })
891
+ })
892
+ ]
686
893
  })
687
894
  ]
688
895
  });
689
896
  }
690
897
 
691
898
  // src/components/LoginFlow.tsx
692
- import { useCallback as useCallback5, useEffect as useEffect4, useRef, useState as useState4 } from "react";
693
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
899
+ import { useCallback as useCallback6, useEffect as useEffect4, useRef, useState as useState4 } from "react";
900
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
694
901
  var OTP_LENGTH = 6;
695
902
  var DIGIT_KEYS = ["d0", "d1", "d2", "d3", "d4", "d5"];
696
903
  function LoginFlow({ requestOtp, verifyOtp, error, isSubmitting }) {
697
904
  const [step, setStep] = useState4("email");
698
905
  const [email, setEmail] = useState4("");
699
- const handleRequestOtp = useCallback5(async (emailValue) => {
906
+ const handleRequestOtp = useCallback6(async (emailValue) => {
700
907
  const success = await requestOtp(emailValue);
701
908
  if (success)
702
909
  setStep("otp");
703
910
  }, [requestOtp]);
704
- const handleVerifyOtp = useCallback5(async (code) => {
911
+ const handleVerifyOtp = useCallback6(async (code) => {
705
912
  await verifyOtp(email, code);
706
913
  }, [verifyOtp, email]);
707
- const handleBack = useCallback5(() => {
914
+ const handleBack = useCallback6(() => {
708
915
  setStep("email");
709
916
  }, []);
710
- const handleResend = useCallback5(async () => {
917
+ const handleResend = useCallback6(async () => {
711
918
  await requestOtp(email);
712
919
  }, [requestOtp, email]);
713
920
  if (step === "otp") {
714
- return /* @__PURE__ */ jsx3(OtpStep, {
921
+ return /* @__PURE__ */ jsx4(OtpStep, {
715
922
  email,
716
923
  onSubmit: handleVerifyOtp,
717
924
  onResend: handleResend,
@@ -720,7 +927,7 @@ function LoginFlow({ requestOtp, verifyOtp, error, isSubmitting }) {
720
927
  isSubmitting
721
928
  });
722
929
  }
723
- return /* @__PURE__ */ jsx3(EmailStep, {
930
+ return /* @__PURE__ */ jsx4(EmailStep, {
724
931
  email,
725
932
  onEmailChange: setEmail,
726
933
  onSubmit: handleRequestOtp,
@@ -734,30 +941,30 @@ function EmailStep({ email, onEmailChange, onSubmit, error, isSubmitting }) {
734
941
  if (email.trim())
735
942
  onSubmit(email.trim());
736
943
  }
737
- return /* @__PURE__ */ jsxs2("div", {
944
+ return /* @__PURE__ */ jsxs3("div", {
738
945
  className: "skippr:flex skippr:flex-1 skippr:flex-col skippr:px-4 skippr:py-4",
739
946
  children: [
740
- /* @__PURE__ */ jsxs2("div", {
947
+ /* @__PURE__ */ jsxs3("div", {
741
948
  className: "skippr:mb-4 skippr:text-center",
742
949
  children: [
743
- /* @__PURE__ */ jsx3(Mail, {
950
+ /* @__PURE__ */ jsx4(Mail, {
744
951
  className: "skippr:mx-auto skippr:mb-2 skippr:size-6 skippr:text-primary"
745
952
  }),
746
- /* @__PURE__ */ jsx3("p", {
953
+ /* @__PURE__ */ jsx4("p", {
747
954
  className: "skippr:text-sm skippr:font-medium skippr:text-foreground",
748
955
  children: "Sign in to continue"
749
956
  }),
750
- /* @__PURE__ */ jsx3("p", {
957
+ /* @__PURE__ */ jsx4("p", {
751
958
  className: "skippr:mt-1 skippr:text-xs skippr:text-muted-foreground",
752
959
  children: "Your email will be used to identify you across sessions"
753
960
  })
754
961
  ]
755
962
  }),
756
- /* @__PURE__ */ jsxs2("form", {
963
+ /* @__PURE__ */ jsxs3("form", {
757
964
  onSubmit: handleSubmit,
758
965
  className: "skippr:flex skippr:flex-col skippr:gap-3",
759
966
  children: [
760
- /* @__PURE__ */ jsx3("input", {
967
+ /* @__PURE__ */ jsx4("input", {
761
968
  type: "email",
762
969
  placeholder: "you@example.com",
763
970
  value: email,
@@ -766,15 +973,15 @@ function EmailStep({ email, onEmailChange, onSubmit, error, isSubmitting }) {
766
973
  required: true,
767
974
  className: "skippr:w-full skippr:rounded-md skippr:border skippr:border-border skippr:bg-background skippr:px-3 skippr:py-2 skippr:text-sm skippr:text-foreground skippr:placeholder-muted-foreground skippr:outline-none focus:skippr:ring-2 focus:skippr:ring-primary/30 focus:skippr:border-primary disabled:skippr:opacity-50"
768
975
  }),
769
- /* @__PURE__ */ jsx3(Button, {
976
+ /* @__PURE__ */ jsx4(Button, {
770
977
  type: "submit",
771
978
  disabled: isSubmitting || !email.trim(),
772
979
  className: "skippr:w-full",
773
- children: isSubmitting ? /* @__PURE__ */ jsx3(LoaderCircle, {
980
+ children: isSubmitting ? /* @__PURE__ */ jsx4(LoaderCircle, {
774
981
  className: "skippr:size-4 skippr:animate-spin"
775
982
  }) : "Continue"
776
983
  }),
777
- error && /* @__PURE__ */ jsx3("p", {
984
+ error && /* @__PURE__ */ jsx4("p", {
778
985
  className: "skippr:text-xs skippr:text-center skippr:text-destructive",
779
986
  children: error
780
987
  })
@@ -801,13 +1008,13 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
801
1008
  const timer = setTimeout(() => setResendCooldown((c) => c - 1), 1000);
802
1009
  return () => clearTimeout(timer);
803
1010
  }, [resendCooldown]);
804
- const submitCode = useCallback5((code) => {
1011
+ const submitCode = useCallback6((code) => {
805
1012
  if (submittedRef.current || isSubmitting)
806
1013
  return;
807
1014
  submittedRef.current = true;
808
1015
  onSubmit(code);
809
1016
  }, [onSubmit, isSubmitting]);
810
- const handleDigitChange = useCallback5((index2, value) => {
1017
+ const handleDigitChange = useCallback6((index2, value) => {
811
1018
  const digit = value.replace(/\D/g, "").slice(-1);
812
1019
  const newDigits = [...digits];
813
1020
  newDigits[index2] = digit;
@@ -821,12 +1028,12 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
821
1028
  submitCode(code);
822
1029
  }
823
1030
  }, [digits, submitCode]);
824
- const handleKeyDown = useCallback5((index2, e) => {
1031
+ const handleKeyDown = useCallback6((index2, e) => {
825
1032
  if (e.key === "Backspace" && !digits[index2] && index2 > 0) {
826
1033
  inputRefs.current[index2 - 1]?.focus();
827
1034
  }
828
1035
  }, [digits]);
829
- const handlePaste = useCallback5((e) => {
1036
+ const handlePaste = useCallback6((e) => {
830
1037
  e.preventDefault();
831
1038
  const pasted = e.clipboardData.getData("text").replace(/\D/g, "").slice(0, OTP_LENGTH);
832
1039
  if (pasted.length > 0) {
@@ -854,22 +1061,22 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
854
1061
  submittedRef.current = false;
855
1062
  inputRefs.current[0]?.focus();
856
1063
  }
857
- return /* @__PURE__ */ jsxs2("div", {
1064
+ return /* @__PURE__ */ jsxs3("div", {
858
1065
  className: "skippr:flex skippr:flex-1 skippr:flex-col skippr:px-4 skippr:py-4",
859
1066
  children: [
860
- /* @__PURE__ */ jsxs2("div", {
1067
+ /* @__PURE__ */ jsxs3("div", {
861
1068
  className: "skippr:mb-4 skippr:text-center",
862
1069
  children: [
863
- /* @__PURE__ */ jsx3("p", {
1070
+ /* @__PURE__ */ jsx4("p", {
864
1071
  className: "skippr:text-sm skippr:font-medium skippr:text-foreground",
865
1072
  children: "Enter verification code"
866
1073
  }),
867
- /* @__PURE__ */ jsxs2("p", {
1074
+ /* @__PURE__ */ jsxs3("p", {
868
1075
  className: "skippr:mt-1 skippr:text-xs skippr:text-muted-foreground",
869
1076
  children: [
870
1077
  "We sent a 6-digit code to",
871
1078
  " ",
872
- /* @__PURE__ */ jsx3("span", {
1079
+ /* @__PURE__ */ jsx4("span", {
873
1080
  className: "skippr:font-medium skippr:text-foreground",
874
1081
  children: email
875
1082
  })
@@ -877,13 +1084,13 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
877
1084
  })
878
1085
  ]
879
1086
  }),
880
- /* @__PURE__ */ jsxs2("form", {
1087
+ /* @__PURE__ */ jsxs3("form", {
881
1088
  onSubmit: handleSubmit,
882
1089
  className: "skippr:flex skippr:flex-col skippr:gap-3",
883
1090
  children: [
884
- /* @__PURE__ */ jsx3("div", {
1091
+ /* @__PURE__ */ jsx4("div", {
885
1092
  className: "skippr:flex skippr:justify-center skippr:gap-1.5",
886
- children: digits.map((digit, index2) => /* @__PURE__ */ jsx3("input", {
1093
+ children: digits.map((digit, index2) => /* @__PURE__ */ jsx4("input", {
887
1094
  ref: (el) => {
888
1095
  inputRefs.current[index2] = el;
889
1096
  },
@@ -898,29 +1105,29 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
898
1105
  className: "skippr:h-10 skippr:w-10 skippr:rounded-md skippr:border skippr:border-border skippr:bg-background skippr:text-center skippr:text-sm skippr:font-semibold skippr:text-foreground skippr:outline-none focus:skippr:ring-2 focus:skippr:ring-primary/30 focus:skippr:border-primary disabled:skippr:opacity-50"
899
1106
  }, DIGIT_KEYS[index2]))
900
1107
  }),
901
- error && /* @__PURE__ */ jsx3("p", {
1108
+ error && /* @__PURE__ */ jsx4("p", {
902
1109
  className: "skippr:text-xs skippr:text-center skippr:text-destructive",
903
1110
  children: error
904
1111
  }),
905
- /* @__PURE__ */ jsx3(Button, {
1112
+ /* @__PURE__ */ jsx4(Button, {
906
1113
  type: "submit",
907
1114
  disabled: isSubmitting || digits.join("").length !== OTP_LENGTH,
908
1115
  className: "skippr:w-full",
909
- children: isSubmitting ? /* @__PURE__ */ jsx3(LoaderCircle, {
1116
+ children: isSubmitting ? /* @__PURE__ */ jsx4(LoaderCircle, {
910
1117
  className: "skippr:size-4 skippr:animate-spin"
911
1118
  }) : "Verify"
912
1119
  }),
913
- /* @__PURE__ */ jsxs2("div", {
1120
+ /* @__PURE__ */ jsxs3("div", {
914
1121
  className: "skippr:flex skippr:items-center skippr:justify-between skippr:text-xs",
915
1122
  children: [
916
- /* @__PURE__ */ jsx3("button", {
1123
+ /* @__PURE__ */ jsx4("button", {
917
1124
  type: "button",
918
1125
  onClick: onBack,
919
1126
  disabled: isSubmitting,
920
1127
  className: "skippr:text-muted-foreground hover:skippr:text-foreground skippr:transition-colors disabled:skippr:opacity-50",
921
1128
  children: "Change email"
922
1129
  }),
923
- /* @__PURE__ */ jsx3("button", {
1130
+ /* @__PURE__ */ jsx4("button", {
924
1131
  type: "button",
925
1132
  onClick: handleResend,
926
1133
  disabled: isSubmitting || resendCooldown > 0,
@@ -936,9 +1143,9 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
936
1143
  }
937
1144
 
938
1145
  // src/components/MeetingControls.tsx
939
- import { useLocalParticipant as useLocalParticipant3 } from "@livekit/components-react";
940
- import { ScreenSharePresets } from "livekit-client";
941
- import { useCallback as useCallback6, useEffect as useEffect5, useRef as useRef2, useState as useState5 } from "react";
1146
+ import { useLocalParticipant as useLocalParticipant4 } from "@livekit/components-react";
1147
+ import { ScreenSharePresets as ScreenSharePresets2 } from "livekit-client";
1148
+ import { useCallback as useCallback7, useEffect as useEffect5, useRef as useRef2, useState as useState5 } from "react";
942
1149
 
943
1150
  // src/lib/format.ts
944
1151
  function formatTime(seconds) {
@@ -952,12 +1159,12 @@ function parseNumber(s) {
952
1159
  }
953
1160
 
954
1161
  // src/components/SessionWarningBanner.tsx
955
- import { jsx as jsx4 } from "react/jsx-runtime";
1162
+ import { jsx as jsx5 } from "react/jsx-runtime";
956
1163
  var SESSION_WARNING_THRESHOLD_SECS = 60;
957
1164
  function SessionWarningBanner({ remaining }) {
958
1165
  if (remaining === null || remaining <= 0 || remaining > SESSION_WARNING_THRESHOLD_SECS)
959
1166
  return null;
960
- return /* @__PURE__ */ jsx4("div", {
1167
+ return /* @__PURE__ */ jsx5("div", {
961
1168
  "data-testid": "session-warning-banner",
962
1169
  className: "skippr:bg-red-50 skippr:px-4 skippr:py-1.5 skippr:text-center skippr:text-xs skippr:font-medium skippr:text-red-700",
963
1170
  children: "Session ending soon"
@@ -965,10 +1172,10 @@ function SessionWarningBanner({ remaining }) {
965
1172
  }
966
1173
 
967
1174
  // src/components/MeetingControls.tsx
968
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1175
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
969
1176
  function MeetingControls({ onHangUp }) {
970
1177
  const maxCallDuration = useAgentState("maxCallDuration", parseNumber, null);
971
- const { localParticipant } = useLocalParticipant3();
1178
+ const { localParticipant } = useLocalParticipant4();
972
1179
  const isMuted = !localParticipant.isMicrophoneEnabled;
973
1180
  const isScreenSharing = localParticipant.isScreenShareEnabled;
974
1181
  const endTimeRef = useRef2(null);
@@ -985,18 +1192,18 @@ function MeetingControls({ onHangUp }) {
985
1192
  const id = setInterval(tick, 1000);
986
1193
  return () => clearInterval(id);
987
1194
  }, [maxCallDuration]);
988
- const toggleMute = useCallback6(async () => {
1195
+ const toggleMute = useCallback7(async () => {
989
1196
  try {
990
1197
  await localParticipant.setMicrophoneEnabled(isMuted);
991
1198
  } catch (e) {
992
1199
  console.error("Failed to toggle microphone:", e);
993
1200
  }
994
1201
  }, [localParticipant, isMuted]);
995
- const toggleScreenShare = useCallback6(async () => {
1202
+ const toggleScreenShare = useCallback7(async () => {
996
1203
  try {
997
1204
  await localParticipant.setScreenShareEnabled(!isScreenSharing, {
998
1205
  video: { displaySurface: "browser" },
999
- resolution: ScreenSharePresets.h720fps30.resolution,
1206
+ resolution: ScreenSharePresets2.h720fps30.resolution,
1000
1207
  contentHint: "detail"
1001
1208
  });
1002
1209
  } catch (e) {
@@ -1006,51 +1213,51 @@ function MeetingControls({ onHangUp }) {
1006
1213
  useEffect5(() => {
1007
1214
  toggleMute().then(() => toggleScreenShare());
1008
1215
  }, []);
1009
- return /* @__PURE__ */ jsxs3("div", {
1216
+ return /* @__PURE__ */ jsxs4("div", {
1010
1217
  children: [
1011
- /* @__PURE__ */ jsx5(SessionWarningBanner, {
1218
+ /* @__PURE__ */ jsx6(SessionWarningBanner, {
1012
1219
  remaining
1013
1220
  }),
1014
- /* @__PURE__ */ jsxs3("div", {
1221
+ /* @__PURE__ */ jsxs4("div", {
1015
1222
  className: "skippr:flex skippr:items-center skippr:justify-between skippr:border-b skippr:px-4 skippr:py-3",
1016
1223
  children: [
1017
- /* @__PURE__ */ jsxs3("div", {
1224
+ /* @__PURE__ */ jsxs4("div", {
1018
1225
  className: "skippr:flex skippr:items-center skippr:gap-2",
1019
1226
  children: [
1020
- /* @__PURE__ */ jsx5(Button, {
1227
+ /* @__PURE__ */ jsx6(Button, {
1021
1228
  size: "icon-sm",
1022
1229
  variant: isMuted ? "destructive" : "outline",
1023
1230
  onClick: toggleMute,
1024
1231
  "aria-label": isMuted ? "Unmute" : "Mute",
1025
- children: isMuted ? /* @__PURE__ */ jsx5(MicOff, {
1232
+ children: isMuted ? /* @__PURE__ */ jsx6(MicOff, {
1026
1233
  className: "skippr:size-4"
1027
- }) : /* @__PURE__ */ jsx5(Mic, {
1234
+ }) : /* @__PURE__ */ jsx6(Mic, {
1028
1235
  className: "skippr:size-4"
1029
1236
  })
1030
1237
  }),
1031
- /* @__PURE__ */ jsx5(Button, {
1238
+ /* @__PURE__ */ jsx6(Button, {
1032
1239
  size: "icon-sm",
1033
- variant: isScreenSharing ? "default" : "outline",
1240
+ variant: isScreenSharing ? "outline" : "destructive",
1034
1241
  onClick: toggleScreenShare,
1035
1242
  "aria-label": isScreenSharing ? "Stop sharing" : "Share screen",
1036
- children: isScreenSharing ? /* @__PURE__ */ jsx5(MonitorOff, {
1243
+ children: isScreenSharing ? /* @__PURE__ */ jsx6(MonitorOff, {
1037
1244
  className: "skippr:size-4"
1038
- }) : /* @__PURE__ */ jsx5(Monitor, {
1245
+ }) : /* @__PURE__ */ jsx6(Monitor, {
1039
1246
  className: "skippr:size-4"
1040
1247
  })
1041
1248
  })
1042
1249
  ]
1043
1250
  }),
1044
- remaining !== null && /* @__PURE__ */ jsx5("span", {
1251
+ remaining !== null && /* @__PURE__ */ jsx6("span", {
1045
1252
  className: cn("skippr:text-sm skippr:font-medium skippr:tabular-nums", remaining <= SESSION_WARNING_THRESHOLD_SECS ? "skippr:text-red-600 skippr:animate-pulse" : "skippr:text-muted-foreground"),
1046
1253
  children: formatTime(remaining)
1047
1254
  }),
1048
- /* @__PURE__ */ jsx5(Button, {
1255
+ /* @__PURE__ */ jsx6(Button, {
1049
1256
  size: "icon-sm",
1050
1257
  variant: "destructive",
1051
1258
  onClick: onHangUp,
1052
1259
  "aria-label": "Hang up",
1053
- children: /* @__PURE__ */ jsx5(PhoneOff, {
1260
+ children: /* @__PURE__ */ jsx6(PhoneOff, {
1054
1261
  className: "skippr:size-4"
1055
1262
  })
1056
1263
  })
@@ -1065,7 +1272,7 @@ import { useEffect as useEffect6, useRef as useRef3 } from "react";
1065
1272
 
1066
1273
  // src/components/ChatInput.tsx
1067
1274
  import { useState as useState6 } from "react";
1068
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1275
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1069
1276
  function ChatInput({ sendChatMessage, isSendingChat }) {
1070
1277
  const [inputText, setInputText] = useState6("");
1071
1278
  const canSend = inputText.trim().length > 0 && !isSendingChat;
@@ -1077,11 +1284,11 @@ function ChatInput({ sendChatMessage, isSendingChat }) {
1077
1284
  setInputText("");
1078
1285
  sendChatMessage(text).catch(() => setInputText(text));
1079
1286
  }
1080
- return /* @__PURE__ */ jsxs4("form", {
1287
+ return /* @__PURE__ */ jsxs5("form", {
1081
1288
  onSubmit: handleSubmit,
1082
1289
  className: "skippr:flex skippr:items-center skippr:gap-2 skippr:border-t skippr:border-border skippr:px-3 skippr:py-2",
1083
1290
  children: [
1084
- /* @__PURE__ */ jsx6("input", {
1291
+ /* @__PURE__ */ jsx7("input", {
1085
1292
  type: "text",
1086
1293
  value: inputText,
1087
1294
  onChange: (e) => setInputText(e.target.value),
@@ -1089,12 +1296,12 @@ function ChatInput({ sendChatMessage, isSendingChat }) {
1089
1296
  className: cn("skippr:flex-1 skippr:rounded-lg skippr:border skippr:border-border skippr:bg-background", "skippr:px-3 skippr:py-2 skippr:text-sm skippr:text-foreground", "skippr:placeholder:text-muted-foreground skippr:outline-none", "skippr:focus:ring-1 skippr:focus:ring-ring"),
1090
1297
  disabled: isSendingChat
1091
1298
  }),
1092
- /* @__PURE__ */ jsx6("button", {
1299
+ /* @__PURE__ */ jsx7("button", {
1093
1300
  type: "submit",
1094
1301
  disabled: !canSend,
1095
1302
  "aria-label": "Send message",
1096
1303
  className: cn("skippr:flex skippr:size-9 skippr:shrink-0 skippr:items-center skippr:justify-center", "skippr:rounded-lg skippr:bg-primary skippr:text-primary-foreground", "skippr:transition-opacity", !canSend && "skippr:opacity-50 skippr:cursor-not-allowed"),
1097
- children: /* @__PURE__ */ jsx6(SendHorizontal, {
1304
+ children: /* @__PURE__ */ jsx7(SendHorizontal, {
1098
1305
  className: "skippr:size-4"
1099
1306
  })
1100
1307
  })
@@ -1103,12 +1310,12 @@ function ChatInput({ sendChatMessage, isSendingChat }) {
1103
1310
  }
1104
1311
 
1105
1312
  // src/components/ChatMessage.tsx
1106
- import { jsx as jsx7 } from "react/jsx-runtime";
1313
+ import { jsx as jsx8 } from "react/jsx-runtime";
1107
1314
  function ChatMessage({ message }) {
1108
1315
  const isUser = message.role === "user";
1109
- return /* @__PURE__ */ jsx7("div", {
1316
+ return /* @__PURE__ */ jsx8("div", {
1110
1317
  className: cn("skippr:flex skippr:w-full skippr:px-4 skippr:py-1", isUser ? "skippr:justify-end" : "skippr:justify-start"),
1111
- children: /* @__PURE__ */ jsx7("div", {
1318
+ children: /* @__PURE__ */ jsx8("div", {
1112
1319
  className: cn("skippr:max-w-[85%] skippr:whitespace-pre-wrap skippr:rounded-2xl skippr:px-4 skippr:py-2.5 skippr:text-sm skippr:leading-relaxed", isUser ? "skippr:rounded-br-sm skippr:bg-primary skippr:text-primary-foreground" : "skippr:rounded-bl-sm skippr:bg-muted skippr:text-foreground"),
1113
1320
  children: message.content
1114
1321
  })
@@ -1116,20 +1323,20 @@ function ChatMessage({ message }) {
1116
1323
  }
1117
1324
 
1118
1325
  // src/components/TypingIndicator.tsx
1119
- import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
1326
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1120
1327
  function TypingIndicator() {
1121
- return /* @__PURE__ */ jsx8("div", {
1328
+ return /* @__PURE__ */ jsx9("div", {
1122
1329
  className: "skippr:flex skippr:items-center skippr:gap-1 skippr:px-4 skippr:py-3",
1123
- children: /* @__PURE__ */ jsxs5("div", {
1330
+ children: /* @__PURE__ */ jsxs6("div", {
1124
1331
  className: "skippr:flex skippr:items-center skippr:gap-1 skippr:rounded-2xl skippr:rounded-bl-sm skippr:bg-muted skippr:px-4 skippr:py-2.5",
1125
1332
  children: [
1126
- /* @__PURE__ */ jsx8("span", {
1333
+ /* @__PURE__ */ jsx9("span", {
1127
1334
  className: "skippr:size-1.5 skippr:animate-bounce skippr:rounded-full skippr:bg-muted-foreground/60 skippr:[animation-delay:0ms]"
1128
1335
  }),
1129
- /* @__PURE__ */ jsx8("span", {
1336
+ /* @__PURE__ */ jsx9("span", {
1130
1337
  className: "skippr:size-1.5 skippr:animate-bounce skippr:rounded-full skippr:bg-muted-foreground/60 skippr:[animation-delay:150ms]"
1131
1338
  }),
1132
- /* @__PURE__ */ jsx8("span", {
1339
+ /* @__PURE__ */ jsx9("span", {
1133
1340
  className: "skippr:size-1.5 skippr:animate-bounce skippr:rounded-full skippr:bg-muted-foreground/60 skippr:[animation-delay:300ms]"
1134
1341
  })
1135
1342
  ]
@@ -1138,7 +1345,7 @@ function TypingIndicator() {
1138
1345
  }
1139
1346
 
1140
1347
  // src/components/MessageList.tsx
1141
- import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1348
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1142
1349
  function MessageList({
1143
1350
  messages,
1144
1351
  isStreaming,
@@ -1151,25 +1358,25 @@ function MessageList({
1151
1358
  scrollRef.current?.scrollIntoView({ behavior: "smooth" });
1152
1359
  }, [messages.length, lastMessage?.content]);
1153
1360
  const showTyping = isStreaming && lastMessage?.role === "assistant" && lastMessage.content === "";
1154
- return /* @__PURE__ */ jsxs6("div", {
1361
+ return /* @__PURE__ */ jsxs7("div", {
1155
1362
  className: "skippr:flex skippr:min-h-0 skippr:flex-1 skippr:flex-col",
1156
1363
  children: [
1157
- /* @__PURE__ */ jsx9("div", {
1364
+ /* @__PURE__ */ jsx10("div", {
1158
1365
  className: "skippr:min-h-0 skippr:flex-1 skippr:overflow-y-auto",
1159
- children: /* @__PURE__ */ jsxs6("div", {
1366
+ children: /* @__PURE__ */ jsxs7("div", {
1160
1367
  className: "skippr:flex skippr:flex-col skippr:gap-1 skippr:py-3",
1161
1368
  children: [
1162
- messages.map((message) => /* @__PURE__ */ jsx9(ChatMessage, {
1369
+ messages.map((message) => /* @__PURE__ */ jsx10(ChatMessage, {
1163
1370
  message
1164
1371
  }, message.id)),
1165
- showTyping && /* @__PURE__ */ jsx9(TypingIndicator, {}),
1166
- /* @__PURE__ */ jsx9("div", {
1372
+ showTyping && /* @__PURE__ */ jsx10(TypingIndicator, {}),
1373
+ /* @__PURE__ */ jsx10("div", {
1167
1374
  ref: scrollRef
1168
1375
  })
1169
1376
  ]
1170
1377
  })
1171
1378
  }),
1172
- /* @__PURE__ */ jsx9(ChatInput, {
1379
+ /* @__PURE__ */ jsx10(ChatInput, {
1173
1380
  sendChatMessage,
1174
1381
  isSendingChat
1175
1382
  })
@@ -1178,30 +1385,30 @@ function MessageList({
1178
1385
  }
1179
1386
 
1180
1387
  // src/components/QuickActions.tsx
1181
- import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1388
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1182
1389
  function QuickActions({ onStartSession, isStarting, error }) {
1183
- return /* @__PURE__ */ jsxs7("div", {
1390
+ return /* @__PURE__ */ jsxs8("div", {
1184
1391
  className: "skippr:flex skippr:flex-1 skippr:flex-col skippr:items-center skippr:gap-6 skippr:overflow-y-auto skippr:px-4 skippr:py-4",
1185
1392
  children: [
1186
- /* @__PURE__ */ jsx10("p", {
1393
+ /* @__PURE__ */ jsx11("p", {
1187
1394
  className: "skippr:mb-1 skippr:text-sm skippr:text-muted-foreground",
1188
1395
  children: "How can I help you today?"
1189
1396
  }),
1190
- /* @__PURE__ */ jsxs7(Button, {
1397
+ /* @__PURE__ */ jsxs8(Button, {
1191
1398
  variant: "outline",
1192
1399
  className: "skippr:h-auto skippr:flex-col skippr:gap-1.5 skippr:whitespace-normal skippr:py-3 skippr:text-xs",
1193
1400
  onClick: onStartSession,
1194
1401
  disabled: isStarting,
1195
1402
  children: [
1196
- isStarting ? /* @__PURE__ */ jsx10(LoaderCircle, {
1403
+ isStarting ? /* @__PURE__ */ jsx11(LoaderCircle, {
1197
1404
  className: "skippr:size-4 skippr:animate-spin skippr:text-primary"
1198
- }) : /* @__PURE__ */ jsx10(MessageCircleQuestionMark, {
1405
+ }) : /* @__PURE__ */ jsx11(MessageCircleQuestionMark, {
1199
1406
  className: "skippr:size-4 skippr:text-primary"
1200
1407
  }),
1201
1408
  isStarting ? "Starting..." : "Start Session"
1202
1409
  ]
1203
1410
  }),
1204
- error && /* @__PURE__ */ jsx10("p", {
1411
+ error && /* @__PURE__ */ jsx11("p", {
1205
1412
  className: "skippr:text-xs skippr:text-destructive",
1206
1413
  children: error
1207
1414
  })
@@ -1210,52 +1417,52 @@ function QuickActions({ onStartSession, isStarting, error }) {
1210
1417
  }
1211
1418
 
1212
1419
  // src/components/SessionAgenda.tsx
1213
- import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1420
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
1214
1421
  function SessionAgenda({ phases, questions = [] }) {
1215
1422
  if (phases.length === 0) {
1216
- return /* @__PURE__ */ jsxs8("div", {
1423
+ return /* @__PURE__ */ jsxs9("div", {
1217
1424
  className: "skippr:flex skippr:flex-col skippr:gap-3 skippr:p-4",
1218
1425
  children: [
1219
- /* @__PURE__ */ jsx11("h3", {
1426
+ /* @__PURE__ */ jsx12("h3", {
1220
1427
  className: "skippr:text-sm skippr:font-semibold",
1221
1428
  children: "Agenda"
1222
1429
  }),
1223
- /* @__PURE__ */ jsx11("p", {
1430
+ /* @__PURE__ */ jsx12("p", {
1224
1431
  className: "skippr:text-xs skippr:text-muted-foreground",
1225
1432
  children: "Waiting for session..."
1226
1433
  })
1227
1434
  ]
1228
1435
  });
1229
1436
  }
1230
- return /* @__PURE__ */ jsxs8("div", {
1437
+ return /* @__PURE__ */ jsxs9("div", {
1231
1438
  className: "skippr:flex skippr:flex-col skippr:gap-3 skippr:p-4",
1232
1439
  children: [
1233
- /* @__PURE__ */ jsx11("h3", {
1440
+ /* @__PURE__ */ jsx12("h3", {
1234
1441
  className: "skippr:text-sm skippr:font-semibold",
1235
1442
  children: "Agenda"
1236
1443
  }),
1237
- /* @__PURE__ */ jsx11("ul", {
1444
+ /* @__PURE__ */ jsx12("ul", {
1238
1445
  className: "skippr:flex skippr:flex-col skippr:gap-2",
1239
1446
  children: phases.map((phase) => {
1240
1447
  const phaseQuestions = questions.filter((q) => q.phaseName === phase.name);
1241
1448
  const answeredCount = phaseQuestions.filter((q) => q.status === "answered").length;
1242
1449
  const totalCount = phaseQuestions.length;
1243
- return /* @__PURE__ */ jsxs8("li", {
1450
+ return /* @__PURE__ */ jsxs9("li", {
1244
1451
  className: "skippr:flex skippr:flex-col skippr:gap-0.5",
1245
1452
  children: [
1246
- /* @__PURE__ */ jsxs8("div", {
1453
+ /* @__PURE__ */ jsxs9("div", {
1247
1454
  className: "skippr:flex skippr:items-center skippr:gap-2 skippr:text-sm",
1248
1455
  children: [
1249
- /* @__PURE__ */ jsx11(PhaseIcon, {
1456
+ /* @__PURE__ */ jsx12(PhaseIcon, {
1250
1457
  status: phase.status
1251
1458
  }),
1252
- /* @__PURE__ */ jsx11("span", {
1459
+ /* @__PURE__ */ jsx12("span", {
1253
1460
  className: cn(phase.status === "completed" && "skippr:text-muted-foreground skippr:line-through", phase.status === "active" && "skippr:font-medium skippr:text-primary"),
1254
1461
  children: phase.name
1255
1462
  })
1256
1463
  ]
1257
1464
  }),
1258
- totalCount > 0 && /* @__PURE__ */ jsxs8("span", {
1465
+ totalCount > 0 && /* @__PURE__ */ jsxs9("span", {
1259
1466
  className: "skippr:ml-6 skippr:text-xs skippr:text-muted-foreground",
1260
1467
  children: [
1261
1468
  answeredCount,
@@ -1273,35 +1480,110 @@ function SessionAgenda({ phases, questions = [] }) {
1273
1480
  }
1274
1481
  function PhaseIcon({ status }) {
1275
1482
  if (status === "completed") {
1276
- return /* @__PURE__ */ jsx11("div", {
1483
+ return /* @__PURE__ */ jsx12("div", {
1277
1484
  className: "skippr:flex skippr:size-4 skippr:shrink-0 skippr:items-center skippr:justify-center skippr:rounded-full skippr:bg-primary",
1278
- children: /* @__PURE__ */ jsx11(Check, {
1485
+ children: /* @__PURE__ */ jsx12(Check, {
1279
1486
  className: "skippr:size-2.5 skippr:text-primary-foreground",
1280
1487
  strokeWidth: 3
1281
1488
  })
1282
1489
  });
1283
1490
  }
1284
1491
  if (status === "active") {
1285
- return /* @__PURE__ */ jsx11(LoaderCircle, {
1492
+ return /* @__PURE__ */ jsx12(LoaderCircle, {
1286
1493
  className: "skippr:size-4 skippr:shrink-0 skippr:text-primary skippr:animate-spin"
1287
1494
  });
1288
1495
  }
1289
- return /* @__PURE__ */ jsx11(Circle, {
1496
+ return /* @__PURE__ */ jsx12(Circle, {
1290
1497
  className: "skippr:size-4 skippr:shrink-0 skippr:text-muted-foreground"
1291
1498
  });
1292
1499
  }
1293
1500
 
1501
+ // src/components/SettingsView.tsx
1502
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
1503
+ function SettingsView({ onBack }) {
1504
+ const { position, setPosition } = useLiveAgent();
1505
+ return /* @__PURE__ */ jsxs10("div", {
1506
+ className: "skippr:flex skippr:flex-1 skippr:flex-col",
1507
+ children: [
1508
+ /* @__PURE__ */ jsxs10("div", {
1509
+ className: "skippr:flex skippr:items-center skippr:gap-2 skippr:border-b skippr:border-border skippr:px-4 skippr:py-3",
1510
+ children: [
1511
+ /* @__PURE__ */ jsx13(Button, {
1512
+ variant: "ghost",
1513
+ size: "icon-xs",
1514
+ onClick: onBack,
1515
+ "aria-label": "Back",
1516
+ children: /* @__PURE__ */ jsx13(ArrowLeft, {
1517
+ className: "skippr:size-4"
1518
+ })
1519
+ }),
1520
+ /* @__PURE__ */ jsx13("p", {
1521
+ className: "skippr:text-sm skippr:font-semibold",
1522
+ children: "Settings"
1523
+ })
1524
+ ]
1525
+ }),
1526
+ /* @__PURE__ */ jsx13("div", {
1527
+ className: "skippr:flex-1 skippr:overflow-y-auto skippr:p-4",
1528
+ children: /* @__PURE__ */ jsxs10("div", {
1529
+ className: "skippr:mb-4",
1530
+ children: [
1531
+ /* @__PURE__ */ jsx13("p", {
1532
+ className: "skippr:mb-2 skippr:text-xs skippr:font-medium skippr:uppercase skippr:tracking-wide skippr:text-muted-foreground",
1533
+ children: "Widget Position"
1534
+ }),
1535
+ /* @__PURE__ */ jsxs10("div", {
1536
+ className: "skippr:flex skippr:gap-2",
1537
+ children: [
1538
+ /* @__PURE__ */ jsxs10("button", {
1539
+ type: "button",
1540
+ onClick: () => setPosition("left"),
1541
+ className: cn("skippr:flex skippr:flex-1 skippr:flex-col skippr:items-center skippr:gap-2 skippr:rounded-lg skippr:border skippr:p-3 skippr:cursor-pointer skippr:transition-colors", position === "left" ? "skippr:border-primary skippr:bg-primary/5 skippr:text-primary" : "skippr:border-border skippr:text-muted-foreground skippr:hover:border-primary/40"),
1542
+ children: [
1543
+ /* @__PURE__ */ jsx13(PanelLeft, {
1544
+ className: "skippr:size-5"
1545
+ }),
1546
+ /* @__PURE__ */ jsx13("span", {
1547
+ className: "skippr:text-xs skippr:font-medium",
1548
+ children: "Left"
1549
+ })
1550
+ ]
1551
+ }),
1552
+ /* @__PURE__ */ jsxs10("button", {
1553
+ type: "button",
1554
+ onClick: () => setPosition("right"),
1555
+ className: cn("skippr:flex skippr:flex-1 skippr:flex-col skippr:items-center skippr:gap-2 skippr:rounded-lg skippr:border skippr:p-3 skippr:cursor-pointer skippr:transition-colors", position === "right" ? "skippr:border-primary skippr:bg-primary/5 skippr:text-primary" : "skippr:border-border skippr:text-muted-foreground skippr:hover:border-primary/40"),
1556
+ children: [
1557
+ /* @__PURE__ */ jsx13(PanelRight, {
1558
+ className: "skippr:size-5"
1559
+ }),
1560
+ /* @__PURE__ */ jsx13("span", {
1561
+ className: "skippr:text-xs skippr:font-medium",
1562
+ children: "Right"
1563
+ })
1564
+ ]
1565
+ })
1566
+ ]
1567
+ })
1568
+ ]
1569
+ })
1570
+ })
1571
+ ]
1572
+ });
1573
+ }
1574
+
1294
1575
  // src/components/Sidebar.tsx
1295
- import { jsx as jsx12, jsxs as jsxs9, Fragment } from "react/jsx-runtime";
1576
+ import { jsx as jsx14, jsxs as jsxs11, Fragment as Fragment2 } from "react/jsx-runtime";
1296
1577
  function Sidebar() {
1297
1578
  const {
1579
+ variant,
1298
1580
  isConnected,
1299
1581
  isStarting,
1300
1582
  error,
1301
1583
  startSession,
1302
1584
  disconnect,
1303
1585
  isPanelOpen,
1304
- closePanel,
1586
+ position,
1305
1587
  isAuthenticated,
1306
1588
  isValidating,
1307
1589
  authError,
@@ -1309,42 +1591,53 @@ function Sidebar() {
1309
1591
  verifyOtp,
1310
1592
  isAuthSubmitting
1311
1593
  } = useLiveAgent();
1594
+ const [view, setView] = useState7("main");
1595
+ const isFloating = variant === "floating";
1596
+ const isSidebar = variant === "sidebar";
1312
1597
  useEffect7(() => {
1313
- document.body.style.transition = "margin-right 300ms ease-in-out";
1314
- document.body.style.marginRight = isPanelOpen ? `${SIDEBAR_WIDTH}px` : "0px";
1315
- }, [isPanelOpen]);
1316
- useEffect7(() => {
1598
+ if (!isSidebar)
1599
+ return;
1600
+ const prop = position === "right" ? "marginRight" : "marginLeft";
1601
+ const opposite = position === "right" ? "marginLeft" : "marginRight";
1602
+ document.body.style.transition = "margin 300ms ease-in-out";
1603
+ document.body.style[opposite] = "";
1604
+ document.body.style[prop] = isPanelOpen ? `${SIDEBAR_WIDTH}px` : "";
1317
1605
  return () => {
1318
1606
  document.body.style.marginRight = "";
1607
+ document.body.style.marginLeft = "";
1319
1608
  document.body.style.transition = "";
1320
1609
  };
1321
- }, []);
1322
- return /* @__PURE__ */ jsxs9("div", {
1323
- className: cn("skippr:fixed skippr:top-0 skippr:right-0 skippr:h-full skippr:z-[9999]", "skippr:bg-background skippr:border-l skippr:border-border", "skippr:flex skippr:flex-col", "skippr:transition-all skippr:duration-300 skippr:ease-in-out skippr:overflow-hidden", !isPanelOpen && "skippr:w-0 skippr:border-l-0"),
1610
+ }, [isSidebar, isPanelOpen, position]);
1611
+ return /* @__PURE__ */ jsx14("div", {
1612
+ className: cn("skippr:fixed skippr:z-[9999]", "skippr:bg-background skippr:border skippr:border-border", "skippr:flex skippr:flex-col", "skippr:transition-all skippr:duration-300 skippr:ease-in-out skippr:overflow-hidden", isFloating && "skippr:bottom-4 skippr:min-h-[28rem] skippr:max-h-[calc(100vh-6rem)] skippr:rounded-2xl skippr:shadow-2xl", isFloating && (position === "right" ? "skippr:right-4" : "skippr:left-4"), isFloating && !isPanelOpen && "skippr:w-0 skippr:h-0 skippr:border-0", isSidebar && "skippr:top-0 skippr:h-full", isSidebar && position === "right" && "skippr:right-0 skippr:border-l skippr:border-l-border", isSidebar && position === "left" && "skippr:left-0 skippr:border-r skippr:border-r-border", isSidebar && !isPanelOpen && "skippr:w-0 skippr:border-0"),
1324
1613
  style: { width: isPanelOpen ? SIDEBAR_WIDTH : undefined },
1325
- children: [
1326
- /* @__PURE__ */ jsx12(ChatHeader, {
1327
- onClose: closePanel
1328
- }),
1329
- isConnected ? /* @__PURE__ */ jsx12(ConnectedContent, {
1330
- onDisconnect: disconnect
1331
- }) : isValidating ? /* @__PURE__ */ jsx12("div", {
1332
- className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center",
1333
- children: /* @__PURE__ */ jsx12("p", {
1334
- className: "skippr:text-sm skippr:text-muted-foreground",
1335
- children: "Loading..."
1614
+ children: view === "settings" ? /* @__PURE__ */ jsx14(SettingsView, {
1615
+ onBack: () => setView("main")
1616
+ }) : /* @__PURE__ */ jsxs11(Fragment2, {
1617
+ children: [
1618
+ /* @__PURE__ */ jsx14(ChatHeader, {
1619
+ onOpenSettings: () => setView("settings")
1620
+ }),
1621
+ isConnected ? /* @__PURE__ */ jsx14(ConnectedContent, {
1622
+ onDisconnect: disconnect
1623
+ }) : isValidating ? /* @__PURE__ */ jsx14("div", {
1624
+ className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center",
1625
+ children: /* @__PURE__ */ jsx14("p", {
1626
+ className: "skippr:text-sm skippr:text-muted-foreground",
1627
+ children: "Loading..."
1628
+ })
1629
+ }) : isAuthenticated ? /* @__PURE__ */ jsx14(QuickActions, {
1630
+ onStartSession: startSession,
1631
+ isStarting,
1632
+ error
1633
+ }) : /* @__PURE__ */ jsx14(LoginFlow, {
1634
+ requestOtp,
1635
+ verifyOtp,
1636
+ error: authError,
1637
+ isSubmitting: isAuthSubmitting
1336
1638
  })
1337
- }) : isAuthenticated ? /* @__PURE__ */ jsx12(QuickActions, {
1338
- onStartSession: startSession,
1339
- isStarting,
1340
- error
1341
- }) : /* @__PURE__ */ jsx12(LoginFlow, {
1342
- requestOtp,
1343
- verifyOtp,
1344
- error: authError,
1345
- isSubmitting: isAuthSubmitting
1346
- })
1347
- ]
1639
+ ]
1640
+ })
1348
1641
  });
1349
1642
  }
1350
1643
  function ConnectedContent({ onDisconnect }) {
@@ -1354,33 +1647,33 @@ function ConnectedContent({ onDisconnect }) {
1354
1647
  const { phases } = usePhaseUpdates();
1355
1648
  const { questions } = useQuestionUpdates();
1356
1649
  if (!isConnected) {
1357
- return /* @__PURE__ */ jsx12("div", {
1650
+ return /* @__PURE__ */ jsx14("div", {
1358
1651
  className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center",
1359
- children: /* @__PURE__ */ jsx12("p", {
1652
+ children: /* @__PURE__ */ jsx14("p", {
1360
1653
  className: "skippr:text-sm skippr:text-muted-foreground",
1361
1654
  children: "Connecting..."
1362
1655
  })
1363
1656
  });
1364
1657
  }
1365
1658
  const isAgentSpeaking = agentState === "speaking";
1366
- return /* @__PURE__ */ jsxs9(Fragment, {
1659
+ return /* @__PURE__ */ jsxs11(Fragment2, {
1367
1660
  children: [
1368
- /* @__PURE__ */ jsx12(MeetingControls, {
1661
+ /* @__PURE__ */ jsx14(MeetingControls, {
1369
1662
  onHangUp: onDisconnect
1370
1663
  }),
1371
- /* @__PURE__ */ jsxs9("div", {
1664
+ /* @__PURE__ */ jsxs11("div", {
1372
1665
  className: "skippr:flex skippr:min-h-0 skippr:flex-1",
1373
1666
  children: [
1374
- /* @__PURE__ */ jsx12("div", {
1375
- className: "skippr:w-[260px] skippr:shrink-0 skippr:overflow-y-auto skippr:border-r",
1376
- children: /* @__PURE__ */ jsx12(SessionAgenda, {
1667
+ /* @__PURE__ */ jsx14("div", {
1668
+ className: "skippr:w-[180px] skippr:shrink-0 skippr:overflow-y-auto skippr:border-r",
1669
+ children: /* @__PURE__ */ jsx14(SessionAgenda, {
1377
1670
  phases,
1378
1671
  questions
1379
1672
  })
1380
1673
  }),
1381
- /* @__PURE__ */ jsx12("div", {
1674
+ /* @__PURE__ */ jsx14("div", {
1382
1675
  className: "skippr:flex skippr:min-w-0 skippr:flex-1 skippr:flex-col",
1383
- children: /* @__PURE__ */ jsx12(MessageList, {
1676
+ children: /* @__PURE__ */ jsx14(MessageList, {
1384
1677
  messages: allMessages,
1385
1678
  isStreaming: isAgentSpeaking,
1386
1679
  sendChatMessage,
@@ -1394,32 +1687,34 @@ function ConnectedContent({ onDisconnect }) {
1394
1687
  }
1395
1688
 
1396
1689
  // src/components/SidebarTrigger.tsx
1397
- import { jsx as jsx13 } from "react/jsx-runtime";
1398
- var TRIGGER_GAP = 16;
1399
- var TRIGGER_DEFAULT_RIGHT = 24;
1690
+ import { jsx as jsx15 } from "react/jsx-runtime";
1400
1691
  function SidebarTrigger() {
1401
- const { isPanelOpen, togglePanel } = useLiveAgent();
1402
- return /* @__PURE__ */ jsx13(Button, {
1692
+ const { isPanelOpen, togglePanel, position, isMinimized, isConnected } = useLiveAgent();
1693
+ if (isMinimized && isConnected)
1694
+ return null;
1695
+ return /* @__PURE__ */ jsx15(Button, {
1403
1696
  size: "icon-lg",
1404
1697
  onClick: togglePanel,
1405
- className: "skippr:fixed skippr:bottom-6 skippr:z-[9998] skippr:size-14 skippr:rounded-full skippr:shadow-lg skippr:transition-all skippr:duration-300",
1406
- style: { right: isPanelOpen ? SIDEBAR_WIDTH + TRIGGER_GAP : TRIGGER_DEFAULT_RIGHT },
1698
+ className: cn("skippr:fixed skippr:bottom-6 skippr:z-[9998] skippr:size-14 skippr:rounded-full skippr:shadow-lg skippr:transition-all skippr:duration-300", position === "right" ? "skippr:right-6" : "skippr:left-6"),
1407
1699
  title: isPanelOpen ? "Close chat" : "Chat with us",
1408
- children: isPanelOpen ? /* @__PURE__ */ jsx13(X, {
1700
+ children: isPanelOpen ? /* @__PURE__ */ jsx15(X, {
1409
1701
  className: "skippr:size-6"
1410
- }) : /* @__PURE__ */ jsx13(MessageCircle, {
1702
+ }) : /* @__PURE__ */ jsx15(MessageCircle, {
1411
1703
  className: "skippr:size-6"
1412
1704
  })
1413
1705
  });
1414
1706
  }
1415
1707
 
1416
1708
  // src/components/LiveAgent.tsx
1417
- import { jsx as jsx14, jsxs as jsxs10, Fragment as Fragment2 } from "react/jsx-runtime";
1709
+ import { jsx as jsx16, jsxs as jsxs12, Fragment as Fragment3 } from "react/jsx-runtime";
1418
1710
  function LiveAgent({
1419
1711
  agentId,
1420
1712
  authToken: authTokenProp,
1421
1713
  appKey,
1422
1714
  userToken,
1715
+ position = "right",
1716
+ variant = "floating",
1717
+ minimizable = true,
1423
1718
  defaultOpen = false,
1424
1719
  children
1425
1720
  }) {
@@ -1431,12 +1726,45 @@ function LiveAgent({
1431
1726
  appKey,
1432
1727
  userToken
1433
1728
  });
1434
- const [isPanelOpen, setIsPanelOpen] = useState7(defaultOpen);
1435
- const openPanel = useCallback7(() => setIsPanelOpen(true), []);
1436
- const closePanel = useCallback7(() => setIsPanelOpen(false), []);
1437
- const togglePanel = useCallback7(() => setIsPanelOpen((prev) => !prev), []);
1729
+ const [isPanelOpen, setIsPanelOpen] = useState8(defaultOpen);
1730
+ const [isMinimized, setIsMinimized] = useState8(false);
1731
+ const [currentPosition, setCurrentPosition] = useState8(() => {
1732
+ try {
1733
+ const saved = localStorage.getItem("skippr_widget_position");
1734
+ if (saved === "left" || saved === "right")
1735
+ return saved;
1736
+ } catch {}
1737
+ return position;
1738
+ });
1739
+ const setPositionWithPersist = useCallback8((pos) => {
1740
+ setCurrentPosition(pos);
1741
+ try {
1742
+ localStorage.setItem("skippr_widget_position", pos);
1743
+ } catch {}
1744
+ }, []);
1745
+ const openPanel = useCallback8(() => setIsPanelOpen(true), []);
1746
+ const closePanel = useCallback8(() => setIsPanelOpen(false), []);
1747
+ const togglePanel = useCallback8(() => setIsPanelOpen((prev) => !prev), []);
1748
+ const expandPanel = useCallback8(() => {
1749
+ setIsMinimized(false);
1750
+ setIsPanelOpen(true);
1751
+ }, []);
1752
+ const minimizePanel = useCallback8(() => {
1753
+ if (!minimizable)
1754
+ return;
1755
+ setIsMinimized(true);
1756
+ setIsPanelOpen(false);
1757
+ }, [minimizable]);
1438
1758
  const isConnected = connection !== null;
1439
1759
  const isAuthenticated = !!userToken || !!authTokenProp || auth.isAuthenticated;
1760
+ useEffect8(() => {
1761
+ if (connection && minimizable) {
1762
+ setIsMinimized(true);
1763
+ setIsPanelOpen(false);
1764
+ } else if (!connection) {
1765
+ setIsMinimized(false);
1766
+ }
1767
+ }, [connection, minimizable]);
1440
1768
  const ctx = useMemo4(() => ({
1441
1769
  connection,
1442
1770
  shouldConnect,
@@ -1449,6 +1777,13 @@ function LiveAgent({
1449
1777
  openPanel,
1450
1778
  closePanel,
1451
1779
  togglePanel,
1780
+ variant,
1781
+ position: currentPosition,
1782
+ setPosition: setPositionWithPersist,
1783
+ minimizable,
1784
+ isMinimized,
1785
+ expandPanel,
1786
+ minimizePanel,
1452
1787
  isAuthenticated,
1453
1788
  isValidating: auth.isValidating,
1454
1789
  authError: auth.error,
@@ -1468,6 +1803,13 @@ function LiveAgent({
1468
1803
  openPanel,
1469
1804
  closePanel,
1470
1805
  togglePanel,
1806
+ variant,
1807
+ currentPosition,
1808
+ setPositionWithPersist,
1809
+ minimizable,
1810
+ isMinimized,
1811
+ expandPanel,
1812
+ minimizePanel,
1471
1813
  isAuthenticated,
1472
1814
  auth.isValidating,
1473
1815
  auth.error,
@@ -1476,17 +1818,18 @@ function LiveAgent({
1476
1818
  auth.logout,
1477
1819
  auth.isSubmitting
1478
1820
  ]);
1479
- const widgetContent = /* @__PURE__ */ jsxs10(Fragment2, {
1821
+ const widgetContent = /* @__PURE__ */ jsxs12(Fragment3, {
1480
1822
  children: [
1481
- connection && /* @__PURE__ */ jsx14(RoomAudioRenderer, {}),
1482
- /* @__PURE__ */ jsx14(SidebarTrigger, {}),
1483
- /* @__PURE__ */ jsx14(Sidebar, {}),
1823
+ connection && /* @__PURE__ */ jsx16(RoomAudioRenderer, {}),
1824
+ isMinimized && isConnected && /* @__PURE__ */ jsx16(MinimizedBubble, {}),
1825
+ /* @__PURE__ */ jsx16(SidebarTrigger, {}),
1826
+ /* @__PURE__ */ jsx16(Sidebar, {}),
1484
1827
  children
1485
1828
  ]
1486
1829
  });
1487
- return /* @__PURE__ */ jsx14(LiveAgentContext.Provider, {
1830
+ return /* @__PURE__ */ jsx16(LiveAgentContext.Provider, {
1488
1831
  value: ctx,
1489
- children: connection ? /* @__PURE__ */ jsx14(LiveKitRoom, {
1832
+ children: connection ? /* @__PURE__ */ jsx16(LiveKitRoom, {
1490
1833
  serverUrl: connection.livekitUrl,
1491
1834
  token: connection.token,
1492
1835
  connect: shouldConnect,