@supernal/interface-nextjs 1.0.25 → 1.0.28

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.
package/dist/index.js CHANGED
@@ -31,12 +31,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  // src/index.ts
32
32
  var index_exports = {};
33
33
  __export(index_exports, {
34
+ ApiKeyProvider: () => ApiKeyProvider,
34
35
  AutoNavigationContext: () => AutoNavigationContext,
35
36
  ChatBubble: () => ChatBubble,
36
37
  ChatBubbleSettingsModal: () => ChatBubbleSettingsModal,
37
38
  ChatBubbleVariant: () => ChatBubbleVariant,
38
39
  ChatInputProvider: () => ChatInputProvider,
39
40
  ChatProvider: () => ChatProvider,
41
+ ClaudeClient: () => ClaudeClient,
40
42
  CodeBlock: () => CodeBlock,
41
43
  Components: () => Components,
42
44
  DemoAIInterface: () => DemoAIInterface,
@@ -50,9 +52,13 @@ __export(index_exports, {
50
52
  ToolManager: () => ToolManager,
51
53
  ToolMenuPopup: () => ToolMenuPopup,
52
54
  ToolMenuPopupTrigger: () => ToolMenuPopupTrigger,
55
+ createClaudeClient: () => createClaudeClient,
53
56
  findBestMatch: () => findBestMatch,
54
57
  scoreToolMatch: () => scoreToolMatch,
55
58
  useAllContexts: () => useAllContexts,
59
+ useApiKey: () => useApiKey,
60
+ useApiKeyOptional: () => useApiKeyOptional,
61
+ useApiKeyStorage: () => useApiKeyStorage,
56
62
  useChatContext: () => useChatContext,
57
63
  useChatInput: () => useChatInput,
58
64
  useCurrentContext: () => useCurrentContext,
@@ -65,7 +71,7 @@ __export(index_exports, {
65
71
  module.exports = __toCommonJS(index_exports);
66
72
 
67
73
  // src/components/SupernalProvider.tsx
68
- var import_react19 = require("react");
74
+ var import_react21 = require("react");
69
75
 
70
76
  // src/contexts/ChatInputContext.tsx
71
77
  var import_react = require("react");
@@ -92,10 +98,10 @@ function ChatInputProvider({ children }) {
92
98
  }
93
99
 
94
100
  // src/contexts/ChatProvider.tsx
95
- var import_react2 = require("react");
101
+ var import_react4 = require("react");
96
102
 
97
103
  // src/lib/ChatAIInterface.ts
98
- var import_interface = require("@supernal/interface");
104
+ var import_browser2 = require("@supernal/interface/browser");
99
105
 
100
106
  // src/lib/ToolManager.ts
101
107
  var import_browser = require("@supernal/interface/browser");
@@ -190,7 +196,7 @@ var ToolManagerClass = class {
190
196
  var ToolManager = new ToolManagerClass();
191
197
 
192
198
  // src/lib/ChatAIInterface.ts
193
- var DemoAIInterface = class extends import_interface.AIInterface {
199
+ var DemoAIInterface = class extends import_browser2.AIInterface {
194
200
  constructor() {
195
201
  super();
196
202
  this.toolExecutionListeners = [];
@@ -234,17 +240,466 @@ var DemoAIInterface = class extends import_interface.AIInterface {
234
240
  }
235
241
  };
236
242
 
237
- // src/contexts/ChatProvider.tsx
243
+ // src/lib/ClaudeClient.ts
244
+ var COST_PER_1K = {
245
+ "claude-sonnet-4-20250514": { input: 3e-3, output: 0.015 },
246
+ "claude-3-5-sonnet-20241022": { input: 3e-3, output: 0.015 },
247
+ "claude-3-opus-20240229": { input: 0.015, output: 0.075 },
248
+ "claude-3-haiku-20240307": { input: 25e-5, output: 125e-5 }
249
+ };
250
+ var ClaudeClient = class {
251
+ constructor(config) {
252
+ this.apiKey = config.apiKey;
253
+ this.model = config.model || "claude-sonnet-4-20250514";
254
+ this.maxTokens = config.maxTokens || 4096;
255
+ this.systemPrompt = config.systemPrompt || "You are a helpful AI assistant integrated into a web application. Be concise and helpful.";
256
+ }
257
+ /**
258
+ * Send a message to Claude and get a response
259
+ */
260
+ async sendMessage(userMessage, options = {}) {
261
+ const messages = [
262
+ ...options.messages || [],
263
+ { role: "user", content: userMessage }
264
+ ];
265
+ try {
266
+ const response = await fetch("https://api.anthropic.com/v1/messages", {
267
+ method: "POST",
268
+ headers: {
269
+ "Content-Type": "application/json",
270
+ "x-api-key": this.apiKey,
271
+ "anthropic-version": "2023-06-01",
272
+ "anthropic-dangerous-direct-browser-access": "true"
273
+ },
274
+ body: JSON.stringify({
275
+ model: this.model,
276
+ max_tokens: options.maxTokens || this.maxTokens,
277
+ system: options.systemPrompt || this.systemPrompt,
278
+ messages: messages.map((m) => ({
279
+ role: m.role,
280
+ content: m.content
281
+ })),
282
+ temperature: options.temperature
283
+ })
284
+ });
285
+ if (!response.ok) {
286
+ const errorData = await response.json().catch(() => ({}));
287
+ if (response.status === 401) {
288
+ return {
289
+ success: false,
290
+ message: "Invalid API key. Please check your API key and try again.",
291
+ error: "INVALID_API_KEY"
292
+ };
293
+ }
294
+ if (response.status === 429) {
295
+ return {
296
+ success: false,
297
+ message: "Rate limit exceeded. Please wait a moment and try again.",
298
+ error: "RATE_LIMITED"
299
+ };
300
+ }
301
+ if (response.status === 400) {
302
+ return {
303
+ success: false,
304
+ message: errorData.error?.message || "Invalid request",
305
+ error: "BAD_REQUEST"
306
+ };
307
+ }
308
+ return {
309
+ success: false,
310
+ message: errorData.error?.message || `API error: ${response.status}`,
311
+ error: "API_ERROR"
312
+ };
313
+ }
314
+ const data = await response.json();
315
+ const textContent = data.content.find((c) => c.type === "text");
316
+ const responseText = textContent?.text || "";
317
+ const modelCosts = COST_PER_1K[this.model] || COST_PER_1K["claude-sonnet-4-20250514"];
318
+ const inputCost = data.usage.input_tokens / 1e3 * modelCosts.input;
319
+ const outputCost = data.usage.output_tokens / 1e3 * modelCosts.output;
320
+ return {
321
+ success: true,
322
+ message: responseText,
323
+ response: data,
324
+ usage: {
325
+ inputTokens: data.usage.input_tokens,
326
+ outputTokens: data.usage.output_tokens,
327
+ estimatedCost: inputCost + outputCost
328
+ }
329
+ };
330
+ } catch (err) {
331
+ console.error("ClaudeClient error:", err);
332
+ if (err instanceof TypeError && err.message.includes("fetch")) {
333
+ return {
334
+ success: false,
335
+ message: "Network error. Please check your connection.",
336
+ error: "NETWORK_ERROR"
337
+ };
338
+ }
339
+ return {
340
+ success: false,
341
+ message: err instanceof Error ? err.message : "Unknown error occurred",
342
+ error: "UNKNOWN_ERROR"
343
+ };
344
+ }
345
+ }
346
+ /**
347
+ * Update the API key
348
+ */
349
+ setApiKey(apiKey) {
350
+ this.apiKey = apiKey;
351
+ }
352
+ /**
353
+ * Update the model
354
+ */
355
+ setModel(model) {
356
+ this.model = model;
357
+ }
358
+ /**
359
+ * Update the system prompt
360
+ */
361
+ setSystemPrompt(systemPrompt) {
362
+ this.systemPrompt = systemPrompt;
363
+ }
364
+ };
365
+ function createClaudeClient(config) {
366
+ return new ClaudeClient(config);
367
+ }
368
+
369
+ // src/contexts/ApiKeyContext.tsx
370
+ var import_react3 = __toESM(require("react"));
371
+
372
+ // src/hooks/useApiKeyStorage.ts
373
+ var import_react2 = require("react");
374
+ var STORAGE_KEY = "supernal-api-key";
375
+ var ENCRYPTED_STORAGE_KEY = "supernal-vault-v1";
376
+ function validateApiKeyFormat(key) {
377
+ if (!key || key.trim() === "") {
378
+ return { valid: false, error: "API key is required" };
379
+ }
380
+ if (!key.startsWith("sk-ant-")) {
381
+ return { valid: false, error: 'Invalid format. Keys start with "sk-ant-"' };
382
+ }
383
+ if (key.length < 50) {
384
+ return { valid: false, error: "API key appears too short" };
385
+ }
386
+ return { valid: true };
387
+ }
388
+ function maskApiKey(key) {
389
+ if (key.length <= 14) return "\u2022".repeat(key.length);
390
+ return `${key.slice(0, 10)}...${key.slice(-4)}`;
391
+ }
392
+ async function validateApiKeyWithAnthropic(apiKey) {
393
+ try {
394
+ const response = await fetch("https://api.anthropic.com/v1/messages", {
395
+ method: "POST",
396
+ headers: {
397
+ "Content-Type": "application/json",
398
+ "x-api-key": apiKey,
399
+ "anthropic-version": "2023-06-01",
400
+ "anthropic-dangerous-direct-browser-access": "true"
401
+ },
402
+ body: JSON.stringify({
403
+ model: "claude-sonnet-4-20250514",
404
+ max_tokens: 1,
405
+ messages: [{ role: "user", content: "hi" }]
406
+ })
407
+ });
408
+ if (response.ok) {
409
+ return { valid: true };
410
+ }
411
+ const data = await response.json().catch(() => ({}));
412
+ if (response.status === 401) {
413
+ return { valid: false, error: "Invalid API key" };
414
+ }
415
+ if (response.status === 403) {
416
+ return { valid: false, error: "API key does not have permission" };
417
+ }
418
+ if (response.status === 429) {
419
+ return { valid: true };
420
+ }
421
+ return { valid: false, error: data.error?.message || "Validation failed" };
422
+ } catch (err) {
423
+ console.warn("Could not validate API key with Anthropic:", err);
424
+ return validateApiKeyFormat(apiKey);
425
+ }
426
+ }
427
+ var SALT_LENGTH = 32;
428
+ var IV_LENGTH = 12;
429
+ var ITERATIONS = 1e5;
430
+ async function deriveKey(passphrase, salt) {
431
+ const keyMaterial = await crypto.subtle.importKey(
432
+ "raw",
433
+ new TextEncoder().encode(passphrase),
434
+ "PBKDF2",
435
+ false,
436
+ ["deriveKey"]
437
+ );
438
+ const saltBuffer = salt.buffer.slice(salt.byteOffset, salt.byteOffset + salt.byteLength);
439
+ return crypto.subtle.deriveKey(
440
+ { name: "PBKDF2", salt: saltBuffer, iterations: ITERATIONS, hash: "SHA-256" },
441
+ keyMaterial,
442
+ { name: "AES-GCM", length: 256 },
443
+ false,
444
+ ["encrypt", "decrypt"]
445
+ );
446
+ }
447
+ async function encryptValue(key, plaintext, salt) {
448
+ const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));
449
+ const ivBuffer = iv.buffer.slice(iv.byteOffset, iv.byteOffset + iv.byteLength);
450
+ const ciphertext = await crypto.subtle.encrypt(
451
+ { name: "AES-GCM", iv: ivBuffer },
452
+ key,
453
+ new TextEncoder().encode(plaintext)
454
+ );
455
+ return {
456
+ version: 1,
457
+ ciphertext: arrayBufferToBase64(ciphertext),
458
+ salt: uint8ArrayToBase64(salt),
459
+ iv: uint8ArrayToBase64(iv),
460
+ encryptedAt: Date.now()
461
+ };
462
+ }
463
+ async function decryptValue(key, entry) {
464
+ const ciphertext = base64ToArrayBuffer(entry.ciphertext);
465
+ const iv = base64ToUint8Array(entry.iv);
466
+ const ivBuffer = iv.buffer.slice(iv.byteOffset, iv.byteOffset + iv.byteLength);
467
+ const plaintext = await crypto.subtle.decrypt(
468
+ { name: "AES-GCM", iv: ivBuffer },
469
+ key,
470
+ ciphertext
471
+ );
472
+ return new TextDecoder().decode(plaintext);
473
+ }
474
+ function arrayBufferToBase64(buffer) {
475
+ const bytes = new Uint8Array(buffer);
476
+ let binary = "";
477
+ for (let i = 0; i < bytes.byteLength; i++) {
478
+ binary += String.fromCharCode(bytes[i]);
479
+ }
480
+ return btoa(binary);
481
+ }
482
+ function base64ToArrayBuffer(base64) {
483
+ const binary = atob(base64);
484
+ const bytes = new Uint8Array(binary.length);
485
+ for (let i = 0; i < binary.length; i++) {
486
+ bytes[i] = binary.charCodeAt(i);
487
+ }
488
+ return bytes.buffer;
489
+ }
490
+ function uint8ArrayToBase64(array) {
491
+ const buffer = array.buffer.slice(array.byteOffset, array.byteOffset + array.byteLength);
492
+ return arrayBufferToBase64(buffer);
493
+ }
494
+ function base64ToUint8Array(base64) {
495
+ return new Uint8Array(base64ToArrayBuffer(base64));
496
+ }
497
+ function loadEncryptedEntry() {
498
+ if (typeof window === "undefined") return null;
499
+ try {
500
+ const stored = localStorage.getItem(ENCRYPTED_STORAGE_KEY);
501
+ if (stored) {
502
+ const entry = JSON.parse(stored);
503
+ if (entry.version === 1 && entry.ciphertext && entry.salt) {
504
+ return entry;
505
+ }
506
+ }
507
+ } catch {
508
+ }
509
+ return null;
510
+ }
511
+ function useApiKeyStorage(options = {}) {
512
+ const [state, setState] = (0, import_react2.useState)({
513
+ apiKey: null,
514
+ status: options.encrypted ? "locked" : "none",
515
+ error: null,
516
+ maskedKey: null
517
+ });
518
+ const derivedKeyRef = (0, import_react2.useRef)(null);
519
+ const saltRef = (0, import_react2.useRef)(null);
520
+ (0, import_react2.useEffect)(() => {
521
+ if (typeof window === "undefined") return;
522
+ if (options.encrypted) {
523
+ const entry = loadEncryptedEntry();
524
+ if (entry) {
525
+ setState((prev) => ({ ...prev, status: "locked" }));
526
+ } else {
527
+ setState((prev) => ({ ...prev, status: "locked" }));
528
+ }
529
+ return;
530
+ }
531
+ try {
532
+ const saved = localStorage.getItem(STORAGE_KEY);
533
+ if (saved) {
534
+ const validation = validateApiKeyFormat(saved);
535
+ setState({
536
+ apiKey: saved,
537
+ status: validation.valid ? "valid" : "invalid",
538
+ error: validation.error || null,
539
+ maskedKey: maskApiKey(saved)
540
+ });
541
+ }
542
+ } catch (err) {
543
+ console.error("Failed to load API key from storage:", err);
544
+ }
545
+ }, [options.encrypted]);
546
+ const unlock = (0, import_react2.useCallback)(async (passphrase) => {
547
+ if (!options.encrypted) {
548
+ return true;
549
+ }
550
+ try {
551
+ const entry = loadEncryptedEntry();
552
+ if (entry) {
553
+ const salt = base64ToUint8Array(entry.salt);
554
+ const key = await deriveKey(passphrase, salt);
555
+ try {
556
+ const apiKey = await decryptValue(key, entry);
557
+ derivedKeyRef.current = key;
558
+ saltRef.current = salt;
559
+ const validation = validateApiKeyFormat(apiKey);
560
+ setState({
561
+ apiKey,
562
+ status: validation.valid ? "valid" : "invalid",
563
+ error: validation.error || null,
564
+ maskedKey: maskApiKey(apiKey)
565
+ });
566
+ return true;
567
+ } catch {
568
+ options.onPassphraseInvalid?.();
569
+ return false;
570
+ }
571
+ } else {
572
+ const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));
573
+ const key = await deriveKey(passphrase, salt);
574
+ derivedKeyRef.current = key;
575
+ saltRef.current = salt;
576
+ setState((prev) => ({
577
+ ...prev,
578
+ status: "none"
579
+ // Unlocked but no key yet
580
+ }));
581
+ return true;
582
+ }
583
+ } catch (error) {
584
+ console.error("[useApiKeyStorage] Unlock failed:", error);
585
+ return false;
586
+ }
587
+ }, [options.encrypted, options.onPassphraseInvalid]);
588
+ const lock = (0, import_react2.useCallback)(() => {
589
+ if (!options.encrypted) return;
590
+ derivedKeyRef.current = null;
591
+ setState((prev) => ({
592
+ ...prev,
593
+ status: "locked",
594
+ apiKey: null,
595
+ maskedKey: null
596
+ }));
597
+ }, [options.encrypted]);
598
+ const setApiKey = (0, import_react2.useCallback)(async (key, validate = true) => {
599
+ const formatValidation = validateApiKeyFormat(key);
600
+ if (!formatValidation.valid) {
601
+ setState({
602
+ apiKey: null,
603
+ status: "invalid",
604
+ error: formatValidation.error || "Invalid API key",
605
+ maskedKey: null
606
+ });
607
+ return false;
608
+ }
609
+ setState({
610
+ apiKey: key,
611
+ status: validate ? "validating" : "valid",
612
+ error: null,
613
+ maskedKey: maskApiKey(key)
614
+ });
615
+ try {
616
+ if (options.encrypted && derivedKeyRef.current && saltRef.current) {
617
+ const entry = await encryptValue(derivedKeyRef.current, key, saltRef.current);
618
+ localStorage.setItem(ENCRYPTED_STORAGE_KEY, JSON.stringify(entry));
619
+ } else {
620
+ localStorage.setItem(STORAGE_KEY, key);
621
+ }
622
+ } catch (err) {
623
+ console.error("Failed to save API key:", err);
624
+ }
625
+ if (validate) {
626
+ const liveValidation = await validateApiKeyWithAnthropic(key);
627
+ setState((prev) => ({
628
+ ...prev,
629
+ status: liveValidation.valid ? "valid" : "invalid",
630
+ error: liveValidation.error || null
631
+ }));
632
+ return liveValidation.valid;
633
+ }
634
+ return true;
635
+ }, [options.encrypted]);
636
+ const clearApiKey = (0, import_react2.useCallback)(() => {
637
+ try {
638
+ if (options.encrypted) {
639
+ localStorage.removeItem(ENCRYPTED_STORAGE_KEY);
640
+ } else {
641
+ localStorage.removeItem(STORAGE_KEY);
642
+ }
643
+ } catch (err) {
644
+ console.error("Failed to clear API key:", err);
645
+ }
646
+ setState({
647
+ apiKey: null,
648
+ status: options.encrypted ? "locked" : "none",
649
+ error: null,
650
+ maskedKey: null
651
+ });
652
+ }, [options.encrypted]);
653
+ const revalidate = (0, import_react2.useCallback)(async () => {
654
+ if (!state.apiKey) return false;
655
+ return setApiKey(state.apiKey, true);
656
+ }, [state.apiKey, setApiKey]);
657
+ return {
658
+ ...state,
659
+ hasApiKey: !!state.apiKey && state.status === "valid",
660
+ isLocked: state.status === "locked",
661
+ setApiKey,
662
+ clearApiKey,
663
+ revalidate,
664
+ unlock,
665
+ lock
666
+ };
667
+ }
668
+
669
+ // src/contexts/ApiKeyContext.tsx
238
670
  var import_jsx_runtime2 = require("react/jsx-runtime");
239
- var ChatContext = (0, import_react2.createContext)(null);
671
+ var ApiKeyContext = (0, import_react3.createContext)(null);
672
+ function ApiKeyProvider({ children, initialApiKey }) {
673
+ const apiKeyStorage = useApiKeyStorage();
674
+ import_react3.default.useEffect(() => {
675
+ if (initialApiKey && !apiKeyStorage.apiKey && apiKeyStorage.status === "none") {
676
+ apiKeyStorage.setApiKey(initialApiKey, false);
677
+ }
678
+ }, [initialApiKey, apiKeyStorage]);
679
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ApiKeyContext.Provider, { value: apiKeyStorage, children });
680
+ }
681
+ function useApiKey() {
682
+ const context = (0, import_react3.useContext)(ApiKeyContext);
683
+ if (!context) {
684
+ throw new Error("useApiKey must be used within ApiKeyProvider");
685
+ }
686
+ return context;
687
+ }
688
+ function useApiKeyOptional() {
689
+ return (0, import_react3.useContext)(ApiKeyContext);
690
+ }
691
+
692
+ // src/contexts/ChatProvider.tsx
693
+ var import_jsx_runtime3 = require("react/jsx-runtime");
694
+ var ChatContext = (0, import_react4.createContext)(null);
240
695
  function useChatContext() {
241
- const context = (0, import_react2.useContext)(ChatContext);
696
+ const context = (0, import_react4.useContext)(ChatContext);
242
697
  if (!context) {
243
698
  throw new Error("useChatContext must be used within ChatProvider");
244
699
  }
245
700
  return context;
246
701
  }
247
- var STORAGE_KEY = "supernal-chat-messages";
702
+ var STORAGE_KEY2 = "supernal-chat-messages";
248
703
  var MAX_MESSAGES = 100;
249
704
  function getInitialMessages() {
250
705
  return [
@@ -289,14 +744,30 @@ function getInitialMessages() {
289
744
  function ChatProvider({
290
745
  children,
291
746
  mode = "fuzzy",
292
- apiKey,
747
+ apiKey: propApiKey,
293
748
  onToolExecute
294
749
  }) {
295
- const [messages, setMessages] = (0, import_react2.useState)([]);
296
- (0, import_react2.useEffect)(() => {
750
+ const [messages, setMessages] = (0, import_react4.useState)([]);
751
+ const apiKeyContext = useApiKeyOptional();
752
+ const activeApiKey = apiKeyContext?.hasApiKey ? apiKeyContext.apiKey : propApiKey;
753
+ const isAiMode = !!activeApiKey;
754
+ const claudeClientRef = (0, import_react4.useRef)(null);
755
+ (0, import_react4.useEffect)(() => {
756
+ if (activeApiKey) {
757
+ claudeClientRef.current = new ClaudeClient({
758
+ apiKey: activeApiKey,
759
+ systemPrompt: `You are a helpful AI assistant integrated into a web application powered by Supernal Interface.
760
+ You can help users navigate the application and perform tasks.
761
+ Be concise, friendly, and helpful. Use markdown formatting when appropriate.`
762
+ });
763
+ } else {
764
+ claudeClientRef.current = null;
765
+ }
766
+ }, [activeApiKey]);
767
+ (0, import_react4.useEffect)(() => {
297
768
  if (typeof window === "undefined") return;
298
769
  try {
299
- const saved = localStorage.getItem(STORAGE_KEY);
770
+ const saved = localStorage.getItem(STORAGE_KEY2);
300
771
  if (saved) {
301
772
  const loaded = JSON.parse(saved).map((m) => ({
302
773
  ...m,
@@ -311,24 +782,24 @@ function ChatProvider({
311
782
  setMessages(getInitialMessages());
312
783
  }
313
784
  }, []);
314
- const [isLoading, setIsLoading] = (0, import_react2.useState)(false);
315
- const [aiInterface] = (0, import_react2.useState)(() => new DemoAIInterface());
316
- (0, import_react2.useEffect)(() => {
785
+ const [isLoading, setIsLoading] = (0, import_react4.useState)(false);
786
+ const [aiInterface] = (0, import_react4.useState)(() => new DemoAIInterface());
787
+ (0, import_react4.useEffect)(() => {
317
788
  if (onToolExecute) {
318
789
  return aiInterface.onToolExecution((result) => {
319
790
  onToolExecute(result.toolName, result);
320
791
  });
321
792
  }
322
793
  }, [aiInterface, onToolExecute]);
323
- (0, import_react2.useEffect)(() => {
794
+ (0, import_react4.useEffect)(() => {
324
795
  try {
325
796
  const toSave = messages.slice(-MAX_MESSAGES);
326
- localStorage.setItem(STORAGE_KEY, JSON.stringify(toSave));
797
+ localStorage.setItem(STORAGE_KEY2, JSON.stringify(toSave));
327
798
  } catch (error) {
328
799
  console.error("Failed to save messages:", error);
329
800
  }
330
801
  }, [messages]);
331
- const sendMessage = (0, import_react2.useCallback)(async (text) => {
802
+ const sendMessage = (0, import_react4.useCallback)(async (text) => {
332
803
  const userMessage = {
333
804
  id: Date.now().toString(),
334
805
  text,
@@ -338,14 +809,31 @@ function ChatProvider({
338
809
  setMessages((prev) => [...prev, userMessage]);
339
810
  setIsLoading(true);
340
811
  try {
341
- const result = await aiInterface.findAndExecuteCommand(text);
342
- const aiMessage = {
343
- id: (Date.now() + 1).toString(),
344
- text: result.message,
345
- type: result.success ? "ai" : "system",
346
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
347
- };
348
- setMessages((prev) => [...prev, aiMessage]);
812
+ if (claudeClientRef.current) {
813
+ const conversationHistory = messages.slice(-20).filter((m) => m.type === "user" || m.type === "ai").map((m) => ({
814
+ role: m.type === "user" ? "user" : "assistant",
815
+ content: m.text
816
+ }));
817
+ const result = await claudeClientRef.current.sendMessage(text, {
818
+ messages: conversationHistory
819
+ });
820
+ const aiMessage = {
821
+ id: (Date.now() + 1).toString(),
822
+ text: result.message,
823
+ type: result.success ? "ai" : "system",
824
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
825
+ };
826
+ setMessages((prev) => [...prev, aiMessage]);
827
+ } else {
828
+ const result = await aiInterface.findAndExecuteCommand(text);
829
+ const aiMessage = {
830
+ id: (Date.now() + 1).toString(),
831
+ text: result.message,
832
+ type: result.success ? "ai" : "system",
833
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
834
+ };
835
+ setMessages((prev) => [...prev, aiMessage]);
836
+ }
349
837
  } catch (error) {
350
838
  const errorMessage = {
351
839
  id: (Date.now() + 1).toString(),
@@ -357,16 +845,16 @@ function ChatProvider({
357
845
  } finally {
358
846
  setIsLoading(false);
359
847
  }
360
- }, [aiInterface]);
361
- const clearMessages = (0, import_react2.useCallback)(() => {
848
+ }, [aiInterface, messages]);
849
+ const clearMessages = (0, import_react4.useCallback)(() => {
362
850
  setMessages([]);
363
- localStorage.removeItem(STORAGE_KEY);
851
+ localStorage.removeItem(STORAGE_KEY2);
364
852
  }, []);
365
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChatContext.Provider, { value: { messages, sendMessage, clearMessages, isLoading }, children });
853
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChatContext.Provider, { value: { messages, sendMessage, clearMessages, isLoading, isAiMode }, children });
366
854
  }
367
855
 
368
856
  // src/components/ChatBubble/constants.ts
369
- var import_react3 = __toESM(require("react"));
857
+ var import_react5 = __toESM(require("react"));
370
858
 
371
859
  // src/names/Components.ts
372
860
  var Components = {
@@ -374,7 +862,20 @@ var Components = {
374
862
  ChatToggleButton: "chat-toggle-button",
375
863
  ChatInput: "chat-message-input",
376
864
  ChatSendButton: "chat-send-button",
377
- ChatClearButton: "chat-clear-button"
865
+ ChatClearButton: "chat-clear-button",
866
+ ChatMoreMenu: "chat-more-menu",
867
+ ChatMoreMenuButton: "chat-more-menu-button",
868
+ // API Key configuration components (BYOK mode)
869
+ ApiKeySection: "api-key-section",
870
+ ApiKeyInput: "api-key-input",
871
+ ApiKeySubmitButton: "api-key-submit-button",
872
+ ApiKeyClearButton: "api-key-clear-button",
873
+ ApiKeyConfigureButton: "api-key-configure-button",
874
+ ApiKeyStatus: "api-key-status",
875
+ ApiKeyMasked: "api-key-masked",
876
+ ApiKeyError: "api-key-error",
877
+ ApiKeyShowToggle: "api-key-show-toggle",
878
+ ApiKeyCancelButton: "api-key-cancel-button"
378
879
  };
379
880
  var ChatBubbleVariant = {
380
881
  full: "full",
@@ -576,7 +1077,7 @@ var GLASS_INVERTED = {
576
1077
  var DEFAULT_CONFIG = {
577
1078
  title: "Supernal Interface",
578
1079
  logo: DEFAULT_LOGO,
579
- avatar: import_react3.default.createElement("img", { src: DEFAULT_LOGO, alt: "Supernal", className: "w-6 h-6" }),
1080
+ avatar: import_react5.default.createElement("img", { src: DEFAULT_LOGO, alt: "Supernal", className: "w-6 h-6" }),
580
1081
  description: "I'm a TOOL system AI can use to control this site",
581
1082
  placeholder: "Try: toggle notifications",
582
1083
  sendButtonLabel: "Send",
@@ -599,7 +1100,7 @@ var DEFAULT_CONFIG = {
599
1100
  };
600
1101
 
601
1102
  // src/components/ChatBubble/InputField.tsx
602
- var import_jsx_runtime3 = require("react/jsx-runtime");
1103
+ var import_jsx_runtime4 = require("react/jsx-runtime");
603
1104
  var InputField = ({
604
1105
  compact = false,
605
1106
  inputValue,
@@ -615,8 +1116,8 @@ var InputField = ({
615
1116
  onMicClick,
616
1117
  modKey = "Ctrl",
617
1118
  onKeyDown
618
- }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("form", { onSubmit, className: compact ? "flex space-x-2" : THEME_CLASSES.bg.inputForm + " bg-transparent", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: compact ? "flex space-x-2 flex-1" : "relative", children: [
619
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1119
+ }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("form", { onSubmit, className: compact ? "flex space-x-2" : THEME_CLASSES.bg.inputForm + " bg-transparent", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: compact ? "flex space-x-2 flex-1" : "relative", children: [
1120
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
620
1121
  "input",
621
1122
  {
622
1123
  ref: compact ? void 0 : inputRef,
@@ -630,7 +1131,7 @@ var InputField = ({
630
1131
  "data-testid": ChatNames.input
631
1132
  }
632
1133
  ),
633
- voiceEnabled && onMicClick && !compact && (!inputValue.trim() || isListening) && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1134
+ voiceEnabled && onMicClick && !compact && (!inputValue.trim() || isListening) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
634
1135
  "button",
635
1136
  {
636
1137
  type: "button",
@@ -638,33 +1139,33 @@ var InputField = ({
638
1139
  className: `absolute right-2 top-1/2 -translate-y-1/2 p-2 rounded-full transition-all ${isListening ? "bg-red-500 text-white animate-pulse" : "text-gray-500 hover:text-blue-600 hover:bg-gray-100 dark:hover:bg-gray-700"}`,
639
1140
  title: isListening ? "Stop recording (ESC)" : `Voice input (click or press ${modKey}+/)`,
640
1141
  "data-testid": "voice-input-button",
641
- children: isListening ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z" }) })
1142
+ children: isListening ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z" }) })
642
1143
  }
643
1144
  ),
644
- inputValue.trim() && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1145
+ inputValue.trim() && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
645
1146
  "button",
646
1147
  {
647
1148
  type: "submit",
648
1149
  className: compact ? "px-3 py-2 bg-gradient-to-r from-blue-500 to-blue-600 text-white rounded-xl hover:from-blue-600 hover:to-blue-700 disabled:from-gray-300 disabled:to-gray-400 disabled:cursor-not-allowed transition-all text-xs font-medium shadow-md hover:shadow-lg" : THEME_CLASSES.input.sendButton,
649
1150
  "data-testid": ChatNames.sendButton,
650
1151
  title: sendButtonLabel,
651
- children: compact ? "\u2192" : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "2.5", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13 5l7 7m0 0l-7 7m7-7H3" }) })
1152
+ children: compact ? "\u2192" : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "2.5", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13 5l7 7m0 0l-7 7m7-7H3" }) })
652
1153
  }
653
1154
  )
654
1155
  ] }) });
655
1156
 
656
1157
  // src/components/ChatBubble/Avatar.tsx
657
- var import_jsx_runtime4 = require("react/jsx-runtime");
1158
+ var import_jsx_runtime5 = require("react/jsx-runtime");
658
1159
  var Avatar = ({ avatar, size = "normal" }) => {
659
1160
  if (!avatar) return null;
660
1161
  if (typeof avatar === "string") {
661
- return size === "small" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-lg", children: avatar }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "w-10 h-10 bg-blue-600 rounded-lg flex items-center justify-center shadow-md", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-white text-sm font-bold", children: avatar }) });
1162
+ return size === "small" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-lg", children: avatar }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-10 h-10 bg-blue-600 rounded-lg flex items-center justify-center shadow-md", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-white text-sm font-bold", children: avatar }) });
662
1163
  }
663
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: avatar });
1164
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children: avatar });
664
1165
  };
665
1166
 
666
1167
  // src/components/ChatBubble/ChatBubble.tsx
667
- var import_react11 = __toESM(require("react"));
1168
+ var import_react13 = __toESM(require("react"));
668
1169
 
669
1170
  // src/components/MessageRenderer.tsx
670
1171
  var import_react_markdown = __toESM(require("react-markdown"));
@@ -674,12 +1175,12 @@ var import_remark_directive = __toESM(require("remark-directive"));
674
1175
  var import_rehype_katex = __toESM(require("rehype-katex"));
675
1176
 
676
1177
  // src/components/CodeBlock.tsx
677
- var import_react4 = __toESM(require("react"));
1178
+ var import_react6 = __toESM(require("react"));
678
1179
  var import_react_syntax_highlighter = require("react-syntax-highlighter");
679
- var import_prism = require("react-syntax-highlighter/dist/cjs/styles/prism");
680
- var import_jsx_runtime5 = require("react/jsx-runtime");
1180
+ var import_prism = require("react-syntax-highlighter/dist/esm/styles/prism");
1181
+ var import_jsx_runtime6 = require("react/jsx-runtime");
681
1182
  function CodeBlock({ children, className, inline, theme = "dark" }) {
682
- const [copied, setCopied] = (0, import_react4.useState)(false);
1183
+ const [copied, setCopied] = (0, import_react6.useState)(false);
683
1184
  const match = /language-(\w+)/.exec(className || "");
684
1185
  const language = match ? match[1] : "text";
685
1186
  const handleCopy = async () => {
@@ -688,25 +1189,25 @@ function CodeBlock({ children, className, inline, theme = "dark" }) {
688
1189
  setTimeout(() => setCopied(false), 2e3);
689
1190
  };
690
1191
  if (inline) {
691
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { className: `${className || ""} px-1.5 py-0.5 rounded text-sm font-mono ${theme === "dark" ? "bg-gray-800 text-gray-200" : "bg-gray-100 text-gray-800"}`, children });
1192
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { className: `${className || ""} px-1.5 py-0.5 rounded text-sm font-mono ${theme === "dark" ? "bg-gray-800 text-gray-200" : "bg-gray-100 text-gray-800"}`, children });
692
1193
  }
693
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "relative group my-4", children: [
694
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1194
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "relative group my-4", children: [
1195
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
695
1196
  "button",
696
1197
  {
697
1198
  onClick: handleCopy,
698
1199
  className: `absolute top-2 right-2 px-3 py-1.5 text-xs font-medium rounded transition-all ${theme === "dark" ? "bg-gray-700 hover:bg-gray-600 text-gray-200" : "bg-gray-200 hover:bg-gray-300 text-gray-700"} ${copied ? "opacity-100" : "opacity-0 group-hover:opacity-100"}`,
699
1200
  "aria-label": "Copy code",
700
- children: copied ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "flex items-center gap-1", children: [
701
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }),
1201
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "flex items-center gap-1", children: [
1202
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }),
702
1203
  "Copied!"
703
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "flex items-center gap-1", children: [
704
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" }) }),
1204
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "flex items-center gap-1", children: [
1205
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" }) }),
705
1206
  "Copy"
706
1207
  ] })
707
1208
  }
708
1209
  ),
709
- import_react4.default.createElement(import_react_syntax_highlighter.Prism, {
1210
+ import_react6.default.createElement(import_react_syntax_highlighter.Prism, {
710
1211
  language,
711
1212
  style: theme === "dark" ? import_prism.vscDarkPlus : import_prism.vs,
712
1213
  customStyle: {
@@ -723,13 +1224,13 @@ function CodeBlock({ children, className, inline, theme = "dark" }) {
723
1224
  }
724
1225
 
725
1226
  // src/components/MermaidDiagram.tsx
726
- var import_react5 = require("react");
727
- var import_jsx_runtime6 = require("react/jsx-runtime");
1227
+ var import_react7 = require("react");
1228
+ var import_jsx_runtime7 = require("react/jsx-runtime");
728
1229
  function MermaidDiagram({ chart, theme = "dark" }) {
729
- const containerRef = (0, import_react5.useRef)(null);
730
- const [error, setError] = (0, import_react5.useState)(null);
731
- const [isLoading, setIsLoading] = (0, import_react5.useState)(true);
732
- (0, import_react5.useEffect)(() => {
1230
+ const containerRef = (0, import_react7.useRef)(null);
1231
+ const [error, setError] = (0, import_react7.useState)(null);
1232
+ const [isLoading, setIsLoading] = (0, import_react7.useState)(true);
1233
+ (0, import_react7.useEffect)(() => {
733
1234
  let mounted = true;
734
1235
  const renderDiagram = async () => {
735
1236
  if (!containerRef.current) return;
@@ -763,18 +1264,18 @@ function MermaidDiagram({ chart, theme = "dark" }) {
763
1264
  };
764
1265
  }, [chart, theme]);
765
1266
  if (error) {
766
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `my-4 p-4 rounded-lg border ${theme === "dark" ? "bg-red-900/20 border-red-500 text-red-200" : "bg-red-50 border-red-300 text-red-800"}`, children: [
767
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "font-semibold mb-1", children: "Mermaid Diagram Error" }),
768
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "text-sm opacity-90", children: error }),
769
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("details", { className: "mt-2 text-xs opacity-75", children: [
770
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("summary", { className: "cursor-pointer", children: "View diagram source" }),
771
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("pre", { className: "mt-2 whitespace-pre-wrap", children: chart })
1267
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `my-4 p-4 rounded-lg border ${theme === "dark" ? "bg-red-900/20 border-red-500 text-red-200" : "bg-red-50 border-red-300 text-red-800"}`, children: [
1268
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "font-semibold mb-1", children: "Mermaid Diagram Error" }),
1269
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-sm opacity-90", children: error }),
1270
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("details", { className: "mt-2 text-xs opacity-75", children: [
1271
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("summary", { className: "cursor-pointer", children: "View diagram source" }),
1272
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("pre", { className: "mt-2 whitespace-pre-wrap", children: chart })
772
1273
  ] })
773
1274
  ] });
774
1275
  }
775
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "my-4 flex justify-center", children: [
776
- isLoading && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: `py-8 text-sm ${theme === "dark" ? "text-gray-400" : "text-gray-600"}`, children: "Rendering diagram..." }),
777
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1276
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "my-4 flex justify-center", children: [
1277
+ isLoading && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: `py-8 text-sm ${theme === "dark" ? "text-gray-400" : "text-gray-600"}`, children: "Rendering diagram..." }),
1278
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
778
1279
  "div",
779
1280
  {
780
1281
  ref: containerRef,
@@ -785,7 +1286,7 @@ function MermaidDiagram({ chart, theme = "dark" }) {
785
1286
  }
786
1287
 
787
1288
  // src/components/MessageRenderer.tsx
788
- var import_jsx_runtime7 = require("react/jsx-runtime");
1289
+ var import_jsx_runtime8 = require("react/jsx-runtime");
789
1290
  function MessageRenderer({ content, theme = "dark" }) {
790
1291
  const components = {
791
1292
  // Code blocks with syntax highlighting
@@ -796,9 +1297,9 @@ function MessageRenderer({ content, theme = "dark" }) {
796
1297
  const language = match ? match[1] : "";
797
1298
  const inline = !className;
798
1299
  if (language === "mermaid") {
799
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MermaidDiagram, { chart: value, theme });
1300
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MermaidDiagram, { chart: value, theme });
800
1301
  }
801
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1302
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
802
1303
  CodeBlock,
803
1304
  {
804
1305
  className,
@@ -809,13 +1310,13 @@ function MessageRenderer({ content, theme = "dark" }) {
809
1310
  );
810
1311
  },
811
1312
  // Headings with better styling
812
- h1: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h1", { className: `text-2xl font-bold mt-6 mb-3 ${theme === "dark" ? "text-gray-100" : "text-gray-900"}`, children }),
813
- h2: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { className: `text-xl font-bold mt-5 mb-2.5 ${theme === "dark" ? "text-gray-100" : "text-gray-900"}`, children }),
814
- h3: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { className: `text-lg font-semibold mt-4 mb-2 ${theme === "dark" ? "text-gray-200" : "text-gray-800"}`, children }),
1313
+ h1: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h1", { className: `text-2xl font-bold mt-6 mb-3 ${theme === "dark" ? "text-gray-100" : "text-gray-900"}`, children }),
1314
+ h2: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h2", { className: `text-xl font-bold mt-5 mb-2.5 ${theme === "dark" ? "text-gray-100" : "text-gray-900"}`, children }),
1315
+ h3: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { className: `text-lg font-semibold mt-4 mb-2 ${theme === "dark" ? "text-gray-200" : "text-gray-800"}`, children }),
815
1316
  // Paragraphs
816
- p: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: `mb-3 leading-relaxed ${theme === "dark" ? "text-gray-300" : "text-gray-700"}`, children }),
1317
+ p: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: `mb-3 leading-relaxed ${theme === "dark" ? "text-gray-300" : "text-gray-700"}`, children }),
817
1318
  // Links
818
- a: ({ href, children }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1319
+ a: ({ href, children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
819
1320
  "a",
820
1321
  {
821
1322
  href,
@@ -826,17 +1327,17 @@ function MessageRenderer({ content, theme = "dark" }) {
826
1327
  }
827
1328
  ),
828
1329
  // Lists
829
- ul: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { className: `list-disc list-inside mb-3 space-y-1 ${theme === "dark" ? "text-gray-300" : "text-gray-700"}`, children }),
830
- ol: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ol", { className: `list-decimal list-inside mb-3 space-y-1 ${theme === "dark" ? "text-gray-300" : "text-gray-700"}`, children }),
1330
+ ul: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { className: `list-disc list-inside mb-3 space-y-1 ${theme === "dark" ? "text-gray-300" : "text-gray-700"}`, children }),
1331
+ ol: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ol", { className: `list-decimal list-inside mb-3 space-y-1 ${theme === "dark" ? "text-gray-300" : "text-gray-700"}`, children }),
831
1332
  // Blockquotes
832
- blockquote: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("blockquote", { className: `border-l-4 pl-4 my-3 italic ${theme === "dark" ? "border-blue-500 bg-blue-900/20 py-2 pr-2" : "border-blue-400 bg-blue-50 py-2 pr-2"}`, children }),
1333
+ blockquote: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("blockquote", { className: `border-l-4 pl-4 my-3 italic ${theme === "dark" ? "border-blue-500 bg-blue-900/20 py-2 pr-2" : "border-blue-400 bg-blue-50 py-2 pr-2"}`, children }),
833
1334
  // Tables
834
- table: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "overflow-x-auto my-4", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("table", { className: `min-w-full border-collapse ${theme === "dark" ? "border-gray-700" : "border-gray-300"}`, children }) }),
835
- thead: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("thead", { className: theme === "dark" ? "bg-gray-800" : "bg-gray-100", children }),
836
- th: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { className: `px-4 py-2 text-left font-semibold border ${theme === "dark" ? "border-gray-700 text-gray-200" : "border-gray-300 text-gray-800"}`, children }),
837
- td: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { className: `px-4 py-2 border ${theme === "dark" ? "border-gray-700 text-gray-300" : "border-gray-300 text-gray-700"}`, children }),
1335
+ table: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "overflow-x-auto my-4", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("table", { className: `min-w-full border-collapse ${theme === "dark" ? "border-gray-700" : "border-gray-300"}`, children }) }),
1336
+ thead: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("thead", { className: theme === "dark" ? "bg-gray-800" : "bg-gray-100", children }),
1337
+ th: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { className: `px-4 py-2 text-left font-semibold border ${theme === "dark" ? "border-gray-700 text-gray-200" : "border-gray-300 text-gray-800"}`, children }),
1338
+ td: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { className: `px-4 py-2 border ${theme === "dark" ? "border-gray-700 text-gray-300" : "border-gray-300 text-gray-700"}`, children }),
838
1339
  // Horizontal rule
839
- hr: () => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("hr", { className: `my-4 border-t ${theme === "dark" ? "border-gray-700" : "border-gray-300"}` }),
1340
+ hr: () => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("hr", { className: `my-4 border-t ${theme === "dark" ? "border-gray-700" : "border-gray-300"}` }),
840
1341
  // Admonitions support (using containerDirective from remark-directive)
841
1342
  div: ({ node, className, children, ...props }) => {
842
1343
  if (className?.includes("admonition")) {
@@ -864,15 +1365,15 @@ function MessageRenderer({ content, theme = "dark" }) {
864
1365
  }
865
1366
  };
866
1367
  const style = styles[type] || styles.info;
867
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: `my-4 p-4 border-l-4 rounded-r-lg ${style.border} ${style.bg}`, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-start gap-2", children: [
868
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-lg flex-shrink-0", children: style.icon }),
869
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex-1", children })
1368
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: `my-4 p-4 border-l-4 rounded-r-lg ${style.border} ${style.bg}`, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-start gap-2", children: [
1369
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-lg flex-shrink-0", children: style.icon }),
1370
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "flex-1", children })
870
1371
  ] }) });
871
1372
  }
872
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className, ...props, children });
1373
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className, ...props, children });
873
1374
  }
874
1375
  };
875
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "markdown-content", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1376
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "markdown-content", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
876
1377
  import_react_markdown.default,
877
1378
  {
878
1379
  remarkPlugins: [import_remark_gfm.default, import_remark_math.default, import_remark_directive.default],
@@ -884,7 +1385,7 @@ function MessageRenderer({ content, theme = "dark" }) {
884
1385
  }
885
1386
 
886
1387
  // src/hooks/useTTS.ts
887
- var import_react6 = require("react");
1388
+ var import_react8 = require("react");
888
1389
  var Platform = {
889
1390
  isNative: typeof window !== "undefined" && "Capacitor" in window,
890
1391
  isWeb: typeof window !== "undefined" && !("Capacitor" in window)
@@ -899,13 +1400,13 @@ function isNativeTTSSupported() {
899
1400
  return false;
900
1401
  }
901
1402
  function useTTS() {
902
- const [isPlaying, setIsPlaying] = (0, import_react6.useState)(false);
903
- const [error, setError] = (0, import_react6.useState)(null);
904
- const [currentText, setCurrentText] = (0, import_react6.useState)(null);
905
- const audioRef = (0, import_react6.useRef)(null);
906
- const utteranceRef = (0, import_react6.useRef)(null);
1403
+ const [isPlaying, setIsPlaying] = (0, import_react8.useState)(false);
1404
+ const [error, setError] = (0, import_react8.useState)(null);
1405
+ const [currentText, setCurrentText] = (0, import_react8.useState)(null);
1406
+ const audioRef = (0, import_react8.useRef)(null);
1407
+ const utteranceRef = (0, import_react8.useRef)(null);
907
1408
  const isNativeSupported = isNativeTTSSupported();
908
- const speakNative = (0, import_react6.useCallback)(
1409
+ const speakNative = (0, import_react8.useCallback)(
909
1410
  async (text, options = {}) => {
910
1411
  if (Platform.isNative) {
911
1412
  try {
@@ -950,7 +1451,7 @@ function useTTS() {
950
1451
  },
951
1452
  []
952
1453
  );
953
- const speakAPI = (0, import_react6.useCallback)(
1454
+ const speakAPI = (0, import_react8.useCallback)(
954
1455
  async (text, options = {}) => {
955
1456
  const apiUrl = process.env.NEXT_PUBLIC_TTS_API_URL || "https://tts.supernal.ai";
956
1457
  const apiKey = process.env.NEXT_PUBLIC_TTS_API_KEY || "";
@@ -1011,7 +1512,7 @@ function useTTS() {
1011
1512
  },
1012
1513
  []
1013
1514
  );
1014
- const speak = (0, import_react6.useCallback)(
1515
+ const speak = (0, import_react8.useCallback)(
1015
1516
  async (options) => {
1016
1517
  const {
1017
1518
  text,
@@ -1055,7 +1556,7 @@ function useTTS() {
1055
1556
  },
1056
1557
  [speakNative, speakAPI, isNativeSupported]
1057
1558
  );
1058
- const stop = (0, import_react6.useCallback)(() => {
1559
+ const stop = (0, import_react8.useCallback)(() => {
1059
1560
  if ("speechSynthesis" in window && window.speechSynthesis.speaking) {
1060
1561
  window.speechSynthesis.cancel();
1061
1562
  utteranceRef.current = null;
@@ -1088,18 +1589,18 @@ function base64ToBlob(base64, mimeType) {
1088
1589
  }
1089
1590
 
1090
1591
  // src/hooks/useSTT.ts
1091
- var import_react7 = require("react");
1592
+ var import_react9 = require("react");
1092
1593
  var Platform2 = {
1093
1594
  isNative: typeof window !== "undefined" && "Capacitor" in window,
1094
1595
  isWeb: typeof window !== "undefined" && !("Capacitor" in window)
1095
1596
  };
1096
1597
  function useSTT() {
1097
- const [isListening, setIsListening] = (0, import_react7.useState)(false);
1098
- const [transcript, setTranscript] = (0, import_react7.useState)("");
1099
- const [interimTranscript, setInterimTranscript] = (0, import_react7.useState)("");
1100
- const [error, setError] = (0, import_react7.useState)(null);
1101
- const recognitionRef = (0, import_react7.useRef)(null);
1102
- const isSupported = (0, import_react7.useMemo)(() => {
1598
+ const [isListening, setIsListening] = (0, import_react9.useState)(false);
1599
+ const [transcript, setTranscript] = (0, import_react9.useState)("");
1600
+ const [interimTranscript, setInterimTranscript] = (0, import_react9.useState)("");
1601
+ const [error, setError] = (0, import_react9.useState)(null);
1602
+ const recognitionRef = (0, import_react9.useRef)(null);
1603
+ const isSupported = (0, import_react9.useMemo)(() => {
1103
1604
  if (Platform2.isNative) {
1104
1605
  return true;
1105
1606
  }
@@ -1108,7 +1609,7 @@ function useSTT() {
1108
1609
  }
1109
1610
  return false;
1110
1611
  }, []);
1111
- (0, import_react7.useEffect)(() => {
1612
+ (0, import_react9.useEffect)(() => {
1112
1613
  if (!isSupported || Platform2.isNative) return;
1113
1614
  const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
1114
1615
  if (!SpeechRecognition) return;
@@ -1146,7 +1647,7 @@ function useSTT() {
1146
1647
  }
1147
1648
  };
1148
1649
  }, [isSupported]);
1149
- const startListening = (0, import_react7.useCallback)(async () => {
1650
+ const startListening = (0, import_react9.useCallback)(async () => {
1150
1651
  setError(null);
1151
1652
  setTranscript("");
1152
1653
  setInterimTranscript("");
@@ -1178,7 +1679,7 @@ function useSTT() {
1178
1679
  setIsListening(false);
1179
1680
  }
1180
1681
  }, []);
1181
- const stopListening = (0, import_react7.useCallback)(() => {
1682
+ const stopListening = (0, import_react9.useCallback)(() => {
1182
1683
  if (Platform2.isNative) {
1183
1684
  setIsListening(false);
1184
1685
  return;
@@ -1187,7 +1688,7 @@ function useSTT() {
1187
1688
  recognitionRef.current.stop();
1188
1689
  }
1189
1690
  }, []);
1190
- const resetTranscript = (0, import_react7.useCallback)(() => {
1691
+ const resetTranscript = (0, import_react9.useCallback)(() => {
1191
1692
  setTranscript("");
1192
1693
  setInterimTranscript("");
1193
1694
  setError(null);
@@ -1205,7 +1706,7 @@ function useSTT() {
1205
1706
  }
1206
1707
 
1207
1708
  // src/components/TTSButton.tsx
1208
- var import_jsx_runtime8 = require("react/jsx-runtime");
1709
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1209
1710
  function TTSButton({
1210
1711
  text,
1211
1712
  usePremiumVoices = false,
@@ -1233,7 +1734,7 @@ function TTSButton({
1233
1734
  const isDark = theme === "dark";
1234
1735
  const iconSize = size === "small" ? "w-3 h-3" : "w-4 h-4";
1235
1736
  const buttonPadding = size === "small" ? "p-1" : "p-2";
1236
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1737
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1237
1738
  "button",
1238
1739
  {
1239
1740
  onClick: handleClick,
@@ -1243,23 +1744,23 @@ function TTSButton({
1243
1744
  "aria-label": isPlaying ? "Stop speaking" : "Read aloud",
1244
1745
  children: isPlaying ? (
1245
1746
  // Stop icon (pulsing square)
1246
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("svg", { className: iconSize, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) })
1747
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { className: iconSize, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) })
1247
1748
  ) : error ? (
1248
1749
  // Error icon
1249
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("svg", { className: iconSize, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) })
1750
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { className: iconSize, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) })
1250
1751
  ) : (
1251
1752
  // Speaker icon
1252
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("svg", { className: iconSize, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15.536 8.464a5 5 0 010 7.072m2.828-9.9a9 9 0 010 12.728M5.586 15.414a2 2 0 002.828 0l1.768-1.768a2 2 0 00 0-2.828l-1.768-1.768a2 2 0 00-2.828 0V15.414z" }) })
1753
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { className: iconSize, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15.536 8.464a5 5 0 010 7.072m2.828-9.9a9 9 0 010 12.728M5.586 15.414a2 2 0 002.828 0l1.768-1.768a2 2 0 00 0-2.828l-1.768-1.768a2 2 0 00-2.828 0V15.414z" }) })
1253
1754
  )
1254
1755
  }
1255
1756
  );
1256
1757
  }
1257
1758
 
1258
1759
  // src/components/SubtitleOverlay.tsx
1259
- var import_react8 = require("react");
1760
+ var import_react10 = require("react");
1260
1761
 
1261
1762
  // src/components/TTSPlaylistMenu.tsx
1262
- var import_jsx_runtime9 = require("react/jsx-runtime");
1763
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1263
1764
  var TTSPlaylistMenu = ({
1264
1765
  isOpen,
1265
1766
  onClose,
@@ -1280,7 +1781,7 @@ var TTSPlaylistMenu = ({
1280
1781
  border: "1px solid rgba(0, 0, 0, 0.1)",
1281
1782
  boxShadow: "0 8px 32px rgba(0, 0, 0, 0.2)"
1282
1783
  };
1283
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1784
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1284
1785
  "div",
1285
1786
  {
1286
1787
  className: "fixed z-50",
@@ -1291,7 +1792,7 @@ var TTSPlaylistMenu = ({
1291
1792
  width: "min(90vw, 400px)"
1292
1793
  },
1293
1794
  "data-testid": "tts-playlist-menu",
1294
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1795
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1295
1796
  "div",
1296
1797
  {
1297
1798
  style: {
@@ -1301,38 +1802,38 @@ var TTSPlaylistMenu = ({
1301
1802
  borderRadius: "16px"
1302
1803
  },
1303
1804
  children: [
1304
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1805
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1305
1806
  "div",
1306
1807
  {
1307
1808
  className: `p-4 border-b flex items-center justify-between ${theme === "dark" ? "border-white/10" : "border-black/10"}`,
1308
1809
  children: [
1309
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1810
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1310
1811
  "h3",
1311
1812
  {
1312
1813
  className: `font-semibold text-sm ${theme === "dark" ? "text-white" : "text-gray-900"}`,
1313
1814
  children: "Readable Sections"
1314
1815
  }
1315
1816
  ),
1316
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1817
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1317
1818
  "button",
1318
1819
  {
1319
1820
  onClick: onClose,
1320
1821
  className: `p-1.5 rounded-lg transition-all ${theme === "dark" ? "text-gray-400 hover:text-white hover:bg-white/10" : "text-gray-600 hover:text-gray-900 hover:bg-black/5"}`,
1321
1822
  title: "Close",
1322
1823
  "data-testid": "close-playlist-menu",
1323
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-lg font-bold", "aria-hidden": "true", children: "\xD7" })
1824
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-lg font-bold", "aria-hidden": "true", children: "\xD7" })
1324
1825
  }
1325
1826
  )
1326
1827
  ]
1327
1828
  }
1328
1829
  ),
1329
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "overflow-y-auto max-h-80 p-2", children: widgets.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1830
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "overflow-y-auto max-h-80 p-2", children: widgets.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1330
1831
  "div",
1331
1832
  {
1332
1833
  className: `p-6 text-center text-sm ${theme === "dark" ? "text-gray-400" : "text-gray-600"}`,
1333
1834
  children: "No readable sections found on this page"
1334
1835
  }
1335
- ) : widgets.map((widget) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1836
+ ) : widgets.map((widget) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1336
1837
  "button",
1337
1838
  {
1338
1839
  onClick: () => handleWidgetClick(widget),
@@ -1342,12 +1843,12 @@ var TTSPlaylistMenu = ({
1342
1843
  WebkitBackdropFilter: "blur(8px)"
1343
1844
  },
1344
1845
  "data-testid": "playlist-widget-item",
1345
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1846
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1346
1847
  "div",
1347
1848
  {
1348
1849
  className: `font-medium text-sm flex items-center ${theme === "dark" ? "text-white" : "text-gray-900"}`,
1349
1850
  children: [
1350
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "mr-2", "aria-hidden": "true", children: "\u{1F50A}" }),
1851
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "mr-2", "aria-hidden": "true", children: "\u{1F50A}" }),
1351
1852
  widget.label || `TTS Widget ${widget.id}`
1352
1853
  ]
1353
1854
  }
@@ -1570,7 +2071,7 @@ function extractTTSWidgets() {
1570
2071
  }
1571
2072
 
1572
2073
  // src/components/SubtitleOverlay.tsx
1573
- var import_jsx_runtime10 = require("react/jsx-runtime");
2074
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1574
2075
  var opacityStates = {
1575
2076
  mobile: {
1576
2077
  idle: 1,
@@ -1614,47 +2115,47 @@ var SubtitleOverlay = ({
1614
2115
  resetTranscript,
1615
2116
  onSwitchToFullMode
1616
2117
  }) => {
1617
- const [overlayState, setOverlayState] = (0, import_react8.useState)("idle");
1618
- const [opacity, setOpacity] = (0, import_react8.useState)(1);
1619
- const [lastInputMethod, setLastInputMethod] = (0, import_react8.useState)(null);
1620
- const [isMobile, setIsMobile] = (0, import_react8.useState)(false);
1621
- const [messageOpacity, setMessageOpacity] = (0, import_react8.useState)(1);
1622
- const [expansionState, setExpansionState] = (0, import_react8.useState)(() => {
2118
+ const [overlayState, setOverlayState] = (0, import_react10.useState)("idle");
2119
+ const [opacity, setOpacity] = (0, import_react10.useState)(1);
2120
+ const [lastInputMethod, setLastInputMethod] = (0, import_react10.useState)(null);
2121
+ const [isMobile, setIsMobile] = (0, import_react10.useState)(false);
2122
+ const [messageOpacity, setMessageOpacity] = (0, import_react10.useState)(1);
2123
+ const [expansionState, setExpansionState] = (0, import_react10.useState)(() => {
1623
2124
  if (typeof window !== "undefined") {
1624
2125
  const saved = localStorage.getItem("subtitle-overlay-expanded");
1625
2126
  return saved === "true" ? "expanded" : "collapsed";
1626
2127
  }
1627
2128
  return "collapsed";
1628
2129
  });
1629
- const [touchStartY, setTouchStartY] = (0, import_react8.useState)(null);
1630
- const lastInputTimeRef = (0, import_react8.useRef)(Date.now());
1631
- const autoFadeTimerRef = (0, import_react8.useRef)(null);
1632
- const messageFadeTimerRef = (0, import_react8.useRef)(null);
1633
- const inputRef = (0, import_react8.useRef)(null);
1634
- const [suggestions, setSuggestions] = (0, import_react8.useState)([]);
1635
- const [currentSuggestionIndex, setCurrentSuggestionIndex] = (0, import_react8.useState)(0);
1636
- const [glassTheme, setGlassTheme] = (0, import_react8.useState)("auto");
1637
- const [detectedGlassTheme, setDetectedGlassTheme] = (0, import_react8.useState)("light");
1638
- const [hasTTSWidgets, setHasTTSWidgets] = (0, import_react8.useState)(false);
1639
- const [showPlaylist, setShowPlaylist] = (0, import_react8.useState)(false);
1640
- const [ttsWidgets, setTTSWidgets] = (0, import_react8.useState)([]);
1641
- const [touchStartYInput, setTouchStartYInput] = (0, import_react8.useState)(null);
1642
- const [completedActions, setCompletedActions] = (0, import_react8.useState)([]);
1643
- const [showCompletedActions, setShowCompletedActions] = (0, import_react8.useState)(false);
1644
- const [shouldShowAiResponse, setShouldShowAiResponse] = (0, import_react8.useState)(false);
1645
- const [latestActionOpacity, setLatestActionOpacity] = (0, import_react8.useState)(0);
1646
- const latestActionFadeRef = (0, import_react8.useRef)(null);
1647
- const lastUserMessageRef = (0, import_react8.useRef)("");
1648
- const lastShownAiMessageRef = (0, import_react8.useRef)("");
1649
- const justExpandedViaSlashRef = (0, import_react8.useRef)(false);
1650
- const [isDragging, setIsDragging] = (0, import_react8.useState)(false);
1651
- const [position, setPosition] = (0, import_react8.useState)({ x: 0, y: 0 });
1652
- const [dragStart, setDragStart] = (0, import_react8.useState)({ x: 0, y: 0 });
1653
- const dragRef = (0, import_react8.useRef)(null);
1654
- const dragDistanceRef = (0, import_react8.useRef)(0);
1655
- const lastEscapeTimeRef = (0, import_react8.useRef)(0);
2130
+ const [touchStartY, setTouchStartY] = (0, import_react10.useState)(null);
2131
+ const lastInputTimeRef = (0, import_react10.useRef)(Date.now());
2132
+ const autoFadeTimerRef = (0, import_react10.useRef)(null);
2133
+ const messageFadeTimerRef = (0, import_react10.useRef)(null);
2134
+ const inputRef = (0, import_react10.useRef)(null);
2135
+ const [suggestions, setSuggestions] = (0, import_react10.useState)([]);
2136
+ const [currentSuggestionIndex, setCurrentSuggestionIndex] = (0, import_react10.useState)(0);
2137
+ const [glassTheme, setGlassTheme] = (0, import_react10.useState)("auto");
2138
+ const [detectedGlassTheme, setDetectedGlassTheme] = (0, import_react10.useState)("light");
2139
+ const [hasTTSWidgets, setHasTTSWidgets] = (0, import_react10.useState)(false);
2140
+ const [showPlaylist, setShowPlaylist] = (0, import_react10.useState)(false);
2141
+ const [ttsWidgets, setTTSWidgets] = (0, import_react10.useState)([]);
2142
+ const [touchStartYInput, setTouchStartYInput] = (0, import_react10.useState)(null);
2143
+ const [completedActions, setCompletedActions] = (0, import_react10.useState)([]);
2144
+ const [showCompletedActions, setShowCompletedActions] = (0, import_react10.useState)(false);
2145
+ const [shouldShowAiResponse, setShouldShowAiResponse] = (0, import_react10.useState)(false);
2146
+ const [latestActionOpacity, setLatestActionOpacity] = (0, import_react10.useState)(0);
2147
+ const latestActionFadeRef = (0, import_react10.useRef)(null);
2148
+ const lastUserMessageRef = (0, import_react10.useRef)("");
2149
+ const lastShownAiMessageRef = (0, import_react10.useRef)("");
2150
+ const justExpandedViaSlashRef = (0, import_react10.useRef)(false);
2151
+ const [isDragging, setIsDragging] = (0, import_react10.useState)(false);
2152
+ const [position, setPosition] = (0, import_react10.useState)({ x: 0, y: 0 });
2153
+ const [dragStart, setDragStart] = (0, import_react10.useState)({ x: 0, y: 0 });
2154
+ const dragRef = (0, import_react10.useRef)(null);
2155
+ const dragDistanceRef = (0, import_react10.useRef)(0);
2156
+ const lastEscapeTimeRef = (0, import_react10.useRef)(0);
1656
2157
  const DOUBLE_ESCAPE_THRESHOLD_MS = 500;
1657
- (0, import_react8.useEffect)(() => {
2158
+ (0, import_react10.useEffect)(() => {
1658
2159
  const checkMobile = () => {
1659
2160
  const mobile = window.innerWidth < 768;
1660
2161
  setIsMobile(mobile);
@@ -1663,7 +2164,7 @@ var SubtitleOverlay = ({
1663
2164
  window.addEventListener("resize", checkMobile);
1664
2165
  return () => window.removeEventListener("resize", checkMobile);
1665
2166
  }, []);
1666
- (0, import_react8.useEffect)(() => {
2167
+ (0, import_react10.useEffect)(() => {
1667
2168
  if (autoFadeTimerRef.current) {
1668
2169
  clearTimeout(autoFadeTimerRef.current);
1669
2170
  autoFadeTimerRef.current = null;
@@ -1679,7 +2180,7 @@ var SubtitleOverlay = ({
1679
2180
  }
1680
2181
  };
1681
2182
  }, [overlayState, isMobile]);
1682
- (0, import_react8.useEffect)(() => {
2183
+ (0, import_react10.useEffect)(() => {
1683
2184
  if (messageFadeTimerRef.current) {
1684
2185
  clearTimeout(messageFadeTimerRef.current);
1685
2186
  messageFadeTimerRef.current = null;
@@ -1715,7 +2216,7 @@ var SubtitleOverlay = ({
1715
2216
  }
1716
2217
  };
1717
2218
  }, [messages.filter((m) => m.type === "ai").slice(-1)[0]?.text, shouldShowAiResponse]);
1718
- (0, import_react8.useEffect)(() => {
2219
+ (0, import_react10.useEffect)(() => {
1719
2220
  if (sttTranscript && voiceEnabled && resetTranscript) {
1720
2221
  onSendMessage(sttTranscript);
1721
2222
  resetTranscript();
@@ -1732,11 +2233,11 @@ var SubtitleOverlay = ({
1732
2233
  triggerActionFade();
1733
2234
  }
1734
2235
  }, [sttTranscript, voiceEnabled, resetTranscript, onSendMessage]);
1735
- (0, import_react8.useEffect)(() => {
2236
+ (0, import_react10.useEffect)(() => {
1736
2237
  const pageSuggestions = extractPageSuggestions();
1737
2238
  setSuggestions(pageSuggestions);
1738
2239
  }, []);
1739
- (0, import_react8.useEffect)(() => {
2240
+ (0, import_react10.useEffect)(() => {
1740
2241
  const detectWidgets = async () => {
1741
2242
  const detected = await detectTTSWidgets();
1742
2243
  setHasTTSWidgets(detected);
@@ -1771,7 +2272,7 @@ var SubtitleOverlay = ({
1771
2272
  window.removeEventListener("supernal-tts-ready", handleReady);
1772
2273
  };
1773
2274
  }, []);
1774
- (0, import_react8.useEffect)(() => {
2275
+ (0, import_react10.useEffect)(() => {
1775
2276
  if (glassTheme !== "auto") return;
1776
2277
  const { glassTheme: detected } = detectBackgroundContext();
1777
2278
  setDetectedGlassTheme(detected);
@@ -1787,7 +2288,7 @@ var SubtitleOverlay = ({
1787
2288
  window.addEventListener("scroll", handleScroll);
1788
2289
  return () => window.removeEventListener("scroll", handleScroll);
1789
2290
  }, [glassTheme]);
1790
- (0, import_react8.useEffect)(() => {
2291
+ (0, import_react10.useEffect)(() => {
1791
2292
  const handleGlobalKeyDown = (e) => {
1792
2293
  if (e.key === "Escape") {
1793
2294
  const now = Date.now();
@@ -1834,12 +2335,12 @@ var SubtitleOverlay = ({
1834
2335
  window.addEventListener("keydown", handleGlobalKeyDown);
1835
2336
  return () => window.removeEventListener("keydown", handleGlobalKeyDown);
1836
2337
  }, [expansionState, onSwitchToFullMode, voiceEnabled, onMicClick]);
1837
- (0, import_react8.useEffect)(() => {
2338
+ (0, import_react10.useEffect)(() => {
1838
2339
  if (typeof window !== "undefined") {
1839
2340
  localStorage.setItem("subtitle-overlay-expanded", expansionState === "expanded" ? "true" : "false");
1840
2341
  }
1841
2342
  }, [expansionState]);
1842
- (0, import_react8.useEffect)(() => {
2343
+ (0, import_react10.useEffect)(() => {
1843
2344
  if (expansionState === "expanded" && inputRef.current) {
1844
2345
  setTimeout(() => {
1845
2346
  inputRef.current?.focus();
@@ -1853,7 +2354,7 @@ var SubtitleOverlay = ({
1853
2354
  }, 100);
1854
2355
  }
1855
2356
  }, [expansionState]);
1856
- (0, import_react8.useEffect)(() => {
2357
+ (0, import_react10.useEffect)(() => {
1857
2358
  if (isMobile) return;
1858
2359
  const handleMouseMove = (e) => {
1859
2360
  if (!isDragging) return;
@@ -1877,7 +2378,7 @@ var SubtitleOverlay = ({
1877
2378
  window.removeEventListener("mouseup", handleMouseUp);
1878
2379
  };
1879
2380
  }, [isDragging, dragStart, isMobile]);
1880
- (0, import_react8.useEffect)(() => {
2381
+ (0, import_react10.useEffect)(() => {
1881
2382
  const timeSinceLastInput = Date.now() - lastInputTimeRef.current;
1882
2383
  const context = {
1883
2384
  isListening,
@@ -2037,8 +2538,8 @@ var SubtitleOverlay = ({
2037
2538
  return "Tap to start voice input";
2038
2539
  };
2039
2540
  if (expansionState === "collapsed") {
2040
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
2041
- hasTTSWidgets && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2541
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2542
+ hasTTSWidgets && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2042
2543
  "button",
2043
2544
  {
2044
2545
  type: "button",
@@ -2057,10 +2558,10 @@ var SubtitleOverlay = ({
2057
2558
  title: ttsWidgets.length === 1 ? "Go to readable section" : "View readable sections",
2058
2559
  "data-testid": "tts-playlist-button",
2059
2560
  "aria-label": ttsWidgets.length === 1 ? "Go to readable section" : "View readable sections",
2060
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xl font-bold select-none", "aria-hidden": "true", children: "~+" })
2561
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-xl font-bold select-none", "aria-hidden": "true", children: "~+" })
2061
2562
  }
2062
2563
  ),
2063
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2564
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2064
2565
  TTSPlaylistMenu,
2065
2566
  {
2066
2567
  isOpen: showPlaylist,
@@ -2070,7 +2571,7 @@ var SubtitleOverlay = ({
2070
2571
  onWidgetSelect: handleWidgetSelect
2071
2572
  }
2072
2573
  ),
2073
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2574
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2074
2575
  "div",
2075
2576
  {
2076
2577
  className: "fixed",
@@ -2080,7 +2581,7 @@ var SubtitleOverlay = ({
2080
2581
  zIndex: 55
2081
2582
  },
2082
2583
  "data-testid": "subtitle-overlay-collapsed",
2083
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2584
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2084
2585
  "button",
2085
2586
  {
2086
2587
  type: "button",
@@ -2096,14 +2597,14 @@ var SubtitleOverlay = ({
2096
2597
  title: getIconTitle(),
2097
2598
  "data-testid": "voice-input-button",
2098
2599
  "aria-label": getIconTitle(),
2099
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xl font-bold select-none", "aria-hidden": "true", children: getIcon() })
2600
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-xl font-bold select-none", "aria-hidden": "true", children: getIcon() })
2100
2601
  }
2101
2602
  )
2102
2603
  }
2103
2604
  )
2104
2605
  ] });
2105
2606
  }
2106
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2607
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2107
2608
  "div",
2108
2609
  {
2109
2610
  ref: dragRef,
@@ -2129,7 +2630,7 @@ var SubtitleOverlay = ({
2129
2630
  role: "complementary",
2130
2631
  "aria-label": "Chat overlay",
2131
2632
  children: [
2132
- !isMobile && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2633
+ !isMobile && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2133
2634
  "div",
2134
2635
  {
2135
2636
  className: "drag-handle absolute -top-3 left-1/2 transform -translate-x-1/2 cursor-grab active:cursor-grabbing opacity-40 hover:opacity-70 transition-opacity",
@@ -2143,7 +2644,7 @@ var SubtitleOverlay = ({
2143
2644
  "data-testid": "subtitle-overlay-drag-handle"
2144
2645
  }
2145
2646
  ),
2146
- showCompletedActions && completedActions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2647
+ showCompletedActions && completedActions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2147
2648
  "div",
2148
2649
  {
2149
2650
  className: `mb-2 px-4 py-3 text-xs rounded-2xl animate-popup-in ${theme === "dark" ? "text-white" : "text-gray-900"}`,
@@ -2156,9 +2657,9 @@ var SubtitleOverlay = ({
2156
2657
  "aria-label": "Completed actions",
2157
2658
  "data-testid": "completed-actions-list",
2158
2659
  children: [
2159
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "font-medium opacity-70 mb-2 flex items-center justify-between", children: [
2160
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Completed Actions" }),
2161
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2660
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "font-medium opacity-70 mb-2 flex items-center justify-between", children: [
2661
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Completed Actions" }),
2662
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2162
2663
  "button",
2163
2664
  {
2164
2665
  onClick: () => setShowCompletedActions(false),
@@ -2168,14 +2669,14 @@ var SubtitleOverlay = ({
2168
2669
  }
2169
2670
  )
2170
2671
  ] }),
2171
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "space-y-1", children: completedActions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "text-xs opacity-80 border-l-2 border-green-500 pl-2", children: [
2172
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "font-medium", children: action.tool }),
2173
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "opacity-70", children: action.description })
2672
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "space-y-1", children: completedActions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "text-xs opacity-80 border-l-2 border-green-500 pl-2", children: [
2673
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "font-medium", children: action.tool }),
2674
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "opacity-70", children: action.description })
2174
2675
  ] }, action.id)) })
2175
2676
  ]
2176
2677
  }
2177
2678
  ),
2178
- !showCompletedActions && (latestActionOpacity > 0 || lastAiMessage && messageOpacity > 0) && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2679
+ !showCompletedActions && (latestActionOpacity > 0 || lastAiMessage && messageOpacity > 0) && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2179
2680
  "div",
2180
2681
  {
2181
2682
  className: `mb-2 px-4 py-2 text-xs rounded-2xl ${theme === "dark" ? "text-white" : "text-gray-900"}`,
@@ -2191,27 +2692,27 @@ var SubtitleOverlay = ({
2191
2692
  children: [
2192
2693
  latestActionOpacity > 0 && completedActions.length > 0 && (() => {
2193
2694
  const latest = completedActions[completedActions.length - 1];
2194
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2695
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2195
2696
  "div",
2196
2697
  {
2197
2698
  className: "border-l-2 border-green-500 pl-2 mb-1",
2198
2699
  style: { opacity: latestActionOpacity, transition: "opacity 0.6s ease-out" },
2199
2700
  children: [
2200
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-medium", children: latest.tool }),
2201
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "opacity-70 ml-1", children: latest.description })
2701
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-medium", children: latest.tool }),
2702
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "opacity-70 ml-1", children: latest.description })
2202
2703
  ]
2203
2704
  }
2204
2705
  );
2205
2706
  })(),
2206
- lastAiMessage && messageOpacity > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { opacity: messageOpacity, transition: "opacity 0.8s ease-out" }, children: [
2207
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-medium opacity-70", children: "AI:" }),
2707
+ lastAiMessage && messageOpacity > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { opacity: messageOpacity, transition: "opacity 0.8s ease-out" }, children: [
2708
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-medium opacity-70", children: "AI:" }),
2208
2709
  " ",
2209
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-sm", children: lastAiMessage.text })
2710
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-sm", children: lastAiMessage.text })
2210
2711
  ] })
2211
2712
  ]
2212
2713
  }
2213
2714
  ),
2214
- completedActions.length > 0 && !showCompletedActions && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex justify-center mb-1", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2715
+ completedActions.length > 0 && !showCompletedActions && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex justify-center mb-1", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2215
2716
  "button",
2216
2717
  {
2217
2718
  type: "button",
@@ -2227,11 +2728,11 @@ var SubtitleOverlay = ({
2227
2728
  title: `${completedActions.length} previous actions`,
2228
2729
  "data-testid": "completed-actions-toggle",
2229
2730
  "aria-label": `Show ${completedActions.length} completed actions`,
2230
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { width: "16", height: "8", viewBox: "0 0 16 8", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M2 6L8 2L14 6" }) })
2731
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { width: "16", height: "8", viewBox: "0 0 16 8", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M2 6L8 2L14 6" }) })
2231
2732
  }
2232
2733
  ) }),
2233
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center space-x-2", children: [
2234
- hasTTSWidgets && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2734
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center space-x-2", children: [
2735
+ hasTTSWidgets && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2235
2736
  "button",
2236
2737
  {
2237
2738
  type: "button",
@@ -2246,10 +2747,10 @@ var SubtitleOverlay = ({
2246
2747
  title: ttsWidgets.length === 1 ? "Go to readable section" : "View readable sections",
2247
2748
  "data-testid": "tts-playlist-button-expanded",
2248
2749
  "aria-label": ttsWidgets.length === 1 ? "Go to readable section" : "View readable sections",
2249
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-lg font-bold select-none", "aria-hidden": "true", children: "~+" })
2750
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-lg font-bold select-none", "aria-hidden": "true", children: "~+" })
2250
2751
  }
2251
2752
  ),
2252
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2753
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2253
2754
  "div",
2254
2755
  {
2255
2756
  className: "flex-1 flex items-center space-x-2 px-4 py-2 rounded-3xl",
@@ -2258,7 +2759,7 @@ var SubtitleOverlay = ({
2258
2759
  border: effectiveGlassTheme === "dark" ? "1px solid rgba(255, 255, 255, 0.12)" : "1px solid rgba(0, 0, 0, 0.1)"
2259
2760
  },
2260
2761
  children: [
2261
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2762
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2262
2763
  "input",
2263
2764
  {
2264
2765
  ref: inputRef,
@@ -2278,7 +2779,7 @@ var SubtitleOverlay = ({
2278
2779
  "aria-label": "Chat message input"
2279
2780
  }
2280
2781
  ),
2281
- isListening && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex space-x-1 items-center", "aria-hidden": "true", "data-testid": "subtitle-overlay-waveform", children: [...Array(5)].map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2782
+ isListening && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex space-x-1 items-center", "aria-hidden": "true", "data-testid": "subtitle-overlay-waveform", children: [...Array(5)].map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2282
2783
  "div",
2283
2784
  {
2284
2785
  className: "w-0.5 bg-red-500 rounded-full animate-pulse",
@@ -2289,7 +2790,7 @@ var SubtitleOverlay = ({
2289
2790
  },
2290
2791
  i
2291
2792
  )) }),
2292
- inputValue.trim() && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2793
+ inputValue.trim() && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2293
2794
  "button",
2294
2795
  {
2295
2796
  type: "button",
@@ -2305,10 +2806,10 @@ var SubtitleOverlay = ({
2305
2806
  title: "Send message",
2306
2807
  "data-testid": "send-button",
2307
2808
  "aria-label": "Send message",
2308
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-base select-none", "aria-hidden": "true", children: "\u2192" })
2809
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-base select-none", "aria-hidden": "true", children: "\u2192" })
2309
2810
  }
2310
2811
  ),
2311
- voiceEnabled && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2812
+ voiceEnabled && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2312
2813
  "button",
2313
2814
  {
2314
2815
  type: "button",
@@ -2328,10 +2829,10 @@ var SubtitleOverlay = ({
2328
2829
  title: getIconTitle(),
2329
2830
  "data-testid": "voice-input-button",
2330
2831
  "aria-label": getIconTitle(),
2331
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-lg font-bold select-none", "aria-hidden": "true", children: getIcon() })
2832
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-lg font-bold select-none", "aria-hidden": "true", children: getIcon() })
2332
2833
  }
2333
2834
  ),
2334
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2835
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2335
2836
  "button",
2336
2837
  {
2337
2838
  type: "button",
@@ -2346,7 +2847,7 @@ var SubtitleOverlay = ({
2346
2847
  title: "Collapse",
2347
2848
  "data-testid": "collapse-button",
2348
2849
  "aria-label": "Collapse overlay",
2349
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-lg font-bold select-none", "aria-hidden": "true", children: "\xD7" })
2850
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-lg font-bold select-none", "aria-hidden": "true", children: "\xD7" })
2350
2851
  }
2351
2852
  )
2352
2853
  ]
@@ -2359,25 +2860,25 @@ var SubtitleOverlay = ({
2359
2860
  };
2360
2861
 
2361
2862
  // src/components/SlashCommand/useSlashCommand.ts
2362
- var import_react9 = require("react");
2363
- var import_browser2 = require("@supernal/interface/browser");
2863
+ var import_react11 = require("react");
2864
+ var import_browser3 = require("@supernal/interface/browser");
2364
2865
  function useSlashCommand(inputValue, onSelect) {
2365
- const [selectedIndex, setSelectedIndex] = (0, import_react9.useState)(0);
2366
- const prevOpenRef = (0, import_react9.useRef)(false);
2866
+ const [selectedIndex, setSelectedIndex] = (0, import_react11.useState)(0);
2867
+ const prevOpenRef = (0, import_react11.useRef)(false);
2367
2868
  const isOpen = inputValue.startsWith("/");
2368
2869
  const query = isOpen ? inputValue.slice(1) : "";
2369
- (0, import_react9.useEffect)(() => {
2870
+ (0, import_react11.useEffect)(() => {
2370
2871
  if (isOpen && !prevOpenRef.current) {
2371
2872
  setSelectedIndex(0);
2372
2873
  }
2373
2874
  prevOpenRef.current = isOpen;
2374
2875
  }, [isOpen]);
2375
- (0, import_react9.useEffect)(() => {
2876
+ (0, import_react11.useEffect)(() => {
2376
2877
  setSelectedIndex(0);
2377
2878
  }, [query]);
2378
- const filteredTools = (0, import_react9.useMemo)(() => {
2879
+ const filteredTools = (0, import_react11.useMemo)(() => {
2379
2880
  if (!isOpen) return [];
2380
- const locationTools = import_browser2.ToolRegistry.getToolsByLocation();
2881
+ const locationTools = import_browser3.ToolRegistry.getToolsByLocation();
2381
2882
  const aiTools = locationTools.filter((t) => t.aiEnabled);
2382
2883
  if (!query) return aiTools;
2383
2884
  const q = query.toLowerCase();
@@ -2392,13 +2893,13 @@ function useSlashCommand(inputValue, onSelect) {
2392
2893
  return fields.some((f) => f.includes(q));
2393
2894
  });
2394
2895
  }, [isOpen, query]);
2395
- const close = (0, import_react9.useCallback)(() => {
2896
+ const close = (0, import_react11.useCallback)(() => {
2396
2897
  }, []);
2397
- const selectTool = (0, import_react9.useCallback)((tool) => {
2898
+ const selectTool = (0, import_react11.useCallback)((tool) => {
2398
2899
  const command = tool.examples?.[0] || tool.name?.toLowerCase() || tool.toolId;
2399
2900
  onSelect(command);
2400
2901
  }, [onSelect]);
2401
- const onKeyDown = (0, import_react9.useCallback)((e) => {
2902
+ const onKeyDown = (0, import_react11.useCallback)((e) => {
2402
2903
  if (!isOpen || filteredTools.length === 0) return;
2403
2904
  if (e.key === "ArrowDown") {
2404
2905
  e.preventDefault();
@@ -2428,8 +2929,8 @@ function useSlashCommand(inputValue, onSelect) {
2428
2929
  }
2429
2930
 
2430
2931
  // src/components/SlashCommand/SlashCommandPopup.tsx
2431
- var import_react10 = require("react");
2432
- var import_jsx_runtime11 = require("react/jsx-runtime");
2932
+ var import_react12 = require("react");
2933
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2433
2934
  var MAX_VISIBLE_ITEMS = 8;
2434
2935
  var SlashCommandPopup = ({
2435
2936
  tools,
@@ -2437,12 +2938,12 @@ var SlashCommandPopup = ({
2437
2938
  onSelect,
2438
2939
  onClose
2439
2940
  }) => {
2440
- const listRef = (0, import_react10.useRef)(null);
2441
- const selectedRef = (0, import_react10.useRef)(null);
2442
- (0, import_react10.useEffect)(() => {
2941
+ const listRef = (0, import_react12.useRef)(null);
2942
+ const selectedRef = (0, import_react12.useRef)(null);
2943
+ (0, import_react12.useEffect)(() => {
2443
2944
  selectedRef.current?.scrollIntoView({ block: "nearest" });
2444
2945
  }, [selectedIndex]);
2445
- (0, import_react10.useEffect)(() => {
2946
+ (0, import_react12.useEffect)(() => {
2446
2947
  const handleClickOutside = (e) => {
2447
2948
  if (listRef.current && !listRef.current.contains(e.target)) {
2448
2949
  onClose();
@@ -2454,7 +2955,7 @@ var SlashCommandPopup = ({
2454
2955
  if (tools.length === 0) return null;
2455
2956
  const itemHeight = 52;
2456
2957
  const maxHeight = MAX_VISIBLE_ITEMS * itemHeight;
2457
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2958
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2458
2959
  "div",
2459
2960
  {
2460
2961
  ref: listRef,
@@ -2472,7 +2973,7 @@ var SlashCommandPopup = ({
2472
2973
  },
2473
2974
  "data-slash-command-popup": true,
2474
2975
  children: [
2475
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: {
2976
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: {
2476
2977
  padding: "8px 12px 4px",
2477
2978
  color: "rgba(255,255,255,0.45)",
2478
2979
  fontSize: 11,
@@ -2485,7 +2986,7 @@ var SlashCommandPopup = ({
2485
2986
  ] }),
2486
2987
  tools.map((tool, index) => {
2487
2988
  const isSelected = index === selectedIndex;
2488
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2989
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2489
2990
  "button",
2490
2991
  {
2491
2992
  ref: isSelected ? selectedRef : void 0,
@@ -2512,14 +3013,14 @@ var SlashCommandPopup = ({
2512
3013
  }
2513
3014
  },
2514
3015
  children: [
2515
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { fontSize: 13, fontWeight: 500 }, children: [
2516
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: { color: "rgba(147, 197, 253, 0.9)" }, children: [
3016
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { fontSize: 13, fontWeight: 500 }, children: [
3017
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { style: { color: "rgba(147, 197, 253, 0.9)" }, children: [
2517
3018
  "/",
2518
3019
  tool.toolId
2519
3020
  ] }),
2520
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { color: "rgba(255,255,255,0.7)", fontWeight: 400, marginLeft: 8 }, children: tool.name })
3021
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { color: "rgba(255,255,255,0.7)", fontWeight: 400, marginLeft: 8 }, children: tool.name })
2521
3022
  ] }),
2522
- tool.description && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: {
3023
+ tool.description && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: {
2523
3024
  fontSize: 11,
2524
3025
  color: "rgba(255,255,255,0.4)",
2525
3026
  marginTop: 2,
@@ -2533,19 +3034,19 @@ var SlashCommandPopup = ({
2533
3034
  tool.toolId
2534
3035
  );
2535
3036
  }),
2536
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: {
3037
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: {
2537
3038
  padding: "6px 12px",
2538
3039
  borderTop: "1px solid rgba(255,255,255,0.06)",
2539
3040
  color: "rgba(255,255,255,0.3)",
2540
3041
  fontSize: 10
2541
3042
  }, children: [
2542
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("kbd", { style: { padding: "1px 3px", borderRadius: 3, border: "1px solid rgba(255,255,255,0.15)", fontSize: 9 }, children: "\u2191\u2193" }),
3043
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("kbd", { style: { padding: "1px 3px", borderRadius: 3, border: "1px solid rgba(255,255,255,0.15)", fontSize: 9 }, children: "\u2191\u2193" }),
2543
3044
  " navigate",
2544
3045
  " ",
2545
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("kbd", { style: { padding: "1px 3px", borderRadius: 3, border: "1px solid rgba(255,255,255,0.15)", fontSize: 9 }, children: "Enter" }),
3046
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("kbd", { style: { padding: "1px 3px", borderRadius: 3, border: "1px solid rgba(255,255,255,0.15)", fontSize: 9 }, children: "Enter" }),
2546
3047
  " select",
2547
3048
  " ",
2548
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("kbd", { style: { padding: "1px 3px", borderRadius: 3, border: "1px solid rgba(255,255,255,0.15)", fontSize: 9 }, children: "Esc" }),
3049
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("kbd", { style: { padding: "1px 3px", borderRadius: 3, border: "1px solid rgba(255,255,255,0.15)", fontSize: 9 }, children: "Esc" }),
2549
3050
  " dismiss"
2550
3051
  ] })
2551
3052
  ]
@@ -2554,7 +3055,7 @@ var SlashCommandPopup = ({
2554
3055
  };
2555
3056
 
2556
3057
  // src/components/ChatBubble/ChatBubble.tsx
2557
- var import_jsx_runtime12 = require("react/jsx-runtime");
3058
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2558
3059
  var ChatBubble = ({
2559
3060
  messages,
2560
3061
  onSendMessage,
@@ -2569,65 +3070,69 @@ var ChatBubble = ({
2569
3070
  }) => {
2570
3071
  const mergedConfig = { ...DEFAULT_CONFIG, ...userConfig };
2571
3072
  if (userConfig?.logo && !userConfig?.avatar) {
2572
- mergedConfig.avatar = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("img", { src: userConfig.logo, alt: "Supernal", className: "w-6 h-6" });
3073
+ mergedConfig.avatar = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src: userConfig.logo, alt: "Supernal", className: "w-6 h-6" });
2573
3074
  }
2574
3075
  const config = mergedConfig;
2575
- const [isExpanded, setIsExpanded] = (0, import_react11.useState)(defaultExpanded);
2576
- const [isMinimized, setIsMinimized] = (0, import_react11.useState)(false);
2577
- const [inputValue, setInputValue] = (0, import_react11.useState)("");
2578
- const [lastReadMessageCount, setLastReadMessageCount] = (0, import_react11.useState)(0);
2579
- const [showWelcome, setShowWelcome] = (0, import_react11.useState)(
3076
+ const [isExpanded, setIsExpanded] = (0, import_react13.useState)(defaultExpanded);
3077
+ const [isMinimized, setIsMinimized] = (0, import_react13.useState)(false);
3078
+ const [inputValue, setInputValue] = (0, import_react13.useState)("");
3079
+ const [lastReadMessageCount, setLastReadMessageCount] = (0, import_react13.useState)(0);
3080
+ const [showWelcome, setShowWelcome] = (0, import_react13.useState)(
2580
3081
  config.welcome?.enabled && messages.length === 0
2581
3082
  );
2582
- const [isDragging, setIsDragging] = (0, import_react11.useState)(false);
2583
- const [dragInitiated, setDragInitiated] = (0, import_react11.useState)(false);
2584
- const [isDocked, setIsDocked] = (0, import_react11.useState)(true);
2585
- const [dockPosition, setDockPosition] = (0, import_react11.useState)(position);
2586
- const [panelPosition, setPanelPosition] = (0, import_react11.useState)({ x: 0, y: 0 });
2587
- const [theme, setTheme] = (0, import_react11.useState)("light");
2588
- const [showMoreMenu, setShowMoreMenu] = (0, import_react11.useState)(false);
2589
- const [, setTimestampTick] = (0, import_react11.useState)(0);
2590
- const [localGlassMode, setLocalGlassMode] = (0, import_react11.useState)(config.glassMode ?? true);
2591
- const [glassOpacity, setGlassOpacity] = (0, import_react11.useState)("medium");
2592
- const [notifications, setNotifications] = (0, import_react11.useState)(true);
2593
- const [voiceEnabled, setVoiceEnabled] = (0, import_react11.useState)(true);
2594
- const [usePremiumVoices, setUsePremiumVoices] = (0, import_react11.useState)(false);
2595
- const [autoReadResponses, setAutoReadResponses] = (0, import_react11.useState)(false);
2596
- const [ttsSpeed, setTtsSpeed] = (0, import_react11.useState)(1);
2597
- const [sttAutoRecordTimeout, setSttAutoRecordTimeout] = (0, import_react11.useState)(5e3);
2598
- const [sttAutoExecute, setSttAutoExecute] = (0, import_react11.useState)(true);
2599
- const sttAutoRecordTimeoutRef = (0, import_react11.useRef)(null);
3083
+ const [isDragging, setIsDragging] = (0, import_react13.useState)(false);
3084
+ const [dragInitiated, setDragInitiated] = (0, import_react13.useState)(false);
3085
+ const [isDocked, setIsDocked] = (0, import_react13.useState)(true);
3086
+ const [dockPosition, setDockPosition] = (0, import_react13.useState)(position);
3087
+ const [panelPosition, setPanelPosition] = (0, import_react13.useState)({ x: 0, y: 0 });
3088
+ const [theme, setTheme] = (0, import_react13.useState)("light");
3089
+ const [showMoreMenu, setShowMoreMenu] = (0, import_react13.useState)(false);
3090
+ const [, setTimestampTick] = (0, import_react13.useState)(0);
3091
+ const [localGlassMode, setLocalGlassMode] = (0, import_react13.useState)(config.glassMode ?? true);
3092
+ const [glassOpacity, setGlassOpacity] = (0, import_react13.useState)("medium");
3093
+ const [notifications, setNotifications] = (0, import_react13.useState)(true);
3094
+ const [voiceEnabled, setVoiceEnabled] = (0, import_react13.useState)(true);
3095
+ const [usePremiumVoices, setUsePremiumVoices] = (0, import_react13.useState)(false);
3096
+ const [autoReadResponses, setAutoReadResponses] = (0, import_react13.useState)(false);
3097
+ const [ttsSpeed, setTtsSpeed] = (0, import_react13.useState)(1);
3098
+ const [sttAutoRecordTimeout, setSttAutoRecordTimeout] = (0, import_react13.useState)(5e3);
3099
+ const [sttAutoExecute, setSttAutoExecute] = (0, import_react13.useState)(true);
3100
+ const sttAutoRecordTimeoutRef = (0, import_react13.useRef)(null);
2600
3101
  const { speak: speakTTS, stop: stopTTS, isPlaying: isTTSPlaying } = useTTS();
2601
3102
  const { startListening, stopListening, transcript: sttTranscript, isListening, resetTranscript } = useSTT();
3103
+ const apiKey = useApiKeyOptional();
3104
+ const [showApiKeyInput, setShowApiKeyInput] = (0, import_react13.useState)(false);
3105
+ const [apiKeyInputValue, setApiKeyInputValue] = (0, import_react13.useState)("");
3106
+ const [showApiKey, setShowApiKey] = (0, import_react13.useState)(false);
2602
3107
  const slashCommand = useSlashCommand(inputValue, (command) => {
2603
3108
  setInputValue(command);
2604
3109
  setTimeout(() => inputRef.current?.focus(), 0);
2605
3110
  });
2606
- const [displayMode, setDisplayMode] = (0, import_react11.useState)(propDisplayMode);
2607
- const [drawerSide, setDrawerSide] = (0, import_react11.useState)(propDrawerSide);
2608
- const displayModeLoadedFromStorage = (0, import_react11.useRef)(false);
2609
- (0, import_react11.useEffect)(() => {
3111
+ const [displayMode, setDisplayMode] = (0, import_react13.useState)(propDisplayMode);
3112
+ const [drawerSide, setDrawerSide] = (0, import_react13.useState)(propDrawerSide);
3113
+ const displayModeLoadedFromStorage = (0, import_react13.useRef)(false);
3114
+ (0, import_react13.useEffect)(() => {
2610
3115
  if (!displayModeLoadedFromStorage.current) {
2611
3116
  setDisplayMode(propDisplayMode);
2612
3117
  }
2613
3118
  }, [propDisplayMode]);
2614
- const [drawerOpen, setDrawerOpen] = (0, import_react11.useState)(false);
2615
- const [touchStart, setTouchStart] = (0, import_react11.useState)(null);
2616
- const [swipeProgress, setSwipeProgress] = (0, import_react11.useState)(0);
2617
- const [isMobile, setIsMobile] = (0, import_react11.useState)(false);
2618
- const lastEscapeTimeRef = (0, import_react11.useRef)(0);
3119
+ const [drawerOpen, setDrawerOpen] = (0, import_react13.useState)(false);
3120
+ const [touchStart, setTouchStart] = (0, import_react13.useState)(null);
3121
+ const [swipeProgress, setSwipeProgress] = (0, import_react13.useState)(0);
3122
+ const [isMobile, setIsMobile] = (0, import_react13.useState)(false);
3123
+ const lastEscapeTimeRef = (0, import_react13.useRef)(0);
2619
3124
  const DOUBLE_ESCAPE_THRESHOLD_MS = 500;
2620
- const [isMac, setIsMac] = (0, import_react11.useState)(false);
2621
- const [currentHintIndex, setCurrentHintIndex] = (0, import_react11.useState)(0);
2622
- const [isHydrated, setIsHydrated] = (0, import_react11.useState)(false);
2623
- (0, import_react11.useEffect)(() => {
3125
+ const [isMac, setIsMac] = (0, import_react13.useState)(false);
3126
+ const [currentHintIndex, setCurrentHintIndex] = (0, import_react13.useState)(0);
3127
+ const [isHydrated, setIsHydrated] = (0, import_react13.useState)(false);
3128
+ (0, import_react13.useEffect)(() => {
2624
3129
  if (typeof window !== "undefined") {
2625
3130
  const platform = window.navigator.platform.toLowerCase();
2626
3131
  const isMacPlatform = platform.includes("mac");
2627
3132
  setIsMac(isMacPlatform);
2628
3133
  }
2629
3134
  }, []);
2630
- const inputHints = (0, import_react11.useMemo)(() => {
3135
+ const inputHints = (0, import_react13.useMemo)(() => {
2631
3136
  const modKey = isMac ? "Cmd" : "Ctrl";
2632
3137
  return [
2633
3138
  `Press ${modKey}+/ to start voice recording`,
@@ -2636,14 +3141,14 @@ var ChatBubble = ({
2636
3141
  sttAutoExecute ? `Voice commands execute automatically` : "Voice commands fill this input"
2637
3142
  ];
2638
3143
  }, [isMac, sttAutoExecute]);
2639
- (0, import_react11.useEffect)(() => {
3144
+ (0, import_react13.useEffect)(() => {
2640
3145
  setCurrentHintIndex((prev) => (prev + 1) % inputHints.length);
2641
3146
  }, [messages.length, inputHints.length]);
2642
- const messagesEndRef = (0, import_react11.useRef)(null);
2643
- const inputRef = (0, import_react11.useRef)(null);
2644
- const panelRef = (0, import_react11.useRef)(null);
2645
- const dragRef = (0, import_react11.useRef)(null);
2646
- const rafRef = (0, import_react11.useRef)(null);
3147
+ const messagesEndRef = (0, import_react13.useRef)(null);
3148
+ const inputRef = (0, import_react13.useRef)(null);
3149
+ const panelRef = (0, import_react13.useRef)(null);
3150
+ const dragRef = (0, import_react13.useRef)(null);
3151
+ const rafRef = (0, import_react13.useRef)(null);
2647
3152
  const formatRelativeTime = (timestamp) => {
2648
3153
  const now = /* @__PURE__ */ new Date();
2649
3154
  const messageTime = new Date(timestamp);
@@ -2658,7 +3163,7 @@ var ChatBubble = ({
2658
3163
  if (diffDays < 7) return `${diffDays} ${diffDays === 1 ? "day" : "days"} ago`;
2659
3164
  return messageTime.toLocaleDateString();
2660
3165
  };
2661
- (0, import_react11.useEffect)(() => {
3166
+ (0, import_react13.useEffect)(() => {
2662
3167
  if (variant === "floating" && panelPosition.x === 0 && panelPosition.y === 0) {
2663
3168
  try {
2664
3169
  const stored = localStorage.getItem(storageKey);
@@ -2680,7 +3185,7 @@ var ChatBubble = ({
2680
3185
  }
2681
3186
  }
2682
3187
  }, [variant, storageKey, panelPosition.x, panelPosition.y]);
2683
- (0, import_react11.useEffect)(() => {
3188
+ (0, import_react13.useEffect)(() => {
2684
3189
  if (variant === "full" || variant === "drawer" || variant === "subtitle") {
2685
3190
  try {
2686
3191
  const stored = localStorage.getItem(storageKey);
@@ -2758,12 +3263,12 @@ var ChatBubble = ({
2758
3263
  }
2759
3264
  setIsHydrated(true);
2760
3265
  }, [storageKey, variant, defaultExpanded, position]);
2761
- (0, import_react11.useEffect)(() => {
3266
+ (0, import_react13.useEffect)(() => {
2762
3267
  if (variant !== "full" && variant !== "drawer" && variant !== "subtitle") {
2763
3268
  setIsHydrated(true);
2764
3269
  }
2765
3270
  }, [variant]);
2766
- (0, import_react11.useEffect)(() => {
3271
+ (0, import_react13.useEffect)(() => {
2767
3272
  if (!isExpanded || isDocked || !panelRef.current) return;
2768
3273
  const checkBounds = () => {
2769
3274
  const rect = panelRef.current?.getBoundingClientRect();
@@ -2780,7 +3285,7 @@ var ChatBubble = ({
2780
3285
  const timeoutId = setTimeout(checkBounds, 100);
2781
3286
  return () => clearTimeout(timeoutId);
2782
3287
  }, [isExpanded, isDocked]);
2783
- (0, import_react11.useEffect)(() => {
3288
+ (0, import_react13.useEffect)(() => {
2784
3289
  const isSubtitleMode = displayMode === "subtitle" || displayMode === "auto" && variant === "subtitle";
2785
3290
  if (isSubtitleMode) return;
2786
3291
  const handleKeyDown = (e) => {
@@ -2813,13 +3318,13 @@ var ChatBubble = ({
2813
3318
  window.addEventListener("keydown", handleKeyDown);
2814
3319
  return () => window.removeEventListener("keydown", handleKeyDown);
2815
3320
  }, [isExpanded, isDocked, position, variant, displayMode, isMobile]);
2816
- (0, import_react11.useEffect)(() => {
3321
+ (0, import_react13.useEffect)(() => {
2817
3322
  if (typeof window !== "undefined") {
2818
3323
  const isDark = document.documentElement.getAttribute("data-theme") === "dark";
2819
3324
  setTheme(isDark ? "dark" : "light");
2820
3325
  }
2821
3326
  }, []);
2822
- (0, import_react11.useEffect)(() => {
3327
+ (0, import_react13.useEffect)(() => {
2823
3328
  if (typeof window === "undefined") return;
2824
3329
  const mediaQuery = window.matchMedia("(max-width: 767px)");
2825
3330
  const handleChange = (e) => {
@@ -2829,26 +3334,26 @@ var ChatBubble = ({
2829
3334
  mediaQuery.addEventListener("change", handleChange);
2830
3335
  return () => mediaQuery.removeEventListener("change", handleChange);
2831
3336
  }, []);
2832
- const currentVariant = import_react11.default.useMemo(() => {
3337
+ const currentVariant = import_react13.default.useMemo(() => {
2833
3338
  if (displayMode !== "auto") {
2834
3339
  return displayMode;
2835
3340
  }
2836
3341
  return isMobile && variant === "full" ? "subtitle" : variant;
2837
3342
  }, [displayMode, isMobile, variant]);
2838
- const prevVariantRef = import_react11.default.useRef(variant);
2839
- (0, import_react11.useEffect)(() => {
3343
+ const prevVariantRef = import_react13.default.useRef(variant);
3344
+ (0, import_react13.useEffect)(() => {
2840
3345
  if (prevVariantRef.current !== variant && displayMode !== "auto") {
2841
3346
  setDisplayMode("auto");
2842
3347
  prevVariantRef.current = variant;
2843
3348
  }
2844
3349
  }, [variant, displayMode]);
2845
- (0, import_react11.useEffect)(() => {
3350
+ (0, import_react13.useEffect)(() => {
2846
3351
  const interval = setInterval(() => {
2847
3352
  setTimestampTick((tick) => tick + 1);
2848
3353
  }, 6e4);
2849
3354
  return () => clearInterval(interval);
2850
3355
  }, []);
2851
- (0, import_react11.useEffect)(() => {
3356
+ (0, import_react13.useEffect)(() => {
2852
3357
  if (variant === "full" || variant === "drawer" || variant === "subtitle") {
2853
3358
  try {
2854
3359
  localStorage.setItem(
@@ -2880,7 +3385,7 @@ var ChatBubble = ({
2880
3385
  }
2881
3386
  }, [isExpanded, isMinimized, isDocked, dockPosition, panelPosition, theme, localGlassMode, notifications, displayMode, drawerSide, drawerOpen, glassOpacity, voiceEnabled, usePremiumVoices, autoReadResponses, ttsSpeed, sttAutoRecordTimeout, sttAutoExecute, storageKey, variant]);
2882
3387
  const { registerInput } = useChatInput();
2883
- (0, import_react11.useEffect)(() => {
3388
+ (0, import_react13.useEffect)(() => {
2884
3389
  registerInput((text, submit = false) => {
2885
3390
  setInputValue(text);
2886
3391
  if (!isExpanded && variant === "full") {
@@ -2897,7 +3402,7 @@ var ChatBubble = ({
2897
3402
  }, [registerInput, onSendMessage]);
2898
3403
  const unreadCount = Math.max(0, messages.length - lastReadMessageCount);
2899
3404
  const hasUnread = unreadCount > 0 && !isExpanded && variant === "full";
2900
- (0, import_react11.useEffect)(() => {
3405
+ (0, import_react13.useEffect)(() => {
2901
3406
  if (isExpanded || variant === "floating") {
2902
3407
  messagesEndRef.current?.scrollIntoView({ behavior: "auto" });
2903
3408
  setLastReadMessageCount(messages.length);
@@ -2909,12 +3414,12 @@ var ChatBubble = ({
2909
3414
  }
2910
3415
  }
2911
3416
  }, [messages, isExpanded, variant]);
2912
- (0, import_react11.useEffect)(() => {
3417
+ (0, import_react13.useEffect)(() => {
2913
3418
  if (isExpanded && variant === "full") {
2914
3419
  inputRef.current?.focus();
2915
3420
  }
2916
3421
  }, [isExpanded, variant]);
2917
- (0, import_react11.useEffect)(() => {
3422
+ (0, import_react13.useEffect)(() => {
2918
3423
  if (!voiceEnabled || !autoReadResponses || messages.length === 0) return;
2919
3424
  const lastMessage = messages[messages.length - 1];
2920
3425
  if (lastMessage.type === "ai") {
@@ -2926,7 +3431,7 @@ var ChatBubble = ({
2926
3431
  });
2927
3432
  }
2928
3433
  }, [messages, voiceEnabled, autoReadResponses, ttsSpeed, usePremiumVoices, speakTTS]);
2929
- (0, import_react11.useEffect)(() => {
3434
+ (0, import_react13.useEffect)(() => {
2930
3435
  if (currentVariant === "subtitle") return;
2931
3436
  if (sttTranscript && voiceEnabled) {
2932
3437
  setInputValue(sttTranscript);
@@ -2941,7 +3446,7 @@ var ChatBubble = ({
2941
3446
  }
2942
3447
  }
2943
3448
  }, [sttTranscript, voiceEnabled, resetTranscript, sttAutoExecute, onSendMessage, currentVariant]);
2944
- (0, import_react11.useEffect)(() => {
3449
+ (0, import_react13.useEffect)(() => {
2945
3450
  if (currentVariant === "subtitle") return;
2946
3451
  const handleKeyDown = (e) => {
2947
3452
  if ((e.metaKey || e.ctrlKey) && e.key === "/" && voiceEnabled) {
@@ -2999,7 +3504,7 @@ var ChatBubble = ({
2999
3504
  }
3000
3505
  };
3001
3506
  }, [currentVariant, isExpanded, showMoreMenu, voiceEnabled, isListening, startListening, stopListening, sttAutoRecordTimeout]);
3002
- (0, import_react11.useEffect)(() => {
3507
+ (0, import_react13.useEffect)(() => {
3003
3508
  if (currentVariant !== "drawer") return;
3004
3509
  const handleKeyDown = (e) => {
3005
3510
  if (e.key === "Escape" && drawerOpen) {
@@ -3009,7 +3514,7 @@ var ChatBubble = ({
3009
3514
  window.addEventListener("keydown", handleKeyDown);
3010
3515
  return () => window.removeEventListener("keydown", handleKeyDown);
3011
3516
  }, [currentVariant, drawerOpen]);
3012
- (0, import_react11.useEffect)(() => {
3517
+ (0, import_react13.useEffect)(() => {
3013
3518
  if (!showMoreMenu) return;
3014
3519
  const handleClickOutside = (e) => {
3015
3520
  const target = e.target;
@@ -3020,7 +3525,7 @@ var ChatBubble = ({
3020
3525
  document.addEventListener("mousedown", handleClickOutside);
3021
3526
  return () => document.removeEventListener("mousedown", handleClickOutside);
3022
3527
  }, [showMoreMenu]);
3023
- (0, import_react11.useEffect)(() => {
3528
+ (0, import_react13.useEffect)(() => {
3024
3529
  if (typeof window === "undefined" || currentVariant !== "drawer") return;
3025
3530
  const EDGE_ZONE_PX = 20;
3026
3531
  const SWIPE_THRESHOLD = 0.4;
@@ -3105,7 +3610,7 @@ var ChatBubble = ({
3105
3610
  };
3106
3611
  }
3107
3612
  };
3108
- (0, import_react11.useEffect)(() => {
3613
+ (0, import_react13.useEffect)(() => {
3109
3614
  if (!dragInitiated || !dragRef.current) return;
3110
3615
  const dragThresholdPx = 5;
3111
3616
  const handleMouseMove = (e) => {
@@ -3268,7 +3773,7 @@ var ChatBubble = ({
3268
3773
  return null;
3269
3774
  }
3270
3775
  if (currentVariant === "subtitle") {
3271
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3776
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3272
3777
  SubtitleOverlay,
3273
3778
  {
3274
3779
  messages,
@@ -3300,8 +3805,8 @@ var ChatBubble = ({
3300
3805
  }
3301
3806
  if (currentVariant === "drawer") {
3302
3807
  const drawerWidth = "100vw";
3303
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
3304
- (drawerOpen || swipeProgress > 0) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3808
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
3809
+ (drawerOpen || swipeProgress > 0) && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3305
3810
  "div",
3306
3811
  {
3307
3812
  className: "fixed inset-0 bg-black z-[49998] transition-opacity duration-300",
@@ -3313,7 +3818,7 @@ var ChatBubble = ({
3313
3818
  onClick: () => setDrawerOpen(false)
3314
3819
  }
3315
3820
  ),
3316
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3821
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3317
3822
  "div",
3318
3823
  {
3319
3824
  className: `fixed ${drawerSide === "right" ? "right-0" : "left-0"} top-0 h-full z-[49999] flex flex-col ${glassClasses} shadow-2xl`,
@@ -3332,31 +3837,31 @@ var ChatBubble = ({
3332
3837
  onTouchMove: handleDrawerTouchMove,
3333
3838
  onTouchEnd: handleDrawerTouchEnd,
3334
3839
  children: [
3335
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `${THEME_CLASSES.bg.header} ${glassMode ? THEME_CLASSES.bg.headerGradient : THEME_CLASSES.bg.headerLight}`, children: [
3336
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center space-x-3", children: [
3337
- config.avatar && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "relative flex-shrink-0", children: [
3338
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Avatar, { avatar: config.avatar }),
3339
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
3840
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `${THEME_CLASSES.bg.header} ${glassMode ? THEME_CLASSES.bg.headerGradient : THEME_CLASSES.bg.headerLight}`, children: [
3841
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center space-x-3", children: [
3842
+ config.avatar && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "relative flex-shrink-0", children: [
3843
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Avatar, { avatar: config.avatar }),
3844
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
3340
3845
  ] }),
3341
- config.title && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h3", { className: THEME_CLASSES.text.title, children: config.title }) })
3846
+ config.title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h3", { className: THEME_CLASSES.text.title, children: config.title }) })
3342
3847
  ] }),
3343
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { onClick: () => setDrawerOpen(false), className: THEME_CLASSES.button.close, title: "Close drawer", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
3848
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => setDrawerOpen(false), className: THEME_CLASSES.button.close, title: "Close drawer", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
3344
3849
  ] }),
3345
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex-1 overflow-y-auto p-4 space-y-2", children: [
3346
- showWelcome && messages.length === 0 && config.welcome?.enabled && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: THEME_CLASSES.welcome.container, children: [
3347
- config.welcome.title && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h4", { className: THEME_CLASSES.welcome.title, style: INLINE_STYLES.welcomeTitle(theme === "dark"), children: config.welcome.title }),
3348
- config.welcome.content && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: THEME_CLASSES.welcome.content, style: INLINE_STYLES.welcomeContent(theme === "dark"), children: config.welcome.content })
3850
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex-1 overflow-y-auto p-4 space-y-2", "data-testid": "chat-messages", children: [
3851
+ showWelcome && messages.length === 0 && config.welcome?.enabled && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: THEME_CLASSES.welcome.container, children: [
3852
+ config.welcome.title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h4", { className: THEME_CLASSES.welcome.title, style: INLINE_STYLES.welcomeTitle(theme === "dark"), children: config.welcome.title }),
3853
+ config.welcome.content && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: THEME_CLASSES.welcome.content, style: INLINE_STYLES.welcomeContent(theme === "dark"), children: config.welcome.content })
3349
3854
  ] }),
3350
- messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `group flex items-center gap-1 mb-2 ${message.type === "user" ? "flex-row-reverse" : "flex-row"}`, children: [
3351
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3855
+ messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `group flex items-center gap-1 mb-2 ${message.type === "user" ? "flex-row-reverse" : "flex-row"}`, children: [
3856
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3352
3857
  "div",
3353
3858
  {
3354
3859
  className: `inline-block px-4 py-2.5 rounded-2xl max-w-[95%] text-sm shadow-sm transition-all ${message.type === "user" ? THEME_CLASSES.message.user : message.type === "ai" ? THEME_CLASSES.message.ai : THEME_CLASSES.message.system}`,
3355
3860
  style: message.type === "user" ? INLINE_STYLES.messageUser() : message.type === "ai" ? INLINE_STYLES.messageAI(theme === "dark") : INLINE_STYLES.messageSystem(theme === "dark"),
3356
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MessageRenderer, { content: message.text, theme })
3861
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MessageRenderer, { content: message.text, theme })
3357
3862
  }
3358
3863
  ),
3359
- message.type === "ai" && voiceEnabled && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3864
+ message.type === "ai" && voiceEnabled && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3360
3865
  TTSButton,
3361
3866
  {
3362
3867
  text: message.text,
@@ -3366,7 +3871,7 @@ var ChatBubble = ({
3366
3871
  size: "small"
3367
3872
  }
3368
3873
  ),
3369
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3874
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3370
3875
  "div",
3371
3876
  {
3372
3877
  className: `text-xs opacity-0 group-hover:opacity-70 transition-opacity whitespace-nowrap flex-shrink-0 ${message.type === "user" ? "text-gray-400 dark:text-gray-500 text-left" : "text-gray-600 dark:text-gray-400 text-right"}`,
@@ -3375,10 +3880,10 @@ var ChatBubble = ({
3375
3880
  }
3376
3881
  )
3377
3882
  ] }, message.id)),
3378
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { ref: messagesEndRef })
3883
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { ref: messagesEndRef })
3379
3884
  ] }),
3380
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { position: "relative" }, children: [
3381
- slashCommand.isOpen && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3885
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { position: "relative" }, children: [
3886
+ slashCommand.isOpen && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3382
3887
  SlashCommandPopup,
3383
3888
  {
3384
3889
  tools: slashCommand.filteredTools,
@@ -3387,7 +3892,7 @@ var ChatBubble = ({
3387
3892
  onClose: () => setInputValue("")
3388
3893
  }
3389
3894
  ),
3390
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3895
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3391
3896
  InputField,
3392
3897
  {
3393
3898
  inputValue,
@@ -3409,20 +3914,20 @@ var ChatBubble = ({
3409
3914
  ]
3410
3915
  }
3411
3916
  ),
3412
- !drawerOpen && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3917
+ !drawerOpen && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3413
3918
  "div",
3414
3919
  {
3415
3920
  className: `fixed ${drawerSide === "right" ? "right-0" : "left-0"} bottom-20 opacity-70 hover:opacity-100 transition-opacity duration-300 z-[999999] cursor-pointer`,
3416
3921
  style: { zIndex: 999999 },
3417
3922
  onClick: () => setDrawerOpen(true),
3418
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: `${glassMode ? "backdrop-blur-md bg-white/50 dark:bg-gray-800/50" : "bg-white dark:bg-gray-800"} text-gray-700 dark:text-gray-200 px-3 py-3 ${drawerSide === "right" ? "rounded-l-xl" : "rounded-r-xl"} shadow-md hover:shadow-lg flex items-center justify-center transition-all`, children: voiceEnabled ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z" }) }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }) })
3923
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: `${glassMode ? "backdrop-blur-md bg-white/50 dark:bg-gray-800/50" : "bg-white dark:bg-gray-800"} text-gray-700 dark:text-gray-200 px-3 py-3 ${drawerSide === "right" ? "rounded-l-xl" : "rounded-r-xl"} shadow-md hover:shadow-lg flex items-center justify-center transition-all`, children: voiceEnabled ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z" }) }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }) })
3419
3924
  }
3420
3925
  )
3421
3926
  ] });
3422
3927
  }
3423
3928
  if (currentVariant === "floating") {
3424
3929
  const recentMessage = messages[messages.length - 1];
3425
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3930
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3426
3931
  "div",
3427
3932
  {
3428
3933
  className: `fixed z-[999999] ${isDragging ? "cursor-grabbing" : "cursor-grab"}`,
@@ -3435,32 +3940,32 @@ var ChatBubble = ({
3435
3940
  ...!isDragging && { transition: "transform 0.3s cubic-bezier(0.4, 0, 0.2, 1)" }
3436
3941
  },
3437
3942
  onMouseDown: handlePanelMouseDown,
3438
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `${glassClasses} rounded-2xl shadow-2xl p-3 max-w-xs ${!glassMode && "border-gray-200 border"}`, children: [
3439
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
3440
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center space-x-2", children: [
3441
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Avatar, { avatar: config.avatar, size: "small" }),
3442
- config.title && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: THEME_CLASSES.text.floatingTitle, children: config.title })
3943
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `${glassClasses} rounded-2xl shadow-2xl p-3 max-w-xs ${!glassMode && "border-gray-200 border"}`, children: [
3944
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
3945
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center space-x-2", children: [
3946
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Avatar, { avatar: config.avatar, size: "small" }),
3947
+ config.title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: THEME_CLASSES.text.floatingTitle, children: config.title })
3443
3948
  ] }),
3444
- onClearChat && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3949
+ onClearChat && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3445
3950
  "button",
3446
3951
  {
3447
3952
  onClick: onClearChat,
3448
3953
  className: THEME_CLASSES.button.floatingClear,
3449
3954
  title: "Clear chat",
3450
3955
  "data-testid": ChatNames.clearButton,
3451
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
3956
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
3452
3957
  }
3453
3958
  )
3454
3959
  ] }),
3455
- recentMessage && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `mb-2 group flex items-center gap-2 ${recentMessage.type === "user" ? "flex-row-reverse" : "flex-row"}`, children: [
3456
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3960
+ recentMessage && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `mb-2 group flex items-center gap-2 ${recentMessage.type === "user" ? "flex-row-reverse" : "flex-row"}`, children: [
3961
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3457
3962
  "div",
3458
3963
  {
3459
3964
  className: `text-xs px-3 py-2 rounded-xl transition-all ${recentMessage.type === "user" ? "bg-gradient-to-br from-blue-500 to-blue-600 text-white shadow-lg" : recentMessage.type === "ai" ? "bg-gradient-to-br from-gray-100 to-gray-200 dark:from-gray-700 dark:to-gray-800 text-gray-900 dark:text-white shadow-md" : "bg-gradient-to-br from-yellow-100 to-yellow-200 text-yellow-900 shadow-md"}`,
3460
3965
  children: recentMessage.text.length > 60 ? `${recentMessage.text.slice(0, 60)}...` : recentMessage.text
3461
3966
  }
3462
3967
  ),
3463
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3968
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3464
3969
  "div",
3465
3970
  {
3466
3971
  className: `text-xs opacity-0 group-hover:opacity-70 transition-opacity whitespace-nowrap flex-shrink-0 ${recentMessage.type === "user" ? "text-gray-400 dark:text-gray-500 text-left" : "text-gray-600 dark:text-gray-400 text-right"}`,
@@ -3469,8 +3974,8 @@ var ChatBubble = ({
3469
3974
  }
3470
3975
  )
3471
3976
  ] }),
3472
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { position: "relative" }, children: [
3473
- slashCommand.isOpen && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3977
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { position: "relative" }, children: [
3978
+ slashCommand.isOpen && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3474
3979
  SlashCommandPopup,
3475
3980
  {
3476
3981
  tools: slashCommand.filteredTools,
@@ -3479,7 +3984,7 @@ var ChatBubble = ({
3479
3984
  onClose: () => setInputValue("")
3480
3985
  }
3481
3986
  ),
3482
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3987
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3483
3988
  InputField,
3484
3989
  {
3485
3990
  compact: true,
@@ -3499,7 +4004,7 @@ var ChatBubble = ({
3499
4004
  }
3500
4005
  );
3501
4006
  }
3502
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_jsx_runtime12.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4007
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_jsx_runtime13.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3503
4008
  "div",
3504
4009
  {
3505
4010
  className: "fixed",
@@ -3517,7 +4022,7 @@ var ChatBubble = ({
3517
4022
  }
3518
4023
  },
3519
4024
  children: [
3520
- isExpanded && isMinimized && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4025
+ isExpanded && isMinimized && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3521
4026
  "div",
3522
4027
  {
3523
4028
  ref: panelRef,
@@ -3535,7 +4040,7 @@ var ChatBubble = ({
3535
4040
  ...isDragging && { cursor: "grabbing" }
3536
4041
  },
3537
4042
  children: [
3538
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4043
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3539
4044
  "div",
3540
4045
  {
3541
4046
  "data-drag-handle": true,
@@ -3551,15 +4056,15 @@ var ChatBubble = ({
3551
4056
  }
3552
4057
  },
3553
4058
  children: [
3554
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center space-x-3", children: [
3555
- config.avatar && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "relative flex-shrink-0", children: [
3556
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Avatar, { avatar: config.avatar }),
3557
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
4059
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center space-x-3", children: [
4060
+ config.avatar && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "relative flex-shrink-0", children: [
4061
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Avatar, { avatar: config.avatar }),
4062
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
3558
4063
  ] }),
3559
- config.title && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h3", { className: THEME_CLASSES.text.title, children: config.title }) })
4064
+ config.title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h3", { className: THEME_CLASSES.text.title, children: config.title }) })
3560
4065
  ] }),
3561
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center space-x-1 flex-shrink-0", children: [
3562
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4066
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center space-x-1 flex-shrink-0", children: [
4067
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3563
4068
  "button",
3564
4069
  {
3565
4070
  onClick: (e) => {
@@ -3568,10 +4073,10 @@ var ChatBubble = ({
3568
4073
  },
3569
4074
  className: THEME_CLASSES.button.minimize,
3570
4075
  title: "Minimize chat",
3571
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
4076
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
3572
4077
  }
3573
4078
  ),
3574
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4079
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3575
4080
  "button",
3576
4081
  {
3577
4082
  onClick: (e) => {
@@ -3580,20 +4085,20 @@ var ChatBubble = ({
3580
4085
  },
3581
4086
  className: THEME_CLASSES.button.close,
3582
4087
  title: "Close chat",
3583
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
4088
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
3584
4089
  }
3585
4090
  )
3586
4091
  ] })
3587
4092
  ]
3588
4093
  }
3589
4094
  ),
3590
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "p-4", children: [
4095
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "p-4", children: [
3591
4096
  (() => {
3592
4097
  const lastAiMessage = [...messages].reverse().find((m) => m.type === "ai");
3593
- return lastAiMessage ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: `text-xs px-3 py-2 rounded-xl ${THEME_CLASSES.message.ai}`, style: INLINE_STYLES.messageAI(theme === "dark"), children: lastAiMessage.text.length > 100 ? `${lastAiMessage.text.slice(0, 100)}...` : lastAiMessage.text }) }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: THEME_CLASSES.text.minimizedMessage, style: INLINE_STYLES.minimizedMessage(theme === "dark"), children: "No AI responses yet" }) });
4098
+ return lastAiMessage ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: `text-xs px-3 py-2 rounded-xl ${THEME_CLASSES.message.ai}`, style: INLINE_STYLES.messageAI(theme === "dark"), children: lastAiMessage.text.length > 100 ? `${lastAiMessage.text.slice(0, 100)}...` : lastAiMessage.text }) }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: THEME_CLASSES.text.minimizedMessage, style: INLINE_STYLES.minimizedMessage(theme === "dark"), children: "No AI responses yet" }) });
3594
4099
  })(),
3595
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { position: "relative" }, children: [
3596
- slashCommand.isOpen && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4100
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { position: "relative" }, children: [
4101
+ slashCommand.isOpen && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3597
4102
  SlashCommandPopup,
3598
4103
  {
3599
4104
  tools: slashCommand.filteredTools,
@@ -3602,7 +4107,7 @@ var ChatBubble = ({
3602
4107
  onClose: () => setInputValue("")
3603
4108
  }
3604
4109
  ),
3605
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4110
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3606
4111
  InputField,
3607
4112
  {
3608
4113
  compact: true,
@@ -3622,7 +4127,7 @@ var ChatBubble = ({
3622
4127
  ]
3623
4128
  }
3624
4129
  ),
3625
- isExpanded && !isMinimized && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4130
+ isExpanded && !isMinimized && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3626
4131
  "div",
3627
4132
  {
3628
4133
  ref: panelRef,
@@ -3640,22 +4145,22 @@ var ChatBubble = ({
3640
4145
  ...isDragging && { cursor: "grabbing" }
3641
4146
  },
3642
4147
  children: [
3643
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4148
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3644
4149
  "div",
3645
4150
  {
3646
4151
  "data-drag-handle": true,
3647
4152
  className: `${THEME_CLASSES.bg.header} ${glassMode ? THEME_CLASSES.bg.headerGradient : THEME_CLASSES.bg.headerLight} cursor-move`,
3648
4153
  onMouseDown: handlePanelMouseDown,
3649
4154
  children: [
3650
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center space-x-3", children: [
3651
- config.avatar && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "relative flex-shrink-0", children: [
3652
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Avatar, { avatar: config.avatar }),
3653
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
4155
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center space-x-3", children: [
4156
+ config.avatar && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "relative flex-shrink-0", children: [
4157
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Avatar, { avatar: config.avatar }),
4158
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
3654
4159
  ] }),
3655
- config.title && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h3", { className: THEME_CLASSES.text.title, children: config.title }) })
4160
+ config.title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h3", { className: THEME_CLASSES.text.title, children: config.title }) })
3656
4161
  ] }),
3657
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center space-x-1 flex-shrink-0 relative", "data-more-menu": true, children: [
3658
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4162
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center space-x-1 flex-shrink-0 relative", "data-more-menu": true, children: [
4163
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3659
4164
  "a",
3660
4165
  {
3661
4166
  href: "https://www.interface.supernal.ai",
@@ -3663,30 +4168,160 @@ var ChatBubble = ({
3663
4168
  rel: "noopener noreferrer",
3664
4169
  className: "p-2 text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300 transition-colors rounded-lg hover:bg-white/30",
3665
4170
  title: "Visit Supernal Interface Documentation",
3666
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" }) })
4171
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" }) })
3667
4172
  }
3668
4173
  ),
3669
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4174
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3670
4175
  "button",
3671
4176
  {
3672
4177
  onClick: () => setShowMoreMenu(!showMoreMenu),
3673
4178
  className: THEME_CLASSES.button.more,
3674
4179
  title: "More options",
3675
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 5v.01M12 12v.01M12 19v.01M12 6a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2z" }) })
4180
+ "data-testid": "chat-more-menu-button",
4181
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 5v.01M12 12v.01M12 19v.01M12 6a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2z" }) })
3676
4182
  }
3677
4183
  ),
3678
- showMoreMenu && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "absolute right-0 top-10 bg-white dark:bg-gray-800 rounded-lg shadow-xl border border-gray-200 dark:border-gray-600 p-2 min-w-[220px] z-50", "data-more-menu": true, children: [
3679
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "px-3 py-2 border-b border-gray-200 dark:border-gray-600 mb-2", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "grid grid-cols-4 gap-1", children: [
3680
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4184
+ showMoreMenu && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "absolute right-0 top-10 bg-white dark:bg-gray-800 rounded-lg shadow-xl border border-gray-200 dark:border-gray-600 p-2 min-w-[280px] z-50", "data-more-menu": true, "data-testid": "chat-more-menu", children: [
4185
+ apiKey && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "px-3 py-2 border-b border-gray-200 dark:border-gray-600 mb-2", "data-testid": "api-key-section", children: [
4186
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
4187
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-200 flex items-center gap-2", children: [
4188
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" }) }),
4189
+ "API Key"
4190
+ ] }),
4191
+ apiKey.status === "valid" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-green-500", title: "API key is valid", "data-testid": "api-key-status", "data-status": "valid", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z", clipRule: "evenodd" }) }) }),
4192
+ apiKey.status === "invalid" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-red-500", title: "API key is invalid", "data-testid": "api-key-status", "data-status": "invalid", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z", clipRule: "evenodd" }) }) }),
4193
+ apiKey.status === "validating" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-blue-500 animate-spin", title: "Validating...", "data-testid": "api-key-status", "data-status": "validating", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" }) }) })
4194
+ ] }),
4195
+ apiKey.status === "valid" && apiKey.maskedKey ? (
4196
+ // Key is set - show masked key and clear button
4197
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2", children: [
4198
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("code", { className: "flex-1 text-xs bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded text-gray-600 dark:text-gray-300 font-mono", "data-testid": "api-key-masked", children: apiKey.maskedKey }),
4199
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4200
+ "button",
4201
+ {
4202
+ onClick: () => {
4203
+ apiKey.clearApiKey();
4204
+ setApiKeyInputValue("");
4205
+ },
4206
+ className: "text-xs text-red-500 hover:text-red-600 px-2 py-1",
4207
+ title: "Remove API key",
4208
+ "data-testid": "api-key-clear-button",
4209
+ children: "Clear"
4210
+ }
4211
+ )
4212
+ ] })
4213
+ ) : showApiKeyInput ? (
4214
+ // Input mode - show form
4215
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-2", children: [
4216
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex gap-1", children: [
4217
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4218
+ "input",
4219
+ {
4220
+ type: showApiKey ? "text" : "password",
4221
+ value: apiKeyInputValue,
4222
+ onChange: (e) => setApiKeyInputValue(e.target.value),
4223
+ placeholder: "sk-ant-...",
4224
+ className: "flex-1 text-sm px-2 py-1.5 border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-1 focus:ring-blue-500",
4225
+ "data-testid": "api-key-input",
4226
+ onKeyDown: (e) => {
4227
+ if (e.key === "Enter") {
4228
+ e.preventDefault();
4229
+ if (apiKeyInputValue.trim()) {
4230
+ apiKey.setApiKey(apiKeyInputValue.trim()).then((success) => {
4231
+ if (success) {
4232
+ setApiKeyInputValue("");
4233
+ setShowApiKeyInput(false);
4234
+ }
4235
+ });
4236
+ }
4237
+ }
4238
+ if (e.key === "Escape") {
4239
+ setShowApiKeyInput(false);
4240
+ setApiKeyInputValue("");
4241
+ }
4242
+ },
4243
+ autoFocus: true
4244
+ }
4245
+ ),
4246
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4247
+ "button",
4248
+ {
4249
+ onClick: () => setShowApiKey(!showApiKey),
4250
+ className: "px-2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200",
4251
+ title: showApiKey ? "Hide" : "Show",
4252
+ "data-testid": "api-key-show-toggle",
4253
+ children: showApiKey ? "\u{1F648}" : "\u{1F441}\uFE0F"
4254
+ }
4255
+ )
4256
+ ] }),
4257
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex gap-2", children: [
4258
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4259
+ "button",
4260
+ {
4261
+ onClick: async () => {
4262
+ if (apiKeyInputValue.trim()) {
4263
+ const success = await apiKey.setApiKey(apiKeyInputValue.trim());
4264
+ if (success) {
4265
+ setApiKeyInputValue("");
4266
+ setShowApiKeyInput(false);
4267
+ }
4268
+ }
4269
+ },
4270
+ disabled: !apiKeyInputValue.trim() || apiKey.status === "validating",
4271
+ className: "flex-1 text-xs px-3 py-1.5 bg-blue-600 text-white rounded hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed",
4272
+ "data-testid": "api-key-submit-button",
4273
+ children: apiKey.status === "validating" ? "Validating..." : "Save"
4274
+ }
4275
+ ),
4276
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4277
+ "button",
4278
+ {
4279
+ onClick: () => {
4280
+ setShowApiKeyInput(false);
4281
+ setApiKeyInputValue("");
4282
+ },
4283
+ className: "text-xs px-3 py-1.5 text-gray-600 dark:text-gray-300 hover:text-gray-800 dark:hover:text-gray-100",
4284
+ "data-testid": "api-key-cancel-button",
4285
+ children: "Cancel"
4286
+ }
4287
+ )
4288
+ ] }),
4289
+ apiKey.error && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-xs text-red-500", "data-testid": "api-key-error", children: apiKey.error }),
4290
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4291
+ "a",
4292
+ {
4293
+ href: "https://console.anthropic.com/settings/keys",
4294
+ target: "_blank",
4295
+ rel: "noopener noreferrer",
4296
+ className: "block text-xs text-blue-500 hover:underline",
4297
+ children: "Get an API key from Anthropic \u2192"
4298
+ }
4299
+ )
4300
+ ] })
4301
+ ) : (
4302
+ // No key - show configure button
4303
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4304
+ "button",
4305
+ {
4306
+ onClick: () => setShowApiKeyInput(true),
4307
+ className: "w-full text-sm px-3 py-2 bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-200 rounded hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors",
4308
+ "data-testid": "api-key-configure-button",
4309
+ children: "Configure API Key"
4310
+ }
4311
+ )
4312
+ )
4313
+ ] }),
4314
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "px-3 py-2 border-b border-gray-200 dark:border-gray-600 mb-2", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "grid grid-cols-4 gap-1", children: [
4315
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3681
4316
  "button",
3682
4317
  {
3683
4318
  onClick: () => setLocalGlassMode(false),
3684
4319
  className: `flex items-center justify-center p-2 rounded transition-all ${!localGlassMode ? "bg-blue-600 text-white shadow-sm" : "bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-600"}`,
3685
4320
  title: "Glass Off",
3686
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("rect", { x: "8", y: "8", width: "8", height: "8", rx: "1" }) })
4321
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("rect", { x: "8", y: "8", width: "8", height: "8", rx: "1" }) })
3687
4322
  }
3688
4323
  ),
3689
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4324
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3690
4325
  "button",
3691
4326
  {
3692
4327
  onClick: () => {
@@ -3695,10 +4330,10 @@ var ChatBubble = ({
3695
4330
  },
3696
4331
  className: `flex items-center justify-center p-2 rounded transition-all ${localGlassMode && glassOpacity === "low" ? "bg-blue-600 text-white shadow-sm" : "bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-600"}`,
3697
4332
  title: "Glass Low",
3698
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("rect", { x: "9", y: "9", width: "6", height: "6", rx: "1", strokeWidth: "2" }) })
4333
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("rect", { x: "9", y: "9", width: "6", height: "6", rx: "1", strokeWidth: "2" }) })
3699
4334
  }
3700
4335
  ),
3701
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4336
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3702
4337
  "button",
3703
4338
  {
3704
4339
  onClick: () => {
@@ -3707,13 +4342,13 @@ var ChatBubble = ({
3707
4342
  },
3708
4343
  className: `flex items-center justify-center p-2 rounded transition-all ${localGlassMode && glassOpacity === "medium" ? "bg-blue-600 text-white shadow-sm" : "bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-600"}`,
3709
4344
  title: "Glass Medium",
3710
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [
3711
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("rect", { x: "8", y: "8", width: "8", height: "8", rx: "1", strokeWidth: "2" }),
3712
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("rect", { x: "10", y: "10", width: "4", height: "4", rx: "0.5", strokeWidth: "1.5" })
4345
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [
4346
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("rect", { x: "8", y: "8", width: "8", height: "8", rx: "1", strokeWidth: "2" }),
4347
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("rect", { x: "10", y: "10", width: "4", height: "4", rx: "0.5", strokeWidth: "1.5" })
3713
4348
  ] })
3714
4349
  }
3715
4350
  ),
3716
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4351
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3717
4352
  "button",
3718
4353
  {
3719
4354
  onClick: () => {
@@ -3722,15 +4357,15 @@ var ChatBubble = ({
3722
4357
  },
3723
4358
  className: `flex items-center justify-center p-2 rounded transition-all ${localGlassMode && glassOpacity === "high" ? "bg-blue-600 text-white shadow-sm" : "bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-600"}`,
3724
4359
  title: "Glass High",
3725
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [
3726
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("rect", { x: "7", y: "7", width: "10", height: "10", rx: "1", strokeWidth: "2" }),
3727
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("rect", { x: "9", y: "9", width: "6", height: "6", rx: "0.5", strokeWidth: "1.5" }),
3728
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("rect", { x: "11", y: "11", width: "2", height: "2", rx: "0.5", strokeWidth: "1" })
4360
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [
4361
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("rect", { x: "7", y: "7", width: "10", height: "10", rx: "1", strokeWidth: "2" }),
4362
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("rect", { x: "9", y: "9", width: "6", height: "6", rx: "0.5", strokeWidth: "1.5" }),
4363
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("rect", { x: "11", y: "11", width: "2", height: "2", rx: "0.5", strokeWidth: "1" })
3729
4364
  ] })
3730
4365
  }
3731
4366
  )
3732
4367
  ] }) }),
3733
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4368
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3734
4369
  "button",
3735
4370
  {
3736
4371
  onClick: () => {
@@ -3742,15 +4377,15 @@ var ChatBubble = ({
3742
4377
  },
3743
4378
  className: "w-full flex items-center space-x-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
3744
4379
  children: [
3745
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) }),
3746
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { children: [
4380
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) }),
4381
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { children: [
3747
4382
  theme === "light" ? "Dark" : "Light",
3748
4383
  " Mode"
3749
4384
  ] })
3750
4385
  ]
3751
4386
  }
3752
4387
  ),
3753
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4388
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3754
4389
  "button",
3755
4390
  {
3756
4391
  onClick: () => {
@@ -3761,15 +4396,15 @@ var ChatBubble = ({
3761
4396
  },
3762
4397
  className: "w-full flex items-center space-x-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
3763
4398
  children: [
3764
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z" }) }),
3765
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { children: [
4399
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z" }) }),
4400
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { children: [
3766
4401
  voiceEnabled ? "Disable" : "Enable",
3767
4402
  " Voice"
3768
4403
  ] })
3769
4404
  ]
3770
4405
  }
3771
4406
  ),
3772
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4407
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3773
4408
  "button",
3774
4409
  {
3775
4410
  onClick: () => {
@@ -3778,12 +4413,12 @@ var ChatBubble = ({
3778
4413
  },
3779
4414
  className: "w-full flex items-center space-x-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
3780
4415
  children: [
3781
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }),
3782
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: "Reset position" })
4416
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }),
4417
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Reset position" })
3783
4418
  ]
3784
4419
  }
3785
4420
  ),
3786
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4421
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3787
4422
  "button",
3788
4423
  {
3789
4424
  onClick: () => {
@@ -3799,12 +4434,12 @@ var ChatBubble = ({
3799
4434
  },
3800
4435
  className: "w-full flex items-center space-x-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
3801
4436
  children: [
3802
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
3803
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: "How to use" })
4437
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
4438
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "How to use" })
3804
4439
  ]
3805
4440
  }
3806
4441
  ),
3807
- onClearChat && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4442
+ onClearChat && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3808
4443
  "button",
3809
4444
  {
3810
4445
  onClick: () => {
@@ -3813,41 +4448,41 @@ var ChatBubble = ({
3813
4448
  },
3814
4449
  className: "w-full flex items-center space-x-2 px-3 py-2 text-sm text-red-600 dark:text-red-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
3815
4450
  children: [
3816
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }),
3817
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: "Clear chat" })
4451
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }),
4452
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Clear chat" })
3818
4453
  ]
3819
4454
  }
3820
4455
  )
3821
4456
  ] }),
3822
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4457
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3823
4458
  "button",
3824
4459
  {
3825
4460
  onClick: () => setIsMinimized(true),
3826
4461
  className: THEME_CLASSES.button.minimize,
3827
4462
  title: "Minimize",
3828
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20 12H4" }) })
4463
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20 12H4" }) })
3829
4464
  }
3830
4465
  ),
3831
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4466
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3832
4467
  "button",
3833
4468
  {
3834
4469
  onClick: handleToggle,
3835
4470
  className: THEME_CLASSES.button.close,
3836
4471
  title: "Close",
3837
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
4472
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
3838
4473
  }
3839
4474
  )
3840
4475
  ] })
3841
4476
  ]
3842
4477
  }
3843
4478
  ),
3844
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex-1 overflow-y-auto p-4 space-y-2", children: [
3845
- showWelcome && messages.length === 0 && config.welcome?.enabled && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: THEME_CLASSES.welcome.container, children: [
3846
- config.welcome.title && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h4", { className: THEME_CLASSES.welcome.title, style: INLINE_STYLES.welcomeTitle(theme === "dark"), children: config.welcome.title }),
3847
- config.welcome.content && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: THEME_CLASSES.welcome.content, style: INLINE_STYLES.welcomeContent(theme === "dark"), children: config.welcome.content }),
3848
- config.welcome.suggestedCommands && config.welcome.suggestedCommands.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: THEME_CLASSES.welcome.commandsContainer, children: [
3849
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: THEME_CLASSES.welcome.commandsHeader, children: "Try these commands:" }),
3850
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "space-y-1", children: config.welcome.suggestedCommands.map((cmd, idx) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4479
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex-1 overflow-y-auto p-4 space-y-2", "data-testid": "chat-messages", children: [
4480
+ showWelcome && messages.length === 0 && config.welcome?.enabled && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: THEME_CLASSES.welcome.container, children: [
4481
+ config.welcome.title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h4", { className: THEME_CLASSES.welcome.title, style: INLINE_STYLES.welcomeTitle(theme === "dark"), children: config.welcome.title }),
4482
+ config.welcome.content && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: THEME_CLASSES.welcome.content, style: INLINE_STYLES.welcomeContent(theme === "dark"), children: config.welcome.content }),
4483
+ config.welcome.suggestedCommands && config.welcome.suggestedCommands.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: THEME_CLASSES.welcome.commandsContainer, children: [
4484
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: THEME_CLASSES.welcome.commandsHeader, children: "Try these commands:" }),
4485
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "space-y-1", children: config.welcome.suggestedCommands.map((cmd, idx) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3851
4486
  "button",
3852
4487
  {
3853
4488
  onClick: () => {
@@ -3857,29 +4492,29 @@ var ChatBubble = ({
3857
4492
  },
3858
4493
  className: THEME_CLASSES.welcome.commandButton,
3859
4494
  children: [
3860
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: THEME_CLASSES.welcome.commandText, style: INLINE_STYLES.commandText(theme === "dark"), children: [
4495
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: THEME_CLASSES.welcome.commandText, style: INLINE_STYLES.commandText(theme === "dark"), children: [
3861
4496
  '"',
3862
4497
  cmd.text,
3863
4498
  '"'
3864
4499
  ] }),
3865
- cmd.desc && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: THEME_CLASSES.welcome.commandDesc, style: INLINE_STYLES.commandDesc(theme === "dark"), children: cmd.desc })
4500
+ cmd.desc && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: THEME_CLASSES.welcome.commandDesc, style: INLINE_STYLES.commandDesc(theme === "dark"), children: cmd.desc })
3866
4501
  ]
3867
4502
  },
3868
4503
  idx
3869
4504
  )) })
3870
4505
  ] })
3871
4506
  ] }),
3872
- messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `group flex items-center gap-2 mb-2 ${message.type === "user" ? "flex-row-reverse" : "flex-row"}`, children: [
3873
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4507
+ messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `group flex items-center gap-2 mb-2 ${message.type === "user" ? "flex-row-reverse" : "flex-row"}`, children: [
4508
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3874
4509
  "div",
3875
4510
  {
3876
4511
  className: `inline-block px-4 py-2.5 rounded-2xl max-w-[80%] text-sm shadow-sm transition-all ${message.type === "user" ? THEME_CLASSES.message.user : message.type === "ai" ? THEME_CLASSES.message.ai : THEME_CLASSES.message.system}`,
3877
4512
  style: message.type === "user" ? INLINE_STYLES.messageUser() : message.type === "ai" ? INLINE_STYLES.messageAI(theme === "dark") : INLINE_STYLES.messageSystem(theme === "dark"),
3878
4513
  "data-testid": `chat-message-${message.type}`,
3879
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MessageRenderer, { content: message.text, theme })
4514
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MessageRenderer, { content: message.text, theme })
3880
4515
  }
3881
4516
  ),
3882
- message.type === "ai" && voiceEnabled && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4517
+ message.type === "ai" && voiceEnabled && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3883
4518
  TTSButton,
3884
4519
  {
3885
4520
  text: message.text,
@@ -3889,7 +4524,7 @@ var ChatBubble = ({
3889
4524
  size: "small"
3890
4525
  }
3891
4526
  ),
3892
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4527
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3893
4528
  "div",
3894
4529
  {
3895
4530
  className: `text-xs opacity-0 group-hover:opacity-70 transition-opacity whitespace-nowrap flex-shrink-0 ${message.type === "user" ? "text-gray-400 dark:text-gray-500 text-left" : "text-gray-600 dark:text-gray-400 text-right"}`,
@@ -3898,10 +4533,10 @@ var ChatBubble = ({
3898
4533
  }
3899
4534
  )
3900
4535
  ] }, message.id)),
3901
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { ref: messagesEndRef })
4536
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { ref: messagesEndRef })
3902
4537
  ] }),
3903
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { position: "relative" }, children: [
3904
- slashCommand.isOpen && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4538
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { position: "relative" }, children: [
4539
+ slashCommand.isOpen && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3905
4540
  SlashCommandPopup,
3906
4541
  {
3907
4542
  tools: slashCommand.filteredTools,
@@ -3910,7 +4545,7 @@ var ChatBubble = ({
3910
4545
  onClose: () => setInputValue("")
3911
4546
  }
3912
4547
  ),
3913
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4548
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3914
4549
  InputField,
3915
4550
  {
3916
4551
  inputValue,
@@ -3932,7 +4567,7 @@ var ChatBubble = ({
3932
4567
  ]
3933
4568
  }
3934
4569
  ),
3935
- !isExpanded && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4570
+ !isExpanded && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3936
4571
  "button",
3937
4572
  {
3938
4573
  onClick: handleToggle,
@@ -3940,8 +4575,8 @@ var ChatBubble = ({
3940
4575
  "data-testid": ChatNames.bubble,
3941
4576
  title: `Open chat (press ${isMac ? "Cmd" : "Ctrl"}+/ for voice recording)`,
3942
4577
  children: [
3943
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("img", { src: config.logo, alt: "Supernal", className: "w-8 h-8" }),
3944
- hasUnread && notifications && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "absolute -top-1 -right-1 w-5 h-5 bg-red-500 rounded-full flex items-center justify-center animate-pulse shadow-lg", "data-testid": "unread-indicator", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "text-xs text-white font-bold", children: unreadCount > 9 ? "9+" : unreadCount }) })
4578
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src: config.logo, alt: "Supernal", className: "w-8 h-8" }),
4579
+ hasUnread && notifications && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute -top-1 -right-1 w-5 h-5 bg-red-500 rounded-full flex items-center justify-center animate-pulse shadow-lg", "data-testid": "unread-indicator", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-xs text-white font-bold", children: unreadCount > 9 ? "9+" : unreadCount }) })
3945
4580
  ]
3946
4581
  }
3947
4582
  )
@@ -3951,31 +4586,31 @@ var ChatBubble = ({
3951
4586
  };
3952
4587
 
3953
4588
  // src/components/AutoNavigationContext.tsx
3954
- var import_react13 = require("react");
4589
+ var import_react15 = require("react");
3955
4590
 
3956
4591
  // src/hooks/useNavigationGraph.tsx
3957
- var import_react12 = require("react");
3958
- var import_browser3 = require("@supernal/interface/browser");
3959
- var import_jsx_runtime13 = require("react/jsx-runtime");
3960
- var NavigationContextContext = (0, import_react12.createContext)("global");
4592
+ var import_react14 = require("react");
4593
+ var import_browser4 = require("@supernal/interface/browser");
4594
+ var import_jsx_runtime14 = require("react/jsx-runtime");
4595
+ var NavigationContextContext = (0, import_react14.createContext)("global");
3961
4596
  function NavigationContextProvider({
3962
4597
  value,
3963
4598
  children
3964
4599
  }) {
3965
4600
  const graph = useNavigationGraph();
3966
- (0, import_react12.useEffect)(() => {
4601
+ (0, import_react14.useEffect)(() => {
3967
4602
  graph.setCurrentContext(value);
3968
4603
  }, [value, graph]);
3969
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(NavigationContextContext.Provider, { value, children });
4604
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(NavigationContextContext.Provider, { value, children });
3970
4605
  }
3971
4606
  function useNavigationGraph() {
3972
- return import_browser3.NavigationGraph.getInstance();
4607
+ return import_browser4.NavigationGraph.getInstance();
3973
4608
  }
3974
4609
  function useCurrentContext() {
3975
- const contextFromProvider = (0, import_react12.useContext)(NavigationContextContext);
4610
+ const contextFromProvider = (0, import_react14.useContext)(NavigationContextContext);
3976
4611
  const graph = useNavigationGraph();
3977
- const [graphContext, setGraphContext] = (0, import_react12.useState)("");
3978
- (0, import_react12.useEffect)(() => {
4612
+ const [graphContext, setGraphContext] = (0, import_react14.useState)("");
4613
+ (0, import_react14.useEffect)(() => {
3979
4614
  const interval = setInterval(() => {
3980
4615
  const current = graph.getCurrentContext?.() || "";
3981
4616
  if (current !== graphContext) {
@@ -3989,7 +4624,7 @@ function useCurrentContext() {
3989
4624
  function useRegisterTool(toolId, contextId, metadata) {
3990
4625
  const graph = useNavigationGraph();
3991
4626
  const currentContext = useCurrentContext();
3992
- (0, import_react12.useEffect)(() => {
4627
+ (0, import_react14.useEffect)(() => {
3993
4628
  let targetContext = contextId || currentContext;
3994
4629
  if (!contextId && metadata) {
3995
4630
  const detection = graph.detectToolContext?.(toolId, metadata);
@@ -4003,10 +4638,10 @@ function useRegisterTool(toolId, contextId, metadata) {
4003
4638
  function useNavigationPath(targetContextOrToolId, isToolId = false) {
4004
4639
  const graph = useNavigationGraph();
4005
4640
  const currentContext = useCurrentContext();
4006
- const [path, setPath] = (0, import_react12.useState)(null);
4007
- const [loading, setLoading] = (0, import_react12.useState)(true);
4008
- const [error, setError] = (0, import_react12.useState)();
4009
- (0, import_react12.useEffect)(() => {
4641
+ const [path, setPath] = (0, import_react14.useState)(null);
4642
+ const [loading, setLoading] = (0, import_react14.useState)(true);
4643
+ const [error, setError] = (0, import_react14.useState)();
4644
+ (0, import_react14.useEffect)(() => {
4010
4645
  try {
4011
4646
  let targetContext = targetContextOrToolId;
4012
4647
  if (isToolId) {
@@ -4034,9 +4669,9 @@ function useNavigationPath(targetContextOrToolId, isToolId = false) {
4034
4669
  function useNavigate() {
4035
4670
  const graph = useNavigationGraph();
4036
4671
  const currentContext = useCurrentContext();
4037
- const [navigating, setNavigating] = (0, import_react12.useState)(false);
4038
- const [error, setError] = (0, import_react12.useState)();
4039
- const navigateTo = (0, import_react12.useCallback)(async (targetContextOrToolId, isToolId = false, executeNavigation) => {
4672
+ const [navigating, setNavigating] = (0, import_react14.useState)(false);
4673
+ const [error, setError] = (0, import_react14.useState)();
4674
+ const navigateTo = (0, import_react14.useCallback)(async (targetContextOrToolId, isToolId = false, executeNavigation) => {
4040
4675
  setNavigating(true);
4041
4676
  setError(void 0);
4042
4677
  try {
@@ -4078,8 +4713,8 @@ function useNavigate() {
4078
4713
  }
4079
4714
  function useAllContexts() {
4080
4715
  const graph = useNavigationGraph();
4081
- const [contexts, setContexts] = (0, import_react12.useState)(graph.getAllContexts?.());
4082
- (0, import_react12.useEffect)(() => {
4716
+ const [contexts, setContexts] = (0, import_react14.useState)(graph.getAllContexts?.());
4717
+ (0, import_react14.useEffect)(() => {
4083
4718
  const interval = setInterval(() => {
4084
4719
  setContexts(graph.getAllContexts?.());
4085
4720
  }, 1e3);
@@ -4089,28 +4724,28 @@ function useAllContexts() {
4089
4724
  }
4090
4725
 
4091
4726
  // src/components/AutoNavigationContext.tsx
4092
- var import_jsx_runtime14 = require("react/jsx-runtime");
4727
+ var import_jsx_runtime15 = require("react/jsx-runtime");
4093
4728
  function AutoNavigationContext({
4094
4729
  children,
4095
4730
  routes,
4096
4731
  onNavigate
4097
4732
  }) {
4098
- const [pathname, setPathname] = (0, import_react13.useState)("/");
4099
- (0, import_react13.useEffect)(() => {
4733
+ const [pathname, setPathname] = (0, import_react15.useState)("/");
4734
+ (0, import_react15.useEffect)(() => {
4100
4735
  if (typeof window !== "undefined") {
4101
4736
  setPathname(window.location.pathname);
4102
4737
  }
4103
4738
  }, []);
4104
4739
  const context = routes ? inferContextFromPath(pathname, routes) : null;
4105
- (0, import_react13.useEffect)(() => {
4740
+ (0, import_react15.useEffect)(() => {
4106
4741
  if (onNavigate && context) {
4107
4742
  onNavigate(context);
4108
4743
  }
4109
4744
  }, [context, onNavigate]);
4110
4745
  if (!context) {
4111
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children });
4746
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
4112
4747
  }
4113
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(NavigationContextProvider, { value: context, children });
4748
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(NavigationContextProvider, { value: context, children });
4114
4749
  }
4115
4750
  function inferContextFromPath(path, customRoutes) {
4116
4751
  if (customRoutes) {
@@ -4140,11 +4775,11 @@ function inferContextFromPath(path, customRoutes) {
4140
4775
  }
4141
4776
 
4142
4777
  // src/components/SupernalProvider.tsx
4143
- var import_browser6 = require("@supernal/interface/browser");
4778
+ var import_browser7 = require("@supernal/interface/browser");
4144
4779
 
4145
4780
  // src/hooks/useLocationTracking.ts
4146
- var import_react14 = require("react");
4147
- var import_browser4 = require("@supernal/interface/browser");
4781
+ var import_react16 = require("react");
4782
+ var import_browser5 = require("@supernal/interface/browser");
4148
4783
  var usePathname;
4149
4784
  var useSearchParams;
4150
4785
  try {
@@ -4175,8 +4810,8 @@ function getCurrentLocation() {
4175
4810
  };
4176
4811
  }
4177
4812
  function useLocationTracking() {
4178
- const lastLocationRef = (0, import_react14.useRef)("");
4179
- const lastElementsRef = (0, import_react14.useRef)([]);
4813
+ const lastLocationRef = (0, import_react16.useRef)("");
4814
+ const lastElementsRef = (0, import_react16.useRef)([]);
4180
4815
  let pathname = null;
4181
4816
  let searchParams = null;
4182
4817
  try {
@@ -4188,14 +4823,14 @@ function useLocationTracking() {
4188
4823
  }
4189
4824
  } catch {
4190
4825
  }
4191
- (0, import_react14.useEffect)(() => {
4826
+ (0, import_react16.useEffect)(() => {
4192
4827
  const updateLocation = () => {
4193
4828
  const location = pathname !== null ? { pathname, search: searchParams?.toString() || "", asPath: pathname + (searchParams?.toString() ? `?${searchParams.toString()}` : "") } : getCurrentLocation();
4194
4829
  const visibleElements = getVisibleElements();
4195
4830
  const locationChanged = lastLocationRef.current !== location.pathname;
4196
4831
  const elementsChanged = !arraysEqual(lastElementsRef.current, visibleElements);
4197
4832
  if (locationChanged || elementsChanged) {
4198
- import_browser4.LocationContext.setCurrent({
4833
+ import_browser5.LocationContext.setCurrent({
4199
4834
  page: location.pathname,
4200
4835
  route: location.pathname,
4201
4836
  elements: visibleElements,
@@ -4229,7 +4864,7 @@ function useLocationTracking() {
4229
4864
  }
4230
4865
 
4231
4866
  // src/hooks/useNavigationGraphSetup.ts
4232
- var import_react15 = require("react");
4867
+ var import_react17 = require("react");
4233
4868
  var useAppRouter;
4234
4869
  var usePathname2;
4235
4870
  try {
@@ -4239,7 +4874,7 @@ try {
4239
4874
  } catch {
4240
4875
  }
4241
4876
  function useNavigationGraphSetup() {
4242
- const [isInitialized, setIsInitialized] = (0, import_react15.useState)(false);
4877
+ const [isInitialized, setIsInitialized] = (0, import_react17.useState)(false);
4243
4878
  let router = null;
4244
4879
  let pathname = null;
4245
4880
  try {
@@ -4251,7 +4886,7 @@ function useNavigationGraphSetup() {
4251
4886
  }
4252
4887
  } catch {
4253
4888
  }
4254
- const navigate = (0, import_react15.useCallback)((path) => {
4889
+ const navigate = (0, import_react17.useCallback)((path) => {
4255
4890
  const normalizedPath = path.startsWith("/") ? path : `/${path}`;
4256
4891
  if (router?.push) {
4257
4892
  router.push(normalizedPath);
@@ -4260,7 +4895,7 @@ function useNavigationGraphSetup() {
4260
4895
  }
4261
4896
  }, [router]);
4262
4897
  const currentPath = pathname ?? (typeof window !== "undefined" ? window.location.pathname + window.location.search : "/");
4263
- (0, import_react15.useEffect)(() => {
4898
+ (0, import_react17.useEffect)(() => {
4264
4899
  import("@supernal/interface/browser").then(({ NavigationGraph: NavigationGraph2 }) => {
4265
4900
  const graph = NavigationGraph2.getInstance();
4266
4901
  graph.setNavigationHandler(navigate);
@@ -4276,7 +4911,7 @@ function useNavigationGraphSetup() {
4276
4911
  console.log("[NavigationGraphSetup] Auto-configured with Next.js router");
4277
4912
  });
4278
4913
  }, [navigate, currentPath]);
4279
- (0, import_react15.useEffect)(() => {
4914
+ (0, import_react17.useEffect)(() => {
4280
4915
  if (!isInitialized) return;
4281
4916
  import("@supernal/interface/browser").then(({ NavigationGraph: NavigationGraph2 }) => {
4282
4917
  const graph = NavigationGraph2.getInstance();
@@ -4287,8 +4922,8 @@ function useNavigationGraphSetup() {
4287
4922
  }
4288
4923
 
4289
4924
  // src/components/ToolMenuPopup/ToolMenuPopup.tsx
4290
- var import_react16 = require("react");
4291
- var import_jsx_runtime15 = require("react/jsx-runtime");
4925
+ var import_react18 = require("react");
4926
+ var import_jsx_runtime16 = require("react/jsx-runtime");
4292
4927
  var ToolMenuPopup = ({
4293
4928
  isOpen,
4294
4929
  onClose,
@@ -4296,16 +4931,16 @@ var ToolMenuPopup = ({
4296
4931
  totalTools,
4297
4932
  contextLabel
4298
4933
  }) => {
4299
- const [collapsedCategories, setCollapsedCategories] = (0, import_react16.useState)(/* @__PURE__ */ new Set());
4300
- const [isHydrated, setIsHydrated] = (0, import_react16.useState)(false);
4301
- const [isMobile, setIsMobile] = (0, import_react16.useState)(false);
4302
- const popupRef = (0, import_react16.useRef)(null);
4934
+ const [collapsedCategories, setCollapsedCategories] = (0, import_react18.useState)(/* @__PURE__ */ new Set());
4935
+ const [isHydrated, setIsHydrated] = (0, import_react18.useState)(false);
4936
+ const [isMobile, setIsMobile] = (0, import_react18.useState)(false);
4937
+ const popupRef = (0, import_react18.useRef)(null);
4303
4938
  const { insertText } = useChatInput();
4304
- (0, import_react16.useEffect)(() => {
4939
+ (0, import_react18.useEffect)(() => {
4305
4940
  setIsHydrated(true);
4306
4941
  setIsMobile(window.matchMedia("(max-width: 767px)").matches);
4307
4942
  }, []);
4308
- (0, import_react16.useEffect)(() => {
4943
+ (0, import_react18.useEffect)(() => {
4309
4944
  if (!isOpen) return;
4310
4945
  const handleClickOutside = (e) => {
4311
4946
  const target = e.target;
@@ -4316,7 +4951,7 @@ var ToolMenuPopup = ({
4316
4951
  document.addEventListener("mousedown", handleClickOutside);
4317
4952
  return () => document.removeEventListener("mousedown", handleClickOutside);
4318
4953
  }, [isOpen, onClose]);
4319
- (0, import_react16.useEffect)(() => {
4954
+ (0, import_react18.useEffect)(() => {
4320
4955
  if (!isOpen) return;
4321
4956
  const handleKey = (e) => {
4322
4957
  if (e.key === "Escape") {
@@ -4364,23 +4999,23 @@ var ToolMenuPopup = ({
4364
4999
  maxHeight: "70vh",
4365
5000
  borderRadius: 16
4366
5001
  };
4367
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
5002
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
4368
5003
  "div",
4369
5004
  {
4370
5005
  ref: popupRef,
4371
5006
  "data-tool-menu": true,
4372
5007
  style: { ...glassStyle, ...positionStyle, overflowY: "auto" },
4373
5008
  children: [
4374
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: {
5009
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: {
4375
5010
  padding: "16px 20px",
4376
5011
  borderBottom: "1px solid rgba(255, 255, 255, 0.1)",
4377
5012
  display: "flex",
4378
5013
  justifyContent: "space-between",
4379
5014
  alignItems: "center"
4380
5015
  }, children: [
4381
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
4382
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h3", { style: { margin: 0, color: "#fff", fontSize: 16, fontWeight: 600 }, children: "Available Actions" }),
4383
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("p", { style: { margin: "4px 0 0", color: "rgba(255,255,255,0.6)", fontSize: 12 }, children: [
5016
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
5017
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h3", { style: { margin: 0, color: "#fff", fontSize: 16, fontWeight: 600 }, children: "Available Actions" }),
5018
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("p", { style: { margin: "4px 0 0", color: "rgba(255,255,255,0.6)", fontSize: 12 }, children: [
4384
5019
  contextLabel,
4385
5020
  " \xB7 ",
4386
5021
  totalTools,
@@ -4388,7 +5023,7 @@ var ToolMenuPopup = ({
4388
5023
  totalTools !== 1 ? "s" : ""
4389
5024
  ] })
4390
5025
  ] }),
4391
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5026
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4392
5027
  "button",
4393
5028
  {
4394
5029
  onClick: onClose,
@@ -4406,12 +5041,12 @@ var ToolMenuPopup = ({
4406
5041
  }
4407
5042
  )
4408
5043
  ] }),
4409
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { padding: "8px 12px 16px" }, children: [
4410
- categories.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { style: { color: "rgba(255,255,255,0.5)", textAlign: "center", padding: "24px 0", fontSize: 14 }, children: "No tools available on this page." }),
5044
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { padding: "8px 12px 16px" }, children: [
5045
+ categories.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: { color: "rgba(255,255,255,0.5)", textAlign: "center", padding: "24px 0", fontSize: 14 }, children: "No tools available on this page." }),
4411
5046
  categories.map((category) => {
4412
5047
  const isCollapsed = collapsedCategories.has(category.key);
4413
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { marginBottom: 4 }, children: [
4414
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
5048
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { marginBottom: 4 }, children: [
5049
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
4415
5050
  "button",
4416
5051
  {
4417
5052
  onClick: () => toggleCategory(category.key),
@@ -4435,15 +5070,15 @@ var ToolMenuPopup = ({
4435
5070
  e.currentTarget.style.background = "none";
4436
5071
  },
4437
5072
  children: [
4438
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { style: { fontSize: 14, fontWeight: 500 }, children: [
5073
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { style: { fontSize: 14, fontWeight: 500 }, children: [
4439
5074
  category.displayName,
4440
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: { color: "rgba(255,255,255,0.4)", fontWeight: 400, marginLeft: 8, fontSize: 12 }, children: category.tools.length })
5075
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { color: "rgba(255,255,255,0.4)", fontWeight: 400, marginLeft: 8, fontSize: 12 }, children: category.tools.length })
4441
5076
  ] }),
4442
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: { color: "rgba(255,255,255,0.4)", fontSize: 12 }, children: isCollapsed ? "\u25B6" : "\u25BC" })
5077
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { color: "rgba(255,255,255,0.4)", fontSize: 12 }, children: isCollapsed ? "\u25B6" : "\u25BC" })
4443
5078
  ]
4444
5079
  }
4445
5080
  ),
4446
- !isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { paddingLeft: 8, paddingRight: 8 }, children: category.tools.map((tool, idx) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
5081
+ !isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { paddingLeft: 8, paddingRight: 8 }, children: category.tools.map((tool, idx) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
4447
5082
  "button",
4448
5083
  {
4449
5084
  onClick: () => handleToolClick(tool),
@@ -4466,8 +5101,8 @@ var ToolMenuPopup = ({
4466
5101
  e.currentTarget.style.background = "none";
4467
5102
  },
4468
5103
  children: [
4469
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { fontSize: 13, fontWeight: 500 }, children: tool.name }),
4470
- tool.description && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: {
5104
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { fontSize: 13, fontWeight: 500 }, children: tool.name }),
5105
+ tool.description && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: {
4471
5106
  fontSize: 11,
4472
5107
  color: "rgba(255,255,255,0.5)",
4473
5108
  marginTop: 2,
@@ -4483,7 +5118,7 @@ var ToolMenuPopup = ({
4483
5118
  ] }, category.key);
4484
5119
  })
4485
5120
  ] }),
4486
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: {
5121
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: {
4487
5122
  padding: "10px 20px",
4488
5123
  borderTop: "1px solid rgba(255, 255, 255, 0.08)",
4489
5124
  textAlign: "center",
@@ -4491,14 +5126,14 @@ var ToolMenuPopup = ({
4491
5126
  fontSize: 11
4492
5127
  }, children: [
4493
5128
  "Click a tool to insert its command \xB7 Type ",
4494
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("kbd", { style: {
5129
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("kbd", { style: {
4495
5130
  padding: "1px 4px",
4496
5131
  borderRadius: 3,
4497
5132
  border: "1px solid rgba(255,255,255,0.2)",
4498
5133
  fontSize: 10
4499
5134
  }, children: "/" }),
4500
5135
  " in chat for quick commands \xB7 ",
4501
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("kbd", { style: {
5136
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("kbd", { style: {
4502
5137
  padding: "1px 4px",
4503
5138
  borderRadius: 3,
4504
5139
  border: "1px solid rgba(255,255,255,0.2)",
@@ -4512,11 +5147,11 @@ var ToolMenuPopup = ({
4512
5147
  };
4513
5148
 
4514
5149
  // src/components/ToolMenuPopup/ToolMenuPopupTrigger.tsx
4515
- var import_react18 = require("react");
5150
+ var import_react20 = require("react");
4516
5151
 
4517
5152
  // src/components/ToolMenuPopup/useToolMenu.ts
4518
- var import_react17 = require("react");
4519
- var import_browser5 = require("@supernal/interface/browser");
5153
+ var import_react19 = require("react");
5154
+ var import_browser6 = require("@supernal/interface/browser");
4520
5155
  var CATEGORY_DISPLAY = {
4521
5156
  navigation: "Navigation",
4522
5157
  user_interaction: "Controls",
@@ -4536,15 +5171,15 @@ var CATEGORY_DISPLAY = {
4536
5171
  workflow: "Workflow"
4537
5172
  };
4538
5173
  function useToolMenu() {
4539
- const [isOpen, setIsOpen] = (0, import_react17.useState)(false);
4540
- const open = (0, import_react17.useCallback)(() => setIsOpen(true), []);
4541
- const close = (0, import_react17.useCallback)(() => setIsOpen(false), []);
4542
- const toggle = (0, import_react17.useCallback)(() => setIsOpen((prev) => !prev), []);
4543
- const { categories, totalTools, contextLabel } = (0, import_react17.useMemo)(() => {
5174
+ const [isOpen, setIsOpen] = (0, import_react19.useState)(false);
5175
+ const open = (0, import_react19.useCallback)(() => setIsOpen(true), []);
5176
+ const close = (0, import_react19.useCallback)(() => setIsOpen(false), []);
5177
+ const toggle = (0, import_react19.useCallback)(() => setIsOpen((prev) => !prev), []);
5178
+ const { categories, totalTools, contextLabel } = (0, import_react19.useMemo)(() => {
4544
5179
  if (!isOpen) {
4545
5180
  return { categories: [], totalTools: 0, contextLabel: "" };
4546
5181
  }
4547
- const tools = import_browser5.ToolRegistry.getToolsByLocation();
5182
+ const tools = import_browser6.ToolRegistry.getToolsByLocation();
4548
5183
  const aiTools = tools.filter((t) => t.aiEnabled);
4549
5184
  const grouped = {};
4550
5185
  for (const tool of aiTools) {
@@ -4572,10 +5207,10 @@ function useToolMenu() {
4572
5207
  }
4573
5208
 
4574
5209
  // src/components/ToolMenuPopup/ToolMenuPopupTrigger.tsx
4575
- var import_jsx_runtime16 = require("react/jsx-runtime");
5210
+ var import_jsx_runtime17 = require("react/jsx-runtime");
4576
5211
  var ToolMenuPopupTrigger = () => {
4577
5212
  const toolMenu = useToolMenu();
4578
- (0, import_react18.useEffect)(() => {
5213
+ (0, import_react20.useEffect)(() => {
4579
5214
  const handleKeyDown = (e) => {
4580
5215
  if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key === "/") {
4581
5216
  e.preventDefault();
@@ -4614,7 +5249,7 @@ var ToolMenuPopupTrigger = () => {
4614
5249
  return () => document.removeEventListener("keydown", handleKeyDown);
4615
5250
  }, [toolMenu]);
4616
5251
  if (!toolMenu.isOpen) return null;
4617
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5252
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4618
5253
  ToolMenuPopup,
4619
5254
  {
4620
5255
  isOpen: toolMenu.isOpen,
@@ -4627,7 +5262,7 @@ var ToolMenuPopupTrigger = () => {
4627
5262
  };
4628
5263
 
4629
5264
  // src/components/SupernalProvider.tsx
4630
- var import_jsx_runtime17 = require("react/jsx-runtime");
5265
+ var import_jsx_runtime18 = require("react/jsx-runtime");
4631
5266
  function ChatBubbleConnector({
4632
5267
  theme,
4633
5268
  position,
@@ -4644,7 +5279,7 @@ function ChatBubbleConnector({
4644
5279
  glassMode,
4645
5280
  ...logo ? { logo } : {}
4646
5281
  };
4647
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5282
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4648
5283
  ChatBubble,
4649
5284
  {
4650
5285
  messages,
@@ -4683,12 +5318,12 @@ function SupernalProvider({
4683
5318
  console.log("[SupernalProvider] variant:", variant, "effectiveDisplayMode:", effectiveDisplayMode);
4684
5319
  useLocationTracking();
4685
5320
  useNavigationGraphSetup();
4686
- (0, import_react19.useEffect)(() => {
5321
+ (0, import_react21.useEffect)(() => {
4687
5322
  if (typeof window === "undefined") return;
4688
- const collector = import_browser6.ExposureCollector.getInstance();
5323
+ const collector = import_browser7.ExposureCollector.getInstance();
4689
5324
  const registeredToolIds = /* @__PURE__ */ new Set();
4690
5325
  const registerTools = () => {
4691
- const allTools = import_browser6.ToolRegistry.getAllTools();
5326
+ const allTools = import_browser7.ToolRegistry.getAllTools();
4692
5327
  allTools.forEach((tool) => {
4693
5328
  if (tool.elementId && !registeredToolIds.has(tool.toolId)) {
4694
5329
  const element = document.querySelector(`[data-testid="${tool.elementId}"]`);
@@ -4715,9 +5350,9 @@ function SupernalProvider({
4715
5350
  collector.destroy();
4716
5351
  };
4717
5352
  }, []);
4718
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ChatInputProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(ChatProvider, { mode, apiKey, onToolExecute, children: [
4719
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(AutoNavigationContext, { routes, onNavigate, children }),
4720
- shouldRenderChatBubble ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5353
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ApiKeyProvider, { initialApiKey: apiKey, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ChatInputProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(ChatProvider, { mode, apiKey, onToolExecute, children: [
5354
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AutoNavigationContext, { routes, onNavigate, children }),
5355
+ shouldRenderChatBubble ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4721
5356
  ChatBubbleConnector,
4722
5357
  {
4723
5358
  theme,
@@ -4730,26 +5365,26 @@ function SupernalProvider({
4730
5365
  drawerSide
4731
5366
  }
4732
5367
  ) : null,
4733
- !disabled && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ToolMenuPopupTrigger, {})
4734
- ] }) });
5368
+ !disabled && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ToolMenuPopupTrigger, {})
5369
+ ] }) }) });
4735
5370
  }
4736
5371
 
4737
5372
  // src/components/ChatBubbleSettingsModal.tsx
4738
- var import_react20 = __toESM(require("react"));
4739
- var import_jsx_runtime18 = require("react/jsx-runtime");
5373
+ var import_react22 = __toESM(require("react"));
5374
+ var import_jsx_runtime19 = require("react/jsx-runtime");
4740
5375
  function ChatBubbleSettingsModal({
4741
5376
  isOpen,
4742
5377
  onClose,
4743
5378
  settings,
4744
5379
  onSettingsChange
4745
5380
  }) {
4746
- const [localSettings, setLocalSettings] = import_react20.default.useState(settings);
4747
- (0, import_react20.useEffect)(() => {
5381
+ const [localSettings, setLocalSettings] = import_react22.default.useState(settings);
5382
+ (0, import_react22.useEffect)(() => {
4748
5383
  if (isOpen) {
4749
5384
  setLocalSettings(settings);
4750
5385
  }
4751
5386
  }, [isOpen, settings]);
4752
- (0, import_react20.useEffect)(() => {
5387
+ (0, import_react22.useEffect)(() => {
4753
5388
  const handleEscape = (e) => {
4754
5389
  if (e.key === "Escape" && isOpen) {
4755
5390
  onClose();
@@ -4770,8 +5405,8 @@ function ChatBubbleSettingsModal({
4770
5405
  onClose();
4771
5406
  };
4772
5407
  const isDark = localSettings.theme === "dark";
4773
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4774
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5408
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
5409
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4775
5410
  "div",
4776
5411
  {
4777
5412
  className: "fixed inset-0 bg-black bg-opacity-50 z-[60] backdrop-blur-sm",
@@ -4779,12 +5414,12 @@ function ChatBubbleSettingsModal({
4779
5414
  "aria-hidden": "true"
4780
5415
  }
4781
5416
  ),
4782
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5417
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4783
5418
  "div",
4784
5419
  {
4785
5420
  className: "fixed inset-0 z-[70] flex items-center justify-center p-4",
4786
5421
  "data-testid": "chat-settings-modal",
4787
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5422
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4788
5423
  "div",
4789
5424
  {
4790
5425
  className: `${isDark ? "bg-gray-800 text-white" : "bg-white text-gray-900"} rounded-2xl shadow-2xl max-w-md w-full p-6 border ${isDark ? "border-gray-700" : "border-gray-200"}`,
@@ -4793,8 +5428,8 @@ function ChatBubbleSettingsModal({
4793
5428
  "aria-labelledby": "settings-modal-title",
4794
5429
  onClick: (e) => e.stopPropagation(),
4795
5430
  children: [
4796
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center justify-between mb-6", children: [
4797
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5431
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between mb-6", children: [
5432
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4798
5433
  "h2",
4799
5434
  {
4800
5435
  id: "settings-modal-title",
@@ -4802,56 +5437,56 @@ function ChatBubbleSettingsModal({
4802
5437
  children: "Chat Settings"
4803
5438
  }
4804
5439
  ),
4805
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5440
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4806
5441
  "button",
4807
5442
  {
4808
5443
  onClick: handleCancel,
4809
5444
  className: `${isDark ? "text-gray-400 hover:text-gray-200" : "text-gray-400 hover:text-gray-600"} transition-colors p-1 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700`,
4810
5445
  "aria-label": "Close modal",
4811
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { className: "w-6 h-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
5446
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { className: "w-6 h-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
4812
5447
  }
4813
5448
  )
4814
5449
  ] }),
4815
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "space-y-5 mb-6", children: [
4816
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center justify-between", children: [
4817
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
4818
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("label", { className: "block text-base font-medium mb-1", children: "Theme" }),
4819
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Switch between light and dark modes" })
5450
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "space-y-5 mb-6", children: [
5451
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between", children: [
5452
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
5453
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "block text-base font-medium mb-1", children: "Theme" }),
5454
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Switch between light and dark modes" })
4820
5455
  ] }),
4821
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center space-x-2", children: [
4822
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5456
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center space-x-2", children: [
5457
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4823
5458
  "button",
4824
5459
  {
4825
5460
  onClick: () => setLocalSettings({ ...localSettings, theme: "light" }),
4826
5461
  className: `p-2 rounded-lg transition-all ${localSettings.theme === "light" ? "bg-blue-600 text-white shadow-lg" : isDark ? "bg-gray-700 text-gray-300 hover:bg-gray-600" : "bg-gray-100 text-gray-600 hover:bg-gray-200"}`,
4827
5462
  title: "Light mode",
4828
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) })
5463
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) })
4829
5464
  }
4830
5465
  ),
4831
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5466
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4832
5467
  "button",
4833
5468
  {
4834
5469
  onClick: () => setLocalSettings({ ...localSettings, theme: "dark" }),
4835
5470
  className: `p-2 rounded-lg transition-all ${localSettings.theme === "dark" ? "bg-blue-600 text-white shadow-lg" : isDark ? "bg-gray-700 text-gray-300 hover:bg-gray-600" : "bg-gray-100 text-gray-600 hover:bg-gray-200"}`,
4836
5471
  title: "Dark mode",
4837
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) })
5472
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) })
4838
5473
  }
4839
5474
  )
4840
5475
  ] })
4841
5476
  ] }),
4842
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center justify-between", children: [
4843
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
4844
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("label", { className: "block text-base font-medium mb-1", children: "Glass Mode" }),
4845
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Enable glassmorphism transparency effect" })
5477
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between", children: [
5478
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
5479
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "block text-base font-medium mb-1", children: "Glass Mode" }),
5480
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Enable glassmorphism transparency effect" })
4846
5481
  ] }),
4847
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5482
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4848
5483
  "button",
4849
5484
  {
4850
5485
  onClick: () => setLocalSettings({ ...localSettings, glassMode: !localSettings.glassMode }),
4851
5486
  className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${localSettings.glassMode ? "bg-blue-600" : isDark ? "bg-gray-700" : "bg-gray-300"}`,
4852
5487
  role: "switch",
4853
5488
  "aria-checked": localSettings.glassMode,
4854
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5489
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4855
5490
  "span",
4856
5491
  {
4857
5492
  className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.glassMode ? "translate-x-6" : "translate-x-1"}`
@@ -4860,19 +5495,19 @@ function ChatBubbleSettingsModal({
4860
5495
  }
4861
5496
  )
4862
5497
  ] }),
4863
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center justify-between", children: [
4864
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
4865
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("label", { className: "block text-base font-medium mb-1", children: "Notifications" }),
4866
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Show unread message indicators" })
5498
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between", children: [
5499
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
5500
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "block text-base font-medium mb-1", children: "Notifications" }),
5501
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Show unread message indicators" })
4867
5502
  ] }),
4868
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5503
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4869
5504
  "button",
4870
5505
  {
4871
5506
  onClick: () => setLocalSettings({ ...localSettings, notifications: !localSettings.notifications }),
4872
5507
  className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${localSettings.notifications ? "bg-blue-600" : isDark ? "bg-gray-700" : "bg-gray-300"}`,
4873
5508
  role: "switch",
4874
5509
  "aria-checked": localSettings.notifications,
4875
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5510
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4876
5511
  "span",
4877
5512
  {
4878
5513
  className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.notifications ? "translate-x-6" : "translate-x-1"}`
@@ -4881,16 +5516,16 @@ function ChatBubbleSettingsModal({
4881
5516
  }
4882
5517
  )
4883
5518
  ] }),
4884
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: `border-t ${isDark ? "border-gray-700" : "border-gray-200"} my-2` }),
4885
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center justify-between", children: [
4886
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
4887
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "block text-base font-medium mb-1 flex items-center space-x-2", children: [
4888
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "Subtitle Overlay" }),
4889
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "inline-block px-2 py-0.5 text-xs font-semibold rounded-full bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200", children: "BETA" })
5519
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: `border-t ${isDark ? "border-gray-700" : "border-gray-200"} my-2` }),
5520
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between", children: [
5521
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
5522
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "block text-base font-medium mb-1 flex items-center space-x-2", children: [
5523
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "Subtitle Overlay" }),
5524
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "inline-block px-2 py-0.5 text-xs font-semibold rounded-full bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200", children: "BETA" })
4890
5525
  ] }),
4891
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Minimalist voice-first overlay with @/ icon" })
5526
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Minimalist voice-first overlay with @/ icon" })
4892
5527
  ] }),
4893
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5528
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4894
5529
  "button",
4895
5530
  {
4896
5531
  onClick: () => setLocalSettings({
@@ -4902,7 +5537,7 @@ function ChatBubbleSettingsModal({
4902
5537
  className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${localSettings.subtitleOverlayEnabled ? "bg-blue-600" : isDark ? "bg-gray-700" : "bg-gray-300"}`,
4903
5538
  role: "switch",
4904
5539
  "aria-checked": localSettings.subtitleOverlayEnabled,
4905
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5540
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4906
5541
  "span",
4907
5542
  {
4908
5543
  className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.subtitleOverlayEnabled ? "translate-x-6" : "translate-x-1"}`
@@ -4911,12 +5546,12 @@ function ChatBubbleSettingsModal({
4911
5546
  }
4912
5547
  )
4913
5548
  ] }),
4914
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center justify-between", children: [
4915
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
4916
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("label", { className: "block text-base font-medium mb-1", children: "Display Mode" }),
4917
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Auto switches drawer on mobile, panel on desktop" })
5549
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between", children: [
5550
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
5551
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "block text-base font-medium mb-1", children: "Display Mode" }),
5552
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Auto switches drawer on mobile, panel on desktop" })
4918
5553
  ] }),
4919
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5554
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4920
5555
  "select",
4921
5556
  {
4922
5557
  value: localSettings.displayMode || "auto",
@@ -4926,22 +5561,22 @@ function ChatBubbleSettingsModal({
4926
5561
  }),
4927
5562
  className: `px-3 py-2 rounded-lg border ${isDark ? "bg-gray-700 border-gray-600 text-white" : "bg-white border-gray-300 text-gray-900"} focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all`,
4928
5563
  children: [
4929
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "auto", children: "Auto (Recommended)" }),
4930
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "drawer", children: "Always Drawer" }),
4931
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "full", children: "Always Panel" }),
4932
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "floating", children: "Always Floating" }),
4933
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "subtitle", children: "Subtitle Overlay (Beta)" })
5564
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "auto", children: "Auto (Recommended)" }),
5565
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "drawer", children: "Always Drawer" }),
5566
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "full", children: "Always Panel" }),
5567
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "floating", children: "Always Floating" }),
5568
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "subtitle", children: "Subtitle Overlay (Beta)" })
4934
5569
  ]
4935
5570
  }
4936
5571
  )
4937
5572
  ] }),
4938
- (localSettings.displayMode === "auto" || localSettings.displayMode === "drawer") && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center justify-between", children: [
4939
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
4940
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("label", { className: "block text-base font-medium mb-1", children: "Drawer Side" }),
4941
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Which edge drawer slides from" })
5573
+ (localSettings.displayMode === "auto" || localSettings.displayMode === "drawer") && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between", children: [
5574
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
5575
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "block text-base font-medium mb-1", children: "Drawer Side" }),
5576
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Which edge drawer slides from" })
4942
5577
  ] }),
4943
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center space-x-2", children: [
4944
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5578
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center space-x-2", children: [
5579
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4945
5580
  "button",
4946
5581
  {
4947
5582
  onClick: () => setLocalSettings({ ...localSettings, drawerSide: "left" }),
@@ -4949,7 +5584,7 @@ function ChatBubbleSettingsModal({
4949
5584
  children: "Left"
4950
5585
  }
4951
5586
  ),
4952
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5587
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4953
5588
  "button",
4954
5589
  {
4955
5590
  onClick: () => setLocalSettings({ ...localSettings, drawerSide: "right" }),
@@ -4959,24 +5594,24 @@ function ChatBubbleSettingsModal({
4959
5594
  )
4960
5595
  ] })
4961
5596
  ] }),
4962
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: `border-t ${isDark ? "border-gray-700" : "border-gray-200"} my-2` }),
4963
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "mb-3", children: [
4964
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h3", { className: "text-lg font-semibold mb-1", children: "Voice Control" }),
4965
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Enable voice input and audio feedback" })
5597
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: `border-t ${isDark ? "border-gray-700" : "border-gray-200"} my-2` }),
5598
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "mb-3", children: [
5599
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { className: "text-lg font-semibold mb-1", children: "Voice Control" }),
5600
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Enable voice input and audio feedback" })
4966
5601
  ] }),
4967
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center justify-between", children: [
4968
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
4969
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("label", { className: "block text-base font-medium mb-1", children: "Voice Control" }),
4970
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Enable voice input and TTS responses" })
5602
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between", children: [
5603
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
5604
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "block text-base font-medium mb-1", children: "Voice Control" }),
5605
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Enable voice input and TTS responses" })
4971
5606
  ] }),
4972
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5607
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4973
5608
  "button",
4974
5609
  {
4975
5610
  onClick: () => setLocalSettings({ ...localSettings, voiceEnabled: !localSettings.voiceEnabled }),
4976
5611
  className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${localSettings.voiceEnabled ? "bg-blue-600" : isDark ? "bg-gray-700" : "bg-gray-300"}`,
4977
5612
  role: "switch",
4978
5613
  "aria-checked": localSettings.voiceEnabled,
4979
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5614
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4980
5615
  "span",
4981
5616
  {
4982
5617
  className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.voiceEnabled ? "translate-x-6" : "translate-x-1"}`
@@ -4985,20 +5620,20 @@ function ChatBubbleSettingsModal({
4985
5620
  }
4986
5621
  )
4987
5622
  ] }),
4988
- localSettings.voiceEnabled && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4989
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center justify-between pl-4 border-l-2 border-blue-500/30", children: [
4990
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
4991
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("label", { className: "block text-sm font-medium mb-1", children: "Auto-read AI Responses" }),
4992
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Automatically read AI messages aloud" })
5623
+ localSettings.voiceEnabled && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
5624
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between pl-4 border-l-2 border-blue-500/30", children: [
5625
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
5626
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "block text-sm font-medium mb-1", children: "Auto-read AI Responses" }),
5627
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Automatically read AI messages aloud" })
4993
5628
  ] }),
4994
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5629
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4995
5630
  "button",
4996
5631
  {
4997
5632
  onClick: () => setLocalSettings({ ...localSettings, autoReadResponses: !localSettings.autoReadResponses }),
4998
5633
  className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${localSettings.autoReadResponses ? "bg-blue-600" : isDark ? "bg-gray-700" : "bg-gray-300"}`,
4999
5634
  role: "switch",
5000
5635
  "aria-checked": localSettings.autoReadResponses,
5001
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5636
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5002
5637
  "span",
5003
5638
  {
5004
5639
  className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.autoReadResponses ? "translate-x-6" : "translate-x-1"}`
@@ -5007,19 +5642,19 @@ function ChatBubbleSettingsModal({
5007
5642
  }
5008
5643
  )
5009
5644
  ] }),
5010
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center justify-between pl-4 border-l-2 border-blue-500/30", children: [
5011
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
5012
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("label", { className: "block text-sm font-medium mb-1", children: "Premium Voices \u{1F48E}" }),
5013
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Use high-quality OpenAI voices (requires network)" })
5645
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between pl-4 border-l-2 border-blue-500/30", children: [
5646
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
5647
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "block text-sm font-medium mb-1", children: "Premium Voices \u{1F48E}" }),
5648
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Use high-quality OpenAI voices (requires network)" })
5014
5649
  ] }),
5015
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5650
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5016
5651
  "button",
5017
5652
  {
5018
5653
  onClick: () => setLocalSettings({ ...localSettings, usePremiumVoices: !localSettings.usePremiumVoices }),
5019
5654
  className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${localSettings.usePremiumVoices ? "bg-blue-600" : isDark ? "bg-gray-700" : "bg-gray-300"}`,
5020
5655
  role: "switch",
5021
5656
  "aria-checked": localSettings.usePremiumVoices,
5022
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5657
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5023
5658
  "span",
5024
5659
  {
5025
5660
  className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.usePremiumVoices ? "translate-x-6" : "translate-x-1"}`
@@ -5028,13 +5663,13 @@ function ChatBubbleSettingsModal({
5028
5663
  }
5029
5664
  )
5030
5665
  ] }),
5031
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "pl-4 border-l-2 border-blue-500/30", children: [
5032
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "block text-sm font-medium mb-2", children: [
5666
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "pl-4 border-l-2 border-blue-500/30", children: [
5667
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "block text-sm font-medium mb-2", children: [
5033
5668
  "Voice Speed: ",
5034
5669
  localSettings.ttsSpeed.toFixed(1),
5035
5670
  "x"
5036
5671
  ] }),
5037
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5672
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5038
5673
  "input",
5039
5674
  {
5040
5675
  type: "range",
@@ -5046,30 +5681,30 @@ function ChatBubbleSettingsModal({
5046
5681
  className: "w-full h-2 bg-gray-200 dark:bg-gray-700 rounded-lg appearance-none cursor-pointer accent-blue-600"
5047
5682
  }
5048
5683
  ),
5049
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex justify-between text-xs text-gray-400 mt-1", children: [
5050
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "0.5x (Slow)" }),
5051
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "1.0x (Normal)" }),
5052
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "2.0x (Fast)" })
5684
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex justify-between text-xs text-gray-400 mt-1", children: [
5685
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "0.5x (Slow)" }),
5686
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "1.0x (Normal)" }),
5687
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "2.0x (Fast)" })
5053
5688
  ] })
5054
5689
  ] }),
5055
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: `border-t ${isDark ? "border-gray-700" : "border-gray-200"} my-2` }),
5056
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "mb-3", children: [
5057
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h4", { className: "text-sm font-semibold mb-1", children: "Voice Quick Record (Ctrl+/)" }),
5058
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Press Ctrl+/ (or Cmd+/ on Mac) to auto-record and execute voice commands" })
5690
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: `border-t ${isDark ? "border-gray-700" : "border-gray-200"} my-2` }),
5691
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "mb-3", children: [
5692
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h4", { className: "text-sm font-semibold mb-1", children: "Voice Quick Record (Ctrl+/)" }),
5693
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Press Ctrl+/ (or Cmd+/ on Mac) to auto-record and execute voice commands" })
5059
5694
  ] }),
5060
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center justify-between pl-4 border-l-2 border-purple-500/30", children: [
5061
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
5062
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("label", { className: "block text-sm font-medium mb-1", children: "Auto-Execute Commands" }),
5063
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Automatically run recognized voice commands" })
5695
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between pl-4 border-l-2 border-purple-500/30", children: [
5696
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
5697
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "block text-sm font-medium mb-1", children: "Auto-Execute Commands" }),
5698
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Automatically run recognized voice commands" })
5064
5699
  ] }),
5065
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5700
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5066
5701
  "button",
5067
5702
  {
5068
5703
  onClick: () => setLocalSettings({ ...localSettings, sttAutoExecute: !localSettings.sttAutoExecute }),
5069
5704
  className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${localSettings.sttAutoExecute ? "bg-purple-600" : isDark ? "bg-gray-700" : "bg-gray-300"}`,
5070
5705
  role: "switch",
5071
5706
  "aria-checked": localSettings.sttAutoExecute,
5072
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5707
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5073
5708
  "span",
5074
5709
  {
5075
5710
  className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.sttAutoExecute ? "translate-x-6" : "translate-x-1"}`
@@ -5078,13 +5713,13 @@ function ChatBubbleSettingsModal({
5078
5713
  }
5079
5714
  )
5080
5715
  ] }),
5081
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "pl-4 border-l-2 border-purple-500/30", children: [
5082
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "block text-sm font-medium mb-2", children: [
5716
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "pl-4 border-l-2 border-purple-500/30", children: [
5717
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "block text-sm font-medium mb-2", children: [
5083
5718
  "Recording Timeout: ",
5084
5719
  (localSettings.sttAutoRecordTimeout / 1e3).toFixed(1),
5085
5720
  "s"
5086
5721
  ] }),
5087
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5722
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5088
5723
  "input",
5089
5724
  {
5090
5725
  type: "range",
@@ -5096,22 +5731,22 @@ function ChatBubbleSettingsModal({
5096
5731
  className: "w-full h-2 bg-gray-200 dark:bg-gray-700 rounded-lg appearance-none cursor-pointer accent-purple-600"
5097
5732
  }
5098
5733
  ),
5099
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex justify-between text-xs text-gray-400 mt-1", children: [
5100
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "2s" }),
5101
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "8s" }),
5102
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "15s" })
5734
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex justify-between text-xs text-gray-400 mt-1", children: [
5735
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "2s" }),
5736
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "8s" }),
5737
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "15s" })
5103
5738
  ] })
5104
5739
  ] }),
5105
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: `p-3 rounded-lg ${isDark ? "bg-purple-900/20 border border-purple-500/30" : "bg-purple-50 border border-purple-200"}`, children: [
5106
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: `text-xs ${isDark ? "text-purple-300" : "text-purple-800"} mb-1 font-medium`, children: "\u26A1 Quick Tip: Press Ctrl+/ anywhere (even while typing!)" }),
5107
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: `text-xs ${isDark ? "text-purple-400" : "text-purple-700"}`, children: localSettings.sttAutoExecute ? "Recording auto-stops and executes your command" : "Recording auto-stops and fills the input (press Enter to send)" })
5740
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: `p-3 rounded-lg ${isDark ? "bg-purple-900/20 border border-purple-500/30" : "bg-purple-50 border border-purple-200"}`, children: [
5741
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-xs ${isDark ? "text-purple-300" : "text-purple-800"} mb-1 font-medium`, children: "\u26A1 Quick Tip: Press Ctrl+/ anywhere (even while typing!)" }),
5742
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-xs ${isDark ? "text-purple-400" : "text-purple-700"}`, children: localSettings.sttAutoExecute ? "Recording auto-stops and executes your command" : "Recording auto-stops and fills the input (press Enter to send)" })
5108
5743
  ] }),
5109
- !localSettings.usePremiumVoices && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: `p-3 rounded-lg ${isDark ? "bg-green-900/20 border border-green-500/30" : "bg-green-50 border border-green-200"}`, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: `text-xs ${isDark ? "text-green-300" : "text-green-800"}`, children: "\u{1F49A} Using free device voices (works offline, zero cost)" }) }),
5110
- localSettings.usePremiumVoices && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: `p-3 rounded-lg ${isDark ? "bg-purple-900/20 border border-purple-500/30" : "bg-purple-50 border border-purple-200"}`, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: `text-xs ${isDark ? "text-purple-300" : "text-purple-800"}`, children: "\u{1F48E} Using premium OpenAI voices (requires internet connection)" }) })
5744
+ !localSettings.usePremiumVoices && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: `p-3 rounded-lg ${isDark ? "bg-green-900/20 border border-green-500/30" : "bg-green-50 border border-green-200"}`, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-xs ${isDark ? "text-green-300" : "text-green-800"}`, children: "\u{1F49A} Using free device voices (works offline, zero cost)" }) }),
5745
+ localSettings.usePremiumVoices && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: `p-3 rounded-lg ${isDark ? "bg-purple-900/20 border border-purple-500/30" : "bg-purple-50 border border-purple-200"}`, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-xs ${isDark ? "text-purple-300" : "text-purple-800"}`, children: "\u{1F48E} Using premium OpenAI voices (requires internet connection)" }) })
5111
5746
  ] })
5112
5747
  ] }),
5113
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex justify-end space-x-3 pt-4 border-t border-gray-200 dark:border-gray-700", children: [
5114
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5748
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex justify-end space-x-3 pt-4 border-t border-gray-200 dark:border-gray-700", children: [
5749
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5115
5750
  "button",
5116
5751
  {
5117
5752
  onClick: handleCancel,
@@ -5119,7 +5754,7 @@ function ChatBubbleSettingsModal({
5119
5754
  children: "Cancel"
5120
5755
  }
5121
5756
  ),
5122
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5757
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5123
5758
  "button",
5124
5759
  {
5125
5760
  onClick: handleSave,
@@ -5256,12 +5891,14 @@ function findBestMatch(query, tools) {
5256
5891
  }
5257
5892
  // Annotate the CommonJS export names for ESM import in node:
5258
5893
  0 && (module.exports = {
5894
+ ApiKeyProvider,
5259
5895
  AutoNavigationContext,
5260
5896
  ChatBubble,
5261
5897
  ChatBubbleSettingsModal,
5262
5898
  ChatBubbleVariant,
5263
5899
  ChatInputProvider,
5264
5900
  ChatProvider,
5901
+ ClaudeClient,
5265
5902
  CodeBlock,
5266
5903
  Components,
5267
5904
  DemoAIInterface,
@@ -5275,9 +5912,13 @@ function findBestMatch(query, tools) {
5275
5912
  ToolManager,
5276
5913
  ToolMenuPopup,
5277
5914
  ToolMenuPopupTrigger,
5915
+ createClaudeClient,
5278
5916
  findBestMatch,
5279
5917
  scoreToolMatch,
5280
5918
  useAllContexts,
5919
+ useApiKey,
5920
+ useApiKeyOptional,
5921
+ useApiKeyStorage,
5281
5922
  useChatContext,
5282
5923
  useChatInput,
5283
5924
  useCurrentContext,