@supernal/interface-nextjs 1.0.26 → 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.mjs CHANGED
@@ -7,7 +7,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
7
7
  });
8
8
 
9
9
  // src/components/SupernalProvider.tsx
10
- import { useEffect as useEffect14 } from "react";
10
+ import { useEffect as useEffect15 } from "react";
11
11
 
12
12
  // src/contexts/ChatInputContext.tsx
13
13
  import { createContext, useContext, useCallback, useRef } from "react";
@@ -34,12 +34,12 @@ function ChatInputProvider({ children }) {
34
34
  }
35
35
 
36
36
  // src/contexts/ChatProvider.tsx
37
- import { createContext as createContext2, useContext as useContext2, useState, useCallback as useCallback2, useEffect } from "react";
37
+ import { createContext as createContext3, useContext as useContext3, useState as useState2, useCallback as useCallback3, useEffect as useEffect2, useRef as useRef3 } from "react";
38
38
 
39
39
  // src/lib/ChatAIInterface.ts
40
40
  import {
41
41
  AIInterface
42
- } from "@supernal/interface";
42
+ } from "@supernal/interface/browser";
43
43
 
44
44
  // src/lib/ToolManager.ts
45
45
  import { setDefaultToolReporter, setGlobalToolReporter } from "@supernal/interface/browser";
@@ -178,17 +178,466 @@ var DemoAIInterface = class extends AIInterface {
178
178
  }
179
179
  };
180
180
 
181
- // src/contexts/ChatProvider.tsx
181
+ // src/lib/ClaudeClient.ts
182
+ var COST_PER_1K = {
183
+ "claude-sonnet-4-20250514": { input: 3e-3, output: 0.015 },
184
+ "claude-3-5-sonnet-20241022": { input: 3e-3, output: 0.015 },
185
+ "claude-3-opus-20240229": { input: 0.015, output: 0.075 },
186
+ "claude-3-haiku-20240307": { input: 25e-5, output: 125e-5 }
187
+ };
188
+ var ClaudeClient = class {
189
+ constructor(config) {
190
+ this.apiKey = config.apiKey;
191
+ this.model = config.model || "claude-sonnet-4-20250514";
192
+ this.maxTokens = config.maxTokens || 4096;
193
+ this.systemPrompt = config.systemPrompt || "You are a helpful AI assistant integrated into a web application. Be concise and helpful.";
194
+ }
195
+ /**
196
+ * Send a message to Claude and get a response
197
+ */
198
+ async sendMessage(userMessage, options = {}) {
199
+ const messages = [
200
+ ...options.messages || [],
201
+ { role: "user", content: userMessage }
202
+ ];
203
+ try {
204
+ const response = await fetch("https://api.anthropic.com/v1/messages", {
205
+ method: "POST",
206
+ headers: {
207
+ "Content-Type": "application/json",
208
+ "x-api-key": this.apiKey,
209
+ "anthropic-version": "2023-06-01",
210
+ "anthropic-dangerous-direct-browser-access": "true"
211
+ },
212
+ body: JSON.stringify({
213
+ model: this.model,
214
+ max_tokens: options.maxTokens || this.maxTokens,
215
+ system: options.systemPrompt || this.systemPrompt,
216
+ messages: messages.map((m) => ({
217
+ role: m.role,
218
+ content: m.content
219
+ })),
220
+ temperature: options.temperature
221
+ })
222
+ });
223
+ if (!response.ok) {
224
+ const errorData = await response.json().catch(() => ({}));
225
+ if (response.status === 401) {
226
+ return {
227
+ success: false,
228
+ message: "Invalid API key. Please check your API key and try again.",
229
+ error: "INVALID_API_KEY"
230
+ };
231
+ }
232
+ if (response.status === 429) {
233
+ return {
234
+ success: false,
235
+ message: "Rate limit exceeded. Please wait a moment and try again.",
236
+ error: "RATE_LIMITED"
237
+ };
238
+ }
239
+ if (response.status === 400) {
240
+ return {
241
+ success: false,
242
+ message: errorData.error?.message || "Invalid request",
243
+ error: "BAD_REQUEST"
244
+ };
245
+ }
246
+ return {
247
+ success: false,
248
+ message: errorData.error?.message || `API error: ${response.status}`,
249
+ error: "API_ERROR"
250
+ };
251
+ }
252
+ const data = await response.json();
253
+ const textContent = data.content.find((c) => c.type === "text");
254
+ const responseText = textContent?.text || "";
255
+ const modelCosts = COST_PER_1K[this.model] || COST_PER_1K["claude-sonnet-4-20250514"];
256
+ const inputCost = data.usage.input_tokens / 1e3 * modelCosts.input;
257
+ const outputCost = data.usage.output_tokens / 1e3 * modelCosts.output;
258
+ return {
259
+ success: true,
260
+ message: responseText,
261
+ response: data,
262
+ usage: {
263
+ inputTokens: data.usage.input_tokens,
264
+ outputTokens: data.usage.output_tokens,
265
+ estimatedCost: inputCost + outputCost
266
+ }
267
+ };
268
+ } catch (err) {
269
+ console.error("ClaudeClient error:", err);
270
+ if (err instanceof TypeError && err.message.includes("fetch")) {
271
+ return {
272
+ success: false,
273
+ message: "Network error. Please check your connection.",
274
+ error: "NETWORK_ERROR"
275
+ };
276
+ }
277
+ return {
278
+ success: false,
279
+ message: err instanceof Error ? err.message : "Unknown error occurred",
280
+ error: "UNKNOWN_ERROR"
281
+ };
282
+ }
283
+ }
284
+ /**
285
+ * Update the API key
286
+ */
287
+ setApiKey(apiKey) {
288
+ this.apiKey = apiKey;
289
+ }
290
+ /**
291
+ * Update the model
292
+ */
293
+ setModel(model) {
294
+ this.model = model;
295
+ }
296
+ /**
297
+ * Update the system prompt
298
+ */
299
+ setSystemPrompt(systemPrompt) {
300
+ this.systemPrompt = systemPrompt;
301
+ }
302
+ };
303
+ function createClaudeClient(config) {
304
+ return new ClaudeClient(config);
305
+ }
306
+
307
+ // src/contexts/ApiKeyContext.tsx
308
+ import React2, { createContext as createContext2, useContext as useContext2 } from "react";
309
+
310
+ // src/hooks/useApiKeyStorage.ts
311
+ import { useState, useCallback as useCallback2, useEffect, useRef as useRef2 } from "react";
312
+ var STORAGE_KEY = "supernal-api-key";
313
+ var ENCRYPTED_STORAGE_KEY = "supernal-vault-v1";
314
+ function validateApiKeyFormat(key) {
315
+ if (!key || key.trim() === "") {
316
+ return { valid: false, error: "API key is required" };
317
+ }
318
+ if (!key.startsWith("sk-ant-")) {
319
+ return { valid: false, error: 'Invalid format. Keys start with "sk-ant-"' };
320
+ }
321
+ if (key.length < 50) {
322
+ return { valid: false, error: "API key appears too short" };
323
+ }
324
+ return { valid: true };
325
+ }
326
+ function maskApiKey(key) {
327
+ if (key.length <= 14) return "\u2022".repeat(key.length);
328
+ return `${key.slice(0, 10)}...${key.slice(-4)}`;
329
+ }
330
+ async function validateApiKeyWithAnthropic(apiKey) {
331
+ try {
332
+ const response = await fetch("https://api.anthropic.com/v1/messages", {
333
+ method: "POST",
334
+ headers: {
335
+ "Content-Type": "application/json",
336
+ "x-api-key": apiKey,
337
+ "anthropic-version": "2023-06-01",
338
+ "anthropic-dangerous-direct-browser-access": "true"
339
+ },
340
+ body: JSON.stringify({
341
+ model: "claude-sonnet-4-20250514",
342
+ max_tokens: 1,
343
+ messages: [{ role: "user", content: "hi" }]
344
+ })
345
+ });
346
+ if (response.ok) {
347
+ return { valid: true };
348
+ }
349
+ const data = await response.json().catch(() => ({}));
350
+ if (response.status === 401) {
351
+ return { valid: false, error: "Invalid API key" };
352
+ }
353
+ if (response.status === 403) {
354
+ return { valid: false, error: "API key does not have permission" };
355
+ }
356
+ if (response.status === 429) {
357
+ return { valid: true };
358
+ }
359
+ return { valid: false, error: data.error?.message || "Validation failed" };
360
+ } catch (err) {
361
+ console.warn("Could not validate API key with Anthropic:", err);
362
+ return validateApiKeyFormat(apiKey);
363
+ }
364
+ }
365
+ var SALT_LENGTH = 32;
366
+ var IV_LENGTH = 12;
367
+ var ITERATIONS = 1e5;
368
+ async function deriveKey(passphrase, salt) {
369
+ const keyMaterial = await crypto.subtle.importKey(
370
+ "raw",
371
+ new TextEncoder().encode(passphrase),
372
+ "PBKDF2",
373
+ false,
374
+ ["deriveKey"]
375
+ );
376
+ const saltBuffer = salt.buffer.slice(salt.byteOffset, salt.byteOffset + salt.byteLength);
377
+ return crypto.subtle.deriveKey(
378
+ { name: "PBKDF2", salt: saltBuffer, iterations: ITERATIONS, hash: "SHA-256" },
379
+ keyMaterial,
380
+ { name: "AES-GCM", length: 256 },
381
+ false,
382
+ ["encrypt", "decrypt"]
383
+ );
384
+ }
385
+ async function encryptValue(key, plaintext, salt) {
386
+ const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));
387
+ const ivBuffer = iv.buffer.slice(iv.byteOffset, iv.byteOffset + iv.byteLength);
388
+ const ciphertext = await crypto.subtle.encrypt(
389
+ { name: "AES-GCM", iv: ivBuffer },
390
+ key,
391
+ new TextEncoder().encode(plaintext)
392
+ );
393
+ return {
394
+ version: 1,
395
+ ciphertext: arrayBufferToBase64(ciphertext),
396
+ salt: uint8ArrayToBase64(salt),
397
+ iv: uint8ArrayToBase64(iv),
398
+ encryptedAt: Date.now()
399
+ };
400
+ }
401
+ async function decryptValue(key, entry) {
402
+ const ciphertext = base64ToArrayBuffer(entry.ciphertext);
403
+ const iv = base64ToUint8Array(entry.iv);
404
+ const ivBuffer = iv.buffer.slice(iv.byteOffset, iv.byteOffset + iv.byteLength);
405
+ const plaintext = await crypto.subtle.decrypt(
406
+ { name: "AES-GCM", iv: ivBuffer },
407
+ key,
408
+ ciphertext
409
+ );
410
+ return new TextDecoder().decode(plaintext);
411
+ }
412
+ function arrayBufferToBase64(buffer) {
413
+ const bytes = new Uint8Array(buffer);
414
+ let binary = "";
415
+ for (let i = 0; i < bytes.byteLength; i++) {
416
+ binary += String.fromCharCode(bytes[i]);
417
+ }
418
+ return btoa(binary);
419
+ }
420
+ function base64ToArrayBuffer(base64) {
421
+ const binary = atob(base64);
422
+ const bytes = new Uint8Array(binary.length);
423
+ for (let i = 0; i < binary.length; i++) {
424
+ bytes[i] = binary.charCodeAt(i);
425
+ }
426
+ return bytes.buffer;
427
+ }
428
+ function uint8ArrayToBase64(array) {
429
+ const buffer = array.buffer.slice(array.byteOffset, array.byteOffset + array.byteLength);
430
+ return arrayBufferToBase64(buffer);
431
+ }
432
+ function base64ToUint8Array(base64) {
433
+ return new Uint8Array(base64ToArrayBuffer(base64));
434
+ }
435
+ function loadEncryptedEntry() {
436
+ if (typeof window === "undefined") return null;
437
+ try {
438
+ const stored = localStorage.getItem(ENCRYPTED_STORAGE_KEY);
439
+ if (stored) {
440
+ const entry = JSON.parse(stored);
441
+ if (entry.version === 1 && entry.ciphertext && entry.salt) {
442
+ return entry;
443
+ }
444
+ }
445
+ } catch {
446
+ }
447
+ return null;
448
+ }
449
+ function useApiKeyStorage(options = {}) {
450
+ const [state, setState] = useState({
451
+ apiKey: null,
452
+ status: options.encrypted ? "locked" : "none",
453
+ error: null,
454
+ maskedKey: null
455
+ });
456
+ const derivedKeyRef = useRef2(null);
457
+ const saltRef = useRef2(null);
458
+ useEffect(() => {
459
+ if (typeof window === "undefined") return;
460
+ if (options.encrypted) {
461
+ const entry = loadEncryptedEntry();
462
+ if (entry) {
463
+ setState((prev) => ({ ...prev, status: "locked" }));
464
+ } else {
465
+ setState((prev) => ({ ...prev, status: "locked" }));
466
+ }
467
+ return;
468
+ }
469
+ try {
470
+ const saved = localStorage.getItem(STORAGE_KEY);
471
+ if (saved) {
472
+ const validation = validateApiKeyFormat(saved);
473
+ setState({
474
+ apiKey: saved,
475
+ status: validation.valid ? "valid" : "invalid",
476
+ error: validation.error || null,
477
+ maskedKey: maskApiKey(saved)
478
+ });
479
+ }
480
+ } catch (err) {
481
+ console.error("Failed to load API key from storage:", err);
482
+ }
483
+ }, [options.encrypted]);
484
+ const unlock = useCallback2(async (passphrase) => {
485
+ if (!options.encrypted) {
486
+ return true;
487
+ }
488
+ try {
489
+ const entry = loadEncryptedEntry();
490
+ if (entry) {
491
+ const salt = base64ToUint8Array(entry.salt);
492
+ const key = await deriveKey(passphrase, salt);
493
+ try {
494
+ const apiKey = await decryptValue(key, entry);
495
+ derivedKeyRef.current = key;
496
+ saltRef.current = salt;
497
+ const validation = validateApiKeyFormat(apiKey);
498
+ setState({
499
+ apiKey,
500
+ status: validation.valid ? "valid" : "invalid",
501
+ error: validation.error || null,
502
+ maskedKey: maskApiKey(apiKey)
503
+ });
504
+ return true;
505
+ } catch {
506
+ options.onPassphraseInvalid?.();
507
+ return false;
508
+ }
509
+ } else {
510
+ const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));
511
+ const key = await deriveKey(passphrase, salt);
512
+ derivedKeyRef.current = key;
513
+ saltRef.current = salt;
514
+ setState((prev) => ({
515
+ ...prev,
516
+ status: "none"
517
+ // Unlocked but no key yet
518
+ }));
519
+ return true;
520
+ }
521
+ } catch (error) {
522
+ console.error("[useApiKeyStorage] Unlock failed:", error);
523
+ return false;
524
+ }
525
+ }, [options.encrypted, options.onPassphraseInvalid]);
526
+ const lock = useCallback2(() => {
527
+ if (!options.encrypted) return;
528
+ derivedKeyRef.current = null;
529
+ setState((prev) => ({
530
+ ...prev,
531
+ status: "locked",
532
+ apiKey: null,
533
+ maskedKey: null
534
+ }));
535
+ }, [options.encrypted]);
536
+ const setApiKey = useCallback2(async (key, validate = true) => {
537
+ const formatValidation = validateApiKeyFormat(key);
538
+ if (!formatValidation.valid) {
539
+ setState({
540
+ apiKey: null,
541
+ status: "invalid",
542
+ error: formatValidation.error || "Invalid API key",
543
+ maskedKey: null
544
+ });
545
+ return false;
546
+ }
547
+ setState({
548
+ apiKey: key,
549
+ status: validate ? "validating" : "valid",
550
+ error: null,
551
+ maskedKey: maskApiKey(key)
552
+ });
553
+ try {
554
+ if (options.encrypted && derivedKeyRef.current && saltRef.current) {
555
+ const entry = await encryptValue(derivedKeyRef.current, key, saltRef.current);
556
+ localStorage.setItem(ENCRYPTED_STORAGE_KEY, JSON.stringify(entry));
557
+ } else {
558
+ localStorage.setItem(STORAGE_KEY, key);
559
+ }
560
+ } catch (err) {
561
+ console.error("Failed to save API key:", err);
562
+ }
563
+ if (validate) {
564
+ const liveValidation = await validateApiKeyWithAnthropic(key);
565
+ setState((prev) => ({
566
+ ...prev,
567
+ status: liveValidation.valid ? "valid" : "invalid",
568
+ error: liveValidation.error || null
569
+ }));
570
+ return liveValidation.valid;
571
+ }
572
+ return true;
573
+ }, [options.encrypted]);
574
+ const clearApiKey = useCallback2(() => {
575
+ try {
576
+ if (options.encrypted) {
577
+ localStorage.removeItem(ENCRYPTED_STORAGE_KEY);
578
+ } else {
579
+ localStorage.removeItem(STORAGE_KEY);
580
+ }
581
+ } catch (err) {
582
+ console.error("Failed to clear API key:", err);
583
+ }
584
+ setState({
585
+ apiKey: null,
586
+ status: options.encrypted ? "locked" : "none",
587
+ error: null,
588
+ maskedKey: null
589
+ });
590
+ }, [options.encrypted]);
591
+ const revalidate = useCallback2(async () => {
592
+ if (!state.apiKey) return false;
593
+ return setApiKey(state.apiKey, true);
594
+ }, [state.apiKey, setApiKey]);
595
+ return {
596
+ ...state,
597
+ hasApiKey: !!state.apiKey && state.status === "valid",
598
+ isLocked: state.status === "locked",
599
+ setApiKey,
600
+ clearApiKey,
601
+ revalidate,
602
+ unlock,
603
+ lock
604
+ };
605
+ }
606
+
607
+ // src/contexts/ApiKeyContext.tsx
182
608
  import { jsx as jsx2 } from "react/jsx-runtime";
183
- var ChatContext = createContext2(null);
609
+ var ApiKeyContext = createContext2(null);
610
+ function ApiKeyProvider({ children, initialApiKey }) {
611
+ const apiKeyStorage = useApiKeyStorage();
612
+ React2.useEffect(() => {
613
+ if (initialApiKey && !apiKeyStorage.apiKey && apiKeyStorage.status === "none") {
614
+ apiKeyStorage.setApiKey(initialApiKey, false);
615
+ }
616
+ }, [initialApiKey, apiKeyStorage]);
617
+ return /* @__PURE__ */ jsx2(ApiKeyContext.Provider, { value: apiKeyStorage, children });
618
+ }
619
+ function useApiKey() {
620
+ const context = useContext2(ApiKeyContext);
621
+ if (!context) {
622
+ throw new Error("useApiKey must be used within ApiKeyProvider");
623
+ }
624
+ return context;
625
+ }
626
+ function useApiKeyOptional() {
627
+ return useContext2(ApiKeyContext);
628
+ }
629
+
630
+ // src/contexts/ChatProvider.tsx
631
+ import { jsx as jsx3 } from "react/jsx-runtime";
632
+ var ChatContext = createContext3(null);
184
633
  function useChatContext() {
185
- const context = useContext2(ChatContext);
634
+ const context = useContext3(ChatContext);
186
635
  if (!context) {
187
636
  throw new Error("useChatContext must be used within ChatProvider");
188
637
  }
189
638
  return context;
190
639
  }
191
- var STORAGE_KEY = "supernal-chat-messages";
640
+ var STORAGE_KEY2 = "supernal-chat-messages";
192
641
  var MAX_MESSAGES = 100;
193
642
  function getInitialMessages() {
194
643
  return [
@@ -233,14 +682,30 @@ function getInitialMessages() {
233
682
  function ChatProvider({
234
683
  children,
235
684
  mode = "fuzzy",
236
- apiKey,
685
+ apiKey: propApiKey,
237
686
  onToolExecute
238
687
  }) {
239
- const [messages, setMessages] = useState([]);
240
- useEffect(() => {
688
+ const [messages, setMessages] = useState2([]);
689
+ const apiKeyContext = useApiKeyOptional();
690
+ const activeApiKey = apiKeyContext?.hasApiKey ? apiKeyContext.apiKey : propApiKey;
691
+ const isAiMode = !!activeApiKey;
692
+ const claudeClientRef = useRef3(null);
693
+ useEffect2(() => {
694
+ if (activeApiKey) {
695
+ claudeClientRef.current = new ClaudeClient({
696
+ apiKey: activeApiKey,
697
+ systemPrompt: `You are a helpful AI assistant integrated into a web application powered by Supernal Interface.
698
+ You can help users navigate the application and perform tasks.
699
+ Be concise, friendly, and helpful. Use markdown formatting when appropriate.`
700
+ });
701
+ } else {
702
+ claudeClientRef.current = null;
703
+ }
704
+ }, [activeApiKey]);
705
+ useEffect2(() => {
241
706
  if (typeof window === "undefined") return;
242
707
  try {
243
- const saved = localStorage.getItem(STORAGE_KEY);
708
+ const saved = localStorage.getItem(STORAGE_KEY2);
244
709
  if (saved) {
245
710
  const loaded = JSON.parse(saved).map((m) => ({
246
711
  ...m,
@@ -255,24 +720,24 @@ function ChatProvider({
255
720
  setMessages(getInitialMessages());
256
721
  }
257
722
  }, []);
258
- const [isLoading, setIsLoading] = useState(false);
259
- const [aiInterface] = useState(() => new DemoAIInterface());
260
- useEffect(() => {
723
+ const [isLoading, setIsLoading] = useState2(false);
724
+ const [aiInterface] = useState2(() => new DemoAIInterface());
725
+ useEffect2(() => {
261
726
  if (onToolExecute) {
262
727
  return aiInterface.onToolExecution((result) => {
263
728
  onToolExecute(result.toolName, result);
264
729
  });
265
730
  }
266
731
  }, [aiInterface, onToolExecute]);
267
- useEffect(() => {
732
+ useEffect2(() => {
268
733
  try {
269
734
  const toSave = messages.slice(-MAX_MESSAGES);
270
- localStorage.setItem(STORAGE_KEY, JSON.stringify(toSave));
735
+ localStorage.setItem(STORAGE_KEY2, JSON.stringify(toSave));
271
736
  } catch (error) {
272
737
  console.error("Failed to save messages:", error);
273
738
  }
274
739
  }, [messages]);
275
- const sendMessage = useCallback2(async (text) => {
740
+ const sendMessage = useCallback3(async (text) => {
276
741
  const userMessage = {
277
742
  id: Date.now().toString(),
278
743
  text,
@@ -282,14 +747,31 @@ function ChatProvider({
282
747
  setMessages((prev) => [...prev, userMessage]);
283
748
  setIsLoading(true);
284
749
  try {
285
- const result = await aiInterface.findAndExecuteCommand(text);
286
- const aiMessage = {
287
- id: (Date.now() + 1).toString(),
288
- text: result.message,
289
- type: result.success ? "ai" : "system",
290
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
291
- };
292
- setMessages((prev) => [...prev, aiMessage]);
750
+ if (claudeClientRef.current) {
751
+ const conversationHistory = messages.slice(-20).filter((m) => m.type === "user" || m.type === "ai").map((m) => ({
752
+ role: m.type === "user" ? "user" : "assistant",
753
+ content: m.text
754
+ }));
755
+ const result = await claudeClientRef.current.sendMessage(text, {
756
+ messages: conversationHistory
757
+ });
758
+ const aiMessage = {
759
+ id: (Date.now() + 1).toString(),
760
+ text: result.message,
761
+ type: result.success ? "ai" : "system",
762
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
763
+ };
764
+ setMessages((prev) => [...prev, aiMessage]);
765
+ } else {
766
+ const result = await aiInterface.findAndExecuteCommand(text);
767
+ const aiMessage = {
768
+ id: (Date.now() + 1).toString(),
769
+ text: result.message,
770
+ type: result.success ? "ai" : "system",
771
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
772
+ };
773
+ setMessages((prev) => [...prev, aiMessage]);
774
+ }
293
775
  } catch (error) {
294
776
  const errorMessage = {
295
777
  id: (Date.now() + 1).toString(),
@@ -301,16 +783,16 @@ function ChatProvider({
301
783
  } finally {
302
784
  setIsLoading(false);
303
785
  }
304
- }, [aiInterface]);
305
- const clearMessages = useCallback2(() => {
786
+ }, [aiInterface, messages]);
787
+ const clearMessages = useCallback3(() => {
306
788
  setMessages([]);
307
- localStorage.removeItem(STORAGE_KEY);
789
+ localStorage.removeItem(STORAGE_KEY2);
308
790
  }, []);
309
- return /* @__PURE__ */ jsx2(ChatContext.Provider, { value: { messages, sendMessage, clearMessages, isLoading }, children });
791
+ return /* @__PURE__ */ jsx3(ChatContext.Provider, { value: { messages, sendMessage, clearMessages, isLoading, isAiMode }, children });
310
792
  }
311
793
 
312
794
  // src/components/ChatBubble/constants.ts
313
- import React3 from "react";
795
+ import React4 from "react";
314
796
 
315
797
  // src/names/Components.ts
316
798
  var Components = {
@@ -318,7 +800,20 @@ var Components = {
318
800
  ChatToggleButton: "chat-toggle-button",
319
801
  ChatInput: "chat-message-input",
320
802
  ChatSendButton: "chat-send-button",
321
- ChatClearButton: "chat-clear-button"
803
+ ChatClearButton: "chat-clear-button",
804
+ ChatMoreMenu: "chat-more-menu",
805
+ ChatMoreMenuButton: "chat-more-menu-button",
806
+ // API Key configuration components (BYOK mode)
807
+ ApiKeySection: "api-key-section",
808
+ ApiKeyInput: "api-key-input",
809
+ ApiKeySubmitButton: "api-key-submit-button",
810
+ ApiKeyClearButton: "api-key-clear-button",
811
+ ApiKeyConfigureButton: "api-key-configure-button",
812
+ ApiKeyStatus: "api-key-status",
813
+ ApiKeyMasked: "api-key-masked",
814
+ ApiKeyError: "api-key-error",
815
+ ApiKeyShowToggle: "api-key-show-toggle",
816
+ ApiKeyCancelButton: "api-key-cancel-button"
322
817
  };
323
818
  var ChatBubbleVariant = {
324
819
  full: "full",
@@ -520,7 +1015,7 @@ var GLASS_INVERTED = {
520
1015
  var DEFAULT_CONFIG = {
521
1016
  title: "Supernal Interface",
522
1017
  logo: DEFAULT_LOGO,
523
- avatar: React3.createElement("img", { src: DEFAULT_LOGO, alt: "Supernal", className: "w-6 h-6" }),
1018
+ avatar: React4.createElement("img", { src: DEFAULT_LOGO, alt: "Supernal", className: "w-6 h-6" }),
524
1019
  description: "I'm a TOOL system AI can use to control this site",
525
1020
  placeholder: "Try: toggle notifications",
526
1021
  sendButtonLabel: "Send",
@@ -543,7 +1038,7 @@ var DEFAULT_CONFIG = {
543
1038
  };
544
1039
 
545
1040
  // src/components/ChatBubble/InputField.tsx
546
- import { jsx as jsx3, jsxs } from "react/jsx-runtime";
1041
+ import { jsx as jsx4, jsxs } from "react/jsx-runtime";
547
1042
  var InputField = ({
548
1043
  compact = false,
549
1044
  inputValue,
@@ -559,8 +1054,8 @@ var InputField = ({
559
1054
  onMicClick,
560
1055
  modKey = "Ctrl",
561
1056
  onKeyDown
562
- }) => /* @__PURE__ */ jsx3("form", { onSubmit, className: compact ? "flex space-x-2" : THEME_CLASSES.bg.inputForm + " bg-transparent", children: /* @__PURE__ */ jsxs("div", { className: compact ? "flex space-x-2 flex-1" : "relative", children: [
563
- /* @__PURE__ */ jsx3(
1057
+ }) => /* @__PURE__ */ jsx4("form", { onSubmit, className: compact ? "flex space-x-2" : THEME_CLASSES.bg.inputForm + " bg-transparent", children: /* @__PURE__ */ jsxs("div", { className: compact ? "flex space-x-2 flex-1" : "relative", children: [
1058
+ /* @__PURE__ */ jsx4(
564
1059
  "input",
565
1060
  {
566
1061
  ref: compact ? void 0 : inputRef,
@@ -574,7 +1069,7 @@ var InputField = ({
574
1069
  "data-testid": ChatNames.input
575
1070
  }
576
1071
  ),
577
- voiceEnabled && onMicClick && !compact && (!inputValue.trim() || isListening) && /* @__PURE__ */ jsx3(
1072
+ voiceEnabled && onMicClick && !compact && (!inputValue.trim() || isListening) && /* @__PURE__ */ jsx4(
578
1073
  "button",
579
1074
  {
580
1075
  type: "button",
@@ -582,33 +1077,33 @@ var InputField = ({
582
1077
  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"}`,
583
1078
  title: isListening ? "Stop recording (ESC)" : `Voice input (click or press ${modKey}+/)`,
584
1079
  "data-testid": "voice-input-button",
585
- children: isListening ? /* @__PURE__ */ jsx3("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) }) : /* @__PURE__ */ jsx3("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3("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" }) })
1080
+ children: isListening ? /* @__PURE__ */ jsx4("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) }) : /* @__PURE__ */ jsx4("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("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" }) })
586
1081
  }
587
1082
  ),
588
- inputValue.trim() && /* @__PURE__ */ jsx3(
1083
+ inputValue.trim() && /* @__PURE__ */ jsx4(
589
1084
  "button",
590
1085
  {
591
1086
  type: "submit",
592
1087
  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,
593
1088
  "data-testid": ChatNames.sendButton,
594
1089
  title: sendButtonLabel,
595
- children: compact ? "\u2192" : /* @__PURE__ */ jsx3("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "2.5", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13 5l7 7m0 0l-7 7m7-7H3" }) })
1090
+ children: compact ? "\u2192" : /* @__PURE__ */ jsx4("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "2.5", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13 5l7 7m0 0l-7 7m7-7H3" }) })
596
1091
  }
597
1092
  )
598
1093
  ] }) });
599
1094
 
600
1095
  // src/components/ChatBubble/Avatar.tsx
601
- import { Fragment, jsx as jsx4 } from "react/jsx-runtime";
1096
+ import { Fragment, jsx as jsx5 } from "react/jsx-runtime";
602
1097
  var Avatar = ({ avatar, size = "normal" }) => {
603
1098
  if (!avatar) return null;
604
1099
  if (typeof avatar === "string") {
605
- return size === "small" ? /* @__PURE__ */ jsx4("span", { className: "text-lg", children: avatar }) : /* @__PURE__ */ jsx4("div", { className: "w-10 h-10 bg-blue-600 rounded-lg flex items-center justify-center shadow-md", children: /* @__PURE__ */ jsx4("span", { className: "text-white text-sm font-bold", children: avatar }) });
1100
+ return size === "small" ? /* @__PURE__ */ jsx5("span", { className: "text-lg", children: avatar }) : /* @__PURE__ */ jsx5("div", { className: "w-10 h-10 bg-blue-600 rounded-lg flex items-center justify-center shadow-md", children: /* @__PURE__ */ jsx5("span", { className: "text-white text-sm font-bold", children: avatar }) });
606
1101
  }
607
- return /* @__PURE__ */ jsx4(Fragment, { children: avatar });
1102
+ return /* @__PURE__ */ jsx5(Fragment, { children: avatar });
608
1103
  };
609
1104
 
610
1105
  // src/components/ChatBubble/ChatBubble.tsx
611
- import React8, { useState as useState8, useRef as useRef8, useEffect as useEffect7, useMemo as useMemo3 } from "react";
1106
+ import React9, { useState as useState9, useRef as useRef10, useEffect as useEffect8, useMemo as useMemo4 } from "react";
612
1107
 
613
1108
  // src/components/MessageRenderer.tsx
614
1109
  import ReactMarkdown from "react-markdown";
@@ -618,12 +1113,12 @@ import remarkDirective from "remark-directive";
618
1113
  import rehypeKatex from "rehype-katex";
619
1114
 
620
1115
  // src/components/CodeBlock.tsx
621
- import React4, { useState as useState2 } from "react";
1116
+ import React5, { useState as useState3 } from "react";
622
1117
  import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
623
- import { vscDarkPlus, vs } from "react-syntax-highlighter/dist/cjs/styles/prism";
624
- import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
1118
+ import { vscDarkPlus, vs } from "react-syntax-highlighter/dist/esm/styles/prism";
1119
+ import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
625
1120
  function CodeBlock({ children, className, inline, theme = "dark" }) {
626
- const [copied, setCopied] = useState2(false);
1121
+ const [copied, setCopied] = useState3(false);
627
1122
  const match = /language-(\w+)/.exec(className || "");
628
1123
  const language = match ? match[1] : "text";
629
1124
  const handleCopy = async () => {
@@ -632,25 +1127,25 @@ function CodeBlock({ children, className, inline, theme = "dark" }) {
632
1127
  setTimeout(() => setCopied(false), 2e3);
633
1128
  };
634
1129
  if (inline) {
635
- return /* @__PURE__ */ jsx5("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 });
1130
+ return /* @__PURE__ */ jsx6("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 });
636
1131
  }
637
1132
  return /* @__PURE__ */ jsxs2("div", { className: "relative group my-4", children: [
638
- /* @__PURE__ */ jsx5(
1133
+ /* @__PURE__ */ jsx6(
639
1134
  "button",
640
1135
  {
641
1136
  onClick: handleCopy,
642
1137
  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"}`,
643
1138
  "aria-label": "Copy code",
644
1139
  children: copied ? /* @__PURE__ */ jsxs2("span", { className: "flex items-center gap-1", children: [
645
- /* @__PURE__ */ jsx5("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }),
1140
+ /* @__PURE__ */ jsx6("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }),
646
1141
  "Copied!"
647
1142
  ] }) : /* @__PURE__ */ jsxs2("span", { className: "flex items-center gap-1", children: [
648
- /* @__PURE__ */ jsx5("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("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" }) }),
1143
+ /* @__PURE__ */ jsx6("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6("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" }) }),
649
1144
  "Copy"
650
1145
  ] })
651
1146
  }
652
1147
  ),
653
- React4.createElement(SyntaxHighlighter, {
1148
+ React5.createElement(SyntaxHighlighter, {
654
1149
  language,
655
1150
  style: theme === "dark" ? vscDarkPlus : vs,
656
1151
  customStyle: {
@@ -667,13 +1162,13 @@ function CodeBlock({ children, className, inline, theme = "dark" }) {
667
1162
  }
668
1163
 
669
1164
  // src/components/MermaidDiagram.tsx
670
- import { useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
671
- import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
1165
+ import { useEffect as useEffect3, useRef as useRef4, useState as useState4 } from "react";
1166
+ import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
672
1167
  function MermaidDiagram({ chart, theme = "dark" }) {
673
- const containerRef = useRef2(null);
674
- const [error, setError] = useState3(null);
675
- const [isLoading, setIsLoading] = useState3(true);
676
- useEffect2(() => {
1168
+ const containerRef = useRef4(null);
1169
+ const [error, setError] = useState4(null);
1170
+ const [isLoading, setIsLoading] = useState4(true);
1171
+ useEffect3(() => {
677
1172
  let mounted = true;
678
1173
  const renderDiagram = async () => {
679
1174
  if (!containerRef.current) return;
@@ -708,17 +1203,17 @@ function MermaidDiagram({ chart, theme = "dark" }) {
708
1203
  }, [chart, theme]);
709
1204
  if (error) {
710
1205
  return /* @__PURE__ */ jsxs3("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: [
711
- /* @__PURE__ */ jsx6("div", { className: "font-semibold mb-1", children: "Mermaid Diagram Error" }),
712
- /* @__PURE__ */ jsx6("div", { className: "text-sm opacity-90", children: error }),
1206
+ /* @__PURE__ */ jsx7("div", { className: "font-semibold mb-1", children: "Mermaid Diagram Error" }),
1207
+ /* @__PURE__ */ jsx7("div", { className: "text-sm opacity-90", children: error }),
713
1208
  /* @__PURE__ */ jsxs3("details", { className: "mt-2 text-xs opacity-75", children: [
714
- /* @__PURE__ */ jsx6("summary", { className: "cursor-pointer", children: "View diagram source" }),
715
- /* @__PURE__ */ jsx6("pre", { className: "mt-2 whitespace-pre-wrap", children: chart })
1209
+ /* @__PURE__ */ jsx7("summary", { className: "cursor-pointer", children: "View diagram source" }),
1210
+ /* @__PURE__ */ jsx7("pre", { className: "mt-2 whitespace-pre-wrap", children: chart })
716
1211
  ] })
717
1212
  ] });
718
1213
  }
719
1214
  return /* @__PURE__ */ jsxs3("div", { className: "my-4 flex justify-center", children: [
720
- isLoading && /* @__PURE__ */ jsx6("div", { className: `py-8 text-sm ${theme === "dark" ? "text-gray-400" : "text-gray-600"}`, children: "Rendering diagram..." }),
721
- /* @__PURE__ */ jsx6(
1215
+ isLoading && /* @__PURE__ */ jsx7("div", { className: `py-8 text-sm ${theme === "dark" ? "text-gray-400" : "text-gray-600"}`, children: "Rendering diagram..." }),
1216
+ /* @__PURE__ */ jsx7(
722
1217
  "div",
723
1218
  {
724
1219
  ref: containerRef,
@@ -729,7 +1224,7 @@ function MermaidDiagram({ chart, theme = "dark" }) {
729
1224
  }
730
1225
 
731
1226
  // src/components/MessageRenderer.tsx
732
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
1227
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
733
1228
  function MessageRenderer({ content, theme = "dark" }) {
734
1229
  const components = {
735
1230
  // Code blocks with syntax highlighting
@@ -740,9 +1235,9 @@ function MessageRenderer({ content, theme = "dark" }) {
740
1235
  const language = match ? match[1] : "";
741
1236
  const inline = !className;
742
1237
  if (language === "mermaid") {
743
- return /* @__PURE__ */ jsx7(MermaidDiagram, { chart: value, theme });
1238
+ return /* @__PURE__ */ jsx8(MermaidDiagram, { chart: value, theme });
744
1239
  }
745
- return /* @__PURE__ */ jsx7(
1240
+ return /* @__PURE__ */ jsx8(
746
1241
  CodeBlock,
747
1242
  {
748
1243
  className,
@@ -753,13 +1248,13 @@ function MessageRenderer({ content, theme = "dark" }) {
753
1248
  );
754
1249
  },
755
1250
  // Headings with better styling
756
- h1: ({ children }) => /* @__PURE__ */ jsx7("h1", { className: `text-2xl font-bold mt-6 mb-3 ${theme === "dark" ? "text-gray-100" : "text-gray-900"}`, children }),
757
- h2: ({ children }) => /* @__PURE__ */ jsx7("h2", { className: `text-xl font-bold mt-5 mb-2.5 ${theme === "dark" ? "text-gray-100" : "text-gray-900"}`, children }),
758
- h3: ({ children }) => /* @__PURE__ */ jsx7("h3", { className: `text-lg font-semibold mt-4 mb-2 ${theme === "dark" ? "text-gray-200" : "text-gray-800"}`, children }),
1251
+ h1: ({ children }) => /* @__PURE__ */ jsx8("h1", { className: `text-2xl font-bold mt-6 mb-3 ${theme === "dark" ? "text-gray-100" : "text-gray-900"}`, children }),
1252
+ h2: ({ children }) => /* @__PURE__ */ jsx8("h2", { className: `text-xl font-bold mt-5 mb-2.5 ${theme === "dark" ? "text-gray-100" : "text-gray-900"}`, children }),
1253
+ h3: ({ children }) => /* @__PURE__ */ jsx8("h3", { className: `text-lg font-semibold mt-4 mb-2 ${theme === "dark" ? "text-gray-200" : "text-gray-800"}`, children }),
759
1254
  // Paragraphs
760
- p: ({ children }) => /* @__PURE__ */ jsx7("p", { className: `mb-3 leading-relaxed ${theme === "dark" ? "text-gray-300" : "text-gray-700"}`, children }),
1255
+ p: ({ children }) => /* @__PURE__ */ jsx8("p", { className: `mb-3 leading-relaxed ${theme === "dark" ? "text-gray-300" : "text-gray-700"}`, children }),
761
1256
  // Links
762
- a: ({ href, children }) => /* @__PURE__ */ jsx7(
1257
+ a: ({ href, children }) => /* @__PURE__ */ jsx8(
763
1258
  "a",
764
1259
  {
765
1260
  href,
@@ -770,17 +1265,17 @@ function MessageRenderer({ content, theme = "dark" }) {
770
1265
  }
771
1266
  ),
772
1267
  // Lists
773
- ul: ({ children }) => /* @__PURE__ */ jsx7("ul", { className: `list-disc list-inside mb-3 space-y-1 ${theme === "dark" ? "text-gray-300" : "text-gray-700"}`, children }),
774
- ol: ({ children }) => /* @__PURE__ */ jsx7("ol", { className: `list-decimal list-inside mb-3 space-y-1 ${theme === "dark" ? "text-gray-300" : "text-gray-700"}`, children }),
1268
+ ul: ({ children }) => /* @__PURE__ */ jsx8("ul", { className: `list-disc list-inside mb-3 space-y-1 ${theme === "dark" ? "text-gray-300" : "text-gray-700"}`, children }),
1269
+ ol: ({ children }) => /* @__PURE__ */ jsx8("ol", { className: `list-decimal list-inside mb-3 space-y-1 ${theme === "dark" ? "text-gray-300" : "text-gray-700"}`, children }),
775
1270
  // Blockquotes
776
- blockquote: ({ children }) => /* @__PURE__ */ jsx7("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 }),
1271
+ blockquote: ({ children }) => /* @__PURE__ */ jsx8("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 }),
777
1272
  // Tables
778
- table: ({ children }) => /* @__PURE__ */ jsx7("div", { className: "overflow-x-auto my-4", children: /* @__PURE__ */ jsx7("table", { className: `min-w-full border-collapse ${theme === "dark" ? "border-gray-700" : "border-gray-300"}`, children }) }),
779
- thead: ({ children }) => /* @__PURE__ */ jsx7("thead", { className: theme === "dark" ? "bg-gray-800" : "bg-gray-100", children }),
780
- th: ({ children }) => /* @__PURE__ */ jsx7("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 }),
781
- td: ({ children }) => /* @__PURE__ */ jsx7("td", { className: `px-4 py-2 border ${theme === "dark" ? "border-gray-700 text-gray-300" : "border-gray-300 text-gray-700"}`, children }),
1273
+ table: ({ children }) => /* @__PURE__ */ jsx8("div", { className: "overflow-x-auto my-4", children: /* @__PURE__ */ jsx8("table", { className: `min-w-full border-collapse ${theme === "dark" ? "border-gray-700" : "border-gray-300"}`, children }) }),
1274
+ thead: ({ children }) => /* @__PURE__ */ jsx8("thead", { className: theme === "dark" ? "bg-gray-800" : "bg-gray-100", children }),
1275
+ th: ({ children }) => /* @__PURE__ */ jsx8("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 }),
1276
+ td: ({ children }) => /* @__PURE__ */ jsx8("td", { className: `px-4 py-2 border ${theme === "dark" ? "border-gray-700 text-gray-300" : "border-gray-300 text-gray-700"}`, children }),
782
1277
  // Horizontal rule
783
- hr: () => /* @__PURE__ */ jsx7("hr", { className: `my-4 border-t ${theme === "dark" ? "border-gray-700" : "border-gray-300"}` }),
1278
+ hr: () => /* @__PURE__ */ jsx8("hr", { className: `my-4 border-t ${theme === "dark" ? "border-gray-700" : "border-gray-300"}` }),
784
1279
  // Admonitions support (using containerDirective from remark-directive)
785
1280
  div: ({ node, className, children, ...props }) => {
786
1281
  if (className?.includes("admonition")) {
@@ -808,15 +1303,15 @@ function MessageRenderer({ content, theme = "dark" }) {
808
1303
  }
809
1304
  };
810
1305
  const style = styles[type] || styles.info;
811
- return /* @__PURE__ */ jsx7("div", { className: `my-4 p-4 border-l-4 rounded-r-lg ${style.border} ${style.bg}`, children: /* @__PURE__ */ jsxs4("div", { className: "flex items-start gap-2", children: [
812
- /* @__PURE__ */ jsx7("span", { className: "text-lg flex-shrink-0", children: style.icon }),
813
- /* @__PURE__ */ jsx7("div", { className: "flex-1", children })
1306
+ return /* @__PURE__ */ jsx8("div", { className: `my-4 p-4 border-l-4 rounded-r-lg ${style.border} ${style.bg}`, children: /* @__PURE__ */ jsxs4("div", { className: "flex items-start gap-2", children: [
1307
+ /* @__PURE__ */ jsx8("span", { className: "text-lg flex-shrink-0", children: style.icon }),
1308
+ /* @__PURE__ */ jsx8("div", { className: "flex-1", children })
814
1309
  ] }) });
815
1310
  }
816
- return /* @__PURE__ */ jsx7("div", { className, ...props, children });
1311
+ return /* @__PURE__ */ jsx8("div", { className, ...props, children });
817
1312
  }
818
1313
  };
819
- return /* @__PURE__ */ jsx7("div", { className: "markdown-content", children: /* @__PURE__ */ jsx7(
1314
+ return /* @__PURE__ */ jsx8("div", { className: "markdown-content", children: /* @__PURE__ */ jsx8(
820
1315
  ReactMarkdown,
821
1316
  {
822
1317
  remarkPlugins: [remarkGfm, remarkMath, remarkDirective],
@@ -828,7 +1323,7 @@ function MessageRenderer({ content, theme = "dark" }) {
828
1323
  }
829
1324
 
830
1325
  // src/hooks/useTTS.ts
831
- import { useState as useState4, useRef as useRef3, useCallback as useCallback3 } from "react";
1326
+ import { useState as useState5, useRef as useRef5, useCallback as useCallback4 } from "react";
832
1327
  var Platform = {
833
1328
  isNative: typeof window !== "undefined" && "Capacitor" in window,
834
1329
  isWeb: typeof window !== "undefined" && !("Capacitor" in window)
@@ -843,13 +1338,13 @@ function isNativeTTSSupported() {
843
1338
  return false;
844
1339
  }
845
1340
  function useTTS() {
846
- const [isPlaying, setIsPlaying] = useState4(false);
847
- const [error, setError] = useState4(null);
848
- const [currentText, setCurrentText] = useState4(null);
849
- const audioRef = useRef3(null);
850
- const utteranceRef = useRef3(null);
1341
+ const [isPlaying, setIsPlaying] = useState5(false);
1342
+ const [error, setError] = useState5(null);
1343
+ const [currentText, setCurrentText] = useState5(null);
1344
+ const audioRef = useRef5(null);
1345
+ const utteranceRef = useRef5(null);
851
1346
  const isNativeSupported = isNativeTTSSupported();
852
- const speakNative = useCallback3(
1347
+ const speakNative = useCallback4(
853
1348
  async (text, options = {}) => {
854
1349
  if (Platform.isNative) {
855
1350
  try {
@@ -894,7 +1389,7 @@ function useTTS() {
894
1389
  },
895
1390
  []
896
1391
  );
897
- const speakAPI = useCallback3(
1392
+ const speakAPI = useCallback4(
898
1393
  async (text, options = {}) => {
899
1394
  const apiUrl = process.env.NEXT_PUBLIC_TTS_API_URL || "https://tts.supernal.ai";
900
1395
  const apiKey = process.env.NEXT_PUBLIC_TTS_API_KEY || "";
@@ -955,7 +1450,7 @@ function useTTS() {
955
1450
  },
956
1451
  []
957
1452
  );
958
- const speak = useCallback3(
1453
+ const speak = useCallback4(
959
1454
  async (options) => {
960
1455
  const {
961
1456
  text,
@@ -999,7 +1494,7 @@ function useTTS() {
999
1494
  },
1000
1495
  [speakNative, speakAPI, isNativeSupported]
1001
1496
  );
1002
- const stop = useCallback3(() => {
1497
+ const stop = useCallback4(() => {
1003
1498
  if ("speechSynthesis" in window && window.speechSynthesis.speaking) {
1004
1499
  window.speechSynthesis.cancel();
1005
1500
  utteranceRef.current = null;
@@ -1032,18 +1527,18 @@ function base64ToBlob(base64, mimeType) {
1032
1527
  }
1033
1528
 
1034
1529
  // src/hooks/useSTT.ts
1035
- import { useState as useState5, useRef as useRef4, useCallback as useCallback4, useMemo, useEffect as useEffect3 } from "react";
1530
+ import { useState as useState6, useRef as useRef6, useCallback as useCallback5, useMemo as useMemo2, useEffect as useEffect4 } from "react";
1036
1531
  var Platform2 = {
1037
1532
  isNative: typeof window !== "undefined" && "Capacitor" in window,
1038
1533
  isWeb: typeof window !== "undefined" && !("Capacitor" in window)
1039
1534
  };
1040
1535
  function useSTT() {
1041
- const [isListening, setIsListening] = useState5(false);
1042
- const [transcript, setTranscript] = useState5("");
1043
- const [interimTranscript, setInterimTranscript] = useState5("");
1044
- const [error, setError] = useState5(null);
1045
- const recognitionRef = useRef4(null);
1046
- const isSupported = useMemo(() => {
1536
+ const [isListening, setIsListening] = useState6(false);
1537
+ const [transcript, setTranscript] = useState6("");
1538
+ const [interimTranscript, setInterimTranscript] = useState6("");
1539
+ const [error, setError] = useState6(null);
1540
+ const recognitionRef = useRef6(null);
1541
+ const isSupported = useMemo2(() => {
1047
1542
  if (Platform2.isNative) {
1048
1543
  return true;
1049
1544
  }
@@ -1052,7 +1547,7 @@ function useSTT() {
1052
1547
  }
1053
1548
  return false;
1054
1549
  }, []);
1055
- useEffect3(() => {
1550
+ useEffect4(() => {
1056
1551
  if (!isSupported || Platform2.isNative) return;
1057
1552
  const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
1058
1553
  if (!SpeechRecognition) return;
@@ -1090,7 +1585,7 @@ function useSTT() {
1090
1585
  }
1091
1586
  };
1092
1587
  }, [isSupported]);
1093
- const startListening = useCallback4(async () => {
1588
+ const startListening = useCallback5(async () => {
1094
1589
  setError(null);
1095
1590
  setTranscript("");
1096
1591
  setInterimTranscript("");
@@ -1122,7 +1617,7 @@ function useSTT() {
1122
1617
  setIsListening(false);
1123
1618
  }
1124
1619
  }, []);
1125
- const stopListening = useCallback4(() => {
1620
+ const stopListening = useCallback5(() => {
1126
1621
  if (Platform2.isNative) {
1127
1622
  setIsListening(false);
1128
1623
  return;
@@ -1131,7 +1626,7 @@ function useSTT() {
1131
1626
  recognitionRef.current.stop();
1132
1627
  }
1133
1628
  }, []);
1134
- const resetTranscript = useCallback4(() => {
1629
+ const resetTranscript = useCallback5(() => {
1135
1630
  setTranscript("");
1136
1631
  setInterimTranscript("");
1137
1632
  setError(null);
@@ -1149,7 +1644,7 @@ function useSTT() {
1149
1644
  }
1150
1645
 
1151
1646
  // src/components/TTSButton.tsx
1152
- import { jsx as jsx8 } from "react/jsx-runtime";
1647
+ import { jsx as jsx9 } from "react/jsx-runtime";
1153
1648
  function TTSButton({
1154
1649
  text,
1155
1650
  usePremiumVoices = false,
@@ -1177,7 +1672,7 @@ function TTSButton({
1177
1672
  const isDark = theme === "dark";
1178
1673
  const iconSize = size === "small" ? "w-3 h-3" : "w-4 h-4";
1179
1674
  const buttonPadding = size === "small" ? "p-1" : "p-2";
1180
- return /* @__PURE__ */ jsx8(
1675
+ return /* @__PURE__ */ jsx9(
1181
1676
  "button",
1182
1677
  {
1183
1678
  onClick: handleClick,
@@ -1187,23 +1682,23 @@ function TTSButton({
1187
1682
  "aria-label": isPlaying ? "Stop speaking" : "Read aloud",
1188
1683
  children: isPlaying ? (
1189
1684
  // Stop icon (pulsing square)
1190
- /* @__PURE__ */ jsx8("svg", { className: iconSize, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx8("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) })
1685
+ /* @__PURE__ */ jsx9("svg", { className: iconSize, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx9("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) })
1191
1686
  ) : error ? (
1192
1687
  // Error icon
1193
- /* @__PURE__ */ jsx8("svg", { className: iconSize, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx8("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) })
1688
+ /* @__PURE__ */ jsx9("svg", { className: iconSize, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx9("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) })
1194
1689
  ) : (
1195
1690
  // Speaker icon
1196
- /* @__PURE__ */ jsx8("svg", { className: iconSize, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx8("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" }) })
1691
+ /* @__PURE__ */ jsx9("svg", { className: iconSize, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx9("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" }) })
1197
1692
  )
1198
1693
  }
1199
1694
  );
1200
1695
  }
1201
1696
 
1202
1697
  // src/components/SubtitleOverlay.tsx
1203
- import { useState as useState6, useEffect as useEffect4, useRef as useRef5 } from "react";
1698
+ import { useState as useState7, useEffect as useEffect5, useRef as useRef7 } from "react";
1204
1699
 
1205
1700
  // src/components/TTSPlaylistMenu.tsx
1206
- import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
1701
+ import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
1207
1702
  var TTSPlaylistMenu = ({
1208
1703
  isOpen,
1209
1704
  onClose,
@@ -1224,7 +1719,7 @@ var TTSPlaylistMenu = ({
1224
1719
  border: "1px solid rgba(0, 0, 0, 0.1)",
1225
1720
  boxShadow: "0 8px 32px rgba(0, 0, 0, 0.2)"
1226
1721
  };
1227
- return /* @__PURE__ */ jsx9(
1722
+ return /* @__PURE__ */ jsx10(
1228
1723
  "div",
1229
1724
  {
1230
1725
  className: "fixed z-50",
@@ -1250,33 +1745,33 @@ var TTSPlaylistMenu = ({
1250
1745
  {
1251
1746
  className: `p-4 border-b flex items-center justify-between ${theme === "dark" ? "border-white/10" : "border-black/10"}`,
1252
1747
  children: [
1253
- /* @__PURE__ */ jsx9(
1748
+ /* @__PURE__ */ jsx10(
1254
1749
  "h3",
1255
1750
  {
1256
1751
  className: `font-semibold text-sm ${theme === "dark" ? "text-white" : "text-gray-900"}`,
1257
1752
  children: "Readable Sections"
1258
1753
  }
1259
1754
  ),
1260
- /* @__PURE__ */ jsx9(
1755
+ /* @__PURE__ */ jsx10(
1261
1756
  "button",
1262
1757
  {
1263
1758
  onClick: onClose,
1264
1759
  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"}`,
1265
1760
  title: "Close",
1266
1761
  "data-testid": "close-playlist-menu",
1267
- children: /* @__PURE__ */ jsx9("span", { className: "text-lg font-bold", "aria-hidden": "true", children: "\xD7" })
1762
+ children: /* @__PURE__ */ jsx10("span", { className: "text-lg font-bold", "aria-hidden": "true", children: "\xD7" })
1268
1763
  }
1269
1764
  )
1270
1765
  ]
1271
1766
  }
1272
1767
  ),
1273
- /* @__PURE__ */ jsx9("div", { className: "overflow-y-auto max-h-80 p-2", children: widgets.length === 0 ? /* @__PURE__ */ jsx9(
1768
+ /* @__PURE__ */ jsx10("div", { className: "overflow-y-auto max-h-80 p-2", children: widgets.length === 0 ? /* @__PURE__ */ jsx10(
1274
1769
  "div",
1275
1770
  {
1276
1771
  className: `p-6 text-center text-sm ${theme === "dark" ? "text-gray-400" : "text-gray-600"}`,
1277
1772
  children: "No readable sections found on this page"
1278
1773
  }
1279
- ) : widgets.map((widget) => /* @__PURE__ */ jsx9(
1774
+ ) : widgets.map((widget) => /* @__PURE__ */ jsx10(
1280
1775
  "button",
1281
1776
  {
1282
1777
  onClick: () => handleWidgetClick(widget),
@@ -1291,7 +1786,7 @@ var TTSPlaylistMenu = ({
1291
1786
  {
1292
1787
  className: `font-medium text-sm flex items-center ${theme === "dark" ? "text-white" : "text-gray-900"}`,
1293
1788
  children: [
1294
- /* @__PURE__ */ jsx9("span", { className: "mr-2", "aria-hidden": "true", children: "\u{1F50A}" }),
1789
+ /* @__PURE__ */ jsx10("span", { className: "mr-2", "aria-hidden": "true", children: "\u{1F50A}" }),
1295
1790
  widget.label || `TTS Widget ${widget.id}`
1296
1791
  ]
1297
1792
  }
@@ -1514,7 +2009,7 @@ function extractTTSWidgets() {
1514
2009
  }
1515
2010
 
1516
2011
  // src/components/SubtitleOverlay.tsx
1517
- import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
2012
+ import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
1518
2013
  var opacityStates = {
1519
2014
  mobile: {
1520
2015
  idle: 1,
@@ -1558,47 +2053,47 @@ var SubtitleOverlay = ({
1558
2053
  resetTranscript,
1559
2054
  onSwitchToFullMode
1560
2055
  }) => {
1561
- const [overlayState, setOverlayState] = useState6("idle");
1562
- const [opacity, setOpacity] = useState6(1);
1563
- const [lastInputMethod, setLastInputMethod] = useState6(null);
1564
- const [isMobile, setIsMobile] = useState6(false);
1565
- const [messageOpacity, setMessageOpacity] = useState6(1);
1566
- const [expansionState, setExpansionState] = useState6(() => {
2056
+ const [overlayState, setOverlayState] = useState7("idle");
2057
+ const [opacity, setOpacity] = useState7(1);
2058
+ const [lastInputMethod, setLastInputMethod] = useState7(null);
2059
+ const [isMobile, setIsMobile] = useState7(false);
2060
+ const [messageOpacity, setMessageOpacity] = useState7(1);
2061
+ const [expansionState, setExpansionState] = useState7(() => {
1567
2062
  if (typeof window !== "undefined") {
1568
2063
  const saved = localStorage.getItem("subtitle-overlay-expanded");
1569
2064
  return saved === "true" ? "expanded" : "collapsed";
1570
2065
  }
1571
2066
  return "collapsed";
1572
2067
  });
1573
- const [touchStartY, setTouchStartY] = useState6(null);
1574
- const lastInputTimeRef = useRef5(Date.now());
1575
- const autoFadeTimerRef = useRef5(null);
1576
- const messageFadeTimerRef = useRef5(null);
1577
- const inputRef = useRef5(null);
1578
- const [suggestions, setSuggestions] = useState6([]);
1579
- const [currentSuggestionIndex, setCurrentSuggestionIndex] = useState6(0);
1580
- const [glassTheme, setGlassTheme] = useState6("auto");
1581
- const [detectedGlassTheme, setDetectedGlassTheme] = useState6("light");
1582
- const [hasTTSWidgets, setHasTTSWidgets] = useState6(false);
1583
- const [showPlaylist, setShowPlaylist] = useState6(false);
1584
- const [ttsWidgets, setTTSWidgets] = useState6([]);
1585
- const [touchStartYInput, setTouchStartYInput] = useState6(null);
1586
- const [completedActions, setCompletedActions] = useState6([]);
1587
- const [showCompletedActions, setShowCompletedActions] = useState6(false);
1588
- const [shouldShowAiResponse, setShouldShowAiResponse] = useState6(false);
1589
- const [latestActionOpacity, setLatestActionOpacity] = useState6(0);
1590
- const latestActionFadeRef = useRef5(null);
1591
- const lastUserMessageRef = useRef5("");
1592
- const lastShownAiMessageRef = useRef5("");
1593
- const justExpandedViaSlashRef = useRef5(false);
1594
- const [isDragging, setIsDragging] = useState6(false);
1595
- const [position, setPosition] = useState6({ x: 0, y: 0 });
1596
- const [dragStart, setDragStart] = useState6({ x: 0, y: 0 });
1597
- const dragRef = useRef5(null);
1598
- const dragDistanceRef = useRef5(0);
1599
- const lastEscapeTimeRef = useRef5(0);
2068
+ const [touchStartY, setTouchStartY] = useState7(null);
2069
+ const lastInputTimeRef = useRef7(Date.now());
2070
+ const autoFadeTimerRef = useRef7(null);
2071
+ const messageFadeTimerRef = useRef7(null);
2072
+ const inputRef = useRef7(null);
2073
+ const [suggestions, setSuggestions] = useState7([]);
2074
+ const [currentSuggestionIndex, setCurrentSuggestionIndex] = useState7(0);
2075
+ const [glassTheme, setGlassTheme] = useState7("auto");
2076
+ const [detectedGlassTheme, setDetectedGlassTheme] = useState7("light");
2077
+ const [hasTTSWidgets, setHasTTSWidgets] = useState7(false);
2078
+ const [showPlaylist, setShowPlaylist] = useState7(false);
2079
+ const [ttsWidgets, setTTSWidgets] = useState7([]);
2080
+ const [touchStartYInput, setTouchStartYInput] = useState7(null);
2081
+ const [completedActions, setCompletedActions] = useState7([]);
2082
+ const [showCompletedActions, setShowCompletedActions] = useState7(false);
2083
+ const [shouldShowAiResponse, setShouldShowAiResponse] = useState7(false);
2084
+ const [latestActionOpacity, setLatestActionOpacity] = useState7(0);
2085
+ const latestActionFadeRef = useRef7(null);
2086
+ const lastUserMessageRef = useRef7("");
2087
+ const lastShownAiMessageRef = useRef7("");
2088
+ const justExpandedViaSlashRef = useRef7(false);
2089
+ const [isDragging, setIsDragging] = useState7(false);
2090
+ const [position, setPosition] = useState7({ x: 0, y: 0 });
2091
+ const [dragStart, setDragStart] = useState7({ x: 0, y: 0 });
2092
+ const dragRef = useRef7(null);
2093
+ const dragDistanceRef = useRef7(0);
2094
+ const lastEscapeTimeRef = useRef7(0);
1600
2095
  const DOUBLE_ESCAPE_THRESHOLD_MS = 500;
1601
- useEffect4(() => {
2096
+ useEffect5(() => {
1602
2097
  const checkMobile = () => {
1603
2098
  const mobile = window.innerWidth < 768;
1604
2099
  setIsMobile(mobile);
@@ -1607,7 +2102,7 @@ var SubtitleOverlay = ({
1607
2102
  window.addEventListener("resize", checkMobile);
1608
2103
  return () => window.removeEventListener("resize", checkMobile);
1609
2104
  }, []);
1610
- useEffect4(() => {
2105
+ useEffect5(() => {
1611
2106
  if (autoFadeTimerRef.current) {
1612
2107
  clearTimeout(autoFadeTimerRef.current);
1613
2108
  autoFadeTimerRef.current = null;
@@ -1623,7 +2118,7 @@ var SubtitleOverlay = ({
1623
2118
  }
1624
2119
  };
1625
2120
  }, [overlayState, isMobile]);
1626
- useEffect4(() => {
2121
+ useEffect5(() => {
1627
2122
  if (messageFadeTimerRef.current) {
1628
2123
  clearTimeout(messageFadeTimerRef.current);
1629
2124
  messageFadeTimerRef.current = null;
@@ -1659,7 +2154,7 @@ var SubtitleOverlay = ({
1659
2154
  }
1660
2155
  };
1661
2156
  }, [messages.filter((m) => m.type === "ai").slice(-1)[0]?.text, shouldShowAiResponse]);
1662
- useEffect4(() => {
2157
+ useEffect5(() => {
1663
2158
  if (sttTranscript && voiceEnabled && resetTranscript) {
1664
2159
  onSendMessage(sttTranscript);
1665
2160
  resetTranscript();
@@ -1676,11 +2171,11 @@ var SubtitleOverlay = ({
1676
2171
  triggerActionFade();
1677
2172
  }
1678
2173
  }, [sttTranscript, voiceEnabled, resetTranscript, onSendMessage]);
1679
- useEffect4(() => {
2174
+ useEffect5(() => {
1680
2175
  const pageSuggestions = extractPageSuggestions();
1681
2176
  setSuggestions(pageSuggestions);
1682
2177
  }, []);
1683
- useEffect4(() => {
2178
+ useEffect5(() => {
1684
2179
  const detectWidgets = async () => {
1685
2180
  const detected = await detectTTSWidgets();
1686
2181
  setHasTTSWidgets(detected);
@@ -1715,7 +2210,7 @@ var SubtitleOverlay = ({
1715
2210
  window.removeEventListener("supernal-tts-ready", handleReady);
1716
2211
  };
1717
2212
  }, []);
1718
- useEffect4(() => {
2213
+ useEffect5(() => {
1719
2214
  if (glassTheme !== "auto") return;
1720
2215
  const { glassTheme: detected } = detectBackgroundContext();
1721
2216
  setDetectedGlassTheme(detected);
@@ -1731,7 +2226,7 @@ var SubtitleOverlay = ({
1731
2226
  window.addEventListener("scroll", handleScroll);
1732
2227
  return () => window.removeEventListener("scroll", handleScroll);
1733
2228
  }, [glassTheme]);
1734
- useEffect4(() => {
2229
+ useEffect5(() => {
1735
2230
  const handleGlobalKeyDown = (e) => {
1736
2231
  if (e.key === "Escape") {
1737
2232
  const now = Date.now();
@@ -1778,12 +2273,12 @@ var SubtitleOverlay = ({
1778
2273
  window.addEventListener("keydown", handleGlobalKeyDown);
1779
2274
  return () => window.removeEventListener("keydown", handleGlobalKeyDown);
1780
2275
  }, [expansionState, onSwitchToFullMode, voiceEnabled, onMicClick]);
1781
- useEffect4(() => {
2276
+ useEffect5(() => {
1782
2277
  if (typeof window !== "undefined") {
1783
2278
  localStorage.setItem("subtitle-overlay-expanded", expansionState === "expanded" ? "true" : "false");
1784
2279
  }
1785
2280
  }, [expansionState]);
1786
- useEffect4(() => {
2281
+ useEffect5(() => {
1787
2282
  if (expansionState === "expanded" && inputRef.current) {
1788
2283
  setTimeout(() => {
1789
2284
  inputRef.current?.focus();
@@ -1797,7 +2292,7 @@ var SubtitleOverlay = ({
1797
2292
  }, 100);
1798
2293
  }
1799
2294
  }, [expansionState]);
1800
- useEffect4(() => {
2295
+ useEffect5(() => {
1801
2296
  if (isMobile) return;
1802
2297
  const handleMouseMove = (e) => {
1803
2298
  if (!isDragging) return;
@@ -1821,7 +2316,7 @@ var SubtitleOverlay = ({
1821
2316
  window.removeEventListener("mouseup", handleMouseUp);
1822
2317
  };
1823
2318
  }, [isDragging, dragStart, isMobile]);
1824
- useEffect4(() => {
2319
+ useEffect5(() => {
1825
2320
  const timeSinceLastInput = Date.now() - lastInputTimeRef.current;
1826
2321
  const context = {
1827
2322
  isListening,
@@ -1982,7 +2477,7 @@ var SubtitleOverlay = ({
1982
2477
  };
1983
2478
  if (expansionState === "collapsed") {
1984
2479
  return /* @__PURE__ */ jsxs6(Fragment2, { children: [
1985
- hasTTSWidgets && /* @__PURE__ */ jsx10(
2480
+ hasTTSWidgets && /* @__PURE__ */ jsx11(
1986
2481
  "button",
1987
2482
  {
1988
2483
  type: "button",
@@ -2001,10 +2496,10 @@ var SubtitleOverlay = ({
2001
2496
  title: ttsWidgets.length === 1 ? "Go to readable section" : "View readable sections",
2002
2497
  "data-testid": "tts-playlist-button",
2003
2498
  "aria-label": ttsWidgets.length === 1 ? "Go to readable section" : "View readable sections",
2004
- children: /* @__PURE__ */ jsx10("span", { className: "text-xl font-bold select-none", "aria-hidden": "true", children: "~+" })
2499
+ children: /* @__PURE__ */ jsx11("span", { className: "text-xl font-bold select-none", "aria-hidden": "true", children: "~+" })
2005
2500
  }
2006
2501
  ),
2007
- /* @__PURE__ */ jsx10(
2502
+ /* @__PURE__ */ jsx11(
2008
2503
  TTSPlaylistMenu,
2009
2504
  {
2010
2505
  isOpen: showPlaylist,
@@ -2014,7 +2509,7 @@ var SubtitleOverlay = ({
2014
2509
  onWidgetSelect: handleWidgetSelect
2015
2510
  }
2016
2511
  ),
2017
- /* @__PURE__ */ jsx10(
2512
+ /* @__PURE__ */ jsx11(
2018
2513
  "div",
2019
2514
  {
2020
2515
  className: "fixed",
@@ -2024,7 +2519,7 @@ var SubtitleOverlay = ({
2024
2519
  zIndex: 55
2025
2520
  },
2026
2521
  "data-testid": "subtitle-overlay-collapsed",
2027
- children: /* @__PURE__ */ jsx10(
2522
+ children: /* @__PURE__ */ jsx11(
2028
2523
  "button",
2029
2524
  {
2030
2525
  type: "button",
@@ -2040,7 +2535,7 @@ var SubtitleOverlay = ({
2040
2535
  title: getIconTitle(),
2041
2536
  "data-testid": "voice-input-button",
2042
2537
  "aria-label": getIconTitle(),
2043
- children: /* @__PURE__ */ jsx10("span", { className: "text-xl font-bold select-none", "aria-hidden": "true", children: getIcon() })
2538
+ children: /* @__PURE__ */ jsx11("span", { className: "text-xl font-bold select-none", "aria-hidden": "true", children: getIcon() })
2044
2539
  }
2045
2540
  )
2046
2541
  }
@@ -2073,7 +2568,7 @@ var SubtitleOverlay = ({
2073
2568
  role: "complementary",
2074
2569
  "aria-label": "Chat overlay",
2075
2570
  children: [
2076
- !isMobile && /* @__PURE__ */ jsx10(
2571
+ !isMobile && /* @__PURE__ */ jsx11(
2077
2572
  "div",
2078
2573
  {
2079
2574
  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",
@@ -2101,8 +2596,8 @@ var SubtitleOverlay = ({
2101
2596
  "data-testid": "completed-actions-list",
2102
2597
  children: [
2103
2598
  /* @__PURE__ */ jsxs6("div", { className: "font-medium opacity-70 mb-2 flex items-center justify-between", children: [
2104
- /* @__PURE__ */ jsx10("span", { children: "Completed Actions" }),
2105
- /* @__PURE__ */ jsx10(
2599
+ /* @__PURE__ */ jsx11("span", { children: "Completed Actions" }),
2600
+ /* @__PURE__ */ jsx11(
2106
2601
  "button",
2107
2602
  {
2108
2603
  onClick: () => setShowCompletedActions(false),
@@ -2112,9 +2607,9 @@ var SubtitleOverlay = ({
2112
2607
  }
2113
2608
  )
2114
2609
  ] }),
2115
- /* @__PURE__ */ jsx10("div", { className: "space-y-1", children: completedActions.map((action) => /* @__PURE__ */ jsxs6("div", { className: "text-xs opacity-80 border-l-2 border-green-500 pl-2", children: [
2116
- /* @__PURE__ */ jsx10("div", { className: "font-medium", children: action.tool }),
2117
- /* @__PURE__ */ jsx10("div", { className: "opacity-70", children: action.description })
2610
+ /* @__PURE__ */ jsx11("div", { className: "space-y-1", children: completedActions.map((action) => /* @__PURE__ */ jsxs6("div", { className: "text-xs opacity-80 border-l-2 border-green-500 pl-2", children: [
2611
+ /* @__PURE__ */ jsx11("div", { className: "font-medium", children: action.tool }),
2612
+ /* @__PURE__ */ jsx11("div", { className: "opacity-70", children: action.description })
2118
2613
  ] }, action.id)) })
2119
2614
  ]
2120
2615
  }
@@ -2141,21 +2636,21 @@ var SubtitleOverlay = ({
2141
2636
  className: "border-l-2 border-green-500 pl-2 mb-1",
2142
2637
  style: { opacity: latestActionOpacity, transition: "opacity 0.6s ease-out" },
2143
2638
  children: [
2144
- /* @__PURE__ */ jsx10("span", { className: "font-medium", children: latest.tool }),
2145
- /* @__PURE__ */ jsx10("span", { className: "opacity-70 ml-1", children: latest.description })
2639
+ /* @__PURE__ */ jsx11("span", { className: "font-medium", children: latest.tool }),
2640
+ /* @__PURE__ */ jsx11("span", { className: "opacity-70 ml-1", children: latest.description })
2146
2641
  ]
2147
2642
  }
2148
2643
  );
2149
2644
  })(),
2150
2645
  lastAiMessage && messageOpacity > 0 && /* @__PURE__ */ jsxs6("div", { style: { opacity: messageOpacity, transition: "opacity 0.8s ease-out" }, children: [
2151
- /* @__PURE__ */ jsx10("span", { className: "font-medium opacity-70", children: "AI:" }),
2646
+ /* @__PURE__ */ jsx11("span", { className: "font-medium opacity-70", children: "AI:" }),
2152
2647
  " ",
2153
- /* @__PURE__ */ jsx10("span", { className: "text-sm", children: lastAiMessage.text })
2648
+ /* @__PURE__ */ jsx11("span", { className: "text-sm", children: lastAiMessage.text })
2154
2649
  ] })
2155
2650
  ]
2156
2651
  }
2157
2652
  ),
2158
- completedActions.length > 0 && !showCompletedActions && /* @__PURE__ */ jsx10("div", { className: "flex justify-center mb-1", children: /* @__PURE__ */ jsx10(
2653
+ completedActions.length > 0 && !showCompletedActions && /* @__PURE__ */ jsx11("div", { className: "flex justify-center mb-1", children: /* @__PURE__ */ jsx11(
2159
2654
  "button",
2160
2655
  {
2161
2656
  type: "button",
@@ -2171,11 +2666,11 @@ var SubtitleOverlay = ({
2171
2666
  title: `${completedActions.length} previous actions`,
2172
2667
  "data-testid": "completed-actions-toggle",
2173
2668
  "aria-label": `Show ${completedActions.length} completed actions`,
2174
- children: /* @__PURE__ */ jsx10("svg", { width: "16", height: "8", viewBox: "0 0 16 8", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx10("path", { d: "M2 6L8 2L14 6" }) })
2669
+ children: /* @__PURE__ */ jsx11("svg", { width: "16", height: "8", viewBox: "0 0 16 8", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx11("path", { d: "M2 6L8 2L14 6" }) })
2175
2670
  }
2176
2671
  ) }),
2177
2672
  /* @__PURE__ */ jsxs6("div", { className: "flex items-center space-x-2", children: [
2178
- hasTTSWidgets && /* @__PURE__ */ jsx10(
2673
+ hasTTSWidgets && /* @__PURE__ */ jsx11(
2179
2674
  "button",
2180
2675
  {
2181
2676
  type: "button",
@@ -2190,7 +2685,7 @@ var SubtitleOverlay = ({
2190
2685
  title: ttsWidgets.length === 1 ? "Go to readable section" : "View readable sections",
2191
2686
  "data-testid": "tts-playlist-button-expanded",
2192
2687
  "aria-label": ttsWidgets.length === 1 ? "Go to readable section" : "View readable sections",
2193
- children: /* @__PURE__ */ jsx10("span", { className: "text-lg font-bold select-none", "aria-hidden": "true", children: "~+" })
2688
+ children: /* @__PURE__ */ jsx11("span", { className: "text-lg font-bold select-none", "aria-hidden": "true", children: "~+" })
2194
2689
  }
2195
2690
  ),
2196
2691
  /* @__PURE__ */ jsxs6(
@@ -2202,7 +2697,7 @@ var SubtitleOverlay = ({
2202
2697
  border: effectiveGlassTheme === "dark" ? "1px solid rgba(255, 255, 255, 0.12)" : "1px solid rgba(0, 0, 0, 0.1)"
2203
2698
  },
2204
2699
  children: [
2205
- /* @__PURE__ */ jsx10(
2700
+ /* @__PURE__ */ jsx11(
2206
2701
  "input",
2207
2702
  {
2208
2703
  ref: inputRef,
@@ -2222,7 +2717,7 @@ var SubtitleOverlay = ({
2222
2717
  "aria-label": "Chat message input"
2223
2718
  }
2224
2719
  ),
2225
- isListening && /* @__PURE__ */ jsx10("div", { className: "flex space-x-1 items-center", "aria-hidden": "true", "data-testid": "subtitle-overlay-waveform", children: [...Array(5)].map((_, i) => /* @__PURE__ */ jsx10(
2720
+ isListening && /* @__PURE__ */ jsx11("div", { className: "flex space-x-1 items-center", "aria-hidden": "true", "data-testid": "subtitle-overlay-waveform", children: [...Array(5)].map((_, i) => /* @__PURE__ */ jsx11(
2226
2721
  "div",
2227
2722
  {
2228
2723
  className: "w-0.5 bg-red-500 rounded-full animate-pulse",
@@ -2233,7 +2728,7 @@ var SubtitleOverlay = ({
2233
2728
  },
2234
2729
  i
2235
2730
  )) }),
2236
- inputValue.trim() && /* @__PURE__ */ jsx10(
2731
+ inputValue.trim() && /* @__PURE__ */ jsx11(
2237
2732
  "button",
2238
2733
  {
2239
2734
  type: "button",
@@ -2249,10 +2744,10 @@ var SubtitleOverlay = ({
2249
2744
  title: "Send message",
2250
2745
  "data-testid": "send-button",
2251
2746
  "aria-label": "Send message",
2252
- children: /* @__PURE__ */ jsx10("span", { className: "text-base select-none", "aria-hidden": "true", children: "\u2192" })
2747
+ children: /* @__PURE__ */ jsx11("span", { className: "text-base select-none", "aria-hidden": "true", children: "\u2192" })
2253
2748
  }
2254
2749
  ),
2255
- voiceEnabled && /* @__PURE__ */ jsx10(
2750
+ voiceEnabled && /* @__PURE__ */ jsx11(
2256
2751
  "button",
2257
2752
  {
2258
2753
  type: "button",
@@ -2272,10 +2767,10 @@ var SubtitleOverlay = ({
2272
2767
  title: getIconTitle(),
2273
2768
  "data-testid": "voice-input-button",
2274
2769
  "aria-label": getIconTitle(),
2275
- children: /* @__PURE__ */ jsx10("span", { className: "text-lg font-bold select-none", "aria-hidden": "true", children: getIcon() })
2770
+ children: /* @__PURE__ */ jsx11("span", { className: "text-lg font-bold select-none", "aria-hidden": "true", children: getIcon() })
2276
2771
  }
2277
2772
  ),
2278
- /* @__PURE__ */ jsx10(
2773
+ /* @__PURE__ */ jsx11(
2279
2774
  "button",
2280
2775
  {
2281
2776
  type: "button",
@@ -2290,7 +2785,7 @@ var SubtitleOverlay = ({
2290
2785
  title: "Collapse",
2291
2786
  "data-testid": "collapse-button",
2292
2787
  "aria-label": "Collapse overlay",
2293
- children: /* @__PURE__ */ jsx10("span", { className: "text-lg font-bold select-none", "aria-hidden": "true", children: "\xD7" })
2788
+ children: /* @__PURE__ */ jsx11("span", { className: "text-lg font-bold select-none", "aria-hidden": "true", children: "\xD7" })
2294
2789
  }
2295
2790
  )
2296
2791
  ]
@@ -2303,23 +2798,23 @@ var SubtitleOverlay = ({
2303
2798
  };
2304
2799
 
2305
2800
  // src/components/SlashCommand/useSlashCommand.ts
2306
- import { useState as useState7, useMemo as useMemo2, useCallback as useCallback5, useRef as useRef6, useEffect as useEffect5 } from "react";
2801
+ import { useState as useState8, useMemo as useMemo3, useCallback as useCallback6, useRef as useRef8, useEffect as useEffect6 } from "react";
2307
2802
  import { ToolRegistry } from "@supernal/interface/browser";
2308
2803
  function useSlashCommand(inputValue, onSelect) {
2309
- const [selectedIndex, setSelectedIndex] = useState7(0);
2310
- const prevOpenRef = useRef6(false);
2804
+ const [selectedIndex, setSelectedIndex] = useState8(0);
2805
+ const prevOpenRef = useRef8(false);
2311
2806
  const isOpen = inputValue.startsWith("/");
2312
2807
  const query = isOpen ? inputValue.slice(1) : "";
2313
- useEffect5(() => {
2808
+ useEffect6(() => {
2314
2809
  if (isOpen && !prevOpenRef.current) {
2315
2810
  setSelectedIndex(0);
2316
2811
  }
2317
2812
  prevOpenRef.current = isOpen;
2318
2813
  }, [isOpen]);
2319
- useEffect5(() => {
2814
+ useEffect6(() => {
2320
2815
  setSelectedIndex(0);
2321
2816
  }, [query]);
2322
- const filteredTools = useMemo2(() => {
2817
+ const filteredTools = useMemo3(() => {
2323
2818
  if (!isOpen) return [];
2324
2819
  const locationTools = ToolRegistry.getToolsByLocation();
2325
2820
  const aiTools = locationTools.filter((t) => t.aiEnabled);
@@ -2336,13 +2831,13 @@ function useSlashCommand(inputValue, onSelect) {
2336
2831
  return fields.some((f) => f.includes(q));
2337
2832
  });
2338
2833
  }, [isOpen, query]);
2339
- const close = useCallback5(() => {
2834
+ const close = useCallback6(() => {
2340
2835
  }, []);
2341
- const selectTool = useCallback5((tool) => {
2836
+ const selectTool = useCallback6((tool) => {
2342
2837
  const command = tool.examples?.[0] || tool.name?.toLowerCase() || tool.toolId;
2343
2838
  onSelect(command);
2344
2839
  }, [onSelect]);
2345
- const onKeyDown = useCallback5((e) => {
2840
+ const onKeyDown = useCallback6((e) => {
2346
2841
  if (!isOpen || filteredTools.length === 0) return;
2347
2842
  if (e.key === "ArrowDown") {
2348
2843
  e.preventDefault();
@@ -2372,8 +2867,8 @@ function useSlashCommand(inputValue, onSelect) {
2372
2867
  }
2373
2868
 
2374
2869
  // src/components/SlashCommand/SlashCommandPopup.tsx
2375
- import { useEffect as useEffect6, useRef as useRef7 } from "react";
2376
- import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
2870
+ import { useEffect as useEffect7, useRef as useRef9 } from "react";
2871
+ import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
2377
2872
  var MAX_VISIBLE_ITEMS = 8;
2378
2873
  var SlashCommandPopup = ({
2379
2874
  tools,
@@ -2381,12 +2876,12 @@ var SlashCommandPopup = ({
2381
2876
  onSelect,
2382
2877
  onClose
2383
2878
  }) => {
2384
- const listRef = useRef7(null);
2385
- const selectedRef = useRef7(null);
2386
- useEffect6(() => {
2879
+ const listRef = useRef9(null);
2880
+ const selectedRef = useRef9(null);
2881
+ useEffect7(() => {
2387
2882
  selectedRef.current?.scrollIntoView({ block: "nearest" });
2388
2883
  }, [selectedIndex]);
2389
- useEffect6(() => {
2884
+ useEffect7(() => {
2390
2885
  const handleClickOutside = (e) => {
2391
2886
  if (listRef.current && !listRef.current.contains(e.target)) {
2392
2887
  onClose();
@@ -2461,9 +2956,9 @@ var SlashCommandPopup = ({
2461
2956
  "/",
2462
2957
  tool.toolId
2463
2958
  ] }),
2464
- /* @__PURE__ */ jsx11("span", { style: { color: "rgba(255,255,255,0.7)", fontWeight: 400, marginLeft: 8 }, children: tool.name })
2959
+ /* @__PURE__ */ jsx12("span", { style: { color: "rgba(255,255,255,0.7)", fontWeight: 400, marginLeft: 8 }, children: tool.name })
2465
2960
  ] }),
2466
- tool.description && /* @__PURE__ */ jsx11("div", { style: {
2961
+ tool.description && /* @__PURE__ */ jsx12("div", { style: {
2467
2962
  fontSize: 11,
2468
2963
  color: "rgba(255,255,255,0.4)",
2469
2964
  marginTop: 2,
@@ -2483,13 +2978,13 @@ var SlashCommandPopup = ({
2483
2978
  color: "rgba(255,255,255,0.3)",
2484
2979
  fontSize: 10
2485
2980
  }, children: [
2486
- /* @__PURE__ */ jsx11("kbd", { style: { padding: "1px 3px", borderRadius: 3, border: "1px solid rgba(255,255,255,0.15)", fontSize: 9 }, children: "\u2191\u2193" }),
2981
+ /* @__PURE__ */ jsx12("kbd", { style: { padding: "1px 3px", borderRadius: 3, border: "1px solid rgba(255,255,255,0.15)", fontSize: 9 }, children: "\u2191\u2193" }),
2487
2982
  " navigate",
2488
2983
  " ",
2489
- /* @__PURE__ */ jsx11("kbd", { style: { padding: "1px 3px", borderRadius: 3, border: "1px solid rgba(255,255,255,0.15)", fontSize: 9 }, children: "Enter" }),
2984
+ /* @__PURE__ */ jsx12("kbd", { style: { padding: "1px 3px", borderRadius: 3, border: "1px solid rgba(255,255,255,0.15)", fontSize: 9 }, children: "Enter" }),
2490
2985
  " select",
2491
2986
  " ",
2492
- /* @__PURE__ */ jsx11("kbd", { style: { padding: "1px 3px", borderRadius: 3, border: "1px solid rgba(255,255,255,0.15)", fontSize: 9 }, children: "Esc" }),
2987
+ /* @__PURE__ */ jsx12("kbd", { style: { padding: "1px 3px", borderRadius: 3, border: "1px solid rgba(255,255,255,0.15)", fontSize: 9 }, children: "Esc" }),
2493
2988
  " dismiss"
2494
2989
  ] })
2495
2990
  ]
@@ -2498,7 +2993,7 @@ var SlashCommandPopup = ({
2498
2993
  };
2499
2994
 
2500
2995
  // src/components/ChatBubble/ChatBubble.tsx
2501
- import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
2996
+ import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
2502
2997
  var ChatBubble = ({
2503
2998
  messages,
2504
2999
  onSendMessage,
@@ -2513,65 +3008,69 @@ var ChatBubble = ({
2513
3008
  }) => {
2514
3009
  const mergedConfig = { ...DEFAULT_CONFIG, ...userConfig };
2515
3010
  if (userConfig?.logo && !userConfig?.avatar) {
2516
- mergedConfig.avatar = /* @__PURE__ */ jsx12("img", { src: userConfig.logo, alt: "Supernal", className: "w-6 h-6" });
3011
+ mergedConfig.avatar = /* @__PURE__ */ jsx13("img", { src: userConfig.logo, alt: "Supernal", className: "w-6 h-6" });
2517
3012
  }
2518
3013
  const config = mergedConfig;
2519
- const [isExpanded, setIsExpanded] = useState8(defaultExpanded);
2520
- const [isMinimized, setIsMinimized] = useState8(false);
2521
- const [inputValue, setInputValue] = useState8("");
2522
- const [lastReadMessageCount, setLastReadMessageCount] = useState8(0);
2523
- const [showWelcome, setShowWelcome] = useState8(
3014
+ const [isExpanded, setIsExpanded] = useState9(defaultExpanded);
3015
+ const [isMinimized, setIsMinimized] = useState9(false);
3016
+ const [inputValue, setInputValue] = useState9("");
3017
+ const [lastReadMessageCount, setLastReadMessageCount] = useState9(0);
3018
+ const [showWelcome, setShowWelcome] = useState9(
2524
3019
  config.welcome?.enabled && messages.length === 0
2525
3020
  );
2526
- const [isDragging, setIsDragging] = useState8(false);
2527
- const [dragInitiated, setDragInitiated] = useState8(false);
2528
- const [isDocked, setIsDocked] = useState8(true);
2529
- const [dockPosition, setDockPosition] = useState8(position);
2530
- const [panelPosition, setPanelPosition] = useState8({ x: 0, y: 0 });
2531
- const [theme, setTheme] = useState8("light");
2532
- const [showMoreMenu, setShowMoreMenu] = useState8(false);
2533
- const [, setTimestampTick] = useState8(0);
2534
- const [localGlassMode, setLocalGlassMode] = useState8(config.glassMode ?? true);
2535
- const [glassOpacity, setGlassOpacity] = useState8("medium");
2536
- const [notifications, setNotifications] = useState8(true);
2537
- const [voiceEnabled, setVoiceEnabled] = useState8(true);
2538
- const [usePremiumVoices, setUsePremiumVoices] = useState8(false);
2539
- const [autoReadResponses, setAutoReadResponses] = useState8(false);
2540
- const [ttsSpeed, setTtsSpeed] = useState8(1);
2541
- const [sttAutoRecordTimeout, setSttAutoRecordTimeout] = useState8(5e3);
2542
- const [sttAutoExecute, setSttAutoExecute] = useState8(true);
2543
- const sttAutoRecordTimeoutRef = useRef8(null);
3021
+ const [isDragging, setIsDragging] = useState9(false);
3022
+ const [dragInitiated, setDragInitiated] = useState9(false);
3023
+ const [isDocked, setIsDocked] = useState9(true);
3024
+ const [dockPosition, setDockPosition] = useState9(position);
3025
+ const [panelPosition, setPanelPosition] = useState9({ x: 0, y: 0 });
3026
+ const [theme, setTheme] = useState9("light");
3027
+ const [showMoreMenu, setShowMoreMenu] = useState9(false);
3028
+ const [, setTimestampTick] = useState9(0);
3029
+ const [localGlassMode, setLocalGlassMode] = useState9(config.glassMode ?? true);
3030
+ const [glassOpacity, setGlassOpacity] = useState9("medium");
3031
+ const [notifications, setNotifications] = useState9(true);
3032
+ const [voiceEnabled, setVoiceEnabled] = useState9(true);
3033
+ const [usePremiumVoices, setUsePremiumVoices] = useState9(false);
3034
+ const [autoReadResponses, setAutoReadResponses] = useState9(false);
3035
+ const [ttsSpeed, setTtsSpeed] = useState9(1);
3036
+ const [sttAutoRecordTimeout, setSttAutoRecordTimeout] = useState9(5e3);
3037
+ const [sttAutoExecute, setSttAutoExecute] = useState9(true);
3038
+ const sttAutoRecordTimeoutRef = useRef10(null);
2544
3039
  const { speak: speakTTS, stop: stopTTS, isPlaying: isTTSPlaying } = useTTS();
2545
3040
  const { startListening, stopListening, transcript: sttTranscript, isListening, resetTranscript } = useSTT();
3041
+ const apiKey = useApiKeyOptional();
3042
+ const [showApiKeyInput, setShowApiKeyInput] = useState9(false);
3043
+ const [apiKeyInputValue, setApiKeyInputValue] = useState9("");
3044
+ const [showApiKey, setShowApiKey] = useState9(false);
2546
3045
  const slashCommand = useSlashCommand(inputValue, (command) => {
2547
3046
  setInputValue(command);
2548
3047
  setTimeout(() => inputRef.current?.focus(), 0);
2549
3048
  });
2550
- const [displayMode, setDisplayMode] = useState8(propDisplayMode);
2551
- const [drawerSide, setDrawerSide] = useState8(propDrawerSide);
2552
- const displayModeLoadedFromStorage = useRef8(false);
2553
- useEffect7(() => {
3049
+ const [displayMode, setDisplayMode] = useState9(propDisplayMode);
3050
+ const [drawerSide, setDrawerSide] = useState9(propDrawerSide);
3051
+ const displayModeLoadedFromStorage = useRef10(false);
3052
+ useEffect8(() => {
2554
3053
  if (!displayModeLoadedFromStorage.current) {
2555
3054
  setDisplayMode(propDisplayMode);
2556
3055
  }
2557
3056
  }, [propDisplayMode]);
2558
- const [drawerOpen, setDrawerOpen] = useState8(false);
2559
- const [touchStart, setTouchStart] = useState8(null);
2560
- const [swipeProgress, setSwipeProgress] = useState8(0);
2561
- const [isMobile, setIsMobile] = useState8(false);
2562
- const lastEscapeTimeRef = useRef8(0);
3057
+ const [drawerOpen, setDrawerOpen] = useState9(false);
3058
+ const [touchStart, setTouchStart] = useState9(null);
3059
+ const [swipeProgress, setSwipeProgress] = useState9(0);
3060
+ const [isMobile, setIsMobile] = useState9(false);
3061
+ const lastEscapeTimeRef = useRef10(0);
2563
3062
  const DOUBLE_ESCAPE_THRESHOLD_MS = 500;
2564
- const [isMac, setIsMac] = useState8(false);
2565
- const [currentHintIndex, setCurrentHintIndex] = useState8(0);
2566
- const [isHydrated, setIsHydrated] = useState8(false);
2567
- useEffect7(() => {
3063
+ const [isMac, setIsMac] = useState9(false);
3064
+ const [currentHintIndex, setCurrentHintIndex] = useState9(0);
3065
+ const [isHydrated, setIsHydrated] = useState9(false);
3066
+ useEffect8(() => {
2568
3067
  if (typeof window !== "undefined") {
2569
3068
  const platform = window.navigator.platform.toLowerCase();
2570
3069
  const isMacPlatform = platform.includes("mac");
2571
3070
  setIsMac(isMacPlatform);
2572
3071
  }
2573
3072
  }, []);
2574
- const inputHints = useMemo3(() => {
3073
+ const inputHints = useMemo4(() => {
2575
3074
  const modKey = isMac ? "Cmd" : "Ctrl";
2576
3075
  return [
2577
3076
  `Press ${modKey}+/ to start voice recording`,
@@ -2580,14 +3079,14 @@ var ChatBubble = ({
2580
3079
  sttAutoExecute ? `Voice commands execute automatically` : "Voice commands fill this input"
2581
3080
  ];
2582
3081
  }, [isMac, sttAutoExecute]);
2583
- useEffect7(() => {
3082
+ useEffect8(() => {
2584
3083
  setCurrentHintIndex((prev) => (prev + 1) % inputHints.length);
2585
3084
  }, [messages.length, inputHints.length]);
2586
- const messagesEndRef = useRef8(null);
2587
- const inputRef = useRef8(null);
2588
- const panelRef = useRef8(null);
2589
- const dragRef = useRef8(null);
2590
- const rafRef = useRef8(null);
3085
+ const messagesEndRef = useRef10(null);
3086
+ const inputRef = useRef10(null);
3087
+ const panelRef = useRef10(null);
3088
+ const dragRef = useRef10(null);
3089
+ const rafRef = useRef10(null);
2591
3090
  const formatRelativeTime = (timestamp) => {
2592
3091
  const now = /* @__PURE__ */ new Date();
2593
3092
  const messageTime = new Date(timestamp);
@@ -2602,7 +3101,7 @@ var ChatBubble = ({
2602
3101
  if (diffDays < 7) return `${diffDays} ${diffDays === 1 ? "day" : "days"} ago`;
2603
3102
  return messageTime.toLocaleDateString();
2604
3103
  };
2605
- useEffect7(() => {
3104
+ useEffect8(() => {
2606
3105
  if (variant === "floating" && panelPosition.x === 0 && panelPosition.y === 0) {
2607
3106
  try {
2608
3107
  const stored = localStorage.getItem(storageKey);
@@ -2624,7 +3123,7 @@ var ChatBubble = ({
2624
3123
  }
2625
3124
  }
2626
3125
  }, [variant, storageKey, panelPosition.x, panelPosition.y]);
2627
- useEffect7(() => {
3126
+ useEffect8(() => {
2628
3127
  if (variant === "full" || variant === "drawer" || variant === "subtitle") {
2629
3128
  try {
2630
3129
  const stored = localStorage.getItem(storageKey);
@@ -2702,12 +3201,12 @@ var ChatBubble = ({
2702
3201
  }
2703
3202
  setIsHydrated(true);
2704
3203
  }, [storageKey, variant, defaultExpanded, position]);
2705
- useEffect7(() => {
3204
+ useEffect8(() => {
2706
3205
  if (variant !== "full" && variant !== "drawer" && variant !== "subtitle") {
2707
3206
  setIsHydrated(true);
2708
3207
  }
2709
3208
  }, [variant]);
2710
- useEffect7(() => {
3209
+ useEffect8(() => {
2711
3210
  if (!isExpanded || isDocked || !panelRef.current) return;
2712
3211
  const checkBounds = () => {
2713
3212
  const rect = panelRef.current?.getBoundingClientRect();
@@ -2724,7 +3223,7 @@ var ChatBubble = ({
2724
3223
  const timeoutId = setTimeout(checkBounds, 100);
2725
3224
  return () => clearTimeout(timeoutId);
2726
3225
  }, [isExpanded, isDocked]);
2727
- useEffect7(() => {
3226
+ useEffect8(() => {
2728
3227
  const isSubtitleMode = displayMode === "subtitle" || displayMode === "auto" && variant === "subtitle";
2729
3228
  if (isSubtitleMode) return;
2730
3229
  const handleKeyDown = (e) => {
@@ -2757,13 +3256,13 @@ var ChatBubble = ({
2757
3256
  window.addEventListener("keydown", handleKeyDown);
2758
3257
  return () => window.removeEventListener("keydown", handleKeyDown);
2759
3258
  }, [isExpanded, isDocked, position, variant, displayMode, isMobile]);
2760
- useEffect7(() => {
3259
+ useEffect8(() => {
2761
3260
  if (typeof window !== "undefined") {
2762
3261
  const isDark = document.documentElement.getAttribute("data-theme") === "dark";
2763
3262
  setTheme(isDark ? "dark" : "light");
2764
3263
  }
2765
3264
  }, []);
2766
- useEffect7(() => {
3265
+ useEffect8(() => {
2767
3266
  if (typeof window === "undefined") return;
2768
3267
  const mediaQuery = window.matchMedia("(max-width: 767px)");
2769
3268
  const handleChange = (e) => {
@@ -2773,26 +3272,26 @@ var ChatBubble = ({
2773
3272
  mediaQuery.addEventListener("change", handleChange);
2774
3273
  return () => mediaQuery.removeEventListener("change", handleChange);
2775
3274
  }, []);
2776
- const currentVariant = React8.useMemo(() => {
3275
+ const currentVariant = React9.useMemo(() => {
2777
3276
  if (displayMode !== "auto") {
2778
3277
  return displayMode;
2779
3278
  }
2780
3279
  return isMobile && variant === "full" ? "subtitle" : variant;
2781
3280
  }, [displayMode, isMobile, variant]);
2782
- const prevVariantRef = React8.useRef(variant);
2783
- useEffect7(() => {
3281
+ const prevVariantRef = React9.useRef(variant);
3282
+ useEffect8(() => {
2784
3283
  if (prevVariantRef.current !== variant && displayMode !== "auto") {
2785
3284
  setDisplayMode("auto");
2786
3285
  prevVariantRef.current = variant;
2787
3286
  }
2788
3287
  }, [variant, displayMode]);
2789
- useEffect7(() => {
3288
+ useEffect8(() => {
2790
3289
  const interval = setInterval(() => {
2791
3290
  setTimestampTick((tick) => tick + 1);
2792
3291
  }, 6e4);
2793
3292
  return () => clearInterval(interval);
2794
3293
  }, []);
2795
- useEffect7(() => {
3294
+ useEffect8(() => {
2796
3295
  if (variant === "full" || variant === "drawer" || variant === "subtitle") {
2797
3296
  try {
2798
3297
  localStorage.setItem(
@@ -2824,7 +3323,7 @@ var ChatBubble = ({
2824
3323
  }
2825
3324
  }, [isExpanded, isMinimized, isDocked, dockPosition, panelPosition, theme, localGlassMode, notifications, displayMode, drawerSide, drawerOpen, glassOpacity, voiceEnabled, usePremiumVoices, autoReadResponses, ttsSpeed, sttAutoRecordTimeout, sttAutoExecute, storageKey, variant]);
2826
3325
  const { registerInput } = useChatInput();
2827
- useEffect7(() => {
3326
+ useEffect8(() => {
2828
3327
  registerInput((text, submit = false) => {
2829
3328
  setInputValue(text);
2830
3329
  if (!isExpanded && variant === "full") {
@@ -2841,7 +3340,7 @@ var ChatBubble = ({
2841
3340
  }, [registerInput, onSendMessage]);
2842
3341
  const unreadCount = Math.max(0, messages.length - lastReadMessageCount);
2843
3342
  const hasUnread = unreadCount > 0 && !isExpanded && variant === "full";
2844
- useEffect7(() => {
3343
+ useEffect8(() => {
2845
3344
  if (isExpanded || variant === "floating") {
2846
3345
  messagesEndRef.current?.scrollIntoView({ behavior: "auto" });
2847
3346
  setLastReadMessageCount(messages.length);
@@ -2853,12 +3352,12 @@ var ChatBubble = ({
2853
3352
  }
2854
3353
  }
2855
3354
  }, [messages, isExpanded, variant]);
2856
- useEffect7(() => {
3355
+ useEffect8(() => {
2857
3356
  if (isExpanded && variant === "full") {
2858
3357
  inputRef.current?.focus();
2859
3358
  }
2860
3359
  }, [isExpanded, variant]);
2861
- useEffect7(() => {
3360
+ useEffect8(() => {
2862
3361
  if (!voiceEnabled || !autoReadResponses || messages.length === 0) return;
2863
3362
  const lastMessage = messages[messages.length - 1];
2864
3363
  if (lastMessage.type === "ai") {
@@ -2870,7 +3369,7 @@ var ChatBubble = ({
2870
3369
  });
2871
3370
  }
2872
3371
  }, [messages, voiceEnabled, autoReadResponses, ttsSpeed, usePremiumVoices, speakTTS]);
2873
- useEffect7(() => {
3372
+ useEffect8(() => {
2874
3373
  if (currentVariant === "subtitle") return;
2875
3374
  if (sttTranscript && voiceEnabled) {
2876
3375
  setInputValue(sttTranscript);
@@ -2885,7 +3384,7 @@ var ChatBubble = ({
2885
3384
  }
2886
3385
  }
2887
3386
  }, [sttTranscript, voiceEnabled, resetTranscript, sttAutoExecute, onSendMessage, currentVariant]);
2888
- useEffect7(() => {
3387
+ useEffect8(() => {
2889
3388
  if (currentVariant === "subtitle") return;
2890
3389
  const handleKeyDown = (e) => {
2891
3390
  if ((e.metaKey || e.ctrlKey) && e.key === "/" && voiceEnabled) {
@@ -2943,7 +3442,7 @@ var ChatBubble = ({
2943
3442
  }
2944
3443
  };
2945
3444
  }, [currentVariant, isExpanded, showMoreMenu, voiceEnabled, isListening, startListening, stopListening, sttAutoRecordTimeout]);
2946
- useEffect7(() => {
3445
+ useEffect8(() => {
2947
3446
  if (currentVariant !== "drawer") return;
2948
3447
  const handleKeyDown = (e) => {
2949
3448
  if (e.key === "Escape" && drawerOpen) {
@@ -2953,7 +3452,7 @@ var ChatBubble = ({
2953
3452
  window.addEventListener("keydown", handleKeyDown);
2954
3453
  return () => window.removeEventListener("keydown", handleKeyDown);
2955
3454
  }, [currentVariant, drawerOpen]);
2956
- useEffect7(() => {
3455
+ useEffect8(() => {
2957
3456
  if (!showMoreMenu) return;
2958
3457
  const handleClickOutside = (e) => {
2959
3458
  const target = e.target;
@@ -2964,7 +3463,7 @@ var ChatBubble = ({
2964
3463
  document.addEventListener("mousedown", handleClickOutside);
2965
3464
  return () => document.removeEventListener("mousedown", handleClickOutside);
2966
3465
  }, [showMoreMenu]);
2967
- useEffect7(() => {
3466
+ useEffect8(() => {
2968
3467
  if (typeof window === "undefined" || currentVariant !== "drawer") return;
2969
3468
  const EDGE_ZONE_PX = 20;
2970
3469
  const SWIPE_THRESHOLD = 0.4;
@@ -3049,7 +3548,7 @@ var ChatBubble = ({
3049
3548
  };
3050
3549
  }
3051
3550
  };
3052
- useEffect7(() => {
3551
+ useEffect8(() => {
3053
3552
  if (!dragInitiated || !dragRef.current) return;
3054
3553
  const dragThresholdPx = 5;
3055
3554
  const handleMouseMove = (e) => {
@@ -3212,7 +3711,7 @@ var ChatBubble = ({
3212
3711
  return null;
3213
3712
  }
3214
3713
  if (currentVariant === "subtitle") {
3215
- return /* @__PURE__ */ jsx12(
3714
+ return /* @__PURE__ */ jsx13(
3216
3715
  SubtitleOverlay,
3217
3716
  {
3218
3717
  messages,
@@ -3245,7 +3744,7 @@ var ChatBubble = ({
3245
3744
  if (currentVariant === "drawer") {
3246
3745
  const drawerWidth = "100vw";
3247
3746
  return /* @__PURE__ */ jsxs8(Fragment3, { children: [
3248
- (drawerOpen || swipeProgress > 0) && /* @__PURE__ */ jsx12(
3747
+ (drawerOpen || swipeProgress > 0) && /* @__PURE__ */ jsx13(
3249
3748
  "div",
3250
3749
  {
3251
3750
  className: "fixed inset-0 bg-black z-[49998] transition-opacity duration-300",
@@ -3279,28 +3778,28 @@ var ChatBubble = ({
3279
3778
  /* @__PURE__ */ jsxs8("div", { className: `${THEME_CLASSES.bg.header} ${glassMode ? THEME_CLASSES.bg.headerGradient : THEME_CLASSES.bg.headerLight}`, children: [
3280
3779
  /* @__PURE__ */ jsxs8("div", { className: "flex items-center space-x-3", children: [
3281
3780
  config.avatar && /* @__PURE__ */ jsxs8("div", { className: "relative flex-shrink-0", children: [
3282
- /* @__PURE__ */ jsx12(Avatar, { avatar: config.avatar }),
3283
- /* @__PURE__ */ jsx12("div", { className: "absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
3781
+ /* @__PURE__ */ jsx13(Avatar, { avatar: config.avatar }),
3782
+ /* @__PURE__ */ jsx13("div", { className: "absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
3284
3783
  ] }),
3285
- config.title && /* @__PURE__ */ jsx12("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx12("h3", { className: THEME_CLASSES.text.title, children: config.title }) })
3784
+ config.title && /* @__PURE__ */ jsx13("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx13("h3", { className: THEME_CLASSES.text.title, children: config.title }) })
3286
3785
  ] }),
3287
- /* @__PURE__ */ jsx12("button", { onClick: () => setDrawerOpen(false), className: THEME_CLASSES.button.close, title: "Close drawer", children: /* @__PURE__ */ jsx12("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx12("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
3786
+ /* @__PURE__ */ jsx13("button", { onClick: () => setDrawerOpen(false), className: THEME_CLASSES.button.close, title: "Close drawer", children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
3288
3787
  ] }),
3289
- /* @__PURE__ */ jsxs8("div", { className: "flex-1 overflow-y-auto p-4 space-y-2", children: [
3788
+ /* @__PURE__ */ jsxs8("div", { className: "flex-1 overflow-y-auto p-4 space-y-2", "data-testid": "chat-messages", children: [
3290
3789
  showWelcome && messages.length === 0 && config.welcome?.enabled && /* @__PURE__ */ jsxs8("div", { className: THEME_CLASSES.welcome.container, children: [
3291
- config.welcome.title && /* @__PURE__ */ jsx12("h4", { className: THEME_CLASSES.welcome.title, style: INLINE_STYLES.welcomeTitle(theme === "dark"), children: config.welcome.title }),
3292
- config.welcome.content && /* @__PURE__ */ jsx12("p", { className: THEME_CLASSES.welcome.content, style: INLINE_STYLES.welcomeContent(theme === "dark"), children: config.welcome.content })
3790
+ config.welcome.title && /* @__PURE__ */ jsx13("h4", { className: THEME_CLASSES.welcome.title, style: INLINE_STYLES.welcomeTitle(theme === "dark"), children: config.welcome.title }),
3791
+ config.welcome.content && /* @__PURE__ */ jsx13("p", { className: THEME_CLASSES.welcome.content, style: INLINE_STYLES.welcomeContent(theme === "dark"), children: config.welcome.content })
3293
3792
  ] }),
3294
3793
  messages.map((message) => /* @__PURE__ */ jsxs8("div", { className: `group flex items-center gap-1 mb-2 ${message.type === "user" ? "flex-row-reverse" : "flex-row"}`, children: [
3295
- /* @__PURE__ */ jsx12(
3794
+ /* @__PURE__ */ jsx13(
3296
3795
  "div",
3297
3796
  {
3298
3797
  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}`,
3299
3798
  style: message.type === "user" ? INLINE_STYLES.messageUser() : message.type === "ai" ? INLINE_STYLES.messageAI(theme === "dark") : INLINE_STYLES.messageSystem(theme === "dark"),
3300
- children: /* @__PURE__ */ jsx12(MessageRenderer, { content: message.text, theme })
3799
+ children: /* @__PURE__ */ jsx13(MessageRenderer, { content: message.text, theme })
3301
3800
  }
3302
3801
  ),
3303
- message.type === "ai" && voiceEnabled && /* @__PURE__ */ jsx12(
3802
+ message.type === "ai" && voiceEnabled && /* @__PURE__ */ jsx13(
3304
3803
  TTSButton,
3305
3804
  {
3306
3805
  text: message.text,
@@ -3310,7 +3809,7 @@ var ChatBubble = ({
3310
3809
  size: "small"
3311
3810
  }
3312
3811
  ),
3313
- /* @__PURE__ */ jsx12(
3812
+ /* @__PURE__ */ jsx13(
3314
3813
  "div",
3315
3814
  {
3316
3815
  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"}`,
@@ -3319,10 +3818,10 @@ var ChatBubble = ({
3319
3818
  }
3320
3819
  )
3321
3820
  ] }, message.id)),
3322
- /* @__PURE__ */ jsx12("div", { ref: messagesEndRef })
3821
+ /* @__PURE__ */ jsx13("div", { ref: messagesEndRef })
3323
3822
  ] }),
3324
3823
  /* @__PURE__ */ jsxs8("div", { style: { position: "relative" }, children: [
3325
- slashCommand.isOpen && /* @__PURE__ */ jsx12(
3824
+ slashCommand.isOpen && /* @__PURE__ */ jsx13(
3326
3825
  SlashCommandPopup,
3327
3826
  {
3328
3827
  tools: slashCommand.filteredTools,
@@ -3331,7 +3830,7 @@ var ChatBubble = ({
3331
3830
  onClose: () => setInputValue("")
3332
3831
  }
3333
3832
  ),
3334
- /* @__PURE__ */ jsx12(
3833
+ /* @__PURE__ */ jsx13(
3335
3834
  InputField,
3336
3835
  {
3337
3836
  inputValue,
@@ -3353,20 +3852,20 @@ var ChatBubble = ({
3353
3852
  ]
3354
3853
  }
3355
3854
  ),
3356
- !drawerOpen && /* @__PURE__ */ jsx12(
3855
+ !drawerOpen && /* @__PURE__ */ jsx13(
3357
3856
  "div",
3358
3857
  {
3359
3858
  className: `fixed ${drawerSide === "right" ? "right-0" : "left-0"} bottom-20 opacity-70 hover:opacity-100 transition-opacity duration-300 z-[999999] cursor-pointer`,
3360
3859
  style: { zIndex: 999999 },
3361
3860
  onClick: () => setDrawerOpen(true),
3362
- children: /* @__PURE__ */ jsx12("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__ */ jsx12("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx12("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__ */ jsx12("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx12("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" }) }) })
3861
+ children: /* @__PURE__ */ jsx13("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__ */ jsx13("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("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__ */ jsx13("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("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" }) }) })
3363
3862
  }
3364
3863
  )
3365
3864
  ] });
3366
3865
  }
3367
3866
  if (currentVariant === "floating") {
3368
3867
  const recentMessage = messages[messages.length - 1];
3369
- return /* @__PURE__ */ jsx12(
3868
+ return /* @__PURE__ */ jsx13(
3370
3869
  "div",
3371
3870
  {
3372
3871
  className: `fixed z-[999999] ${isDragging ? "cursor-grabbing" : "cursor-grab"}`,
@@ -3382,29 +3881,29 @@ var ChatBubble = ({
3382
3881
  children: /* @__PURE__ */ jsxs8("div", { className: `${glassClasses} rounded-2xl shadow-2xl p-3 max-w-xs ${!glassMode && "border-gray-200 border"}`, children: [
3383
3882
  /* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between mb-2", children: [
3384
3883
  /* @__PURE__ */ jsxs8("div", { className: "flex items-center space-x-2", children: [
3385
- /* @__PURE__ */ jsx12(Avatar, { avatar: config.avatar, size: "small" }),
3386
- config.title && /* @__PURE__ */ jsx12("span", { className: THEME_CLASSES.text.floatingTitle, children: config.title })
3884
+ /* @__PURE__ */ jsx13(Avatar, { avatar: config.avatar, size: "small" }),
3885
+ config.title && /* @__PURE__ */ jsx13("span", { className: THEME_CLASSES.text.floatingTitle, children: config.title })
3387
3886
  ] }),
3388
- onClearChat && /* @__PURE__ */ jsx12(
3887
+ onClearChat && /* @__PURE__ */ jsx13(
3389
3888
  "button",
3390
3889
  {
3391
3890
  onClick: onClearChat,
3392
3891
  className: THEME_CLASSES.button.floatingClear,
3393
3892
  title: "Clear chat",
3394
3893
  "data-testid": ChatNames.clearButton,
3395
- children: /* @__PURE__ */ jsx12("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx12("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
3894
+ children: /* @__PURE__ */ jsx13("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
3396
3895
  }
3397
3896
  )
3398
3897
  ] }),
3399
3898
  recentMessage && /* @__PURE__ */ jsxs8("div", { className: `mb-2 group flex items-center gap-2 ${recentMessage.type === "user" ? "flex-row-reverse" : "flex-row"}`, children: [
3400
- /* @__PURE__ */ jsx12(
3899
+ /* @__PURE__ */ jsx13(
3401
3900
  "div",
3402
3901
  {
3403
3902
  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"}`,
3404
3903
  children: recentMessage.text.length > 60 ? `${recentMessage.text.slice(0, 60)}...` : recentMessage.text
3405
3904
  }
3406
3905
  ),
3407
- /* @__PURE__ */ jsx12(
3906
+ /* @__PURE__ */ jsx13(
3408
3907
  "div",
3409
3908
  {
3410
3909
  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"}`,
@@ -3414,7 +3913,7 @@ var ChatBubble = ({
3414
3913
  )
3415
3914
  ] }),
3416
3915
  /* @__PURE__ */ jsxs8("div", { style: { position: "relative" }, children: [
3417
- slashCommand.isOpen && /* @__PURE__ */ jsx12(
3916
+ slashCommand.isOpen && /* @__PURE__ */ jsx13(
3418
3917
  SlashCommandPopup,
3419
3918
  {
3420
3919
  tools: slashCommand.filteredTools,
@@ -3423,7 +3922,7 @@ var ChatBubble = ({
3423
3922
  onClose: () => setInputValue("")
3424
3923
  }
3425
3924
  ),
3426
- /* @__PURE__ */ jsx12(
3925
+ /* @__PURE__ */ jsx13(
3427
3926
  InputField,
3428
3927
  {
3429
3928
  compact: true,
@@ -3443,7 +3942,7 @@ var ChatBubble = ({
3443
3942
  }
3444
3943
  );
3445
3944
  }
3446
- return /* @__PURE__ */ jsx12(Fragment3, { children: /* @__PURE__ */ jsxs8(
3945
+ return /* @__PURE__ */ jsx13(Fragment3, { children: /* @__PURE__ */ jsxs8(
3447
3946
  "div",
3448
3947
  {
3449
3948
  className: "fixed",
@@ -3497,13 +3996,13 @@ var ChatBubble = ({
3497
3996
  children: [
3498
3997
  /* @__PURE__ */ jsxs8("div", { className: "flex items-center space-x-3", children: [
3499
3998
  config.avatar && /* @__PURE__ */ jsxs8("div", { className: "relative flex-shrink-0", children: [
3500
- /* @__PURE__ */ jsx12(Avatar, { avatar: config.avatar }),
3501
- /* @__PURE__ */ jsx12("div", { className: "absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
3999
+ /* @__PURE__ */ jsx13(Avatar, { avatar: config.avatar }),
4000
+ /* @__PURE__ */ jsx13("div", { className: "absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
3502
4001
  ] }),
3503
- config.title && /* @__PURE__ */ jsx12("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx12("h3", { className: THEME_CLASSES.text.title, children: config.title }) })
4002
+ config.title && /* @__PURE__ */ jsx13("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx13("h3", { className: THEME_CLASSES.text.title, children: config.title }) })
3504
4003
  ] }),
3505
4004
  /* @__PURE__ */ jsxs8("div", { className: "flex items-center space-x-1 flex-shrink-0", children: [
3506
- /* @__PURE__ */ jsx12(
4005
+ /* @__PURE__ */ jsx13(
3507
4006
  "button",
3508
4007
  {
3509
4008
  onClick: (e) => {
@@ -3512,10 +4011,10 @@ var ChatBubble = ({
3512
4011
  },
3513
4012
  className: THEME_CLASSES.button.minimize,
3514
4013
  title: "Minimize chat",
3515
- children: /* @__PURE__ */ jsx12("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx12("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
4014
+ children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
3516
4015
  }
3517
4016
  ),
3518
- /* @__PURE__ */ jsx12(
4017
+ /* @__PURE__ */ jsx13(
3519
4018
  "button",
3520
4019
  {
3521
4020
  onClick: (e) => {
@@ -3524,7 +4023,7 @@ var ChatBubble = ({
3524
4023
  },
3525
4024
  className: THEME_CLASSES.button.close,
3526
4025
  title: "Close chat",
3527
- children: /* @__PURE__ */ jsx12("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx12("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
4026
+ children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
3528
4027
  }
3529
4028
  )
3530
4029
  ] })
@@ -3534,10 +4033,10 @@ var ChatBubble = ({
3534
4033
  /* @__PURE__ */ jsxs8("div", { className: "p-4", children: [
3535
4034
  (() => {
3536
4035
  const lastAiMessage = [...messages].reverse().find((m) => m.type === "ai");
3537
- return lastAiMessage ? /* @__PURE__ */ jsx12("div", { className: "mb-3", children: /* @__PURE__ */ jsx12("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__ */ jsx12("div", { className: "mb-3", children: /* @__PURE__ */ jsx12("div", { className: THEME_CLASSES.text.minimizedMessage, style: INLINE_STYLES.minimizedMessage(theme === "dark"), children: "No AI responses yet" }) });
4036
+ return lastAiMessage ? /* @__PURE__ */ jsx13("div", { className: "mb-3", children: /* @__PURE__ */ jsx13("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__ */ jsx13("div", { className: "mb-3", children: /* @__PURE__ */ jsx13("div", { className: THEME_CLASSES.text.minimizedMessage, style: INLINE_STYLES.minimizedMessage(theme === "dark"), children: "No AI responses yet" }) });
3538
4037
  })(),
3539
4038
  /* @__PURE__ */ jsxs8("div", { style: { position: "relative" }, children: [
3540
- slashCommand.isOpen && /* @__PURE__ */ jsx12(
4039
+ slashCommand.isOpen && /* @__PURE__ */ jsx13(
3541
4040
  SlashCommandPopup,
3542
4041
  {
3543
4042
  tools: slashCommand.filteredTools,
@@ -3546,7 +4045,7 @@ var ChatBubble = ({
3546
4045
  onClose: () => setInputValue("")
3547
4046
  }
3548
4047
  ),
3549
- /* @__PURE__ */ jsx12(
4048
+ /* @__PURE__ */ jsx13(
3550
4049
  InputField,
3551
4050
  {
3552
4051
  compact: true,
@@ -3593,13 +4092,13 @@ var ChatBubble = ({
3593
4092
  children: [
3594
4093
  /* @__PURE__ */ jsxs8("div", { className: "flex items-center space-x-3", children: [
3595
4094
  config.avatar && /* @__PURE__ */ jsxs8("div", { className: "relative flex-shrink-0", children: [
3596
- /* @__PURE__ */ jsx12(Avatar, { avatar: config.avatar }),
3597
- /* @__PURE__ */ jsx12("div", { className: "absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
4095
+ /* @__PURE__ */ jsx13(Avatar, { avatar: config.avatar }),
4096
+ /* @__PURE__ */ jsx13("div", { className: "absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
3598
4097
  ] }),
3599
- config.title && /* @__PURE__ */ jsx12("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx12("h3", { className: THEME_CLASSES.text.title, children: config.title }) })
4098
+ config.title && /* @__PURE__ */ jsx13("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx13("h3", { className: THEME_CLASSES.text.title, children: config.title }) })
3600
4099
  ] }),
3601
4100
  /* @__PURE__ */ jsxs8("div", { className: "flex items-center space-x-1 flex-shrink-0 relative", "data-more-menu": true, children: [
3602
- /* @__PURE__ */ jsx12(
4101
+ /* @__PURE__ */ jsx13(
3603
4102
  "a",
3604
4103
  {
3605
4104
  href: "https://www.interface.supernal.ai",
@@ -3607,30 +4106,160 @@ var ChatBubble = ({
3607
4106
  rel: "noopener noreferrer",
3608
4107
  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",
3609
4108
  title: "Visit Supernal Interface Documentation",
3610
- children: /* @__PURE__ */ jsx12("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx12("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" }) })
4109
+ children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("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" }) })
3611
4110
  }
3612
4111
  ),
3613
- /* @__PURE__ */ jsx12(
4112
+ /* @__PURE__ */ jsx13(
3614
4113
  "button",
3615
4114
  {
3616
4115
  onClick: () => setShowMoreMenu(!showMoreMenu),
3617
4116
  className: THEME_CLASSES.button.more,
3618
4117
  title: "More options",
3619
- children: /* @__PURE__ */ jsx12("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx12("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" }) })
4118
+ "data-testid": "chat-more-menu-button",
4119
+ children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("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" }) })
3620
4120
  }
3621
4121
  ),
3622
- showMoreMenu && /* @__PURE__ */ jsxs8("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: [
3623
- /* @__PURE__ */ jsx12("div", { className: "px-3 py-2 border-b border-gray-200 dark:border-gray-600 mb-2", children: /* @__PURE__ */ jsxs8("div", { className: "grid grid-cols-4 gap-1", children: [
3624
- /* @__PURE__ */ jsx12(
4122
+ showMoreMenu && /* @__PURE__ */ jsxs8("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: [
4123
+ apiKey && /* @__PURE__ */ jsxs8("div", { className: "px-3 py-2 border-b border-gray-200 dark:border-gray-600 mb-2", "data-testid": "api-key-section", children: [
4124
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between mb-2", children: [
4125
+ /* @__PURE__ */ jsxs8("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-200 flex items-center gap-2", children: [
4126
+ /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("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" }) }),
4127
+ "API Key"
4128
+ ] }),
4129
+ apiKey.status === "valid" && /* @__PURE__ */ jsx13("span", { className: "text-green-500", title: "API key is valid", "data-testid": "api-key-status", "data-status": "valid", children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx13("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" }) }) }),
4130
+ apiKey.status === "invalid" && /* @__PURE__ */ jsx13("span", { className: "text-red-500", title: "API key is invalid", "data-testid": "api-key-status", "data-status": "invalid", children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx13("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" }) }) }),
4131
+ apiKey.status === "validating" && /* @__PURE__ */ jsx13("span", { className: "text-blue-500 animate-spin", title: "Validating...", "data-testid": "api-key-status", "data-status": "validating", children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("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" }) }) })
4132
+ ] }),
4133
+ apiKey.status === "valid" && apiKey.maskedKey ? (
4134
+ // Key is set - show masked key and clear button
4135
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
4136
+ /* @__PURE__ */ jsx13("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 }),
4137
+ /* @__PURE__ */ jsx13(
4138
+ "button",
4139
+ {
4140
+ onClick: () => {
4141
+ apiKey.clearApiKey();
4142
+ setApiKeyInputValue("");
4143
+ },
4144
+ className: "text-xs text-red-500 hover:text-red-600 px-2 py-1",
4145
+ title: "Remove API key",
4146
+ "data-testid": "api-key-clear-button",
4147
+ children: "Clear"
4148
+ }
4149
+ )
4150
+ ] })
4151
+ ) : showApiKeyInput ? (
4152
+ // Input mode - show form
4153
+ /* @__PURE__ */ jsxs8("div", { className: "space-y-2", children: [
4154
+ /* @__PURE__ */ jsxs8("div", { className: "flex gap-1", children: [
4155
+ /* @__PURE__ */ jsx13(
4156
+ "input",
4157
+ {
4158
+ type: showApiKey ? "text" : "password",
4159
+ value: apiKeyInputValue,
4160
+ onChange: (e) => setApiKeyInputValue(e.target.value),
4161
+ placeholder: "sk-ant-...",
4162
+ 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",
4163
+ "data-testid": "api-key-input",
4164
+ onKeyDown: (e) => {
4165
+ if (e.key === "Enter") {
4166
+ e.preventDefault();
4167
+ if (apiKeyInputValue.trim()) {
4168
+ apiKey.setApiKey(apiKeyInputValue.trim()).then((success) => {
4169
+ if (success) {
4170
+ setApiKeyInputValue("");
4171
+ setShowApiKeyInput(false);
4172
+ }
4173
+ });
4174
+ }
4175
+ }
4176
+ if (e.key === "Escape") {
4177
+ setShowApiKeyInput(false);
4178
+ setApiKeyInputValue("");
4179
+ }
4180
+ },
4181
+ autoFocus: true
4182
+ }
4183
+ ),
4184
+ /* @__PURE__ */ jsx13(
4185
+ "button",
4186
+ {
4187
+ onClick: () => setShowApiKey(!showApiKey),
4188
+ className: "px-2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200",
4189
+ title: showApiKey ? "Hide" : "Show",
4190
+ "data-testid": "api-key-show-toggle",
4191
+ children: showApiKey ? "\u{1F648}" : "\u{1F441}\uFE0F"
4192
+ }
4193
+ )
4194
+ ] }),
4195
+ /* @__PURE__ */ jsxs8("div", { className: "flex gap-2", children: [
4196
+ /* @__PURE__ */ jsx13(
4197
+ "button",
4198
+ {
4199
+ onClick: async () => {
4200
+ if (apiKeyInputValue.trim()) {
4201
+ const success = await apiKey.setApiKey(apiKeyInputValue.trim());
4202
+ if (success) {
4203
+ setApiKeyInputValue("");
4204
+ setShowApiKeyInput(false);
4205
+ }
4206
+ }
4207
+ },
4208
+ disabled: !apiKeyInputValue.trim() || apiKey.status === "validating",
4209
+ 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",
4210
+ "data-testid": "api-key-submit-button",
4211
+ children: apiKey.status === "validating" ? "Validating..." : "Save"
4212
+ }
4213
+ ),
4214
+ /* @__PURE__ */ jsx13(
4215
+ "button",
4216
+ {
4217
+ onClick: () => {
4218
+ setShowApiKeyInput(false);
4219
+ setApiKeyInputValue("");
4220
+ },
4221
+ className: "text-xs px-3 py-1.5 text-gray-600 dark:text-gray-300 hover:text-gray-800 dark:hover:text-gray-100",
4222
+ "data-testid": "api-key-cancel-button",
4223
+ children: "Cancel"
4224
+ }
4225
+ )
4226
+ ] }),
4227
+ apiKey.error && /* @__PURE__ */ jsx13("p", { className: "text-xs text-red-500", "data-testid": "api-key-error", children: apiKey.error }),
4228
+ /* @__PURE__ */ jsx13(
4229
+ "a",
4230
+ {
4231
+ href: "https://console.anthropic.com/settings/keys",
4232
+ target: "_blank",
4233
+ rel: "noopener noreferrer",
4234
+ className: "block text-xs text-blue-500 hover:underline",
4235
+ children: "Get an API key from Anthropic \u2192"
4236
+ }
4237
+ )
4238
+ ] })
4239
+ ) : (
4240
+ // No key - show configure button
4241
+ /* @__PURE__ */ jsx13(
4242
+ "button",
4243
+ {
4244
+ onClick: () => setShowApiKeyInput(true),
4245
+ 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",
4246
+ "data-testid": "api-key-configure-button",
4247
+ children: "Configure API Key"
4248
+ }
4249
+ )
4250
+ )
4251
+ ] }),
4252
+ /* @__PURE__ */ jsx13("div", { className: "px-3 py-2 border-b border-gray-200 dark:border-gray-600 mb-2", children: /* @__PURE__ */ jsxs8("div", { className: "grid grid-cols-4 gap-1", children: [
4253
+ /* @__PURE__ */ jsx13(
3625
4254
  "button",
3626
4255
  {
3627
4256
  onClick: () => setLocalGlassMode(false),
3628
4257
  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"}`,
3629
4258
  title: "Glass Off",
3630
- children: /* @__PURE__ */ jsx12("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx12("rect", { x: "8", y: "8", width: "8", height: "8", rx: "1" }) })
4259
+ children: /* @__PURE__ */ jsx13("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("rect", { x: "8", y: "8", width: "8", height: "8", rx: "1" }) })
3631
4260
  }
3632
4261
  ),
3633
- /* @__PURE__ */ jsx12(
4262
+ /* @__PURE__ */ jsx13(
3634
4263
  "button",
3635
4264
  {
3636
4265
  onClick: () => {
@@ -3639,10 +4268,10 @@ var ChatBubble = ({
3639
4268
  },
3640
4269
  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"}`,
3641
4270
  title: "Glass Low",
3642
- children: /* @__PURE__ */ jsx12("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx12("rect", { x: "9", y: "9", width: "6", height: "6", rx: "1", strokeWidth: "2" }) })
4271
+ children: /* @__PURE__ */ jsx13("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("rect", { x: "9", y: "9", width: "6", height: "6", rx: "1", strokeWidth: "2" }) })
3643
4272
  }
3644
4273
  ),
3645
- /* @__PURE__ */ jsx12(
4274
+ /* @__PURE__ */ jsx13(
3646
4275
  "button",
3647
4276
  {
3648
4277
  onClick: () => {
@@ -3652,12 +4281,12 @@ var ChatBubble = ({
3652
4281
  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"}`,
3653
4282
  title: "Glass Medium",
3654
4283
  children: /* @__PURE__ */ jsxs8("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [
3655
- /* @__PURE__ */ jsx12("rect", { x: "8", y: "8", width: "8", height: "8", rx: "1", strokeWidth: "2" }),
3656
- /* @__PURE__ */ jsx12("rect", { x: "10", y: "10", width: "4", height: "4", rx: "0.5", strokeWidth: "1.5" })
4284
+ /* @__PURE__ */ jsx13("rect", { x: "8", y: "8", width: "8", height: "8", rx: "1", strokeWidth: "2" }),
4285
+ /* @__PURE__ */ jsx13("rect", { x: "10", y: "10", width: "4", height: "4", rx: "0.5", strokeWidth: "1.5" })
3657
4286
  ] })
3658
4287
  }
3659
4288
  ),
3660
- /* @__PURE__ */ jsx12(
4289
+ /* @__PURE__ */ jsx13(
3661
4290
  "button",
3662
4291
  {
3663
4292
  onClick: () => {
@@ -3667,9 +4296,9 @@ var ChatBubble = ({
3667
4296
  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"}`,
3668
4297
  title: "Glass High",
3669
4298
  children: /* @__PURE__ */ jsxs8("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [
3670
- /* @__PURE__ */ jsx12("rect", { x: "7", y: "7", width: "10", height: "10", rx: "1", strokeWidth: "2" }),
3671
- /* @__PURE__ */ jsx12("rect", { x: "9", y: "9", width: "6", height: "6", rx: "0.5", strokeWidth: "1.5" }),
3672
- /* @__PURE__ */ jsx12("rect", { x: "11", y: "11", width: "2", height: "2", rx: "0.5", strokeWidth: "1" })
4299
+ /* @__PURE__ */ jsx13("rect", { x: "7", y: "7", width: "10", height: "10", rx: "1", strokeWidth: "2" }),
4300
+ /* @__PURE__ */ jsx13("rect", { x: "9", y: "9", width: "6", height: "6", rx: "0.5", strokeWidth: "1.5" }),
4301
+ /* @__PURE__ */ jsx13("rect", { x: "11", y: "11", width: "2", height: "2", rx: "0.5", strokeWidth: "1" })
3673
4302
  ] })
3674
4303
  }
3675
4304
  )
@@ -3686,7 +4315,7 @@ var ChatBubble = ({
3686
4315
  },
3687
4316
  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",
3688
4317
  children: [
3689
- /* @__PURE__ */ jsx12("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx12("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" }) }),
4318
+ /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("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" }) }),
3690
4319
  /* @__PURE__ */ jsxs8("span", { children: [
3691
4320
  theme === "light" ? "Dark" : "Light",
3692
4321
  " Mode"
@@ -3705,7 +4334,7 @@ var ChatBubble = ({
3705
4334
  },
3706
4335
  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",
3707
4336
  children: [
3708
- /* @__PURE__ */ jsx12("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx12("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" }) }),
4337
+ /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("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" }) }),
3709
4338
  /* @__PURE__ */ jsxs8("span", { children: [
3710
4339
  voiceEnabled ? "Disable" : "Enable",
3711
4340
  " Voice"
@@ -3722,8 +4351,8 @@ var ChatBubble = ({
3722
4351
  },
3723
4352
  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",
3724
4353
  children: [
3725
- /* @__PURE__ */ jsx12("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx12("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" }) }),
3726
- /* @__PURE__ */ jsx12("span", { children: "Reset position" })
4354
+ /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("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" }) }),
4355
+ /* @__PURE__ */ jsx13("span", { children: "Reset position" })
3727
4356
  ]
3728
4357
  }
3729
4358
  ),
@@ -3743,8 +4372,8 @@ var ChatBubble = ({
3743
4372
  },
3744
4373
  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",
3745
4374
  children: [
3746
- /* @__PURE__ */ jsx12("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx12("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" }) }),
3747
- /* @__PURE__ */ jsx12("span", { children: "How to use" })
4375
+ /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("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" }) }),
4376
+ /* @__PURE__ */ jsx13("span", { children: "How to use" })
3748
4377
  ]
3749
4378
  }
3750
4379
  ),
@@ -3757,41 +4386,41 @@ var ChatBubble = ({
3757
4386
  },
3758
4387
  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",
3759
4388
  children: [
3760
- /* @__PURE__ */ jsx12("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx12("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" }) }),
3761
- /* @__PURE__ */ jsx12("span", { children: "Clear chat" })
4389
+ /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("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" }) }),
4390
+ /* @__PURE__ */ jsx13("span", { children: "Clear chat" })
3762
4391
  ]
3763
4392
  }
3764
4393
  )
3765
4394
  ] }),
3766
- /* @__PURE__ */ jsx12(
4395
+ /* @__PURE__ */ jsx13(
3767
4396
  "button",
3768
4397
  {
3769
4398
  onClick: () => setIsMinimized(true),
3770
4399
  className: THEME_CLASSES.button.minimize,
3771
4400
  title: "Minimize",
3772
- children: /* @__PURE__ */ jsx12("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx12("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20 12H4" }) })
4401
+ children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20 12H4" }) })
3773
4402
  }
3774
4403
  ),
3775
- /* @__PURE__ */ jsx12(
4404
+ /* @__PURE__ */ jsx13(
3776
4405
  "button",
3777
4406
  {
3778
4407
  onClick: handleToggle,
3779
4408
  className: THEME_CLASSES.button.close,
3780
4409
  title: "Close",
3781
- children: /* @__PURE__ */ jsx12("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx12("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
4410
+ children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
3782
4411
  }
3783
4412
  )
3784
4413
  ] })
3785
4414
  ]
3786
4415
  }
3787
4416
  ),
3788
- /* @__PURE__ */ jsxs8("div", { className: "flex-1 overflow-y-auto p-4 space-y-2", children: [
4417
+ /* @__PURE__ */ jsxs8("div", { className: "flex-1 overflow-y-auto p-4 space-y-2", "data-testid": "chat-messages", children: [
3789
4418
  showWelcome && messages.length === 0 && config.welcome?.enabled && /* @__PURE__ */ jsxs8("div", { className: THEME_CLASSES.welcome.container, children: [
3790
- config.welcome.title && /* @__PURE__ */ jsx12("h4", { className: THEME_CLASSES.welcome.title, style: INLINE_STYLES.welcomeTitle(theme === "dark"), children: config.welcome.title }),
3791
- config.welcome.content && /* @__PURE__ */ jsx12("p", { className: THEME_CLASSES.welcome.content, style: INLINE_STYLES.welcomeContent(theme === "dark"), children: config.welcome.content }),
4419
+ config.welcome.title && /* @__PURE__ */ jsx13("h4", { className: THEME_CLASSES.welcome.title, style: INLINE_STYLES.welcomeTitle(theme === "dark"), children: config.welcome.title }),
4420
+ config.welcome.content && /* @__PURE__ */ jsx13("p", { className: THEME_CLASSES.welcome.content, style: INLINE_STYLES.welcomeContent(theme === "dark"), children: config.welcome.content }),
3792
4421
  config.welcome.suggestedCommands && config.welcome.suggestedCommands.length > 0 && /* @__PURE__ */ jsxs8("div", { className: THEME_CLASSES.welcome.commandsContainer, children: [
3793
- /* @__PURE__ */ jsx12("p", { className: THEME_CLASSES.welcome.commandsHeader, children: "Try these commands:" }),
3794
- /* @__PURE__ */ jsx12("div", { className: "space-y-1", children: config.welcome.suggestedCommands.map((cmd, idx) => /* @__PURE__ */ jsxs8(
4422
+ /* @__PURE__ */ jsx13("p", { className: THEME_CLASSES.welcome.commandsHeader, children: "Try these commands:" }),
4423
+ /* @__PURE__ */ jsx13("div", { className: "space-y-1", children: config.welcome.suggestedCommands.map((cmd, idx) => /* @__PURE__ */ jsxs8(
3795
4424
  "button",
3796
4425
  {
3797
4426
  onClick: () => {
@@ -3806,7 +4435,7 @@ var ChatBubble = ({
3806
4435
  cmd.text,
3807
4436
  '"'
3808
4437
  ] }),
3809
- cmd.desc && /* @__PURE__ */ jsx12("div", { className: THEME_CLASSES.welcome.commandDesc, style: INLINE_STYLES.commandDesc(theme === "dark"), children: cmd.desc })
4438
+ cmd.desc && /* @__PURE__ */ jsx13("div", { className: THEME_CLASSES.welcome.commandDesc, style: INLINE_STYLES.commandDesc(theme === "dark"), children: cmd.desc })
3810
4439
  ]
3811
4440
  },
3812
4441
  idx
@@ -3814,16 +4443,16 @@ var ChatBubble = ({
3814
4443
  ] })
3815
4444
  ] }),
3816
4445
  messages.map((message) => /* @__PURE__ */ jsxs8("div", { className: `group flex items-center gap-2 mb-2 ${message.type === "user" ? "flex-row-reverse" : "flex-row"}`, children: [
3817
- /* @__PURE__ */ jsx12(
4446
+ /* @__PURE__ */ jsx13(
3818
4447
  "div",
3819
4448
  {
3820
4449
  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}`,
3821
4450
  style: message.type === "user" ? INLINE_STYLES.messageUser() : message.type === "ai" ? INLINE_STYLES.messageAI(theme === "dark") : INLINE_STYLES.messageSystem(theme === "dark"),
3822
4451
  "data-testid": `chat-message-${message.type}`,
3823
- children: /* @__PURE__ */ jsx12(MessageRenderer, { content: message.text, theme })
4452
+ children: /* @__PURE__ */ jsx13(MessageRenderer, { content: message.text, theme })
3824
4453
  }
3825
4454
  ),
3826
- message.type === "ai" && voiceEnabled && /* @__PURE__ */ jsx12(
4455
+ message.type === "ai" && voiceEnabled && /* @__PURE__ */ jsx13(
3827
4456
  TTSButton,
3828
4457
  {
3829
4458
  text: message.text,
@@ -3833,7 +4462,7 @@ var ChatBubble = ({
3833
4462
  size: "small"
3834
4463
  }
3835
4464
  ),
3836
- /* @__PURE__ */ jsx12(
4465
+ /* @__PURE__ */ jsx13(
3837
4466
  "div",
3838
4467
  {
3839
4468
  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"}`,
@@ -3842,10 +4471,10 @@ var ChatBubble = ({
3842
4471
  }
3843
4472
  )
3844
4473
  ] }, message.id)),
3845
- /* @__PURE__ */ jsx12("div", { ref: messagesEndRef })
4474
+ /* @__PURE__ */ jsx13("div", { ref: messagesEndRef })
3846
4475
  ] }),
3847
4476
  /* @__PURE__ */ jsxs8("div", { style: { position: "relative" }, children: [
3848
- slashCommand.isOpen && /* @__PURE__ */ jsx12(
4477
+ slashCommand.isOpen && /* @__PURE__ */ jsx13(
3849
4478
  SlashCommandPopup,
3850
4479
  {
3851
4480
  tools: slashCommand.filteredTools,
@@ -3854,7 +4483,7 @@ var ChatBubble = ({
3854
4483
  onClose: () => setInputValue("")
3855
4484
  }
3856
4485
  ),
3857
- /* @__PURE__ */ jsx12(
4486
+ /* @__PURE__ */ jsx13(
3858
4487
  InputField,
3859
4488
  {
3860
4489
  inputValue,
@@ -3884,8 +4513,8 @@ var ChatBubble = ({
3884
4513
  "data-testid": ChatNames.bubble,
3885
4514
  title: `Open chat (press ${isMac ? "Cmd" : "Ctrl"}+/ for voice recording)`,
3886
4515
  children: [
3887
- /* @__PURE__ */ jsx12("img", { src: config.logo, alt: "Supernal", className: "w-8 h-8" }),
3888
- hasUnread && notifications && /* @__PURE__ */ jsx12("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__ */ jsx12("span", { className: "text-xs text-white font-bold", children: unreadCount > 9 ? "9+" : unreadCount }) })
4516
+ /* @__PURE__ */ jsx13("img", { src: config.logo, alt: "Supernal", className: "w-8 h-8" }),
4517
+ hasUnread && notifications && /* @__PURE__ */ jsx13("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__ */ jsx13("span", { className: "text-xs text-white font-bold", children: unreadCount > 9 ? "9+" : unreadCount }) })
3889
4518
  ]
3890
4519
  }
3891
4520
  )
@@ -3895,33 +4524,33 @@ var ChatBubble = ({
3895
4524
  };
3896
4525
 
3897
4526
  // src/components/AutoNavigationContext.tsx
3898
- import { useEffect as useEffect9, useState as useState10 } from "react";
4527
+ import { useEffect as useEffect10, useState as useState11 } from "react";
3899
4528
 
3900
4529
  // src/hooks/useNavigationGraph.tsx
3901
- import { useEffect as useEffect8, useState as useState9, useCallback as useCallback6, createContext as createContext3, useContext as useContext3 } from "react";
4530
+ import { useEffect as useEffect9, useState as useState10, useCallback as useCallback7, createContext as createContext4, useContext as useContext4 } from "react";
3902
4531
  import {
3903
4532
  NavigationGraph
3904
4533
  } from "@supernal/interface/browser";
3905
- import { jsx as jsx13 } from "react/jsx-runtime";
3906
- var NavigationContextContext = createContext3("global");
4534
+ import { jsx as jsx14 } from "react/jsx-runtime";
4535
+ var NavigationContextContext = createContext4("global");
3907
4536
  function NavigationContextProvider({
3908
4537
  value,
3909
4538
  children
3910
4539
  }) {
3911
4540
  const graph = useNavigationGraph();
3912
- useEffect8(() => {
4541
+ useEffect9(() => {
3913
4542
  graph.setCurrentContext(value);
3914
4543
  }, [value, graph]);
3915
- return /* @__PURE__ */ jsx13(NavigationContextContext.Provider, { value, children });
4544
+ return /* @__PURE__ */ jsx14(NavigationContextContext.Provider, { value, children });
3916
4545
  }
3917
4546
  function useNavigationGraph() {
3918
4547
  return NavigationGraph.getInstance();
3919
4548
  }
3920
4549
  function useCurrentContext() {
3921
- const contextFromProvider = useContext3(NavigationContextContext);
4550
+ const contextFromProvider = useContext4(NavigationContextContext);
3922
4551
  const graph = useNavigationGraph();
3923
- const [graphContext, setGraphContext] = useState9("");
3924
- useEffect8(() => {
4552
+ const [graphContext, setGraphContext] = useState10("");
4553
+ useEffect9(() => {
3925
4554
  const interval = setInterval(() => {
3926
4555
  const current = graph.getCurrentContext?.() || "";
3927
4556
  if (current !== graphContext) {
@@ -3935,7 +4564,7 @@ function useCurrentContext() {
3935
4564
  function useRegisterTool(toolId, contextId, metadata) {
3936
4565
  const graph = useNavigationGraph();
3937
4566
  const currentContext = useCurrentContext();
3938
- useEffect8(() => {
4567
+ useEffect9(() => {
3939
4568
  let targetContext = contextId || currentContext;
3940
4569
  if (!contextId && metadata) {
3941
4570
  const detection = graph.detectToolContext?.(toolId, metadata);
@@ -3949,10 +4578,10 @@ function useRegisterTool(toolId, contextId, metadata) {
3949
4578
  function useNavigationPath(targetContextOrToolId, isToolId = false) {
3950
4579
  const graph = useNavigationGraph();
3951
4580
  const currentContext = useCurrentContext();
3952
- const [path, setPath] = useState9(null);
3953
- const [loading, setLoading] = useState9(true);
3954
- const [error, setError] = useState9();
3955
- useEffect8(() => {
4581
+ const [path, setPath] = useState10(null);
4582
+ const [loading, setLoading] = useState10(true);
4583
+ const [error, setError] = useState10();
4584
+ useEffect9(() => {
3956
4585
  try {
3957
4586
  let targetContext = targetContextOrToolId;
3958
4587
  if (isToolId) {
@@ -3980,9 +4609,9 @@ function useNavigationPath(targetContextOrToolId, isToolId = false) {
3980
4609
  function useNavigate() {
3981
4610
  const graph = useNavigationGraph();
3982
4611
  const currentContext = useCurrentContext();
3983
- const [navigating, setNavigating] = useState9(false);
3984
- const [error, setError] = useState9();
3985
- const navigateTo = useCallback6(async (targetContextOrToolId, isToolId = false, executeNavigation) => {
4612
+ const [navigating, setNavigating] = useState10(false);
4613
+ const [error, setError] = useState10();
4614
+ const navigateTo = useCallback7(async (targetContextOrToolId, isToolId = false, executeNavigation) => {
3986
4615
  setNavigating(true);
3987
4616
  setError(void 0);
3988
4617
  try {
@@ -4024,8 +4653,8 @@ function useNavigate() {
4024
4653
  }
4025
4654
  function useAllContexts() {
4026
4655
  const graph = useNavigationGraph();
4027
- const [contexts, setContexts] = useState9(graph.getAllContexts?.());
4028
- useEffect8(() => {
4656
+ const [contexts, setContexts] = useState10(graph.getAllContexts?.());
4657
+ useEffect9(() => {
4029
4658
  const interval = setInterval(() => {
4030
4659
  setContexts(graph.getAllContexts?.());
4031
4660
  }, 1e3);
@@ -4035,28 +4664,28 @@ function useAllContexts() {
4035
4664
  }
4036
4665
 
4037
4666
  // src/components/AutoNavigationContext.tsx
4038
- import { Fragment as Fragment4, jsx as jsx14 } from "react/jsx-runtime";
4667
+ import { Fragment as Fragment4, jsx as jsx15 } from "react/jsx-runtime";
4039
4668
  function AutoNavigationContext({
4040
4669
  children,
4041
4670
  routes,
4042
4671
  onNavigate
4043
4672
  }) {
4044
- const [pathname, setPathname] = useState10("/");
4045
- useEffect9(() => {
4673
+ const [pathname, setPathname] = useState11("/");
4674
+ useEffect10(() => {
4046
4675
  if (typeof window !== "undefined") {
4047
4676
  setPathname(window.location.pathname);
4048
4677
  }
4049
4678
  }, []);
4050
4679
  const context = routes ? inferContextFromPath(pathname, routes) : null;
4051
- useEffect9(() => {
4680
+ useEffect10(() => {
4052
4681
  if (onNavigate && context) {
4053
4682
  onNavigate(context);
4054
4683
  }
4055
4684
  }, [context, onNavigate]);
4056
4685
  if (!context) {
4057
- return /* @__PURE__ */ jsx14(Fragment4, { children });
4686
+ return /* @__PURE__ */ jsx15(Fragment4, { children });
4058
4687
  }
4059
- return /* @__PURE__ */ jsx14(NavigationContextProvider, { value: context, children });
4688
+ return /* @__PURE__ */ jsx15(NavigationContextProvider, { value: context, children });
4060
4689
  }
4061
4690
  function inferContextFromPath(path, customRoutes) {
4062
4691
  if (customRoutes) {
@@ -4089,7 +4718,7 @@ function inferContextFromPath(path, customRoutes) {
4089
4718
  import { ExposureCollector, ToolRegistry as ToolRegistry3 } from "@supernal/interface/browser";
4090
4719
 
4091
4720
  // src/hooks/useLocationTracking.ts
4092
- import { useEffect as useEffect10, useRef as useRef9 } from "react";
4721
+ import { useEffect as useEffect11, useRef as useRef11 } from "react";
4093
4722
  import { LocationContext } from "@supernal/interface/browser";
4094
4723
  var usePathname;
4095
4724
  var useSearchParams;
@@ -4121,8 +4750,8 @@ function getCurrentLocation() {
4121
4750
  };
4122
4751
  }
4123
4752
  function useLocationTracking() {
4124
- const lastLocationRef = useRef9("");
4125
- const lastElementsRef = useRef9([]);
4753
+ const lastLocationRef = useRef11("");
4754
+ const lastElementsRef = useRef11([]);
4126
4755
  let pathname = null;
4127
4756
  let searchParams = null;
4128
4757
  try {
@@ -4134,7 +4763,7 @@ function useLocationTracking() {
4134
4763
  }
4135
4764
  } catch {
4136
4765
  }
4137
- useEffect10(() => {
4766
+ useEffect11(() => {
4138
4767
  const updateLocation = () => {
4139
4768
  const location = pathname !== null ? { pathname, search: searchParams?.toString() || "", asPath: pathname + (searchParams?.toString() ? `?${searchParams.toString()}` : "") } : getCurrentLocation();
4140
4769
  const visibleElements = getVisibleElements();
@@ -4175,7 +4804,7 @@ function useLocationTracking() {
4175
4804
  }
4176
4805
 
4177
4806
  // src/hooks/useNavigationGraphSetup.ts
4178
- import { useEffect as useEffect11, useState as useState11, useCallback as useCallback7 } from "react";
4807
+ import { useEffect as useEffect12, useState as useState12, useCallback as useCallback8 } from "react";
4179
4808
  var useAppRouter;
4180
4809
  var usePathname2;
4181
4810
  try {
@@ -4185,7 +4814,7 @@ try {
4185
4814
  } catch {
4186
4815
  }
4187
4816
  function useNavigationGraphSetup() {
4188
- const [isInitialized, setIsInitialized] = useState11(false);
4817
+ const [isInitialized, setIsInitialized] = useState12(false);
4189
4818
  let router = null;
4190
4819
  let pathname = null;
4191
4820
  try {
@@ -4197,7 +4826,7 @@ function useNavigationGraphSetup() {
4197
4826
  }
4198
4827
  } catch {
4199
4828
  }
4200
- const navigate = useCallback7((path) => {
4829
+ const navigate = useCallback8((path) => {
4201
4830
  const normalizedPath = path.startsWith("/") ? path : `/${path}`;
4202
4831
  if (router?.push) {
4203
4832
  router.push(normalizedPath);
@@ -4206,7 +4835,7 @@ function useNavigationGraphSetup() {
4206
4835
  }
4207
4836
  }, [router]);
4208
4837
  const currentPath = pathname ?? (typeof window !== "undefined" ? window.location.pathname + window.location.search : "/");
4209
- useEffect11(() => {
4838
+ useEffect12(() => {
4210
4839
  import("@supernal/interface/browser").then(({ NavigationGraph: NavigationGraph2 }) => {
4211
4840
  const graph = NavigationGraph2.getInstance();
4212
4841
  graph.setNavigationHandler(navigate);
@@ -4222,7 +4851,7 @@ function useNavigationGraphSetup() {
4222
4851
  console.log("[NavigationGraphSetup] Auto-configured with Next.js router");
4223
4852
  });
4224
4853
  }, [navigate, currentPath]);
4225
- useEffect11(() => {
4854
+ useEffect12(() => {
4226
4855
  if (!isInitialized) return;
4227
4856
  import("@supernal/interface/browser").then(({ NavigationGraph: NavigationGraph2 }) => {
4228
4857
  const graph = NavigationGraph2.getInstance();
@@ -4233,8 +4862,8 @@ function useNavigationGraphSetup() {
4233
4862
  }
4234
4863
 
4235
4864
  // src/components/ToolMenuPopup/ToolMenuPopup.tsx
4236
- import { useEffect as useEffect12, useRef as useRef10, useState as useState12 } from "react";
4237
- import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
4865
+ import { useEffect as useEffect13, useRef as useRef12, useState as useState13 } from "react";
4866
+ import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
4238
4867
  var ToolMenuPopup = ({
4239
4868
  isOpen,
4240
4869
  onClose,
@@ -4242,16 +4871,16 @@ var ToolMenuPopup = ({
4242
4871
  totalTools,
4243
4872
  contextLabel
4244
4873
  }) => {
4245
- const [collapsedCategories, setCollapsedCategories] = useState12(/* @__PURE__ */ new Set());
4246
- const [isHydrated, setIsHydrated] = useState12(false);
4247
- const [isMobile, setIsMobile] = useState12(false);
4248
- const popupRef = useRef10(null);
4874
+ const [collapsedCategories, setCollapsedCategories] = useState13(/* @__PURE__ */ new Set());
4875
+ const [isHydrated, setIsHydrated] = useState13(false);
4876
+ const [isMobile, setIsMobile] = useState13(false);
4877
+ const popupRef = useRef12(null);
4249
4878
  const { insertText } = useChatInput();
4250
- useEffect12(() => {
4879
+ useEffect13(() => {
4251
4880
  setIsHydrated(true);
4252
4881
  setIsMobile(window.matchMedia("(max-width: 767px)").matches);
4253
4882
  }, []);
4254
- useEffect12(() => {
4883
+ useEffect13(() => {
4255
4884
  if (!isOpen) return;
4256
4885
  const handleClickOutside = (e) => {
4257
4886
  const target = e.target;
@@ -4262,7 +4891,7 @@ var ToolMenuPopup = ({
4262
4891
  document.addEventListener("mousedown", handleClickOutside);
4263
4892
  return () => document.removeEventListener("mousedown", handleClickOutside);
4264
4893
  }, [isOpen, onClose]);
4265
- useEffect12(() => {
4894
+ useEffect13(() => {
4266
4895
  if (!isOpen) return;
4267
4896
  const handleKey = (e) => {
4268
4897
  if (e.key === "Escape") {
@@ -4325,7 +4954,7 @@ var ToolMenuPopup = ({
4325
4954
  alignItems: "center"
4326
4955
  }, children: [
4327
4956
  /* @__PURE__ */ jsxs9("div", { children: [
4328
- /* @__PURE__ */ jsx15("h3", { style: { margin: 0, color: "#fff", fontSize: 16, fontWeight: 600 }, children: "Available Actions" }),
4957
+ /* @__PURE__ */ jsx16("h3", { style: { margin: 0, color: "#fff", fontSize: 16, fontWeight: 600 }, children: "Available Actions" }),
4329
4958
  /* @__PURE__ */ jsxs9("p", { style: { margin: "4px 0 0", color: "rgba(255,255,255,0.6)", fontSize: 12 }, children: [
4330
4959
  contextLabel,
4331
4960
  " \xB7 ",
@@ -4334,7 +4963,7 @@ var ToolMenuPopup = ({
4334
4963
  totalTools !== 1 ? "s" : ""
4335
4964
  ] })
4336
4965
  ] }),
4337
- /* @__PURE__ */ jsx15(
4966
+ /* @__PURE__ */ jsx16(
4338
4967
  "button",
4339
4968
  {
4340
4969
  onClick: onClose,
@@ -4353,7 +4982,7 @@ var ToolMenuPopup = ({
4353
4982
  )
4354
4983
  ] }),
4355
4984
  /* @__PURE__ */ jsxs9("div", { style: { padding: "8px 12px 16px" }, children: [
4356
- categories.length === 0 && /* @__PURE__ */ jsx15("p", { style: { color: "rgba(255,255,255,0.5)", textAlign: "center", padding: "24px 0", fontSize: 14 }, children: "No tools available on this page." }),
4985
+ categories.length === 0 && /* @__PURE__ */ jsx16("p", { style: { color: "rgba(255,255,255,0.5)", textAlign: "center", padding: "24px 0", fontSize: 14 }, children: "No tools available on this page." }),
4357
4986
  categories.map((category) => {
4358
4987
  const isCollapsed = collapsedCategories.has(category.key);
4359
4988
  return /* @__PURE__ */ jsxs9("div", { style: { marginBottom: 4 }, children: [
@@ -4383,13 +5012,13 @@ var ToolMenuPopup = ({
4383
5012
  children: [
4384
5013
  /* @__PURE__ */ jsxs9("span", { style: { fontSize: 14, fontWeight: 500 }, children: [
4385
5014
  category.displayName,
4386
- /* @__PURE__ */ jsx15("span", { style: { color: "rgba(255,255,255,0.4)", fontWeight: 400, marginLeft: 8, fontSize: 12 }, children: category.tools.length })
5015
+ /* @__PURE__ */ jsx16("span", { style: { color: "rgba(255,255,255,0.4)", fontWeight: 400, marginLeft: 8, fontSize: 12 }, children: category.tools.length })
4387
5016
  ] }),
4388
- /* @__PURE__ */ jsx15("span", { style: { color: "rgba(255,255,255,0.4)", fontSize: 12 }, children: isCollapsed ? "\u25B6" : "\u25BC" })
5017
+ /* @__PURE__ */ jsx16("span", { style: { color: "rgba(255,255,255,0.4)", fontSize: 12 }, children: isCollapsed ? "\u25B6" : "\u25BC" })
4389
5018
  ]
4390
5019
  }
4391
5020
  ),
4392
- !isCollapsed && /* @__PURE__ */ jsx15("div", { style: { paddingLeft: 8, paddingRight: 8 }, children: category.tools.map((tool, idx) => /* @__PURE__ */ jsxs9(
5021
+ !isCollapsed && /* @__PURE__ */ jsx16("div", { style: { paddingLeft: 8, paddingRight: 8 }, children: category.tools.map((tool, idx) => /* @__PURE__ */ jsxs9(
4393
5022
  "button",
4394
5023
  {
4395
5024
  onClick: () => handleToolClick(tool),
@@ -4412,8 +5041,8 @@ var ToolMenuPopup = ({
4412
5041
  e.currentTarget.style.background = "none";
4413
5042
  },
4414
5043
  children: [
4415
- /* @__PURE__ */ jsx15("div", { style: { fontSize: 13, fontWeight: 500 }, children: tool.name }),
4416
- tool.description && /* @__PURE__ */ jsx15("div", { style: {
5044
+ /* @__PURE__ */ jsx16("div", { style: { fontSize: 13, fontWeight: 500 }, children: tool.name }),
5045
+ tool.description && /* @__PURE__ */ jsx16("div", { style: {
4417
5046
  fontSize: 11,
4418
5047
  color: "rgba(255,255,255,0.5)",
4419
5048
  marginTop: 2,
@@ -4437,14 +5066,14 @@ var ToolMenuPopup = ({
4437
5066
  fontSize: 11
4438
5067
  }, children: [
4439
5068
  "Click a tool to insert its command \xB7 Type ",
4440
- /* @__PURE__ */ jsx15("kbd", { style: {
5069
+ /* @__PURE__ */ jsx16("kbd", { style: {
4441
5070
  padding: "1px 4px",
4442
5071
  borderRadius: 3,
4443
5072
  border: "1px solid rgba(255,255,255,0.2)",
4444
5073
  fontSize: 10
4445
5074
  }, children: "/" }),
4446
5075
  " in chat for quick commands \xB7 ",
4447
- /* @__PURE__ */ jsx15("kbd", { style: {
5076
+ /* @__PURE__ */ jsx16("kbd", { style: {
4448
5077
  padding: "1px 4px",
4449
5078
  borderRadius: 3,
4450
5079
  border: "1px solid rgba(255,255,255,0.2)",
@@ -4458,10 +5087,10 @@ var ToolMenuPopup = ({
4458
5087
  };
4459
5088
 
4460
5089
  // src/components/ToolMenuPopup/ToolMenuPopupTrigger.tsx
4461
- import { useEffect as useEffect13 } from "react";
5090
+ import { useEffect as useEffect14 } from "react";
4462
5091
 
4463
5092
  // src/components/ToolMenuPopup/useToolMenu.ts
4464
- import { useState as useState13, useMemo as useMemo4, useCallback as useCallback8 } from "react";
5093
+ import { useState as useState14, useMemo as useMemo5, useCallback as useCallback9 } from "react";
4465
5094
  import { ToolRegistry as ToolRegistry2 } from "@supernal/interface/browser";
4466
5095
  var CATEGORY_DISPLAY = {
4467
5096
  navigation: "Navigation",
@@ -4482,11 +5111,11 @@ var CATEGORY_DISPLAY = {
4482
5111
  workflow: "Workflow"
4483
5112
  };
4484
5113
  function useToolMenu() {
4485
- const [isOpen, setIsOpen] = useState13(false);
4486
- const open = useCallback8(() => setIsOpen(true), []);
4487
- const close = useCallback8(() => setIsOpen(false), []);
4488
- const toggle = useCallback8(() => setIsOpen((prev) => !prev), []);
4489
- const { categories, totalTools, contextLabel } = useMemo4(() => {
5114
+ const [isOpen, setIsOpen] = useState14(false);
5115
+ const open = useCallback9(() => setIsOpen(true), []);
5116
+ const close = useCallback9(() => setIsOpen(false), []);
5117
+ const toggle = useCallback9(() => setIsOpen((prev) => !prev), []);
5118
+ const { categories, totalTools, contextLabel } = useMemo5(() => {
4490
5119
  if (!isOpen) {
4491
5120
  return { categories: [], totalTools: 0, contextLabel: "" };
4492
5121
  }
@@ -4518,10 +5147,10 @@ function useToolMenu() {
4518
5147
  }
4519
5148
 
4520
5149
  // src/components/ToolMenuPopup/ToolMenuPopupTrigger.tsx
4521
- import { jsx as jsx16 } from "react/jsx-runtime";
5150
+ import { jsx as jsx17 } from "react/jsx-runtime";
4522
5151
  var ToolMenuPopupTrigger = () => {
4523
5152
  const toolMenu = useToolMenu();
4524
- useEffect13(() => {
5153
+ useEffect14(() => {
4525
5154
  const handleKeyDown = (e) => {
4526
5155
  if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key === "/") {
4527
5156
  e.preventDefault();
@@ -4560,7 +5189,7 @@ var ToolMenuPopupTrigger = () => {
4560
5189
  return () => document.removeEventListener("keydown", handleKeyDown);
4561
5190
  }, [toolMenu]);
4562
5191
  if (!toolMenu.isOpen) return null;
4563
- return /* @__PURE__ */ jsx16(
5192
+ return /* @__PURE__ */ jsx17(
4564
5193
  ToolMenuPopup,
4565
5194
  {
4566
5195
  isOpen: toolMenu.isOpen,
@@ -4573,7 +5202,7 @@ var ToolMenuPopupTrigger = () => {
4573
5202
  };
4574
5203
 
4575
5204
  // src/components/SupernalProvider.tsx
4576
- import { jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
5205
+ import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
4577
5206
  function ChatBubbleConnector({
4578
5207
  theme,
4579
5208
  position,
@@ -4590,7 +5219,7 @@ function ChatBubbleConnector({
4590
5219
  glassMode,
4591
5220
  ...logo ? { logo } : {}
4592
5221
  };
4593
- return /* @__PURE__ */ jsx17(
5222
+ return /* @__PURE__ */ jsx18(
4594
5223
  ChatBubble,
4595
5224
  {
4596
5225
  messages,
@@ -4629,7 +5258,7 @@ function SupernalProvider({
4629
5258
  console.log("[SupernalProvider] variant:", variant, "effectiveDisplayMode:", effectiveDisplayMode);
4630
5259
  useLocationTracking();
4631
5260
  useNavigationGraphSetup();
4632
- useEffect14(() => {
5261
+ useEffect15(() => {
4633
5262
  if (typeof window === "undefined") return;
4634
5263
  const collector = ExposureCollector.getInstance();
4635
5264
  const registeredToolIds = /* @__PURE__ */ new Set();
@@ -4661,9 +5290,9 @@ function SupernalProvider({
4661
5290
  collector.destroy();
4662
5291
  };
4663
5292
  }, []);
4664
- return /* @__PURE__ */ jsx17(ChatInputProvider, { children: /* @__PURE__ */ jsxs10(ChatProvider, { mode, apiKey, onToolExecute, children: [
4665
- /* @__PURE__ */ jsx17(AutoNavigationContext, { routes, onNavigate, children }),
4666
- shouldRenderChatBubble ? /* @__PURE__ */ jsx17(
5293
+ return /* @__PURE__ */ jsx18(ApiKeyProvider, { initialApiKey: apiKey, children: /* @__PURE__ */ jsx18(ChatInputProvider, { children: /* @__PURE__ */ jsxs10(ChatProvider, { mode, apiKey, onToolExecute, children: [
5294
+ /* @__PURE__ */ jsx18(AutoNavigationContext, { routes, onNavigate, children }),
5295
+ shouldRenderChatBubble ? /* @__PURE__ */ jsx18(
4667
5296
  ChatBubbleConnector,
4668
5297
  {
4669
5298
  theme,
@@ -4676,26 +5305,26 @@ function SupernalProvider({
4676
5305
  drawerSide
4677
5306
  }
4678
5307
  ) : null,
4679
- !disabled && /* @__PURE__ */ jsx17(ToolMenuPopupTrigger, {})
4680
- ] }) });
5308
+ !disabled && /* @__PURE__ */ jsx18(ToolMenuPopupTrigger, {})
5309
+ ] }) }) });
4681
5310
  }
4682
5311
 
4683
5312
  // src/components/ChatBubbleSettingsModal.tsx
4684
- import React14, { useEffect as useEffect15 } from "react";
4685
- import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
5313
+ import React15, { useEffect as useEffect16 } from "react";
5314
+ import { Fragment as Fragment5, jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
4686
5315
  function ChatBubbleSettingsModal({
4687
5316
  isOpen,
4688
5317
  onClose,
4689
5318
  settings,
4690
5319
  onSettingsChange
4691
5320
  }) {
4692
- const [localSettings, setLocalSettings] = React14.useState(settings);
4693
- useEffect15(() => {
5321
+ const [localSettings, setLocalSettings] = React15.useState(settings);
5322
+ useEffect16(() => {
4694
5323
  if (isOpen) {
4695
5324
  setLocalSettings(settings);
4696
5325
  }
4697
5326
  }, [isOpen, settings]);
4698
- useEffect15(() => {
5327
+ useEffect16(() => {
4699
5328
  const handleEscape = (e) => {
4700
5329
  if (e.key === "Escape" && isOpen) {
4701
5330
  onClose();
@@ -4717,7 +5346,7 @@ function ChatBubbleSettingsModal({
4717
5346
  };
4718
5347
  const isDark = localSettings.theme === "dark";
4719
5348
  return /* @__PURE__ */ jsxs11(Fragment5, { children: [
4720
- /* @__PURE__ */ jsx18(
5349
+ /* @__PURE__ */ jsx19(
4721
5350
  "div",
4722
5351
  {
4723
5352
  className: "fixed inset-0 bg-black bg-opacity-50 z-[60] backdrop-blur-sm",
@@ -4725,7 +5354,7 @@ function ChatBubbleSettingsModal({
4725
5354
  "aria-hidden": "true"
4726
5355
  }
4727
5356
  ),
4728
- /* @__PURE__ */ jsx18(
5357
+ /* @__PURE__ */ jsx19(
4729
5358
  "div",
4730
5359
  {
4731
5360
  className: "fixed inset-0 z-[70] flex items-center justify-center p-4",
@@ -4740,7 +5369,7 @@ function ChatBubbleSettingsModal({
4740
5369
  onClick: (e) => e.stopPropagation(),
4741
5370
  children: [
4742
5371
  /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between mb-6", children: [
4743
- /* @__PURE__ */ jsx18(
5372
+ /* @__PURE__ */ jsx19(
4744
5373
  "h2",
4745
5374
  {
4746
5375
  id: "settings-modal-title",
@@ -4748,56 +5377,56 @@ function ChatBubbleSettingsModal({
4748
5377
  children: "Chat Settings"
4749
5378
  }
4750
5379
  ),
4751
- /* @__PURE__ */ jsx18(
5380
+ /* @__PURE__ */ jsx19(
4752
5381
  "button",
4753
5382
  {
4754
5383
  onClick: handleCancel,
4755
5384
  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`,
4756
5385
  "aria-label": "Close modal",
4757
- children: /* @__PURE__ */ jsx18("svg", { className: "w-6 h-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx18("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
5386
+ children: /* @__PURE__ */ jsx19("svg", { className: "w-6 h-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx19("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
4758
5387
  }
4759
5388
  )
4760
5389
  ] }),
4761
5390
  /* @__PURE__ */ jsxs11("div", { className: "space-y-5 mb-6", children: [
4762
5391
  /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
4763
5392
  /* @__PURE__ */ jsxs11("div", { children: [
4764
- /* @__PURE__ */ jsx18("label", { className: "block text-base font-medium mb-1", children: "Theme" }),
4765
- /* @__PURE__ */ jsx18("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Switch between light and dark modes" })
5393
+ /* @__PURE__ */ jsx19("label", { className: "block text-base font-medium mb-1", children: "Theme" }),
5394
+ /* @__PURE__ */ jsx19("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Switch between light and dark modes" })
4766
5395
  ] }),
4767
5396
  /* @__PURE__ */ jsxs11("div", { className: "flex items-center space-x-2", children: [
4768
- /* @__PURE__ */ jsx18(
5397
+ /* @__PURE__ */ jsx19(
4769
5398
  "button",
4770
5399
  {
4771
5400
  onClick: () => setLocalSettings({ ...localSettings, theme: "light" }),
4772
5401
  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"}`,
4773
5402
  title: "Light mode",
4774
- children: /* @__PURE__ */ jsx18("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx18("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" }) })
5403
+ children: /* @__PURE__ */ jsx19("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx19("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" }) })
4775
5404
  }
4776
5405
  ),
4777
- /* @__PURE__ */ jsx18(
5406
+ /* @__PURE__ */ jsx19(
4778
5407
  "button",
4779
5408
  {
4780
5409
  onClick: () => setLocalSettings({ ...localSettings, theme: "dark" }),
4781
5410
  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"}`,
4782
5411
  title: "Dark mode",
4783
- children: /* @__PURE__ */ jsx18("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx18("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" }) })
5412
+ children: /* @__PURE__ */ jsx19("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx19("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" }) })
4784
5413
  }
4785
5414
  )
4786
5415
  ] })
4787
5416
  ] }),
4788
5417
  /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
4789
5418
  /* @__PURE__ */ jsxs11("div", { children: [
4790
- /* @__PURE__ */ jsx18("label", { className: "block text-base font-medium mb-1", children: "Glass Mode" }),
4791
- /* @__PURE__ */ jsx18("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Enable glassmorphism transparency effect" })
5419
+ /* @__PURE__ */ jsx19("label", { className: "block text-base font-medium mb-1", children: "Glass Mode" }),
5420
+ /* @__PURE__ */ jsx19("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Enable glassmorphism transparency effect" })
4792
5421
  ] }),
4793
- /* @__PURE__ */ jsx18(
5422
+ /* @__PURE__ */ jsx19(
4794
5423
  "button",
4795
5424
  {
4796
5425
  onClick: () => setLocalSettings({ ...localSettings, glassMode: !localSettings.glassMode }),
4797
5426
  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"}`,
4798
5427
  role: "switch",
4799
5428
  "aria-checked": localSettings.glassMode,
4800
- children: /* @__PURE__ */ jsx18(
5429
+ children: /* @__PURE__ */ jsx19(
4801
5430
  "span",
4802
5431
  {
4803
5432
  className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.glassMode ? "translate-x-6" : "translate-x-1"}`
@@ -4808,17 +5437,17 @@ function ChatBubbleSettingsModal({
4808
5437
  ] }),
4809
5438
  /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
4810
5439
  /* @__PURE__ */ jsxs11("div", { children: [
4811
- /* @__PURE__ */ jsx18("label", { className: "block text-base font-medium mb-1", children: "Notifications" }),
4812
- /* @__PURE__ */ jsx18("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Show unread message indicators" })
5440
+ /* @__PURE__ */ jsx19("label", { className: "block text-base font-medium mb-1", children: "Notifications" }),
5441
+ /* @__PURE__ */ jsx19("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Show unread message indicators" })
4813
5442
  ] }),
4814
- /* @__PURE__ */ jsx18(
5443
+ /* @__PURE__ */ jsx19(
4815
5444
  "button",
4816
5445
  {
4817
5446
  onClick: () => setLocalSettings({ ...localSettings, notifications: !localSettings.notifications }),
4818
5447
  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"}`,
4819
5448
  role: "switch",
4820
5449
  "aria-checked": localSettings.notifications,
4821
- children: /* @__PURE__ */ jsx18(
5450
+ children: /* @__PURE__ */ jsx19(
4822
5451
  "span",
4823
5452
  {
4824
5453
  className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.notifications ? "translate-x-6" : "translate-x-1"}`
@@ -4827,16 +5456,16 @@ function ChatBubbleSettingsModal({
4827
5456
  }
4828
5457
  )
4829
5458
  ] }),
4830
- /* @__PURE__ */ jsx18("div", { className: `border-t ${isDark ? "border-gray-700" : "border-gray-200"} my-2` }),
5459
+ /* @__PURE__ */ jsx19("div", { className: `border-t ${isDark ? "border-gray-700" : "border-gray-200"} my-2` }),
4831
5460
  /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
4832
5461
  /* @__PURE__ */ jsxs11("div", { children: [
4833
5462
  /* @__PURE__ */ jsxs11("label", { className: "block text-base font-medium mb-1 flex items-center space-x-2", children: [
4834
- /* @__PURE__ */ jsx18("span", { children: "Subtitle Overlay" }),
4835
- /* @__PURE__ */ jsx18("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" })
5463
+ /* @__PURE__ */ jsx19("span", { children: "Subtitle Overlay" }),
5464
+ /* @__PURE__ */ jsx19("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" })
4836
5465
  ] }),
4837
- /* @__PURE__ */ jsx18("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Minimalist voice-first overlay with @/ icon" })
5466
+ /* @__PURE__ */ jsx19("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Minimalist voice-first overlay with @/ icon" })
4838
5467
  ] }),
4839
- /* @__PURE__ */ jsx18(
5468
+ /* @__PURE__ */ jsx19(
4840
5469
  "button",
4841
5470
  {
4842
5471
  onClick: () => setLocalSettings({
@@ -4848,7 +5477,7 @@ function ChatBubbleSettingsModal({
4848
5477
  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"}`,
4849
5478
  role: "switch",
4850
5479
  "aria-checked": localSettings.subtitleOverlayEnabled,
4851
- children: /* @__PURE__ */ jsx18(
5480
+ children: /* @__PURE__ */ jsx19(
4852
5481
  "span",
4853
5482
  {
4854
5483
  className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.subtitleOverlayEnabled ? "translate-x-6" : "translate-x-1"}`
@@ -4859,8 +5488,8 @@ function ChatBubbleSettingsModal({
4859
5488
  ] }),
4860
5489
  /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
4861
5490
  /* @__PURE__ */ jsxs11("div", { children: [
4862
- /* @__PURE__ */ jsx18("label", { className: "block text-base font-medium mb-1", children: "Display Mode" }),
4863
- /* @__PURE__ */ jsx18("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Auto switches drawer on mobile, panel on desktop" })
5491
+ /* @__PURE__ */ jsx19("label", { className: "block text-base font-medium mb-1", children: "Display Mode" }),
5492
+ /* @__PURE__ */ jsx19("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Auto switches drawer on mobile, panel on desktop" })
4864
5493
  ] }),
4865
5494
  /* @__PURE__ */ jsxs11(
4866
5495
  "select",
@@ -4872,22 +5501,22 @@ function ChatBubbleSettingsModal({
4872
5501
  }),
4873
5502
  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`,
4874
5503
  children: [
4875
- /* @__PURE__ */ jsx18("option", { value: "auto", children: "Auto (Recommended)" }),
4876
- /* @__PURE__ */ jsx18("option", { value: "drawer", children: "Always Drawer" }),
4877
- /* @__PURE__ */ jsx18("option", { value: "full", children: "Always Panel" }),
4878
- /* @__PURE__ */ jsx18("option", { value: "floating", children: "Always Floating" }),
4879
- /* @__PURE__ */ jsx18("option", { value: "subtitle", children: "Subtitle Overlay (Beta)" })
5504
+ /* @__PURE__ */ jsx19("option", { value: "auto", children: "Auto (Recommended)" }),
5505
+ /* @__PURE__ */ jsx19("option", { value: "drawer", children: "Always Drawer" }),
5506
+ /* @__PURE__ */ jsx19("option", { value: "full", children: "Always Panel" }),
5507
+ /* @__PURE__ */ jsx19("option", { value: "floating", children: "Always Floating" }),
5508
+ /* @__PURE__ */ jsx19("option", { value: "subtitle", children: "Subtitle Overlay (Beta)" })
4880
5509
  ]
4881
5510
  }
4882
5511
  )
4883
5512
  ] }),
4884
5513
  (localSettings.displayMode === "auto" || localSettings.displayMode === "drawer") && /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
4885
5514
  /* @__PURE__ */ jsxs11("div", { children: [
4886
- /* @__PURE__ */ jsx18("label", { className: "block text-base font-medium mb-1", children: "Drawer Side" }),
4887
- /* @__PURE__ */ jsx18("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Which edge drawer slides from" })
5515
+ /* @__PURE__ */ jsx19("label", { className: "block text-base font-medium mb-1", children: "Drawer Side" }),
5516
+ /* @__PURE__ */ jsx19("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Which edge drawer slides from" })
4888
5517
  ] }),
4889
5518
  /* @__PURE__ */ jsxs11("div", { className: "flex items-center space-x-2", children: [
4890
- /* @__PURE__ */ jsx18(
5519
+ /* @__PURE__ */ jsx19(
4891
5520
  "button",
4892
5521
  {
4893
5522
  onClick: () => setLocalSettings({ ...localSettings, drawerSide: "left" }),
@@ -4895,7 +5524,7 @@ function ChatBubbleSettingsModal({
4895
5524
  children: "Left"
4896
5525
  }
4897
5526
  ),
4898
- /* @__PURE__ */ jsx18(
5527
+ /* @__PURE__ */ jsx19(
4899
5528
  "button",
4900
5529
  {
4901
5530
  onClick: () => setLocalSettings({ ...localSettings, drawerSide: "right" }),
@@ -4905,24 +5534,24 @@ function ChatBubbleSettingsModal({
4905
5534
  )
4906
5535
  ] })
4907
5536
  ] }),
4908
- /* @__PURE__ */ jsx18("div", { className: `border-t ${isDark ? "border-gray-700" : "border-gray-200"} my-2` }),
5537
+ /* @__PURE__ */ jsx19("div", { className: `border-t ${isDark ? "border-gray-700" : "border-gray-200"} my-2` }),
4909
5538
  /* @__PURE__ */ jsxs11("div", { className: "mb-3", children: [
4910
- /* @__PURE__ */ jsx18("h3", { className: "text-lg font-semibold mb-1", children: "Voice Control" }),
4911
- /* @__PURE__ */ jsx18("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Enable voice input and audio feedback" })
5539
+ /* @__PURE__ */ jsx19("h3", { className: "text-lg font-semibold mb-1", children: "Voice Control" }),
5540
+ /* @__PURE__ */ jsx19("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Enable voice input and audio feedback" })
4912
5541
  ] }),
4913
5542
  /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
4914
5543
  /* @__PURE__ */ jsxs11("div", { children: [
4915
- /* @__PURE__ */ jsx18("label", { className: "block text-base font-medium mb-1", children: "Voice Control" }),
4916
- /* @__PURE__ */ jsx18("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Enable voice input and TTS responses" })
5544
+ /* @__PURE__ */ jsx19("label", { className: "block text-base font-medium mb-1", children: "Voice Control" }),
5545
+ /* @__PURE__ */ jsx19("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Enable voice input and TTS responses" })
4917
5546
  ] }),
4918
- /* @__PURE__ */ jsx18(
5547
+ /* @__PURE__ */ jsx19(
4919
5548
  "button",
4920
5549
  {
4921
5550
  onClick: () => setLocalSettings({ ...localSettings, voiceEnabled: !localSettings.voiceEnabled }),
4922
5551
  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"}`,
4923
5552
  role: "switch",
4924
5553
  "aria-checked": localSettings.voiceEnabled,
4925
- children: /* @__PURE__ */ jsx18(
5554
+ children: /* @__PURE__ */ jsx19(
4926
5555
  "span",
4927
5556
  {
4928
5557
  className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.voiceEnabled ? "translate-x-6" : "translate-x-1"}`
@@ -4934,17 +5563,17 @@ function ChatBubbleSettingsModal({
4934
5563
  localSettings.voiceEnabled && /* @__PURE__ */ jsxs11(Fragment5, { children: [
4935
5564
  /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between pl-4 border-l-2 border-blue-500/30", children: [
4936
5565
  /* @__PURE__ */ jsxs11("div", { children: [
4937
- /* @__PURE__ */ jsx18("label", { className: "block text-sm font-medium mb-1", children: "Auto-read AI Responses" }),
4938
- /* @__PURE__ */ jsx18("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Automatically read AI messages aloud" })
5566
+ /* @__PURE__ */ jsx19("label", { className: "block text-sm font-medium mb-1", children: "Auto-read AI Responses" }),
5567
+ /* @__PURE__ */ jsx19("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Automatically read AI messages aloud" })
4939
5568
  ] }),
4940
- /* @__PURE__ */ jsx18(
5569
+ /* @__PURE__ */ jsx19(
4941
5570
  "button",
4942
5571
  {
4943
5572
  onClick: () => setLocalSettings({ ...localSettings, autoReadResponses: !localSettings.autoReadResponses }),
4944
5573
  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"}`,
4945
5574
  role: "switch",
4946
5575
  "aria-checked": localSettings.autoReadResponses,
4947
- children: /* @__PURE__ */ jsx18(
5576
+ children: /* @__PURE__ */ jsx19(
4948
5577
  "span",
4949
5578
  {
4950
5579
  className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.autoReadResponses ? "translate-x-6" : "translate-x-1"}`
@@ -4955,17 +5584,17 @@ function ChatBubbleSettingsModal({
4955
5584
  ] }),
4956
5585
  /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between pl-4 border-l-2 border-blue-500/30", children: [
4957
5586
  /* @__PURE__ */ jsxs11("div", { children: [
4958
- /* @__PURE__ */ jsx18("label", { className: "block text-sm font-medium mb-1", children: "Premium Voices \u{1F48E}" }),
4959
- /* @__PURE__ */ jsx18("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Use high-quality OpenAI voices (requires network)" })
5587
+ /* @__PURE__ */ jsx19("label", { className: "block text-sm font-medium mb-1", children: "Premium Voices \u{1F48E}" }),
5588
+ /* @__PURE__ */ jsx19("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Use high-quality OpenAI voices (requires network)" })
4960
5589
  ] }),
4961
- /* @__PURE__ */ jsx18(
5590
+ /* @__PURE__ */ jsx19(
4962
5591
  "button",
4963
5592
  {
4964
5593
  onClick: () => setLocalSettings({ ...localSettings, usePremiumVoices: !localSettings.usePremiumVoices }),
4965
5594
  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"}`,
4966
5595
  role: "switch",
4967
5596
  "aria-checked": localSettings.usePremiumVoices,
4968
- children: /* @__PURE__ */ jsx18(
5597
+ children: /* @__PURE__ */ jsx19(
4969
5598
  "span",
4970
5599
  {
4971
5600
  className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.usePremiumVoices ? "translate-x-6" : "translate-x-1"}`
@@ -4980,7 +5609,7 @@ function ChatBubbleSettingsModal({
4980
5609
  localSettings.ttsSpeed.toFixed(1),
4981
5610
  "x"
4982
5611
  ] }),
4983
- /* @__PURE__ */ jsx18(
5612
+ /* @__PURE__ */ jsx19(
4984
5613
  "input",
4985
5614
  {
4986
5615
  type: "range",
@@ -4993,29 +5622,29 @@ function ChatBubbleSettingsModal({
4993
5622
  }
4994
5623
  ),
4995
5624
  /* @__PURE__ */ jsxs11("div", { className: "flex justify-between text-xs text-gray-400 mt-1", children: [
4996
- /* @__PURE__ */ jsx18("span", { children: "0.5x (Slow)" }),
4997
- /* @__PURE__ */ jsx18("span", { children: "1.0x (Normal)" }),
4998
- /* @__PURE__ */ jsx18("span", { children: "2.0x (Fast)" })
5625
+ /* @__PURE__ */ jsx19("span", { children: "0.5x (Slow)" }),
5626
+ /* @__PURE__ */ jsx19("span", { children: "1.0x (Normal)" }),
5627
+ /* @__PURE__ */ jsx19("span", { children: "2.0x (Fast)" })
4999
5628
  ] })
5000
5629
  ] }),
5001
- /* @__PURE__ */ jsx18("div", { className: `border-t ${isDark ? "border-gray-700" : "border-gray-200"} my-2` }),
5630
+ /* @__PURE__ */ jsx19("div", { className: `border-t ${isDark ? "border-gray-700" : "border-gray-200"} my-2` }),
5002
5631
  /* @__PURE__ */ jsxs11("div", { className: "mb-3", children: [
5003
- /* @__PURE__ */ jsx18("h4", { className: "text-sm font-semibold mb-1", children: "Voice Quick Record (Ctrl+/)" }),
5004
- /* @__PURE__ */ jsx18("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" })
5632
+ /* @__PURE__ */ jsx19("h4", { className: "text-sm font-semibold mb-1", children: "Voice Quick Record (Ctrl+/)" }),
5633
+ /* @__PURE__ */ jsx19("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" })
5005
5634
  ] }),
5006
5635
  /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between pl-4 border-l-2 border-purple-500/30", children: [
5007
5636
  /* @__PURE__ */ jsxs11("div", { children: [
5008
- /* @__PURE__ */ jsx18("label", { className: "block text-sm font-medium mb-1", children: "Auto-Execute Commands" }),
5009
- /* @__PURE__ */ jsx18("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Automatically run recognized voice commands" })
5637
+ /* @__PURE__ */ jsx19("label", { className: "block text-sm font-medium mb-1", children: "Auto-Execute Commands" }),
5638
+ /* @__PURE__ */ jsx19("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Automatically run recognized voice commands" })
5010
5639
  ] }),
5011
- /* @__PURE__ */ jsx18(
5640
+ /* @__PURE__ */ jsx19(
5012
5641
  "button",
5013
5642
  {
5014
5643
  onClick: () => setLocalSettings({ ...localSettings, sttAutoExecute: !localSettings.sttAutoExecute }),
5015
5644
  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"}`,
5016
5645
  role: "switch",
5017
5646
  "aria-checked": localSettings.sttAutoExecute,
5018
- children: /* @__PURE__ */ jsx18(
5647
+ children: /* @__PURE__ */ jsx19(
5019
5648
  "span",
5020
5649
  {
5021
5650
  className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.sttAutoExecute ? "translate-x-6" : "translate-x-1"}`
@@ -5030,7 +5659,7 @@ function ChatBubbleSettingsModal({
5030
5659
  (localSettings.sttAutoRecordTimeout / 1e3).toFixed(1),
5031
5660
  "s"
5032
5661
  ] }),
5033
- /* @__PURE__ */ jsx18(
5662
+ /* @__PURE__ */ jsx19(
5034
5663
  "input",
5035
5664
  {
5036
5665
  type: "range",
@@ -5043,21 +5672,21 @@ function ChatBubbleSettingsModal({
5043
5672
  }
5044
5673
  ),
5045
5674
  /* @__PURE__ */ jsxs11("div", { className: "flex justify-between text-xs text-gray-400 mt-1", children: [
5046
- /* @__PURE__ */ jsx18("span", { children: "2s" }),
5047
- /* @__PURE__ */ jsx18("span", { children: "8s" }),
5048
- /* @__PURE__ */ jsx18("span", { children: "15s" })
5675
+ /* @__PURE__ */ jsx19("span", { children: "2s" }),
5676
+ /* @__PURE__ */ jsx19("span", { children: "8s" }),
5677
+ /* @__PURE__ */ jsx19("span", { children: "15s" })
5049
5678
  ] })
5050
5679
  ] }),
5051
5680
  /* @__PURE__ */ jsxs11("div", { className: `p-3 rounded-lg ${isDark ? "bg-purple-900/20 border border-purple-500/30" : "bg-purple-50 border border-purple-200"}`, children: [
5052
- /* @__PURE__ */ jsx18("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!)" }),
5053
- /* @__PURE__ */ jsx18("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)" })
5681
+ /* @__PURE__ */ jsx19("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!)" }),
5682
+ /* @__PURE__ */ jsx19("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)" })
5054
5683
  ] }),
5055
- !localSettings.usePremiumVoices && /* @__PURE__ */ jsx18("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__ */ jsx18("p", { className: `text-xs ${isDark ? "text-green-300" : "text-green-800"}`, children: "\u{1F49A} Using free device voices (works offline, zero cost)" }) }),
5056
- localSettings.usePremiumVoices && /* @__PURE__ */ jsx18("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__ */ jsx18("p", { className: `text-xs ${isDark ? "text-purple-300" : "text-purple-800"}`, children: "\u{1F48E} Using premium OpenAI voices (requires internet connection)" }) })
5684
+ !localSettings.usePremiumVoices && /* @__PURE__ */ jsx19("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__ */ jsx19("p", { className: `text-xs ${isDark ? "text-green-300" : "text-green-800"}`, children: "\u{1F49A} Using free device voices (works offline, zero cost)" }) }),
5685
+ localSettings.usePremiumVoices && /* @__PURE__ */ jsx19("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__ */ jsx19("p", { className: `text-xs ${isDark ? "text-purple-300" : "text-purple-800"}`, children: "\u{1F48E} Using premium OpenAI voices (requires internet connection)" }) })
5057
5686
  ] })
5058
5687
  ] }),
5059
5688
  /* @__PURE__ */ jsxs11("div", { className: "flex justify-end space-x-3 pt-4 border-t border-gray-200 dark:border-gray-700", children: [
5060
- /* @__PURE__ */ jsx18(
5689
+ /* @__PURE__ */ jsx19(
5061
5690
  "button",
5062
5691
  {
5063
5692
  onClick: handleCancel,
@@ -5065,7 +5694,7 @@ function ChatBubbleSettingsModal({
5065
5694
  children: "Cancel"
5066
5695
  }
5067
5696
  ),
5068
- /* @__PURE__ */ jsx18(
5697
+ /* @__PURE__ */ jsx19(
5069
5698
  "button",
5070
5699
  {
5071
5700
  onClick: handleSave,
@@ -5201,12 +5830,14 @@ function findBestMatch(query, tools) {
5201
5830
  };
5202
5831
  }
5203
5832
  export {
5833
+ ApiKeyProvider,
5204
5834
  AutoNavigationContext,
5205
5835
  ChatBubble,
5206
5836
  ChatBubbleSettingsModal,
5207
5837
  ChatBubbleVariant,
5208
5838
  ChatInputProvider,
5209
5839
  ChatProvider,
5840
+ ClaudeClient,
5210
5841
  CodeBlock,
5211
5842
  Components,
5212
5843
  DemoAIInterface,
@@ -5220,9 +5851,13 @@ export {
5220
5851
  ToolManager,
5221
5852
  ToolMenuPopup,
5222
5853
  ToolMenuPopupTrigger,
5854
+ createClaudeClient,
5223
5855
  findBestMatch,
5224
5856
  scoreToolMatch,
5225
5857
  useAllContexts,
5858
+ useApiKey,
5859
+ useApiKeyOptional,
5860
+ useApiKeyStorage,
5226
5861
  useChatContext,
5227
5862
  useChatInput,
5228
5863
  useCurrentContext,