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