@iblai/iblai-js 1.20.5 → 1.20.7

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.
@@ -363,9 +363,11 @@ const TAURI_EVENTS = {
363
363
  */
364
364
  const TAURI_COMMANDS = {
365
365
  INSTALL_OLLAMA: 'install_ollama',
366
+ STOP_OLLAMA: 'stop_ollama',
366
367
  CHECK_OLLAMA_STATUS: 'check_ollama_status',
367
368
  CHECK_DISK_SPACE: 'check_disk_space_for_model',
368
- DOWNLOAD_MODEL: 'download_phi3_model',
369
+ GET_SYSTEM_MEMORY: 'get_system_memory',
370
+ DOWNLOAD_MODEL: 'download_model',
369
371
  CANCEL_DOWNLOAD: 'cancel_model_download',
370
372
  CHECK_NETWORK_STATUS: 'check_network_status',
371
373
  GET_OS_TYPE: 'get_os_type',
@@ -377,6 +379,67 @@ const TAURI_COMMANDS = {
377
379
  INSTALL_FOUNDRY: 'install_foundry',
378
380
  DOWNLOAD_FOUNDRY_MODEL: 'download_foundry_model_cmd',
379
381
  GET_RECOMMENDED_FOUNDRY_MODELS: 'get_recommended_foundry_models',
382
+ LOG_STDOUT: 'log_stdout',
383
+ };
384
+ // ============================================================================
385
+ // System Control (GhostOS)
386
+ // ----------------------------------------------------------------------------
387
+ // Contract for the "System Control" manager, which installs and sets up GhostOS
388
+ // (https://github.com/ghostwright/ghost-os) on-device via the Tauri host. This
389
+ // mirrors the Local Models (Ollama) contract above: the web layer ships the
390
+ // presentational card + types, while the Tauri host (e.g. the ghost-os desktop
391
+ // app) implements the native install/setup/status commands.
392
+ // ============================================================================
393
+ /** GitHub repository the System Control manager installs and sets up. */
394
+ const GHOST_OS_REPO_URL = 'https://github.com/ghostwright/ghost-os';
395
+ /**
396
+ * Initial state for the System Control install flow.
397
+ */
398
+ const initialGhostOsInstallState = {
399
+ status: 'idle',
400
+ progress: 0,
401
+ message: '',
402
+ logs: [],
403
+ lastUpdated: new Date().toISOString(),
404
+ };
405
+ /**
406
+ * Tauri event names emitted by the host during GhostOS install/setup.
407
+ */
408
+ const GHOST_OS_TAURI_EVENTS = {
409
+ INSTALL_PROGRESS: 'ghost-os:install-progress',
410
+ INSTALLATION_LOG: 'ghost-os:installation-log',
411
+ STATUS: 'ghost-os:status',
412
+ };
413
+ /**
414
+ * Tauri command names the host implements for GhostOS install/setup. The web
415
+ * layer invokes these; the native side performs the clone + setup.
416
+ */
417
+ const GHOST_OS_TAURI_COMMANDS = {
418
+ /** Install and set up GhostOS (clone repo + run setup). */
419
+ INSTALL_GHOST_OS: 'install_ghost_os',
420
+ /** Stop the running GhostOS manager. */
421
+ STOP_GHOST_OS: 'stop_ghost_os',
422
+ /** Report current {@link GhostOsStatus}. */
423
+ CHECK_GHOST_OS_STATUS: 'check_ghost_os_status',
424
+ };
425
+ /**
426
+ * Tauri command strings exposed by `tauri-plugin-macos-permissions`
427
+ * (https://github.com/ayangweb/tauri-plugin-macos-permissions). GhostOS needs
428
+ * macOS Accessibility permission to control the device, so the System Control
429
+ * card surfaces it. These are invoked directly via `useTauri().invoke(...)` —
430
+ * no extra npm dependency. The host must register the plugin in its Tauri app
431
+ * (`tauri_plugin_macos_permissions::init()`). Each `CHECK_*` returns a boolean;
432
+ * each `REQUEST_*` prompts / opens the relevant System Settings pane.
433
+ */
434
+ const MACOS_PERMISSIONS_COMMANDS = {
435
+ CHECK_ACCESSIBILITY: 'plugin:macos-permissions|check_accessibility_permission',
436
+ REQUEST_ACCESSIBILITY: 'plugin:macos-permissions|request_accessibility_permission',
437
+ CHECK_SCREEN_RECORDING: 'plugin:macos-permissions|check_screen_recording_permission',
438
+ REQUEST_SCREEN_RECORDING: 'plugin:macos-permissions|request_screen_recording_permission',
439
+ CHECK_INPUT_MONITORING: 'plugin:macos-permissions|check_input_monitoring_permission',
440
+ REQUEST_INPUT_MONITORING: 'plugin:macos-permissions|request_input_monitoring_permission',
441
+ CHECK_FULL_DISK_ACCESS: 'plugin:macos-permissions|check_full_disk_access_permission',
442
+ REQUEST_FULL_DISK_ACCESS: 'plugin:macos-permissions|request_full_disk_access_permission',
380
443
  };
381
444
 
382
445
  /**
@@ -425,10 +488,17 @@ function useTauri() {
425
488
  * Returns an unlisten function that should be called on cleanup
426
489
  */
427
490
  const listen = useCallback(async (event, handler) => {
428
- if (!(apis === null || apis === void 0 ? void 0 : apis.listen)) {
429
- throw new Error('Tauri is not available');
430
- }
431
- return apis.listen(event, (e) => handler(e.payload));
491
+ // The synchronous global (`__TAURI_INTERNALS__`) exposes `invoke` but
492
+ // frequently NOT `event.listen`, so `apis.listen` can be undefined even
493
+ // though Tauri is fully available. Fall back to the real event API via
494
+ // dynamic import so download progress/completion events are actually
495
+ // delivered — otherwise the UI never leaves the "downloading" state.
496
+ let listenFn = apis === null || apis === void 0 ? void 0 : apis.listen;
497
+ if (!listenFn) {
498
+ const { listen: importedListen } = await import('@tauri-apps/api/event');
499
+ listenFn = importedListen;
500
+ }
501
+ return listenFn(event, (e) => handler(e.payload));
432
502
  }, [apis]);
433
503
  return {
434
504
  isAvailable,
@@ -499,8 +569,15 @@ function useLocalStorage(key, initialValue) {
499
569
  return [storedValue, setValue, removeValue];
500
570
  }
501
571
 
502
- const LOCAL_STORAGE_KEY = 'model_download_state';
572
+ const LOCAL_STORAGE_KEY$1 = 'model_download_state';
503
573
  const FIRST_LAUNCH_DISMISSED_KEY = 'model_download_prompt_dismissed';
574
+ // Manager/download status is authoritative from Tauri, never the persisted
575
+ // snapshot. This flips true the first time any hook instance mounts in a page
576
+ // session so we wipe the persisted state exactly once — clearing a stale
577
+ // `managerInstalling`/`downloading`/`checking` flag (e.g. left behind by an
578
+ // operation interrupted by an app reload) that would otherwise wedge the UI in
579
+ // a permanent "loading" state — then fall back to a fresh backend status check.
580
+ let didResetPersistedState = false;
504
581
  /**
505
582
  * Hook to manage Phi3 Mini model download via Model Manager through Tauri
506
583
  *
@@ -512,11 +589,15 @@ const FIRST_LAUNCH_DISMISSED_KEY = 'model_download_prompt_dismissed';
512
589
  */
513
590
  function useModelDownload() {
514
591
  const { isAvailable, invoke, listen } = useTauri();
515
- const [state, setState] = useLocalStorage(LOCAL_STORAGE_KEY, initialModelDownloadState);
592
+ const [state, setState] = useLocalStorage(LOCAL_STORAGE_KEY$1, initialModelDownloadState);
516
593
  const [ollamaStatus, setOllamaStatus] = useState(null);
594
+ const [systemMemory, setSystemMemory] = useState(null);
517
595
  const [isFirstLaunchDismissed, setIsFirstLaunchDismissed] = useLocalStorage(FIRST_LAUNCH_DISMISSED_KEY, false);
518
596
  const unlistenRefs = useRef([]);
519
597
  const hasCheckedStatus = useRef(false);
598
+ // Stable handle to the latest checkStatus so the mount-time event listeners
599
+ // can refresh status (e.g. after a download completes) without re-subscribing.
600
+ const checkStatusRef = useRef(() => { });
520
601
  console.log('[ModelDownload] Hook initialized:', {
521
602
  isAvailable,
522
603
  stateStatus: state.status,
@@ -576,7 +657,12 @@ function useModelDownload() {
576
657
  });
577
658
  if (payload.status === 'completed') {
578
659
  console.log('[ModelDownload] Download completed successfully!');
579
- toast.success('Phi Mini 3 model downloaded successfully!');
660
+ // Refresh Ollama status so the freshly pulled model shows up in
661
+ // `installed_models` — keeps the row marked "Ready" and selectable
662
+ // even after the modal is closed and reopened. The success toast is
663
+ // shown by startDownload (once per initiated download) to avoid a
664
+ // duplicate from each mounted useModelDownload instance.
665
+ checkStatusRef.current();
580
666
  }
581
667
  });
582
668
  unlistenRefs.current.push(unlistenProgress);
@@ -628,9 +714,36 @@ function useModelDownload() {
628
714
  if (isAvailable && !hasCheckedStatus.current) {
629
715
  console.log('[ModelDownload] First mount, checking status...');
630
716
  hasCheckedStatus.current = true;
717
+ // Wipe any stale persisted manager/download state once per page load, so a
718
+ // leftover `managerInstalling`/`downloading` flag can't keep the toggle or
719
+ // status card stuck "loading". Tauri is the source of truth from here on.
720
+ if (!didResetPersistedState) {
721
+ didResetPersistedState = true;
722
+ setState(initialModelDownloadState);
723
+ }
631
724
  checkStatus();
632
725
  }
633
726
  }, [isAvailable]);
727
+ /**
728
+ * Read system memory (RAM/VRAM) once the desktop bridge is available, so the
729
+ * UI can warn before downloading a model that's large relative to capacity.
730
+ */
731
+ useEffect(() => {
732
+ if (!isAvailable)
733
+ return;
734
+ let cancelled = false;
735
+ invoke(TAURI_COMMANDS.GET_SYSTEM_MEMORY)
736
+ .then((mem) => {
737
+ if (!cancelled)
738
+ setSystemMemory(mem);
739
+ })
740
+ .catch((error) => {
741
+ console.error('[ModelDownload] Failed to read system memory:', error);
742
+ });
743
+ return () => {
744
+ cancelled = true;
745
+ };
746
+ }, [isAvailable, invoke]);
634
747
  /**
635
748
  * Check Model Manager installation and model status
636
749
  */
@@ -670,11 +783,16 @@ function useModelDownload() {
670
783
  }));
671
784
  }
672
785
  }, [isAvailable, invoke, setState]);
786
+ // Keep the ref pointed at the latest checkStatus for use inside the once-on-mount
787
+ // event listeners (which must not depend on checkStatus to avoid re-subscribing).
788
+ useEffect(() => {
789
+ checkStatusRef.current = checkStatus;
790
+ }, [checkStatus]);
673
791
  /**
674
792
  * Start downloading the Phi3 Mini model
675
793
  */
676
- const startDownload = useCallback(async () => {
677
- console.log('[ModelDownload] startDownload called, isAvailable:', isAvailable);
794
+ const startDownload = useCallback(async (modelId) => {
795
+ console.log('[ModelDownload] startDownload called, isAvailable:', isAvailable, 'model:', modelId);
678
796
  if (!isAvailable) {
679
797
  console.log('[ModelDownload] Desktop app not available');
680
798
  toast.error('Desktop app required for local model download');
@@ -689,6 +807,9 @@ function useModelDownload() {
689
807
  message: 'Starting download...',
690
808
  error: undefined,
691
809
  logs: [],
810
+ // Record which model is downloading so the right row shows progress even
811
+ // if the dialog is closed and reopened mid-download (state is persisted).
812
+ activeModel: modelId !== null && modelId !== void 0 ? modelId : 'phi3:mini',
692
813
  }));
693
814
  // Check disk space first
694
815
  console.log('[ModelDownload] Checking disk space...');
@@ -698,20 +819,43 @@ function useModelDownload() {
698
819
  console.log('[ModelDownload] Insufficient disk space');
699
820
  return; // Error will be emitted via event
700
821
  }
701
- // Start the download
702
- console.log('[ModelDownload] Starting model download...');
703
- await invoke(TAURI_COMMANDS.DOWNLOAD_MODEL);
822
+ // Start the download. The selected model identifier is forwarded so the
823
+ // backend can pull it; the current backend defaults to Phi-3 Mini.
824
+ // `invoke` resolves only once the Rust pull has fully finished, so treat a
825
+ // successful resolution as completion. This guarantees the UI leaves the
826
+ // "downloading" state even if the terminal progress event was missed (live
827
+ // progress still streams from the progress events while the pull runs).
828
+ console.log('[ModelDownload] Starting model download...', modelId);
829
+ await invoke(TAURI_COMMANDS.DOWNLOAD_MODEL, modelId ? { model: modelId } : undefined);
704
830
  console.log('[ModelDownload] Download command invoked');
831
+ let didComplete = false;
832
+ setState((prev) => {
833
+ // Don't clobber a cancellation/error that landed while awaiting.
834
+ if (prev.status !== 'downloading')
835
+ return prev;
836
+ didComplete = true;
837
+ return { ...prev, status: 'completed', progress: 100, message: 'Download complete' };
838
+ });
839
+ if (didComplete) {
840
+ toast.success('Model downloaded successfully!');
841
+ }
842
+ // Refresh installed models so the row flips to "Ready" and is selectable.
843
+ checkStatusRef.current();
705
844
  }
706
845
  catch (error) {
707
846
  const errorMessage = error instanceof Error ? error.message : String(error);
708
847
  console.error('[ModelDownload] Download failed:', errorMessage);
709
- setState((prev) => ({
710
- ...prev,
711
- status: 'error',
712
- error: errorMessage,
713
- }));
714
- toast.error(`Download failed: ${errorMessage}`);
848
+ let wasCancelled = false;
849
+ setState((prev) => {
850
+ if (prev.status === 'cancelled') {
851
+ wasCancelled = true;
852
+ return prev;
853
+ }
854
+ return { ...prev, status: 'error', error: errorMessage };
855
+ });
856
+ if (!wasCancelled) {
857
+ toast.error(`Download failed: ${errorMessage}`);
858
+ }
715
859
  }
716
860
  }, [isAvailable, invoke, setState]);
717
861
  /**
@@ -720,14 +864,17 @@ function useModelDownload() {
720
864
  const cancelDownload = useCallback(async () => {
721
865
  if (!isAvailable)
722
866
  return;
867
+ // Mark cancelled up front so the in-flight download promise (which resolves
868
+ // cleanly once the backend aborts the pull) can't race ahead and mark the
869
+ // row "completed".
870
+ setState((prev) => ({
871
+ ...prev,
872
+ status: 'cancelled',
873
+ progress: 0,
874
+ message: 'Download cancelled',
875
+ }));
723
876
  try {
724
877
  await invoke(TAURI_COMMANDS.CANCEL_DOWNLOAD);
725
- setState((prev) => ({
726
- ...prev,
727
- status: 'cancelled',
728
- progress: 0,
729
- message: 'Download cancelled',
730
- }));
731
878
  toast.info('Download cancelled');
732
879
  }
733
880
  catch (error) {
@@ -801,6 +948,26 @@ function useModelDownload() {
801
948
  });
802
949
  }
803
950
  }, [isAvailable, invoke, addLog, checkStatus, setState]);
951
+ /**
952
+ * Stop the model manager (Ollama). Backs turning "Enable Local Models" off.
953
+ */
954
+ const stopManager = useCallback(async () => {
955
+ if (!isAvailable)
956
+ return;
957
+ try {
958
+ addLog({
959
+ timestamp: new Date().toISOString(),
960
+ level: 'info',
961
+ message: 'Stopping model manager...',
962
+ });
963
+ await invoke(TAURI_COMMANDS.STOP_OLLAMA);
964
+ await checkStatus();
965
+ }
966
+ catch (error) {
967
+ const errorMessage = error instanceof Error ? error.message : String(error);
968
+ console.error('[ModelDownload] Failed to stop model manager:', errorMessage);
969
+ }
970
+ }, [isAvailable, invoke, addLog, checkStatus]);
804
971
  /**
805
972
  * Clear all logs
806
973
  */
@@ -836,18 +1003,238 @@ function useModelDownload() {
836
1003
  isAvailable: finalIsAvailable,
837
1004
  state,
838
1005
  ollamaStatus,
1006
+ systemMemory,
839
1007
  shouldShowFirstLaunchPrompt,
840
1008
  // Actions
841
1009
  checkStatus,
842
1010
  startDownload,
843
1011
  cancelDownload,
844
1012
  installOllama,
1013
+ stopManager,
845
1014
  clearLogs,
846
1015
  resetState,
847
1016
  dismissFirstLaunchPrompt,
848
1017
  };
849
1018
  }
850
1019
 
1020
+ const LOCAL_STORAGE_KEY = 'ghost_os_install_state';
1021
+ /**
1022
+ * Manage installing & setting up GhostOS (https://github.com/ghostwright/ghost-os)
1023
+ * via the Tauri host. This is the self-contained backing hook for the System
1024
+ * Control card and deliberately mirrors `useModelDownload`:
1025
+ *
1026
+ * - checks GhostOS install/run status through the host
1027
+ * - installs/sets up GhostOS with real-time progress + logs
1028
+ * - persists state across app restarts
1029
+ *
1030
+ * Outside the desktop (Tauri) app every action is a no-op and `isAvailable` is
1031
+ * false, so the card hides itself.
1032
+ */
1033
+ function useGhostOs() {
1034
+ const { isAvailable, invoke, listen } = useTauri();
1035
+ const [state, setState] = useLocalStorage(LOCAL_STORAGE_KEY, initialGhostOsInstallState);
1036
+ const [status, setStatus] = useState(null);
1037
+ // macOS Accessibility permission, which GhostOS needs to control the device.
1038
+ // null = unknown/not-yet-checked or unsupported (non-macOS / plugin absent).
1039
+ const [accessibilityPermission, setAccessibilityPermission] = useState(null);
1040
+ const unlistenRefs = useRef([]);
1041
+ const hasCheckedStatus = useRef(false);
1042
+ /**
1043
+ * Refresh the macOS Accessibility permission via tauri-plugin-macos-permissions.
1044
+ * Independent of the GhostOS status check so a missing host command for one
1045
+ * doesn't suppress the other. Stays null where unsupported.
1046
+ */
1047
+ const refreshAccessibilityPermission = useCallback(async () => {
1048
+ if (!isAvailable)
1049
+ return;
1050
+ try {
1051
+ const granted = await invoke(MACOS_PERMISSIONS_COMMANDS.CHECK_ACCESSIBILITY);
1052
+ setAccessibilityPermission(granted);
1053
+ }
1054
+ catch (error) {
1055
+ // Plugin not registered or non-macOS host — leave permission unknown.
1056
+ console.warn('[useGhostOs] Accessibility permission check unavailable:', error);
1057
+ setAccessibilityPermission(null);
1058
+ }
1059
+ }, [isAvailable, invoke]);
1060
+ /**
1061
+ * Open the Accessibility pane / prompt so the user can grant permission, then
1062
+ * re-check (the grant happens in System Settings, so we refresh after).
1063
+ */
1064
+ const requestAccessibilityPermission = useCallback(async () => {
1065
+ if (!isAvailable)
1066
+ return;
1067
+ try {
1068
+ await invoke(MACOS_PERMISSIONS_COMMANDS.REQUEST_ACCESSIBILITY);
1069
+ }
1070
+ catch (error) {
1071
+ console.error('[useGhostOs] Failed to request accessibility permission:', error);
1072
+ }
1073
+ await refreshAccessibilityPermission();
1074
+ }, [isAvailable, invoke, refreshAccessibilityPermission]);
1075
+ const addLog = useCallback((log) => {
1076
+ setState((prev) => ({
1077
+ ...prev,
1078
+ logs: [...prev.logs.slice(-99), log],
1079
+ lastUpdated: new Date().toISOString(),
1080
+ }));
1081
+ }, [setState]);
1082
+ /**
1083
+ * Query GhostOS status from the host.
1084
+ */
1085
+ const checkStatus = useCallback(async () => {
1086
+ if (!isAvailable)
1087
+ return;
1088
+ // Refresh the accessibility permission alongside install status (independent).
1089
+ refreshAccessibilityPermission();
1090
+ try {
1091
+ setState((prev) => ({ ...prev, status: 'checking' }));
1092
+ const result = await invoke(GHOST_OS_TAURI_COMMANDS.CHECK_GHOST_OS_STATUS);
1093
+ setStatus(result);
1094
+ setState((prev) => ({
1095
+ ...prev,
1096
+ status: result.installed ? 'completed' : 'idle',
1097
+ progress: result.installed ? 100 : prev.progress,
1098
+ lastUpdated: new Date().toISOString(),
1099
+ }));
1100
+ }
1101
+ catch (error) {
1102
+ console.error('[useGhostOs] Failed to check status:', error);
1103
+ setState((prev) => ({ ...prev, status: 'idle' }));
1104
+ }
1105
+ }, [isAvailable, invoke, setState, refreshAccessibilityPermission]);
1106
+ /**
1107
+ * Install and set up GhostOS. The host clones the repo + runs setup and emits
1108
+ * progress/log/status events along the way.
1109
+ */
1110
+ const install = useCallback(async () => {
1111
+ if (!isAvailable)
1112
+ return;
1113
+ try {
1114
+ setState((prev) => ({
1115
+ ...prev,
1116
+ status: 'installing',
1117
+ progress: 0,
1118
+ message: 'Setting up your assistant…',
1119
+ error: undefined,
1120
+ logs: [],
1121
+ }));
1122
+ addLog({
1123
+ timestamp: new Date().toISOString(),
1124
+ level: 'info',
1125
+ message: 'Starting setup…',
1126
+ });
1127
+ const result = await invoke(GHOST_OS_TAURI_COMMANDS.INSTALL_GHOST_OS);
1128
+ addLog({
1129
+ timestamp: new Date().toISOString(),
1130
+ level: 'info',
1131
+ message: typeof result === 'string' && result ? result : 'Setup complete',
1132
+ });
1133
+ setState((prev) => ({
1134
+ ...prev,
1135
+ status: 'completed',
1136
+ progress: 100,
1137
+ message: 'Your assistant is ready',
1138
+ lastUpdated: new Date().toISOString(),
1139
+ }));
1140
+ await checkStatus();
1141
+ }
1142
+ catch (error) {
1143
+ const message = error instanceof Error ? error.message : String(error);
1144
+ setState((prev) => ({
1145
+ ...prev,
1146
+ status: 'error',
1147
+ error: message,
1148
+ message: 'Setup didn’t finish',
1149
+ lastUpdated: new Date().toISOString(),
1150
+ }));
1151
+ addLog({
1152
+ timestamp: new Date().toISOString(),
1153
+ level: 'error',
1154
+ message: `Install failed: ${message}`,
1155
+ });
1156
+ }
1157
+ }, [isAvailable, invoke, addLog, checkStatus, setState]);
1158
+ /**
1159
+ * Stop the running GhostOS manager.
1160
+ */
1161
+ const stop = useCallback(async () => {
1162
+ if (!isAvailable)
1163
+ return;
1164
+ try {
1165
+ await invoke(GHOST_OS_TAURI_COMMANDS.STOP_GHOST_OS);
1166
+ await checkStatus();
1167
+ }
1168
+ catch (error) {
1169
+ console.error('[useGhostOs] Failed to stop GhostOS:', error);
1170
+ }
1171
+ }, [isAvailable, invoke, checkStatus]);
1172
+ /**
1173
+ * Reset the install state (for retrying after an error).
1174
+ */
1175
+ const resetState = useCallback(() => {
1176
+ setState(initialGhostOsInstallState);
1177
+ }, [setState]);
1178
+ // Wire up host event listeners (progress / logs / status).
1179
+ useEffect(() => {
1180
+ if (!isAvailable)
1181
+ return;
1182
+ const setupListeners = async () => {
1183
+ try {
1184
+ const unlistenProgress = await listen(GHOST_OS_TAURI_EVENTS.INSTALL_PROGRESS, (payload) => {
1185
+ const nextStatus = payload.status === 'completed'
1186
+ ? 'completed'
1187
+ : payload.status === 'cancelled'
1188
+ ? 'cancelled'
1189
+ : payload.status === 'error'
1190
+ ? 'error'
1191
+ : 'installing';
1192
+ setState((prev) => ({
1193
+ ...prev,
1194
+ status: nextStatus,
1195
+ progress: payload.percentage,
1196
+ message: payload.message,
1197
+ lastUpdated: new Date().toISOString(),
1198
+ }));
1199
+ });
1200
+ unlistenRefs.current.push(unlistenProgress);
1201
+ const unlistenLogs = await listen(GHOST_OS_TAURI_EVENTS.INSTALLATION_LOG, addLog);
1202
+ unlistenRefs.current.push(unlistenLogs);
1203
+ const unlistenStatus = await listen(GHOST_OS_TAURI_EVENTS.STATUS, setStatus);
1204
+ unlistenRefs.current.push(unlistenStatus);
1205
+ }
1206
+ catch (error) {
1207
+ console.error('[useGhostOs] Failed to setup event listeners:', error);
1208
+ }
1209
+ };
1210
+ setupListeners();
1211
+ return () => {
1212
+ unlistenRefs.current.forEach((unlisten) => unlisten());
1213
+ unlistenRefs.current = [];
1214
+ };
1215
+ }, [isAvailable, listen, setState, addLog]);
1216
+ // Check status once on mount (in the desktop app).
1217
+ useEffect(() => {
1218
+ if (!isAvailable || hasCheckedStatus.current)
1219
+ return;
1220
+ hasCheckedStatus.current = true;
1221
+ checkStatus();
1222
+ }, [isAvailable, checkStatus]);
1223
+ // Only expose the feature as available inside the desktop (Tauri) app.
1224
+ const finalIsAvailable = isAvailable && isTauriApp();
1225
+ return {
1226
+ isAvailable: finalIsAvailable,
1227
+ state,
1228
+ status,
1229
+ accessibilityPermission,
1230
+ install,
1231
+ stop,
1232
+ checkStatus,
1233
+ resetState,
1234
+ requestAccessibilityPermission,
1235
+ };
1236
+ }
1237
+
851
1238
  // packages/react/compose-refs/src/compose-refs.tsx
852
1239
  function setRef$1(ref, value) {
853
1240
  if (typeof ref === "function") {
@@ -53465,7 +53852,7 @@ const createLucideIcon = (iconName, iconNode) => {
53465
53852
  */
53466
53853
 
53467
53854
 
53468
- const __iconNode$25 = [
53855
+ const __iconNode$28 = [
53469
53856
  [
53470
53857
  "path",
53471
53858
  {
@@ -53474,7 +53861,7 @@ const __iconNode$25 = [
53474
53861
  }
53475
53862
  ]
53476
53863
  ];
53477
- const Activity = createLucideIcon("activity", __iconNode$25);
53864
+ const Activity = createLucideIcon("activity", __iconNode$28);
53478
53865
 
53479
53866
  /**
53480
53867
  * @license lucide-react v0.528.0 - ISC
@@ -53484,12 +53871,12 @@ const Activity = createLucideIcon("activity", __iconNode$25);
53484
53871
  */
53485
53872
 
53486
53873
 
53487
- const __iconNode$24 = [
53874
+ const __iconNode$27 = [
53488
53875
  ["path", { d: "M17 12H7", key: "16if0g" }],
53489
53876
  ["path", { d: "M19 18H5", key: "18s9l3" }],
53490
53877
  ["path", { d: "M21 6H3", key: "1jwq7v" }]
53491
53878
  ];
53492
- const AlignCenter = createLucideIcon("align-center", __iconNode$24);
53879
+ const AlignCenter = createLucideIcon("align-center", __iconNode$27);
53493
53880
 
53494
53881
  /**
53495
53882
  * @license lucide-react v0.528.0 - ISC
@@ -53499,12 +53886,12 @@ const AlignCenter = createLucideIcon("align-center", __iconNode$24);
53499
53886
  */
53500
53887
 
53501
53888
 
53502
- const __iconNode$23 = [
53889
+ const __iconNode$26 = [
53503
53890
  ["path", { d: "M15 12H3", key: "6jk70r" }],
53504
53891
  ["path", { d: "M17 18H3", key: "1amg6g" }],
53505
53892
  ["path", { d: "M21 6H3", key: "1jwq7v" }]
53506
53893
  ];
53507
- const AlignLeft = createLucideIcon("align-left", __iconNode$23);
53894
+ const AlignLeft = createLucideIcon("align-left", __iconNode$26);
53508
53895
 
53509
53896
  /**
53510
53897
  * @license lucide-react v0.528.0 - ISC
@@ -53514,12 +53901,12 @@ const AlignLeft = createLucideIcon("align-left", __iconNode$23);
53514
53901
  */
53515
53902
 
53516
53903
 
53517
- const __iconNode$22 = [
53904
+ const __iconNode$25 = [
53518
53905
  ["path", { d: "M21 12H9", key: "dn1m92" }],
53519
53906
  ["path", { d: "M21 18H7", key: "1ygte8" }],
53520
53907
  ["path", { d: "M21 6H3", key: "1jwq7v" }]
53521
53908
  ];
53522
- const AlignRight = createLucideIcon("align-right", __iconNode$22);
53909
+ const AlignRight = createLucideIcon("align-right", __iconNode$25);
53523
53910
 
53524
53911
  /**
53525
53912
  * @license lucide-react v0.528.0 - ISC
@@ -53529,12 +53916,12 @@ const AlignRight = createLucideIcon("align-right", __iconNode$22);
53529
53916
  */
53530
53917
 
53531
53918
 
53532
- const __iconNode$21 = [
53919
+ const __iconNode$24 = [
53533
53920
  ["rect", { width: "20", height: "5", x: "2", y: "3", rx: "1", key: "1wp1u1" }],
53534
53921
  ["path", { d: "M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8", key: "1s80jp" }],
53535
53922
  ["path", { d: "M10 12h4", key: "a56b0p" }]
53536
53923
  ];
53537
- const Archive = createLucideIcon("archive", __iconNode$21);
53924
+ const Archive = createLucideIcon("archive", __iconNode$24);
53538
53925
 
53539
53926
  /**
53540
53927
  * @license lucide-react v0.528.0 - ISC
@@ -53544,11 +53931,11 @@ const Archive = createLucideIcon("archive", __iconNode$21);
53544
53931
  */
53545
53932
 
53546
53933
 
53547
- const __iconNode$20 = [
53934
+ const __iconNode$23 = [
53548
53935
  ["path", { d: "m12 19-7-7 7-7", key: "1l729n" }],
53549
53936
  ["path", { d: "M19 12H5", key: "x3x0zl" }]
53550
53937
  ];
53551
- const ArrowLeft = createLucideIcon("arrow-left", __iconNode$20);
53938
+ const ArrowLeft = createLucideIcon("arrow-left", __iconNode$23);
53552
53939
 
53553
53940
  /**
53554
53941
  * @license lucide-react v0.528.0 - ISC
@@ -53558,11 +53945,11 @@ const ArrowLeft = createLucideIcon("arrow-left", __iconNode$20);
53558
53945
  */
53559
53946
 
53560
53947
 
53561
- const __iconNode$1$ = [
53948
+ const __iconNode$22 = [
53562
53949
  ["path", { d: "m5 12 7-7 7 7", key: "hav0vg" }],
53563
53950
  ["path", { d: "M12 19V5", key: "x0mq9r" }]
53564
53951
  ];
53565
- const ArrowUp = createLucideIcon("arrow-up", __iconNode$1$);
53952
+ const ArrowUp = createLucideIcon("arrow-up", __iconNode$22);
53566
53953
 
53567
53954
  /**
53568
53955
  * @license lucide-react v0.528.0 - ISC
@@ -53572,11 +53959,11 @@ const ArrowUp = createLucideIcon("arrow-up", __iconNode$1$);
53572
53959
  */
53573
53960
 
53574
53961
 
53575
- const __iconNode$1_ = [
53962
+ const __iconNode$21 = [
53576
53963
  ["path", { d: "M4.929 4.929 19.07 19.071", key: "196cmz" }],
53577
53964
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]
53578
53965
  ];
53579
- const Ban = createLucideIcon("ban", __iconNode$1_);
53966
+ const Ban = createLucideIcon("ban", __iconNode$21);
53580
53967
 
53581
53968
  /**
53582
53969
  * @license lucide-react v0.528.0 - ISC
@@ -53586,12 +53973,12 @@ const Ban = createLucideIcon("ban", __iconNode$1_);
53586
53973
  */
53587
53974
 
53588
53975
 
53589
- const __iconNode$1Z = [
53976
+ const __iconNode$20 = [
53590
53977
  ["rect", { width: "20", height: "12", x: "2", y: "6", rx: "2", key: "9lu3g6" }],
53591
53978
  ["circle", { cx: "12", cy: "12", r: "2", key: "1c9p78" }],
53592
53979
  ["path", { d: "M6 12h.01M18 12h.01", key: "113zkx" }]
53593
53980
  ];
53594
- const Banknote = createLucideIcon("banknote", __iconNode$1Z);
53981
+ const Banknote = createLucideIcon("banknote", __iconNode$20);
53595
53982
 
53596
53983
  /**
53597
53984
  * @license lucide-react v0.528.0 - ISC
@@ -53601,7 +53988,7 @@ const Banknote = createLucideIcon("banknote", __iconNode$1Z);
53601
53988
  */
53602
53989
 
53603
53990
 
53604
- const __iconNode$1Y = [
53991
+ const __iconNode$1$ = [
53605
53992
  ["path", { d: "M10.268 21a2 2 0 0 0 3.464 0", key: "vwvbt9" }],
53606
53993
  ["path", { d: "M22 8c0-2.3-.8-4.3-2-6", key: "5bb3ad" }],
53607
53994
  [
@@ -53613,7 +54000,7 @@ const __iconNode$1Y = [
53613
54000
  ],
53614
54001
  ["path", { d: "M4 2C2.8 3.7 2 5.7 2 8", key: "tap9e0" }]
53615
54002
  ];
53616
- const BellRing = createLucideIcon("bell-ring", __iconNode$1Y);
54003
+ const BellRing = createLucideIcon("bell-ring", __iconNode$1$);
53617
54004
 
53618
54005
  /**
53619
54006
  * @license lucide-react v0.528.0 - ISC
@@ -53623,7 +54010,7 @@ const BellRing = createLucideIcon("bell-ring", __iconNode$1Y);
53623
54010
  */
53624
54011
 
53625
54012
 
53626
- const __iconNode$1X = [
54013
+ const __iconNode$1_ = [
53627
54014
  ["path", { d: "M10.268 21a2 2 0 0 0 3.464 0", key: "vwvbt9" }],
53628
54015
  [
53629
54016
  "path",
@@ -53633,7 +54020,7 @@ const __iconNode$1X = [
53633
54020
  }
53634
54021
  ]
53635
54022
  ];
53636
- const Bell = createLucideIcon("bell", __iconNode$1X);
54023
+ const Bell = createLucideIcon("bell", __iconNode$1_);
53637
54024
 
53638
54025
  /**
53639
54026
  * @license lucide-react v0.528.0 - ISC
@@ -53643,13 +54030,13 @@ const Bell = createLucideIcon("bell", __iconNode$1X);
53643
54030
  */
53644
54031
 
53645
54032
 
53646
- const __iconNode$1W = [
54033
+ const __iconNode$1Z = [
53647
54034
  [
53648
54035
  "path",
53649
54036
  { d: "M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8", key: "mg9rjx" }
53650
54037
  ]
53651
54038
  ];
53652
- const Bold$1 = createLucideIcon("bold", __iconNode$1W);
54039
+ const Bold$1 = createLucideIcon("bold", __iconNode$1Z);
53653
54040
 
53654
54041
  /**
53655
54042
  * @license lucide-react v0.528.0 - ISC
@@ -53659,7 +54046,7 @@ const Bold$1 = createLucideIcon("bold", __iconNode$1W);
53659
54046
  */
53660
54047
 
53661
54048
 
53662
- const __iconNode$1V = [
54049
+ const __iconNode$1Y = [
53663
54050
  ["path", { d: "M12 7v14", key: "1akyts" }],
53664
54051
  [
53665
54052
  "path",
@@ -53669,7 +54056,7 @@ const __iconNode$1V = [
53669
54056
  }
53670
54057
  ]
53671
54058
  ];
53672
- const BookOpen = createLucideIcon("book-open", __iconNode$1V);
54059
+ const BookOpen = createLucideIcon("book-open", __iconNode$1Y);
53673
54060
 
53674
54061
  /**
53675
54062
  * @license lucide-react v0.528.0 - ISC
@@ -53679,7 +54066,7 @@ const BookOpen = createLucideIcon("book-open", __iconNode$1V);
53679
54066
  */
53680
54067
 
53681
54068
 
53682
- const __iconNode$1U = [
54069
+ const __iconNode$1X = [
53683
54070
  ["path", { d: "M12 8V4H8", key: "hb8ula" }],
53684
54071
  ["rect", { width: "16", height: "12", x: "4", y: "8", rx: "2", key: "enze0r" }],
53685
54072
  ["path", { d: "M2 14h2", key: "vft8re" }],
@@ -53687,7 +54074,7 @@ const __iconNode$1U = [
53687
54074
  ["path", { d: "M15 13v2", key: "1xurst" }],
53688
54075
  ["path", { d: "M9 13v2", key: "rq6x2g" }]
53689
54076
  ];
53690
- const Bot = createLucideIcon("bot", __iconNode$1U);
54077
+ const Bot = createLucideIcon("bot", __iconNode$1X);
53691
54078
 
53692
54079
  /**
53693
54080
  * @license lucide-react v0.528.0 - ISC
@@ -53697,11 +54084,11 @@ const Bot = createLucideIcon("bot", __iconNode$1U);
53697
54084
  */
53698
54085
 
53699
54086
 
53700
- const __iconNode$1T = [
54087
+ const __iconNode$1W = [
53701
54088
  ["path", { d: "M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16", key: "jecpp" }],
53702
54089
  ["rect", { width: "20", height: "14", x: "2", y: "6", rx: "2", key: "i6l2r4" }]
53703
54090
  ];
53704
- const Briefcase = createLucideIcon("briefcase", __iconNode$1T);
54091
+ const Briefcase = createLucideIcon("briefcase", __iconNode$1W);
53705
54092
 
53706
54093
  /**
53707
54094
  * @license lucide-react v0.528.0 - ISC
@@ -53711,7 +54098,7 @@ const Briefcase = createLucideIcon("briefcase", __iconNode$1T);
53711
54098
  */
53712
54099
 
53713
54100
 
53714
- const __iconNode$1S = [
54101
+ const __iconNode$1V = [
53715
54102
  ["path", { d: "M6 22V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v18Z", key: "1b4qmf" }],
53716
54103
  ["path", { d: "M6 12H4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2", key: "i71pzd" }],
53717
54104
  ["path", { d: "M18 9h2a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-2", key: "10jefs" }],
@@ -53720,7 +54107,7 @@ const __iconNode$1S = [
53720
54107
  ["path", { d: "M10 14h4", key: "kelpxr" }],
53721
54108
  ["path", { d: "M10 18h4", key: "1ulq68" }]
53722
54109
  ];
53723
- const Building2 = createLucideIcon("building-2", __iconNode$1S);
54110
+ const Building2 = createLucideIcon("building-2", __iconNode$1V);
53724
54111
 
53725
54112
  /**
53726
54113
  * @license lucide-react v0.528.0 - ISC
@@ -53730,13 +54117,13 @@ const Building2 = createLucideIcon("building-2", __iconNode$1S);
53730
54117
  */
53731
54118
 
53732
54119
 
53733
- const __iconNode$1R = [
54120
+ const __iconNode$1U = [
53734
54121
  ["path", { d: "M8 2v4", key: "1cmpym" }],
53735
54122
  ["path", { d: "M16 2v4", key: "4m81vk" }],
53736
54123
  ["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
53737
54124
  ["path", { d: "M3 10h18", key: "8toen8" }]
53738
54125
  ];
53739
- const Calendar$1 = createLucideIcon("calendar", __iconNode$1R);
54126
+ const Calendar$1 = createLucideIcon("calendar", __iconNode$1U);
53740
54127
 
53741
54128
  /**
53742
54129
  * @license lucide-react v0.528.0 - ISC
@@ -53746,11 +54133,11 @@ const Calendar$1 = createLucideIcon("calendar", __iconNode$1R);
53746
54133
  */
53747
54134
 
53748
54135
 
53749
- const __iconNode$1Q = [
54136
+ const __iconNode$1T = [
53750
54137
  ["path", { d: "M18 6 7 17l-5-5", key: "116fxf" }],
53751
54138
  ["path", { d: "m22 10-7.5 7.5L13 16", key: "ke71qq" }]
53752
54139
  ];
53753
- const CheckCheck = createLucideIcon("check-check", __iconNode$1Q);
54140
+ const CheckCheck = createLucideIcon("check-check", __iconNode$1T);
53754
54141
 
53755
54142
  /**
53756
54143
  * @license lucide-react v0.528.0 - ISC
@@ -53760,8 +54147,8 @@ const CheckCheck = createLucideIcon("check-check", __iconNode$1Q);
53760
54147
  */
53761
54148
 
53762
54149
 
53763
- const __iconNode$1P = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
53764
- const Check = createLucideIcon("check", __iconNode$1P);
54150
+ const __iconNode$1S = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
54151
+ const Check = createLucideIcon("check", __iconNode$1S);
53765
54152
 
53766
54153
  /**
53767
54154
  * @license lucide-react v0.528.0 - ISC
@@ -53771,8 +54158,8 @@ const Check = createLucideIcon("check", __iconNode$1P);
53771
54158
  */
53772
54159
 
53773
54160
 
53774
- const __iconNode$1O = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
53775
- const ChevronDown = createLucideIcon("chevron-down", __iconNode$1O);
54161
+ const __iconNode$1R = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
54162
+ const ChevronDown = createLucideIcon("chevron-down", __iconNode$1R);
53776
54163
 
53777
54164
  /**
53778
54165
  * @license lucide-react v0.528.0 - ISC
@@ -53782,11 +54169,11 @@ const ChevronDown = createLucideIcon("chevron-down", __iconNode$1O);
53782
54169
  */
53783
54170
 
53784
54171
 
53785
- const __iconNode$1N = [
54172
+ const __iconNode$1Q = [
53786
54173
  ["path", { d: "m17 18-6-6 6-6", key: "1yerx2" }],
53787
54174
  ["path", { d: "M7 6v12", key: "1p53r6" }]
53788
54175
  ];
53789
- const ChevronFirst = createLucideIcon("chevron-first", __iconNode$1N);
54176
+ const ChevronFirst = createLucideIcon("chevron-first", __iconNode$1Q);
53790
54177
 
53791
54178
  /**
53792
54179
  * @license lucide-react v0.528.0 - ISC
@@ -53796,11 +54183,11 @@ const ChevronFirst = createLucideIcon("chevron-first", __iconNode$1N);
53796
54183
  */
53797
54184
 
53798
54185
 
53799
- const __iconNode$1M = [
54186
+ const __iconNode$1P = [
53800
54187
  ["path", { d: "m7 18 6-6-6-6", key: "lwmzdw" }],
53801
54188
  ["path", { d: "M17 6v12", key: "1o0aio" }]
53802
54189
  ];
53803
- const ChevronLast = createLucideIcon("chevron-last", __iconNode$1M);
54190
+ const ChevronLast = createLucideIcon("chevron-last", __iconNode$1P);
53804
54191
 
53805
54192
  /**
53806
54193
  * @license lucide-react v0.528.0 - ISC
@@ -53810,8 +54197,8 @@ const ChevronLast = createLucideIcon("chevron-last", __iconNode$1M);
53810
54197
  */
53811
54198
 
53812
54199
 
53813
- const __iconNode$1L = [["path", { d: "m15 18-6-6 6-6", key: "1wnfg3" }]];
53814
- const ChevronLeft = createLucideIcon("chevron-left", __iconNode$1L);
54200
+ const __iconNode$1O = [["path", { d: "m15 18-6-6 6-6", key: "1wnfg3" }]];
54201
+ const ChevronLeft = createLucideIcon("chevron-left", __iconNode$1O);
53815
54202
 
53816
54203
  /**
53817
54204
  * @license lucide-react v0.528.0 - ISC
@@ -53821,8 +54208,8 @@ const ChevronLeft = createLucideIcon("chevron-left", __iconNode$1L);
53821
54208
  */
53822
54209
 
53823
54210
 
53824
- const __iconNode$1K = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
53825
- const ChevronRight = createLucideIcon("chevron-right", __iconNode$1K);
54211
+ const __iconNode$1N = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
54212
+ const ChevronRight = createLucideIcon("chevron-right", __iconNode$1N);
53826
54213
 
53827
54214
  /**
53828
54215
  * @license lucide-react v0.528.0 - ISC
@@ -53832,8 +54219,8 @@ const ChevronRight = createLucideIcon("chevron-right", __iconNode$1K);
53832
54219
  */
53833
54220
 
53834
54221
 
53835
- const __iconNode$1J = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
53836
- const ChevronUp = createLucideIcon("chevron-up", __iconNode$1J);
54222
+ const __iconNode$1M = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
54223
+ const ChevronUp = createLucideIcon("chevron-up", __iconNode$1M);
53837
54224
 
53838
54225
  /**
53839
54226
  * @license lucide-react v0.528.0 - ISC
@@ -53843,11 +54230,11 @@ const ChevronUp = createLucideIcon("chevron-up", __iconNode$1J);
53843
54230
  */
53844
54231
 
53845
54232
 
53846
- const __iconNode$1I = [
54233
+ const __iconNode$1L = [
53847
54234
  ["path", { d: "m11 17-5-5 5-5", key: "13zhaf" }],
53848
54235
  ["path", { d: "m18 17-5-5 5-5", key: "h8a8et" }]
53849
54236
  ];
53850
- const ChevronsLeft = createLucideIcon("chevrons-left", __iconNode$1I);
54237
+ const ChevronsLeft = createLucideIcon("chevrons-left", __iconNode$1L);
53851
54238
 
53852
54239
  /**
53853
54240
  * @license lucide-react v0.528.0 - ISC
@@ -53857,11 +54244,11 @@ const ChevronsLeft = createLucideIcon("chevrons-left", __iconNode$1I);
53857
54244
  */
53858
54245
 
53859
54246
 
53860
- const __iconNode$1H = [
54247
+ const __iconNode$1K = [
53861
54248
  ["path", { d: "m6 17 5-5-5-5", key: "xnjwq" }],
53862
54249
  ["path", { d: "m13 17 5-5-5-5", key: "17xmmf" }]
53863
54250
  ];
53864
- const ChevronsRight = createLucideIcon("chevrons-right", __iconNode$1H);
54251
+ const ChevronsRight = createLucideIcon("chevrons-right", __iconNode$1K);
53865
54252
 
53866
54253
  /**
53867
54254
  * @license lucide-react v0.528.0 - ISC
@@ -53871,11 +54258,11 @@ const ChevronsRight = createLucideIcon("chevrons-right", __iconNode$1H);
53871
54258
  */
53872
54259
 
53873
54260
 
53874
- const __iconNode$1G = [
54261
+ const __iconNode$1J = [
53875
54262
  ["path", { d: "m7 15 5 5 5-5", key: "1hf1tw" }],
53876
54263
  ["path", { d: "m7 9 5-5 5 5", key: "sgt6xg" }]
53877
54264
  ];
53878
- const ChevronsUpDown = createLucideIcon("chevrons-up-down", __iconNode$1G);
54265
+ const ChevronsUpDown = createLucideIcon("chevrons-up-down", __iconNode$1J);
53879
54266
 
53880
54267
  /**
53881
54268
  * @license lucide-react v0.528.0 - ISC
@@ -53885,12 +54272,12 @@ const ChevronsUpDown = createLucideIcon("chevrons-up-down", __iconNode$1G);
53885
54272
  */
53886
54273
 
53887
54274
 
53888
- const __iconNode$1F = [
54275
+ const __iconNode$1I = [
53889
54276
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
53890
54277
  ["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
53891
54278
  ["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
53892
54279
  ];
53893
- const CircleAlert = createLucideIcon("circle-alert", __iconNode$1F);
54280
+ const CircleAlert = createLucideIcon("circle-alert", __iconNode$1I);
53894
54281
 
53895
54282
  /**
53896
54283
  * @license lucide-react v0.528.0 - ISC
@@ -53900,11 +54287,26 @@ const CircleAlert = createLucideIcon("circle-alert", __iconNode$1F);
53900
54287
  */
53901
54288
 
53902
54289
 
53903
- const __iconNode$1E = [
54290
+ const __iconNode$1H = [
54291
+ ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
54292
+ ["path", { d: "m16 12-4-4-4 4", key: "177agl" }],
54293
+ ["path", { d: "M12 16V8", key: "1sbj14" }]
54294
+ ];
54295
+ const CircleArrowUp = createLucideIcon("circle-arrow-up", __iconNode$1H);
54296
+
54297
+ /**
54298
+ * @license lucide-react v0.528.0 - ISC
54299
+ *
54300
+ * This source code is licensed under the ISC license.
54301
+ * See the LICENSE file in the root directory of this source tree.
54302
+ */
54303
+
54304
+
54305
+ const __iconNode$1G = [
53904
54306
  ["path", { d: "M21.801 10A10 10 0 1 1 17 3.335", key: "yps3ct" }],
53905
54307
  ["path", { d: "m9 11 3 3L22 4", key: "1pflzl" }]
53906
54308
  ];
53907
- const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$1E);
54309
+ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$1G);
53908
54310
 
53909
54311
  /**
53910
54312
  * @license lucide-react v0.528.0 - ISC
@@ -53914,11 +54316,11 @@ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$1E);
53914
54316
  */
53915
54317
 
53916
54318
 
53917
- const __iconNode$1D = [
54319
+ const __iconNode$1F = [
53918
54320
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
53919
54321
  ["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
53920
54322
  ];
53921
- const CircleCheck = createLucideIcon("circle-check", __iconNode$1D);
54323
+ const CircleCheck = createLucideIcon("circle-check", __iconNode$1F);
53922
54324
 
53923
54325
  /**
53924
54326
  * @license lucide-react v0.528.0 - ISC
@@ -53928,11 +54330,11 @@ const CircleCheck = createLucideIcon("circle-check", __iconNode$1D);
53928
54330
  */
53929
54331
 
53930
54332
 
53931
- const __iconNode$1C = [
54333
+ const __iconNode$1E = [
53932
54334
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
53933
54335
  ["rect", { x: "9", y: "9", width: "6", height: "6", rx: "1", key: "1ssd4o" }]
53934
54336
  ];
53935
- const CircleStop = createLucideIcon("circle-stop", __iconNode$1C);
54337
+ const CircleStop = createLucideIcon("circle-stop", __iconNode$1E);
53936
54338
 
53937
54339
  /**
53938
54340
  * @license lucide-react v0.528.0 - ISC
@@ -53942,12 +54344,12 @@ const CircleStop = createLucideIcon("circle-stop", __iconNode$1C);
53942
54344
  */
53943
54345
 
53944
54346
 
53945
- const __iconNode$1B = [
54347
+ const __iconNode$1D = [
53946
54348
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
53947
54349
  ["path", { d: "m15 9-6 6", key: "1uzhvr" }],
53948
54350
  ["path", { d: "m9 9 6 6", key: "z0biqf" }]
53949
54351
  ];
53950
- const CircleX = createLucideIcon("circle-x", __iconNode$1B);
54352
+ const CircleX = createLucideIcon("circle-x", __iconNode$1D);
53951
54353
 
53952
54354
  /**
53953
54355
  * @license lucide-react v0.528.0 - ISC
@@ -53957,8 +54359,8 @@ const CircleX = createLucideIcon("circle-x", __iconNode$1B);
53957
54359
  */
53958
54360
 
53959
54361
 
53960
- const __iconNode$1A = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
53961
- const Circle = createLucideIcon("circle", __iconNode$1A);
54362
+ const __iconNode$1C = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
54363
+ const Circle = createLucideIcon("circle", __iconNode$1C);
53962
54364
 
53963
54365
  /**
53964
54366
  * @license lucide-react v0.528.0 - ISC
@@ -53968,11 +54370,11 @@ const Circle = createLucideIcon("circle", __iconNode$1A);
53968
54370
  */
53969
54371
 
53970
54372
 
53971
- const __iconNode$1z = [
54373
+ const __iconNode$1B = [
53972
54374
  ["path", { d: "M12 6v6l4 2", key: "mmk7yg" }],
53973
54375
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]
53974
54376
  ];
53975
- const Clock = createLucideIcon("clock", __iconNode$1z);
54377
+ const Clock = createLucideIcon("clock", __iconNode$1B);
53976
54378
 
53977
54379
  /**
53978
54380
  * @license lucide-react v0.528.0 - ISC
@@ -53982,12 +54384,25 @@ const Clock = createLucideIcon("clock", __iconNode$1z);
53982
54384
  */
53983
54385
 
53984
54386
 
53985
- const __iconNode$1y = [
54387
+ const __iconNode$1A = [
54388
+ ["path", { d: "M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z", key: "p7xjir" }]
54389
+ ];
54390
+ const Cloud = createLucideIcon("cloud", __iconNode$1A);
54391
+
54392
+ /**
54393
+ * @license lucide-react v0.528.0 - ISC
54394
+ *
54395
+ * This source code is licensed under the ISC license.
54396
+ * See the LICENSE file in the root directory of this source tree.
54397
+ */
54398
+
54399
+
54400
+ const __iconNode$1z = [
53986
54401
  ["path", { d: "m18 16 4-4-4-4", key: "1inbqp" }],
53987
54402
  ["path", { d: "m6 8-4 4 4 4", key: "15zrgr" }],
53988
54403
  ["path", { d: "m14.5 4-5 16", key: "e7oirm" }]
53989
54404
  ];
53990
- const CodeXml = createLucideIcon("code-xml", __iconNode$1y);
54405
+ const CodeXml = createLucideIcon("code-xml", __iconNode$1z);
53991
54406
 
53992
54407
  /**
53993
54408
  * @license lucide-react v0.528.0 - ISC
@@ -53997,11 +54412,11 @@ const CodeXml = createLucideIcon("code-xml", __iconNode$1y);
53997
54412
  */
53998
54413
 
53999
54414
 
54000
- const __iconNode$1x = [
54415
+ const __iconNode$1y = [
54001
54416
  ["path", { d: "m16 18 6-6-6-6", key: "eg8j8" }],
54002
54417
  ["path", { d: "m8 6-6 6 6 6", key: "ppft3o" }]
54003
54418
  ];
54004
- const Code$1 = createLucideIcon("code", __iconNode$1x);
54419
+ const Code$1 = createLucideIcon("code", __iconNode$1y);
54005
54420
 
54006
54421
  /**
54007
54422
  * @license lucide-react v0.528.0 - ISC
@@ -54011,11 +54426,11 @@ const Code$1 = createLucideIcon("code", __iconNode$1x);
54011
54426
  */
54012
54427
 
54013
54428
 
54014
- const __iconNode$1w = [
54429
+ const __iconNode$1x = [
54015
54430
  ["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
54016
54431
  ["path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2", key: "zix9uf" }]
54017
54432
  ];
54018
- const Copy = createLucideIcon("copy", __iconNode$1w);
54433
+ const Copy = createLucideIcon("copy", __iconNode$1x);
54019
54434
 
54020
54435
  /**
54021
54436
  * @license lucide-react v0.528.0 - ISC
@@ -54025,11 +54440,11 @@ const Copy = createLucideIcon("copy", __iconNode$1w);
54025
54440
  */
54026
54441
 
54027
54442
 
54028
- const __iconNode$1v = [
54443
+ const __iconNode$1w = [
54029
54444
  ["rect", { width: "20", height: "14", x: "2", y: "5", rx: "2", key: "ynyp8z" }],
54030
54445
  ["line", { x1: "2", x2: "22", y1: "10", y2: "10", key: "1b3vmo" }]
54031
54446
  ];
54032
- const CreditCard = createLucideIcon("credit-card", __iconNode$1v);
54447
+ const CreditCard = createLucideIcon("credit-card", __iconNode$1w);
54033
54448
 
54034
54449
  /**
54035
54450
  * @license lucide-react v0.528.0 - ISC
@@ -54039,12 +54454,12 @@ const CreditCard = createLucideIcon("credit-card", __iconNode$1v);
54039
54454
  */
54040
54455
 
54041
54456
 
54042
- const __iconNode$1u = [
54457
+ const __iconNode$1v = [
54043
54458
  ["ellipse", { cx: "12", cy: "5", rx: "9", ry: "3", key: "msslwz" }],
54044
54459
  ["path", { d: "M3 5V19A9 3 0 0 0 21 19V5", key: "1wlel7" }],
54045
54460
  ["path", { d: "M3 12A9 3 0 0 0 21 12", key: "mv7ke4" }]
54046
54461
  ];
54047
- const Database = createLucideIcon("database", __iconNode$1u);
54462
+ const Database = createLucideIcon("database", __iconNode$1v);
54048
54463
 
54049
54464
  /**
54050
54465
  * @license lucide-react v0.528.0 - ISC
@@ -54054,11 +54469,11 @@ const Database = createLucideIcon("database", __iconNode$1u);
54054
54469
  */
54055
54470
 
54056
54471
 
54057
- const __iconNode$1t = [
54472
+ const __iconNode$1u = [
54058
54473
  ["line", { x1: "12", x2: "12", y1: "2", y2: "22", key: "7eqyqh" }],
54059
54474
  ["path", { d: "M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6", key: "1b0p4s" }]
54060
54475
  ];
54061
- const DollarSign = createLucideIcon("dollar-sign", __iconNode$1t);
54476
+ const DollarSign = createLucideIcon("dollar-sign", __iconNode$1u);
54062
54477
 
54063
54478
  /**
54064
54479
  * @license lucide-react v0.528.0 - ISC
@@ -54068,12 +54483,12 @@ const DollarSign = createLucideIcon("dollar-sign", __iconNode$1t);
54068
54483
  */
54069
54484
 
54070
54485
 
54071
- const __iconNode$1s = [
54486
+ const __iconNode$1t = [
54072
54487
  ["path", { d: "M12 15V3", key: "m9g1x1" }],
54073
54488
  ["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", key: "ih7n3h" }],
54074
54489
  ["path", { d: "m7 10 5 5 5-5", key: "brsn70" }]
54075
54490
  ];
54076
- const Download = createLucideIcon("download", __iconNode$1s);
54491
+ const Download = createLucideIcon("download", __iconNode$1t);
54077
54492
 
54078
54493
  /**
54079
54494
  * @license lucide-react v0.528.0 - ISC
@@ -54083,12 +54498,12 @@ const Download = createLucideIcon("download", __iconNode$1s);
54083
54498
  */
54084
54499
 
54085
54500
 
54086
- const __iconNode$1r = [
54501
+ const __iconNode$1s = [
54087
54502
  ["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }],
54088
54503
  ["circle", { cx: "12", cy: "5", r: "1", key: "gxeob9" }],
54089
54504
  ["circle", { cx: "12", cy: "19", r: "1", key: "lyex9k" }]
54090
54505
  ];
54091
- const EllipsisVertical = createLucideIcon("ellipsis-vertical", __iconNode$1r);
54506
+ const EllipsisVertical = createLucideIcon("ellipsis-vertical", __iconNode$1s);
54092
54507
 
54093
54508
  /**
54094
54509
  * @license lucide-react v0.528.0 - ISC
@@ -54098,12 +54513,12 @@ const EllipsisVertical = createLucideIcon("ellipsis-vertical", __iconNode$1r);
54098
54513
  */
54099
54514
 
54100
54515
 
54101
- const __iconNode$1q = [
54516
+ const __iconNode$1r = [
54102
54517
  ["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }],
54103
54518
  ["circle", { cx: "19", cy: "12", r: "1", key: "1wjl8i" }],
54104
54519
  ["circle", { cx: "5", cy: "12", r: "1", key: "1pcz8c" }]
54105
54520
  ];
54106
- const Ellipsis = createLucideIcon("ellipsis", __iconNode$1q);
54521
+ const Ellipsis = createLucideIcon("ellipsis", __iconNode$1r);
54107
54522
 
54108
54523
  /**
54109
54524
  * @license lucide-react v0.528.0 - ISC
@@ -54113,12 +54528,12 @@ const Ellipsis = createLucideIcon("ellipsis", __iconNode$1q);
54113
54528
  */
54114
54529
 
54115
54530
 
54116
- const __iconNode$1p = [
54531
+ const __iconNode$1q = [
54117
54532
  ["path", { d: "M15 3h6v6", key: "1q9fwt" }],
54118
54533
  ["path", { d: "M10 14 21 3", key: "gplh6r" }],
54119
54534
  ["path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6", key: "a6xqqp" }]
54120
54535
  ];
54121
- const ExternalLink = createLucideIcon("external-link", __iconNode$1p);
54536
+ const ExternalLink = createLucideIcon("external-link", __iconNode$1q);
54122
54537
 
54123
54538
  /**
54124
54539
  * @license lucide-react v0.528.0 - ISC
@@ -54128,7 +54543,7 @@ const ExternalLink = createLucideIcon("external-link", __iconNode$1p);
54128
54543
  */
54129
54544
 
54130
54545
 
54131
- const __iconNode$1o = [
54546
+ const __iconNode$1p = [
54132
54547
  [
54133
54548
  "path",
54134
54549
  {
@@ -54146,7 +54561,7 @@ const __iconNode$1o = [
54146
54561
  ],
54147
54562
  ["path", { d: "m2 2 20 20", key: "1ooewy" }]
54148
54563
  ];
54149
- const EyeOff = createLucideIcon("eye-off", __iconNode$1o);
54564
+ const EyeOff = createLucideIcon("eye-off", __iconNode$1p);
54150
54565
 
54151
54566
  /**
54152
54567
  * @license lucide-react v0.528.0 - ISC
@@ -54156,7 +54571,7 @@ const EyeOff = createLucideIcon("eye-off", __iconNode$1o);
54156
54571
  */
54157
54572
 
54158
54573
 
54159
- const __iconNode$1n = [
54574
+ const __iconNode$1o = [
54160
54575
  [
54161
54576
  "path",
54162
54577
  {
@@ -54166,7 +54581,7 @@ const __iconNode$1n = [
54166
54581
  ],
54167
54582
  ["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
54168
54583
  ];
54169
- const Eye = createLucideIcon("eye", __iconNode$1n);
54584
+ const Eye = createLucideIcon("eye", __iconNode$1o);
54170
54585
 
54171
54586
  /**
54172
54587
  * @license lucide-react v0.528.0 - ISC
@@ -54176,7 +54591,7 @@ const Eye = createLucideIcon("eye", __iconNode$1n);
54176
54591
  */
54177
54592
 
54178
54593
 
54179
- const __iconNode$1m = [
54594
+ const __iconNode$1n = [
54180
54595
  ["path", { d: "M10 12v-1", key: "v7bkov" }],
54181
54596
  ["path", { d: "M10 18v-2", key: "1cjy8d" }],
54182
54597
  ["path", { d: "M10 7V6", key: "dljcrl" }],
@@ -54187,7 +54602,7 @@ const __iconNode$1m = [
54187
54602
  ],
54188
54603
  ["circle", { cx: "10", cy: "20", r: "2", key: "1xzdoj" }]
54189
54604
  ];
54190
- const FileArchive = createLucideIcon("file-archive", __iconNode$1m);
54605
+ const FileArchive = createLucideIcon("file-archive", __iconNode$1n);
54191
54606
 
54192
54607
  /**
54193
54608
  * @license lucide-react v0.528.0 - ISC
@@ -54197,7 +54612,7 @@ const FileArchive = createLucideIcon("file-archive", __iconNode$1m);
54197
54612
  */
54198
54613
 
54199
54614
 
54200
- const __iconNode$1l = [
54615
+ const __iconNode$1m = [
54201
54616
  ["path", { d: "M17.5 22h.5a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v3", key: "rslqgf" }],
54202
54617
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
54203
54618
  [
@@ -54208,7 +54623,7 @@ const __iconNode$1l = [
54208
54623
  }
54209
54624
  ]
54210
54625
  ];
54211
- const FileAudio = createLucideIcon("file-audio", __iconNode$1l);
54626
+ const FileAudio = createLucideIcon("file-audio", __iconNode$1m);
54212
54627
 
54213
54628
  /**
54214
54629
  * @license lucide-react v0.528.0 - ISC
@@ -54218,13 +54633,13 @@ const FileAudio = createLucideIcon("file-audio", __iconNode$1l);
54218
54633
  */
54219
54634
 
54220
54635
 
54221
- const __iconNode$1k = [
54636
+ const __iconNode$1l = [
54222
54637
  ["path", { d: "M10 12.5 8 15l2 2.5", key: "1tg20x" }],
54223
54638
  ["path", { d: "m14 12.5 2 2.5-2 2.5", key: "yinavb" }],
54224
54639
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
54225
54640
  ["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z", key: "1mlx9k" }]
54226
54641
  ];
54227
- const FileCode = createLucideIcon("file-code", __iconNode$1k);
54642
+ const FileCode = createLucideIcon("file-code", __iconNode$1l);
54228
54643
 
54229
54644
  /**
54230
54645
  * @license lucide-react v0.528.0 - ISC
@@ -54234,13 +54649,13 @@ const FileCode = createLucideIcon("file-code", __iconNode$1k);
54234
54649
  */
54235
54650
 
54236
54651
 
54237
- const __iconNode$1j = [
54652
+ const __iconNode$1k = [
54238
54653
  ["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
54239
54654
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
54240
54655
  ["path", { d: "M12 18v-6", key: "17g6i2" }],
54241
54656
  ["path", { d: "m9 15 3 3 3-3", key: "1npd3o" }]
54242
54657
  ];
54243
- const FileDown = createLucideIcon("file-down", __iconNode$1j);
54658
+ const FileDown = createLucideIcon("file-down", __iconNode$1k);
54244
54659
 
54245
54660
  /**
54246
54661
  * @license lucide-react v0.528.0 - ISC
@@ -54250,13 +54665,13 @@ const FileDown = createLucideIcon("file-down", __iconNode$1j);
54250
54665
  */
54251
54666
 
54252
54667
 
54253
- const __iconNode$1i = [
54668
+ const __iconNode$1j = [
54254
54669
  ["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
54255
54670
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
54256
54671
  ["circle", { cx: "10", cy: "12", r: "2", key: "737tya" }],
54257
54672
  ["path", { d: "m20 17-1.296-1.296a2.41 2.41 0 0 0-3.408 0L9 22", key: "wt3hpn" }]
54258
54673
  ];
54259
- const FileImage = createLucideIcon("file-image", __iconNode$1i);
54674
+ const FileImage = createLucideIcon("file-image", __iconNode$1j);
54260
54675
 
54261
54676
  /**
54262
54677
  * @license lucide-react v0.528.0 - ISC
@@ -54266,7 +54681,7 @@ const FileImage = createLucideIcon("file-image", __iconNode$1i);
54266
54681
  */
54267
54682
 
54268
54683
 
54269
- const __iconNode$1h = [
54684
+ const __iconNode$1i = [
54270
54685
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
54271
54686
  ["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z", key: "1mlx9k" }],
54272
54687
  [
@@ -54277,7 +54692,7 @@ const __iconNode$1h = [
54277
54692
  }
54278
54693
  ]
54279
54694
  ];
54280
- const FilePlay = createLucideIcon("file-play", __iconNode$1h);
54695
+ const FilePlay = createLucideIcon("file-play", __iconNode$1i);
54281
54696
 
54282
54697
  /**
54283
54698
  * @license lucide-react v0.528.0 - ISC
@@ -54287,7 +54702,7 @@ const FilePlay = createLucideIcon("file-play", __iconNode$1h);
54287
54702
  */
54288
54703
 
54289
54704
 
54290
- const __iconNode$1g = [
54705
+ const __iconNode$1h = [
54291
54706
  ["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
54292
54707
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
54293
54708
  ["path", { d: "M8 13h2", key: "yr2amv" }],
@@ -54295,7 +54710,7 @@ const __iconNode$1g = [
54295
54710
  ["path", { d: "M8 17h2", key: "2yhykz" }],
54296
54711
  ["path", { d: "M14 17h2", key: "10kma7" }]
54297
54712
  ];
54298
- const FileSpreadsheet = createLucideIcon("file-spreadsheet", __iconNode$1g);
54713
+ const FileSpreadsheet = createLucideIcon("file-spreadsheet", __iconNode$1h);
54299
54714
 
54300
54715
  /**
54301
54716
  * @license lucide-react v0.528.0 - ISC
@@ -54305,14 +54720,14 @@ const FileSpreadsheet = createLucideIcon("file-spreadsheet", __iconNode$1g);
54305
54720
  */
54306
54721
 
54307
54722
 
54308
- const __iconNode$1f = [
54723
+ const __iconNode$1g = [
54309
54724
  ["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
54310
54725
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
54311
54726
  ["path", { d: "M10 9H8", key: "b1mrlr" }],
54312
54727
  ["path", { d: "M16 13H8", key: "t4e002" }],
54313
54728
  ["path", { d: "M16 17H8", key: "z1uh3a" }]
54314
54729
  ];
54315
- const FileText = createLucideIcon("file-text", __iconNode$1f);
54730
+ const FileText = createLucideIcon("file-text", __iconNode$1g);
54316
54731
 
54317
54732
  /**
54318
54733
  * @license lucide-react v0.528.0 - ISC
@@ -54322,11 +54737,11 @@ const FileText = createLucideIcon("file-text", __iconNode$1f);
54322
54737
  */
54323
54738
 
54324
54739
 
54325
- const __iconNode$1e = [
54740
+ const __iconNode$1f = [
54326
54741
  ["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
54327
54742
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }]
54328
54743
  ];
54329
- const File$1 = createLucideIcon("file", __iconNode$1e);
54744
+ const File$1 = createLucideIcon("file", __iconNode$1f);
54330
54745
 
54331
54746
  /**
54332
54747
  * @license lucide-react v0.528.0 - ISC
@@ -54336,14 +54751,14 @@ const File$1 = createLucideIcon("file", __iconNode$1e);
54336
54751
  */
54337
54752
 
54338
54753
 
54339
- const __iconNode$1d = [
54754
+ const __iconNode$1e = [
54340
54755
  ["path", { d: "m14.5 12.5-8 8a2.119 2.119 0 1 1-3-3l8-8", key: "15492f" }],
54341
54756
  ["path", { d: "m16 16 6-6", key: "vzrcl6" }],
54342
54757
  ["path", { d: "m8 8 6-6", key: "18bi4p" }],
54343
54758
  ["path", { d: "m9 7 8 8", key: "5jnvq1" }],
54344
54759
  ["path", { d: "m21 11-8-8", key: "z4y7zo" }]
54345
54760
  ];
54346
- const Gavel = createLucideIcon("gavel", __iconNode$1d);
54761
+ const Gavel = createLucideIcon("gavel", __iconNode$1e);
54347
54762
 
54348
54763
  /**
54349
54764
  * @license lucide-react v0.528.0 - ISC
@@ -54353,13 +54768,13 @@ const Gavel = createLucideIcon("gavel", __iconNode$1d);
54353
54768
  */
54354
54769
 
54355
54770
 
54356
- const __iconNode$1c = [
54771
+ const __iconNode$1d = [
54357
54772
  ["line", { x1: "6", x2: "6", y1: "3", y2: "15", key: "17qcm7" }],
54358
54773
  ["circle", { cx: "18", cy: "6", r: "3", key: "1h7g24" }],
54359
54774
  ["circle", { cx: "6", cy: "18", r: "3", key: "fqmcym" }],
54360
54775
  ["path", { d: "M18 9a9 9 0 0 1-9 9", key: "n2h4wq" }]
54361
54776
  ];
54362
- const GitBranch = createLucideIcon("git-branch", __iconNode$1c);
54777
+ const GitBranch = createLucideIcon("git-branch", __iconNode$1d);
54363
54778
 
54364
54779
  /**
54365
54780
  * @license lucide-react v0.528.0 - ISC
@@ -54369,12 +54784,12 @@ const GitBranch = createLucideIcon("git-branch", __iconNode$1c);
54369
54784
  */
54370
54785
 
54371
54786
 
54372
- const __iconNode$1b = [
54787
+ const __iconNode$1c = [
54373
54788
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
54374
54789
  ["path", { d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20", key: "13o1zl" }],
54375
54790
  ["path", { d: "M2 12h20", key: "9i4pu4" }]
54376
54791
  ];
54377
- const Globe = createLucideIcon("globe", __iconNode$1b);
54792
+ const Globe = createLucideIcon("globe", __iconNode$1c);
54378
54793
 
54379
54794
  /**
54380
54795
  * @license lucide-react v0.528.0 - ISC
@@ -54384,7 +54799,7 @@ const Globe = createLucideIcon("globe", __iconNode$1b);
54384
54799
  */
54385
54800
 
54386
54801
 
54387
- const __iconNode$1a = [
54802
+ const __iconNode$1b = [
54388
54803
  [
54389
54804
  "path",
54390
54805
  {
@@ -54395,7 +54810,7 @@ const __iconNode$1a = [
54395
54810
  ["path", { d: "M22 10v6", key: "1lu8f3" }],
54396
54811
  ["path", { d: "M6 12.5V16a6 3 0 0 0 12 0v-3.5", key: "1r8lef" }]
54397
54812
  ];
54398
- const GraduationCap = createLucideIcon("graduation-cap", __iconNode$1a);
54813
+ const GraduationCap = createLucideIcon("graduation-cap", __iconNode$1b);
54399
54814
 
54400
54815
  /**
54401
54816
  * @license lucide-react v0.528.0 - ISC
@@ -54405,7 +54820,7 @@ const GraduationCap = createLucideIcon("graduation-cap", __iconNode$1a);
54405
54820
  */
54406
54821
 
54407
54822
 
54408
- const __iconNode$19 = [
54823
+ const __iconNode$1a = [
54409
54824
  ["path", { d: "M14 18a2 2 0 0 0-4 0", key: "1v8fkw" }],
54410
54825
  [
54411
54826
  "path",
@@ -54418,7 +54833,7 @@ const __iconNode$19 = [
54418
54833
  ["circle", { cx: "17", cy: "18", r: "3", key: "82mm0e" }],
54419
54834
  ["circle", { cx: "7", cy: "18", r: "3", key: "lvkj7j" }]
54420
54835
  ];
54421
- const HatGlasses = createLucideIcon("hat-glasses", __iconNode$19);
54836
+ const HatGlasses = createLucideIcon("hat-glasses", __iconNode$1a);
54422
54837
 
54423
54838
  /**
54424
54839
  * @license lucide-react v0.528.0 - ISC
@@ -54428,13 +54843,13 @@ const HatGlasses = createLucideIcon("hat-glasses", __iconNode$19);
54428
54843
  */
54429
54844
 
54430
54845
 
54431
- const __iconNode$18 = [
54846
+ const __iconNode$19 = [
54432
54847
  ["path", { d: "M4 12h8", key: "17cfdx" }],
54433
54848
  ["path", { d: "M4 18V6", key: "1rz3zl" }],
54434
54849
  ["path", { d: "M12 18V6", key: "zqpxq5" }],
54435
54850
  ["path", { d: "m17 12 3-2v8", key: "1hhhft" }]
54436
54851
  ];
54437
- const Heading1 = createLucideIcon("heading-1", __iconNode$18);
54852
+ const Heading1 = createLucideIcon("heading-1", __iconNode$19);
54438
54853
 
54439
54854
  /**
54440
54855
  * @license lucide-react v0.528.0 - ISC
@@ -54444,13 +54859,13 @@ const Heading1 = createLucideIcon("heading-1", __iconNode$18);
54444
54859
  */
54445
54860
 
54446
54861
 
54447
- const __iconNode$17 = [
54862
+ const __iconNode$18 = [
54448
54863
  ["path", { d: "M4 12h8", key: "17cfdx" }],
54449
54864
  ["path", { d: "M4 18V6", key: "1rz3zl" }],
54450
54865
  ["path", { d: "M12 18V6", key: "zqpxq5" }],
54451
54866
  ["path", { d: "M21 18h-4c0-4 4-3 4-6 0-1.5-2-2.5-4-1", key: "9jr5yi" }]
54452
54867
  ];
54453
- const Heading2 = createLucideIcon("heading-2", __iconNode$17);
54868
+ const Heading2 = createLucideIcon("heading-2", __iconNode$18);
54454
54869
 
54455
54870
  /**
54456
54871
  * @license lucide-react v0.528.0 - ISC
@@ -54460,14 +54875,14 @@ const Heading2 = createLucideIcon("heading-2", __iconNode$17);
54460
54875
  */
54461
54876
 
54462
54877
 
54463
- const __iconNode$16 = [
54878
+ const __iconNode$17 = [
54464
54879
  ["path", { d: "M4 12h8", key: "17cfdx" }],
54465
54880
  ["path", { d: "M4 18V6", key: "1rz3zl" }],
54466
54881
  ["path", { d: "M12 18V6", key: "zqpxq5" }],
54467
54882
  ["path", { d: "M17.5 10.5c1.7-1 3.5 0 3.5 1.5a2 2 0 0 1-2 2", key: "68ncm8" }],
54468
54883
  ["path", { d: "M17 17.5c2 1.5 4 .3 4-1.5a2 2 0 0 0-2-2", key: "1ejuhz" }]
54469
54884
  ];
54470
- const Heading3 = createLucideIcon("heading-3", __iconNode$16);
54885
+ const Heading3 = createLucideIcon("heading-3", __iconNode$17);
54471
54886
 
54472
54887
  /**
54473
54888
  * @license lucide-react v0.528.0 - ISC
@@ -54477,12 +54892,12 @@ const Heading3 = createLucideIcon("heading-3", __iconNode$16);
54477
54892
  */
54478
54893
 
54479
54894
 
54480
- const __iconNode$15 = [
54895
+ const __iconNode$16 = [
54481
54896
  ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2", key: "1m3agn" }],
54482
54897
  ["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }],
54483
54898
  ["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }]
54484
54899
  ];
54485
- const Image$3 = createLucideIcon("image", __iconNode$15);
54900
+ const Image$3 = createLucideIcon("image", __iconNode$16);
54486
54901
 
54487
54902
  /**
54488
54903
  * @license lucide-react v0.528.0 - ISC
@@ -54492,12 +54907,12 @@ const Image$3 = createLucideIcon("image", __iconNode$15);
54492
54907
  */
54493
54908
 
54494
54909
 
54495
- const __iconNode$14 = [
54910
+ const __iconNode$15 = [
54496
54911
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
54497
54912
  ["path", { d: "M12 16v-4", key: "1dtifu" }],
54498
54913
  ["path", { d: "M12 8h.01", key: "e9boi3" }]
54499
54914
  ];
54500
- const Info$3 = createLucideIcon("info", __iconNode$14);
54915
+ const Info$3 = createLucideIcon("info", __iconNode$15);
54501
54916
 
54502
54917
  /**
54503
54918
  * @license lucide-react v0.528.0 - ISC
@@ -54507,12 +54922,12 @@ const Info$3 = createLucideIcon("info", __iconNode$14);
54507
54922
  */
54508
54923
 
54509
54924
 
54510
- const __iconNode$13 = [
54925
+ const __iconNode$14 = [
54511
54926
  ["line", { x1: "19", x2: "10", y1: "4", y2: "4", key: "15jd3p" }],
54512
54927
  ["line", { x1: "14", x2: "5", y1: "20", y2: "20", key: "bu0au3" }],
54513
54928
  ["line", { x1: "15", x2: "9", y1: "4", y2: "20", key: "uljnxc" }]
54514
54929
  ];
54515
- const Italic$1 = createLucideIcon("italic", __iconNode$13);
54930
+ const Italic$1 = createLucideIcon("italic", __iconNode$14);
54516
54931
 
54517
54932
  /**
54518
54933
  * @license lucide-react v0.528.0 - ISC
@@ -54522,7 +54937,7 @@ const Italic$1 = createLucideIcon("italic", __iconNode$13);
54522
54937
  */
54523
54938
 
54524
54939
 
54525
- const __iconNode$12 = [
54940
+ const __iconNode$13 = [
54526
54941
  [
54527
54942
  "path",
54528
54943
  {
@@ -54532,7 +54947,7 @@ const __iconNode$12 = [
54532
54947
  ],
54533
54948
  ["circle", { cx: "16.5", cy: "7.5", r: ".5", fill: "currentColor", key: "w0ekpg" }]
54534
54949
  ];
54535
- const KeyRound = createLucideIcon("key-round", __iconNode$12);
54950
+ const KeyRound = createLucideIcon("key-round", __iconNode$13);
54536
54951
 
54537
54952
  /**
54538
54953
  * @license lucide-react v0.528.0 - ISC
@@ -54542,7 +54957,7 @@ const KeyRound = createLucideIcon("key-round", __iconNode$12);
54542
54957
  */
54543
54958
 
54544
54959
 
54545
- const __iconNode$11 = [
54960
+ const __iconNode$12 = [
54546
54961
  ["path", { d: "M10 18v-7", key: "wt116b" }],
54547
54962
  [
54548
54963
  "path",
@@ -54556,7 +54971,7 @@ const __iconNode$11 = [
54556
54971
  ["path", { d: "M3 22h18", key: "8prr45" }],
54557
54972
  ["path", { d: "M6 18v-7", key: "1ivflk" }]
54558
54973
  ];
54559
- const Landmark = createLucideIcon("landmark", __iconNode$11);
54974
+ const Landmark = createLucideIcon("landmark", __iconNode$12);
54560
54975
 
54561
54976
  /**
54562
54977
  * @license lucide-react v0.528.0 - ISC
@@ -54566,12 +54981,12 @@ const Landmark = createLucideIcon("landmark", __iconNode$11);
54566
54981
  */
54567
54982
 
54568
54983
 
54569
- const __iconNode$10 = [
54984
+ const __iconNode$11 = [
54570
54985
  ["path", { d: "M9 17H7A5 5 0 0 1 7 7h2", key: "8i5ue5" }],
54571
54986
  ["path", { d: "M15 7h2a5 5 0 1 1 0 10h-2", key: "1b9ql8" }],
54572
54987
  ["line", { x1: "8", x2: "16", y1: "12", y2: "12", key: "1jonct" }]
54573
54988
  ];
54574
- const Link2 = createLucideIcon("link-2", __iconNode$10);
54989
+ const Link2 = createLucideIcon("link-2", __iconNode$11);
54575
54990
 
54576
54991
  /**
54577
54992
  * @license lucide-react v0.528.0 - ISC
@@ -54581,11 +54996,11 @@ const Link2 = createLucideIcon("link-2", __iconNode$10);
54581
54996
  */
54582
54997
 
54583
54998
 
54584
- const __iconNode$$ = [
54999
+ const __iconNode$10 = [
54585
55000
  ["path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71", key: "1cjeqo" }],
54586
55001
  ["path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71", key: "19qd67" }]
54587
55002
  ];
54588
- const Link$1 = createLucideIcon("link", __iconNode$$);
55003
+ const Link$1 = createLucideIcon("link", __iconNode$10);
54589
55004
 
54590
55005
  /**
54591
55006
  * @license lucide-react v0.528.0 - ISC
@@ -54595,7 +55010,7 @@ const Link$1 = createLucideIcon("link", __iconNode$$);
54595
55010
  */
54596
55011
 
54597
55012
 
54598
- const __iconNode$_ = [
55013
+ const __iconNode$$ = [
54599
55014
  ["path", { d: "M10 12h11", key: "6m4ad9" }],
54600
55015
  ["path", { d: "M10 18h11", key: "11hvi2" }],
54601
55016
  ["path", { d: "M10 6h11", key: "c7qv1k" }],
@@ -54603,7 +55018,7 @@ const __iconNode$_ = [
54603
55018
  ["path", { d: "M4 6h1v4", key: "cnovpq" }],
54604
55019
  ["path", { d: "M6 18H4c0-1 2-2 2-3s-1-1.5-2-1", key: "m9a95d" }]
54605
55020
  ];
54606
- const ListOrdered = createLucideIcon("list-ordered", __iconNode$_);
55021
+ const ListOrdered = createLucideIcon("list-ordered", __iconNode$$);
54607
55022
 
54608
55023
  /**
54609
55024
  * @license lucide-react v0.528.0 - ISC
@@ -54613,7 +55028,7 @@ const ListOrdered = createLucideIcon("list-ordered", __iconNode$_);
54613
55028
  */
54614
55029
 
54615
55030
 
54616
- const __iconNode$Z = [
55031
+ const __iconNode$_ = [
54617
55032
  ["path", { d: "M3 12h.01", key: "nlz23k" }],
54618
55033
  ["path", { d: "M3 18h.01", key: "1tta3j" }],
54619
55034
  ["path", { d: "M3 6h.01", key: "1rqtza" }],
@@ -54621,7 +55036,7 @@ const __iconNode$Z = [
54621
55036
  ["path", { d: "M8 18h13", key: "1lx6n3" }],
54622
55037
  ["path", { d: "M8 6h13", key: "ik3vkj" }]
54623
55038
  ];
54624
- const List$1 = createLucideIcon("list", __iconNode$Z);
55039
+ const List$1 = createLucideIcon("list", __iconNode$_);
54625
55040
 
54626
55041
  /**
54627
55042
  * @license lucide-react v0.528.0 - ISC
@@ -54631,8 +55046,8 @@ const List$1 = createLucideIcon("list", __iconNode$Z);
54631
55046
  */
54632
55047
 
54633
55048
 
54634
- const __iconNode$Y = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
54635
- const LoaderCircle = createLucideIcon("loader-circle", __iconNode$Y);
55049
+ const __iconNode$Z = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
55050
+ const LoaderCircle = createLucideIcon("loader-circle", __iconNode$Z);
54636
55051
 
54637
55052
  /**
54638
55053
  * @license lucide-react v0.528.0 - ISC
@@ -54642,11 +55057,11 @@ const LoaderCircle = createLucideIcon("loader-circle", __iconNode$Y);
54642
55057
  */
54643
55058
 
54644
55059
 
54645
- const __iconNode$X = [
55060
+ const __iconNode$Y = [
54646
55061
  ["rect", { width: "18", height: "11", x: "3", y: "11", rx: "2", ry: "2", key: "1w4ew1" }],
54647
55062
  ["path", { d: "M7 11V7a5 5 0 0 1 10 0v4", key: "fwvmzm" }]
54648
55063
  ];
54649
- const Lock = createLucideIcon("lock", __iconNode$X);
55064
+ const Lock = createLucideIcon("lock", __iconNode$Y);
54650
55065
 
54651
55066
  /**
54652
55067
  * @license lucide-react v0.528.0 - ISC
@@ -54656,11 +55071,11 @@ const Lock = createLucideIcon("lock", __iconNode$X);
54656
55071
  */
54657
55072
 
54658
55073
 
54659
- const __iconNode$W = [
55074
+ const __iconNode$X = [
54660
55075
  ["path", { d: "m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7", key: "132q7q" }],
54661
55076
  ["rect", { x: "2", y: "4", width: "20", height: "16", rx: "2", key: "izxlao" }]
54662
55077
  ];
54663
- const Mail = createLucideIcon("mail", __iconNode$W);
55078
+ const Mail = createLucideIcon("mail", __iconNode$X);
54664
55079
 
54665
55080
  /**
54666
55081
  * @license lucide-react v0.528.0 - ISC
@@ -54670,10 +55085,10 @@ const Mail = createLucideIcon("mail", __iconNode$W);
54670
55085
  */
54671
55086
 
54672
55087
 
54673
- const __iconNode$V = [
55088
+ const __iconNode$W = [
54674
55089
  ["path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z", key: "1lielz" }]
54675
55090
  ];
54676
- const MessageSquare = createLucideIcon("message-square", __iconNode$V);
55091
+ const MessageSquare = createLucideIcon("message-square", __iconNode$W);
54677
55092
 
54678
55093
  /**
54679
55094
  * @license lucide-react v0.528.0 - ISC
@@ -54683,12 +55098,12 @@ const MessageSquare = createLucideIcon("message-square", __iconNode$V);
54683
55098
  */
54684
55099
 
54685
55100
 
54686
- const __iconNode$U = [
55101
+ const __iconNode$V = [
54687
55102
  ["path", { d: "M12 19v3", key: "npa21l" }],
54688
55103
  ["path", { d: "M19 10v2a7 7 0 0 1-14 0v-2", key: "1vc78b" }],
54689
55104
  ["rect", { x: "9", y: "2", width: "6", height: "13", rx: "3", key: "s6n7sd" }]
54690
55105
  ];
54691
- const Mic = createLucideIcon("mic", __iconNode$U);
55106
+ const Mic = createLucideIcon("mic", __iconNode$V);
54692
55107
 
54693
55108
  /**
54694
55109
  * @license lucide-react v0.528.0 - ISC
@@ -54698,7 +55113,7 @@ const Mic = createLucideIcon("mic", __iconNode$U);
54698
55113
  */
54699
55114
 
54700
55115
 
54701
- const __iconNode$T = [
55116
+ const __iconNode$U = [
54702
55117
  [
54703
55118
  "path",
54704
55119
  {
@@ -54707,7 +55122,7 @@ const __iconNode$T = [
54707
55122
  }
54708
55123
  ]
54709
55124
  ];
54710
- const Paperclip = createLucideIcon("paperclip", __iconNode$T);
55125
+ const Paperclip = createLucideIcon("paperclip", __iconNode$U);
54711
55126
 
54712
55127
  /**
54713
55128
  * @license lucide-react v0.528.0 - ISC
@@ -54717,7 +55132,7 @@ const Paperclip = createLucideIcon("paperclip", __iconNode$T);
54717
55132
  */
54718
55133
 
54719
55134
 
54720
- const __iconNode$S = [
55135
+ const __iconNode$T = [
54721
55136
  ["path", { d: "M13 21h8", key: "1jsn5i" }],
54722
55137
  [
54723
55138
  "path",
@@ -54727,7 +55142,7 @@ const __iconNode$S = [
54727
55142
  }
54728
55143
  ]
54729
55144
  ];
54730
- const PenLine = createLucideIcon("pen-line", __iconNode$S);
55145
+ const PenLine = createLucideIcon("pen-line", __iconNode$T);
54731
55146
 
54732
55147
  /**
54733
55148
  * @license lucide-react v0.528.0 - ISC
@@ -54737,7 +55152,7 @@ const PenLine = createLucideIcon("pen-line", __iconNode$S);
54737
55152
  */
54738
55153
 
54739
55154
 
54740
- const __iconNode$R = [
55155
+ const __iconNode$S = [
54741
55156
  [
54742
55157
  "path",
54743
55158
  {
@@ -54746,7 +55161,7 @@ const __iconNode$R = [
54746
55161
  }
54747
55162
  ]
54748
55163
  ];
54749
- const Pen = createLucideIcon("pen", __iconNode$R);
55164
+ const Pen = createLucideIcon("pen", __iconNode$S);
54750
55165
 
54751
55166
  /**
54752
55167
  * @license lucide-react v0.528.0 - ISC
@@ -54756,7 +55171,7 @@ const Pen = createLucideIcon("pen", __iconNode$R);
54756
55171
  */
54757
55172
 
54758
55173
 
54759
- const __iconNode$Q = [
55174
+ const __iconNode$R = [
54760
55175
  [
54761
55176
  "path",
54762
55177
  {
@@ -54766,7 +55181,7 @@ const __iconNode$Q = [
54766
55181
  ],
54767
55182
  ["path", { d: "m15 5 4 4", key: "1mk7zo" }]
54768
55183
  ];
54769
- const Pencil = createLucideIcon("pencil", __iconNode$Q);
55184
+ const Pencil = createLucideIcon("pencil", __iconNode$R);
54770
55185
 
54771
55186
  /**
54772
55187
  * @license lucide-react v0.528.0 - ISC
@@ -54776,7 +55191,7 @@ const Pencil = createLucideIcon("pencil", __iconNode$Q);
54776
55191
  */
54777
55192
 
54778
55193
 
54779
- const __iconNode$P = [
55194
+ const __iconNode$Q = [
54780
55195
  [
54781
55196
  "path",
54782
55197
  {
@@ -54785,7 +55200,7 @@ const __iconNode$P = [
54785
55200
  }
54786
55201
  ]
54787
55202
  ];
54788
- const Play = createLucideIcon("play", __iconNode$P);
55203
+ const Play = createLucideIcon("play", __iconNode$Q);
54789
55204
 
54790
55205
  /**
54791
55206
  * @license lucide-react v0.528.0 - ISC
@@ -54795,11 +55210,11 @@ const Play = createLucideIcon("play", __iconNode$P);
54795
55210
  */
54796
55211
 
54797
55212
 
54798
- const __iconNode$O = [
55213
+ const __iconNode$P = [
54799
55214
  ["path", { d: "M5 12h14", key: "1ays0h" }],
54800
55215
  ["path", { d: "M12 5v14", key: "s699le" }]
54801
55216
  ];
54802
- const Plus = createLucideIcon("plus", __iconNode$O);
55217
+ const Plus = createLucideIcon("plus", __iconNode$P);
54803
55218
 
54804
55219
  /**
54805
55220
  * @license lucide-react v0.528.0 - ISC
@@ -54809,12 +55224,12 @@ const Plus = createLucideIcon("plus", __iconNode$O);
54809
55224
  */
54810
55225
 
54811
55226
 
54812
- const __iconNode$N = [
55227
+ const __iconNode$O = [
54813
55228
  ["path", { d: "M2 3h20", key: "91anmk" }],
54814
55229
  ["path", { d: "M21 3v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V3", key: "2k9sn8" }],
54815
55230
  ["path", { d: "m7 21 5-5 5 5", key: "bip4we" }]
54816
55231
  ];
54817
- const Presentation = createLucideIcon("presentation", __iconNode$N);
55232
+ const Presentation = createLucideIcon("presentation", __iconNode$O);
54818
55233
 
54819
55234
  /**
54820
55235
  * @license lucide-react v0.528.0 - ISC
@@ -54824,7 +55239,7 @@ const Presentation = createLucideIcon("presentation", __iconNode$N);
54824
55239
  */
54825
55240
 
54826
55241
 
54827
- const __iconNode$M = [
55242
+ const __iconNode$N = [
54828
55243
  [
54829
55244
  "path",
54830
55245
  {
@@ -54833,7 +55248,7 @@ const __iconNode$M = [
54833
55248
  }
54834
55249
  ]
54835
55250
  ];
54836
- const Puzzle = createLucideIcon("puzzle", __iconNode$M);
55251
+ const Puzzle = createLucideIcon("puzzle", __iconNode$N);
54837
55252
 
54838
55253
  /**
54839
55254
  * @license lucide-react v0.528.0 - ISC
@@ -54843,7 +55258,7 @@ const Puzzle = createLucideIcon("puzzle", __iconNode$M);
54843
55258
  */
54844
55259
 
54845
55260
 
54846
- const __iconNode$L = [
55261
+ const __iconNode$M = [
54847
55262
  [
54848
55263
  "path",
54849
55264
  {
@@ -54859,7 +55274,7 @@ const __iconNode$L = [
54859
55274
  }
54860
55275
  ]
54861
55276
  ];
54862
- const Quote = createLucideIcon("quote", __iconNode$L);
55277
+ const Quote = createLucideIcon("quote", __iconNode$M);
54863
55278
 
54864
55279
  /**
54865
55280
  * @license lucide-react v0.528.0 - ISC
@@ -54869,14 +55284,14 @@ const Quote = createLucideIcon("quote", __iconNode$L);
54869
55284
  */
54870
55285
 
54871
55286
 
54872
- const __iconNode$K = [
55287
+ const __iconNode$L = [
54873
55288
  ["path", { d: "M16.247 7.761a6 6 0 0 1 0 8.478", key: "1fwjs5" }],
54874
55289
  ["path", { d: "M19.075 4.933a10 10 0 0 1 0 14.134", key: "ehdyv1" }],
54875
55290
  ["path", { d: "M4.925 19.067a10 10 0 0 1 0-14.134", key: "1q22gi" }],
54876
55291
  ["path", { d: "M7.753 16.239a6 6 0 0 1 0-8.478", key: "r2q7qm" }],
54877
55292
  ["circle", { cx: "12", cy: "12", r: "2", key: "1c9p78" }]
54878
55293
  ];
54879
- const Radio$1 = createLucideIcon("radio", __iconNode$K);
55294
+ const Radio$1 = createLucideIcon("radio", __iconNode$L);
54880
55295
 
54881
55296
  /**
54882
55297
  * @license lucide-react v0.528.0 - ISC
@@ -54886,13 +55301,13 @@ const Radio$1 = createLucideIcon("radio", __iconNode$K);
54886
55301
  */
54887
55302
 
54888
55303
 
54889
- const __iconNode$J = [
55304
+ const __iconNode$K = [
54890
55305
  ["path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8", key: "v9h5vc" }],
54891
55306
  ["path", { d: "M21 3v5h-5", key: "1q7to0" }],
54892
55307
  ["path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", key: "3uifl3" }],
54893
55308
  ["path", { d: "M8 16H3v5", key: "1cv678" }]
54894
55309
  ];
54895
- const RefreshCw = createLucideIcon("refresh-cw", __iconNode$J);
55310
+ const RefreshCw = createLucideIcon("refresh-cw", __iconNode$K);
54896
55311
 
54897
55312
  /**
54898
55313
  * @license lucide-react v0.528.0 - ISC
@@ -54902,13 +55317,13 @@ const RefreshCw = createLucideIcon("refresh-cw", __iconNode$J);
54902
55317
  */
54903
55318
 
54904
55319
 
54905
- const __iconNode$I = [
55320
+ const __iconNode$J = [
54906
55321
  ["path", { d: "m17 2 4 4-4 4", key: "nntrym" }],
54907
55322
  ["path", { d: "M3 11v-1a4 4 0 0 1 4-4h14", key: "84bu3i" }],
54908
55323
  ["path", { d: "m7 22-4-4 4-4", key: "1wqhfi" }],
54909
55324
  ["path", { d: "M21 13v1a4 4 0 0 1-4 4H3", key: "1rx37r" }]
54910
55325
  ];
54911
- const Repeat = createLucideIcon("repeat", __iconNode$I);
55326
+ const Repeat = createLucideIcon("repeat", __iconNode$J);
54912
55327
 
54913
55328
  /**
54914
55329
  * @license lucide-react v0.528.0 - ISC
@@ -54918,11 +55333,11 @@ const Repeat = createLucideIcon("repeat", __iconNode$I);
54918
55333
  */
54919
55334
 
54920
55335
 
54921
- const __iconNode$H = [
55336
+ const __iconNode$I = [
54922
55337
  ["path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8", key: "1357e3" }],
54923
55338
  ["path", { d: "M3 3v5h5", key: "1xhq8a" }]
54924
55339
  ];
54925
- const RotateCcw = createLucideIcon("rotate-ccw", __iconNode$H);
55340
+ const RotateCcw = createLucideIcon("rotate-ccw", __iconNode$I);
54926
55341
 
54927
55342
  /**
54928
55343
  * @license lucide-react v0.528.0 - ISC
@@ -54932,11 +55347,11 @@ const RotateCcw = createLucideIcon("rotate-ccw", __iconNode$H);
54932
55347
  */
54933
55348
 
54934
55349
 
54935
- const __iconNode$G = [
55350
+ const __iconNode$H = [
54936
55351
  ["path", { d: "M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8", key: "1p45f6" }],
54937
55352
  ["path", { d: "M21 3v5h-5", key: "1q7to0" }]
54938
55353
  ];
54939
- const RotateCw = createLucideIcon("rotate-cw", __iconNode$G);
55354
+ const RotateCw = createLucideIcon("rotate-cw", __iconNode$H);
54940
55355
 
54941
55356
  /**
54942
55357
  * @license lucide-react v0.528.0 - ISC
@@ -54946,7 +55361,7 @@ const RotateCw = createLucideIcon("rotate-cw", __iconNode$G);
54946
55361
  */
54947
55362
 
54948
55363
 
54949
- const __iconNode$F = [
55364
+ const __iconNode$G = [
54950
55365
  [
54951
55366
  "path",
54952
55367
  {
@@ -54957,7 +55372,7 @@ const __iconNode$F = [
54957
55372
  ["path", { d: "M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7", key: "1ydtos" }],
54958
55373
  ["path", { d: "M7 3v4a1 1 0 0 0 1 1h7", key: "t51u73" }]
54959
55374
  ];
54960
- const Save = createLucideIcon("save", __iconNode$F);
55375
+ const Save = createLucideIcon("save", __iconNode$G);
54961
55376
 
54962
55377
  /**
54963
55378
  * @license lucide-react v0.528.0 - ISC
@@ -54967,7 +55382,7 @@ const Save = createLucideIcon("save", __iconNode$F);
54967
55382
  */
54968
55383
 
54969
55384
 
54970
- const __iconNode$E = [
55385
+ const __iconNode$F = [
54971
55386
  ["path", { d: "M14 22v-4a2 2 0 1 0-4 0v4", key: "hhkicm" }],
54972
55387
  [
54973
55388
  "path",
@@ -54981,7 +55396,7 @@ const __iconNode$E = [
54981
55396
  ["path", { d: "M6 5v17", key: "1xfsm0" }],
54982
55397
  ["circle", { cx: "12", cy: "9", r: "2", key: "1092wv" }]
54983
55398
  ];
54984
- const School = createLucideIcon("school", __iconNode$E);
55399
+ const School = createLucideIcon("school", __iconNode$F);
54985
55400
 
54986
55401
  /**
54987
55402
  * @license lucide-react v0.528.0 - ISC
@@ -54991,14 +55406,14 @@ const School = createLucideIcon("school", __iconNode$E);
54991
55406
  */
54992
55407
 
54993
55408
 
54994
- const __iconNode$D = [
55409
+ const __iconNode$E = [
54995
55410
  ["path", { d: "M13 3H4a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-3", key: "i8wdob" }],
54996
55411
  ["path", { d: "M8 21h8", key: "1ev6f3" }],
54997
55412
  ["path", { d: "M12 17v4", key: "1riwvh" }],
54998
55413
  ["path", { d: "m17 8 5-5", key: "fqif7o" }],
54999
55414
  ["path", { d: "M17 3h5v5", key: "1o3tu8" }]
55000
55415
  ];
55001
- const ScreenShare = createLucideIcon("screen-share", __iconNode$D);
55416
+ const ScreenShare = createLucideIcon("screen-share", __iconNode$E);
55002
55417
 
55003
55418
  /**
55004
55419
  * @license lucide-react v0.528.0 - ISC
@@ -55008,7 +55423,7 @@ const ScreenShare = createLucideIcon("screen-share", __iconNode$D);
55008
55423
  */
55009
55424
 
55010
55425
 
55011
- const __iconNode$C = [
55426
+ const __iconNode$D = [
55012
55427
  ["path", { d: "M15 12h-5", key: "r7krc0" }],
55013
55428
  ["path", { d: "M15 8h-5", key: "1khuty" }],
55014
55429
  ["path", { d: "M19 17V5a2 2 0 0 0-2-2H4", key: "zz82l3" }],
@@ -55020,7 +55435,7 @@ const __iconNode$C = [
55020
55435
  }
55021
55436
  ]
55022
55437
  ];
55023
- const ScrollText = createLucideIcon("scroll-text", __iconNode$C);
55438
+ const ScrollText = createLucideIcon("scroll-text", __iconNode$D);
55024
55439
 
55025
55440
  /**
55026
55441
  * @license lucide-react v0.528.0 - ISC
@@ -55030,11 +55445,11 @@ const ScrollText = createLucideIcon("scroll-text", __iconNode$C);
55030
55445
  */
55031
55446
 
55032
55447
 
55033
- const __iconNode$B = [
55448
+ const __iconNode$C = [
55034
55449
  ["path", { d: "m21 21-4.34-4.34", key: "14j7rj" }],
55035
55450
  ["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }]
55036
55451
  ];
55037
- const Search = createLucideIcon("search", __iconNode$B);
55452
+ const Search = createLucideIcon("search", __iconNode$C);
55038
55453
 
55039
55454
  /**
55040
55455
  * @license lucide-react v0.528.0 - ISC
@@ -55044,7 +55459,7 @@ const Search = createLucideIcon("search", __iconNode$B);
55044
55459
  */
55045
55460
 
55046
55461
 
55047
- const __iconNode$A = [
55462
+ const __iconNode$B = [
55048
55463
  [
55049
55464
  "path",
55050
55465
  {
@@ -55054,7 +55469,23 @@ const __iconNode$A = [
55054
55469
  ],
55055
55470
  ["path", { d: "m21.854 2.147-10.94 10.939", key: "12cjpa" }]
55056
55471
  ];
55057
- const Send = createLucideIcon("send", __iconNode$A);
55472
+ const Send = createLucideIcon("send", __iconNode$B);
55473
+
55474
+ /**
55475
+ * @license lucide-react v0.528.0 - ISC
55476
+ *
55477
+ * This source code is licensed under the ISC license.
55478
+ * See the LICENSE file in the root directory of this source tree.
55479
+ */
55480
+
55481
+
55482
+ const __iconNode$A = [
55483
+ ["rect", { width: "20", height: "8", x: "2", y: "2", rx: "2", ry: "2", key: "ngkwjq" }],
55484
+ ["rect", { width: "20", height: "8", x: "2", y: "14", rx: "2", ry: "2", key: "iecqi9" }],
55485
+ ["line", { x1: "6", x2: "6.01", y1: "6", y2: "6", key: "16zg32" }],
55486
+ ["line", { x1: "6", x2: "6.01", y1: "18", y2: "18", key: "nzw8ys" }]
55487
+ ];
55488
+ const Server = createLucideIcon("server", __iconNode$A);
55058
55489
 
55059
55490
  /**
55060
55491
  * @license lucide-react v0.528.0 - ISC
@@ -62243,150 +62674,6 @@ var dist = Gravatar;
62243
62674
 
62244
62675
  var Gravatar$1 = /*@__PURE__*/getDefaultExportFromCjs(dist);
62245
62676
 
62246
- var SWITCH_NAME = "Switch";
62247
- var [createSwitchContext, createSwitchScope] = createContextScope$1(SWITCH_NAME);
62248
- var [SwitchProvider, useSwitchContext] = createSwitchContext(SWITCH_NAME);
62249
- var Switch$1 = React.forwardRef(
62250
- (props, forwardedRef) => {
62251
- const {
62252
- __scopeSwitch,
62253
- name,
62254
- checked: checkedProp,
62255
- defaultChecked,
62256
- required,
62257
- disabled,
62258
- value = "on",
62259
- onCheckedChange,
62260
- form,
62261
- ...switchProps
62262
- } = props;
62263
- const [button, setButton] = React.useState(null);
62264
- const composedRefs = useComposedRefs$1(forwardedRef, (node) => setButton(node));
62265
- const hasConsumerStoppedPropagationRef = React.useRef(false);
62266
- const isFormControl = button ? form || !!button.closest("form") : true;
62267
- const [checked, setChecked] = useControllableState$1({
62268
- prop: checkedProp,
62269
- defaultProp: defaultChecked ?? false,
62270
- onChange: onCheckedChange,
62271
- caller: SWITCH_NAME
62272
- });
62273
- return /* @__PURE__ */ jsxs(SwitchProvider, { scope: __scopeSwitch, checked, disabled, children: [
62274
- /* @__PURE__ */ jsx(
62275
- Primitive$3.button,
62276
- {
62277
- type: "button",
62278
- role: "switch",
62279
- "aria-checked": checked,
62280
- "aria-required": required,
62281
- "data-state": getState$2(checked),
62282
- "data-disabled": disabled ? "" : void 0,
62283
- disabled,
62284
- value,
62285
- ...switchProps,
62286
- ref: composedRefs,
62287
- onClick: composeEventHandlers$1(props.onClick, (event) => {
62288
- setChecked((prevChecked) => !prevChecked);
62289
- if (isFormControl) {
62290
- hasConsumerStoppedPropagationRef.current = event.isPropagationStopped();
62291
- if (!hasConsumerStoppedPropagationRef.current) event.stopPropagation();
62292
- }
62293
- })
62294
- }
62295
- ),
62296
- isFormControl && /* @__PURE__ */ jsx(
62297
- SwitchBubbleInput,
62298
- {
62299
- control: button,
62300
- bubbles: !hasConsumerStoppedPropagationRef.current,
62301
- name,
62302
- value,
62303
- checked,
62304
- required,
62305
- disabled,
62306
- form,
62307
- style: { transform: "translateX(-100%)" }
62308
- }
62309
- )
62310
- ] });
62311
- }
62312
- );
62313
- Switch$1.displayName = SWITCH_NAME;
62314
- var THUMB_NAME = "SwitchThumb";
62315
- var SwitchThumb = React.forwardRef(
62316
- (props, forwardedRef) => {
62317
- const { __scopeSwitch, ...thumbProps } = props;
62318
- const context = useSwitchContext(THUMB_NAME, __scopeSwitch);
62319
- return /* @__PURE__ */ jsx(
62320
- Primitive$3.span,
62321
- {
62322
- "data-state": getState$2(context.checked),
62323
- "data-disabled": context.disabled ? "" : void 0,
62324
- ...thumbProps,
62325
- ref: forwardedRef
62326
- }
62327
- );
62328
- }
62329
- );
62330
- SwitchThumb.displayName = THUMB_NAME;
62331
- var BUBBLE_INPUT_NAME = "SwitchBubbleInput";
62332
- var SwitchBubbleInput = React.forwardRef(
62333
- ({
62334
- __scopeSwitch,
62335
- control,
62336
- checked,
62337
- bubbles = true,
62338
- ...props
62339
- }, forwardedRef) => {
62340
- const ref = React.useRef(null);
62341
- const composedRefs = useComposedRefs$1(ref, forwardedRef);
62342
- const prevChecked = usePrevious$1(checked);
62343
- const controlSize = useSize$1(control);
62344
- React.useEffect(() => {
62345
- const input = ref.current;
62346
- if (!input) return;
62347
- const inputProto = window.HTMLInputElement.prototype;
62348
- const descriptor = Object.getOwnPropertyDescriptor(
62349
- inputProto,
62350
- "checked"
62351
- );
62352
- const setChecked = descriptor.set;
62353
- if (prevChecked !== checked && setChecked) {
62354
- const event = new Event("click", { bubbles });
62355
- setChecked.call(input, checked);
62356
- input.dispatchEvent(event);
62357
- }
62358
- }, [prevChecked, checked, bubbles]);
62359
- return /* @__PURE__ */ jsx(
62360
- "input",
62361
- {
62362
- type: "checkbox",
62363
- "aria-hidden": true,
62364
- defaultChecked: checked,
62365
- ...props,
62366
- tabIndex: -1,
62367
- ref: composedRefs,
62368
- style: {
62369
- ...props.style,
62370
- ...controlSize,
62371
- position: "absolute",
62372
- pointerEvents: "none",
62373
- opacity: 0,
62374
- margin: 0
62375
- }
62376
- }
62377
- );
62378
- }
62379
- );
62380
- SwitchBubbleInput.displayName = BUBBLE_INPUT_NAME;
62381
- function getState$2(checked) {
62382
- return checked ? "checked" : "unchecked";
62383
- }
62384
- var Root$9 = Switch$1;
62385
- var Thumb = SwitchThumb;
62386
-
62387
- const Switch = React.forwardRef(({ className, ...props }, ref) => (jsx(Root$9, { className: cn("peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input", className), ...props, ref: ref, children: jsx(Thumb, { className: cn("pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0") }) })));
62388
- Switch.displayName = Root$9.displayName;
62389
-
62390
62677
  var DISMISSABLE_LAYER_NAME = "DismissableLayer";
62391
62678
  var CONTEXT_UPDATE = "dismissableLayer.update";
62392
62679
  var POINTER_DOWN_OUTSIDE = "dismissableLayer.pointerDownOutside";
@@ -62607,7 +62894,7 @@ var Arrow$1 = React.forwardRef((props, forwardedRef) => {
62607
62894
  );
62608
62895
  });
62609
62896
  Arrow$1.displayName = NAME$4;
62610
- var Root$8 = Arrow$1;
62897
+ var Root$9 = Arrow$1;
62611
62898
 
62612
62899
  var POPPER_NAME = "Popper";
62613
62900
  var [createPopperContext, createPopperScope] = createContextScope$1(POPPER_NAME);
@@ -62815,7 +63102,7 @@ var PopperArrow = React.forwardRef(function PopperArrow2(props, forwardedRef) {
62815
63102
  visibility: contentContext.shouldHideArrow ? "hidden" : void 0
62816
63103
  },
62817
63104
  children: /* @__PURE__ */ jsx(
62818
- Root$8,
63105
+ Root$9,
62819
63106
  {
62820
63107
  ...arrowProps,
62821
63108
  ref: forwardedRef,
@@ -62912,7 +63199,7 @@ var VisuallyHidden = React.forwardRef(
62912
63199
  }
62913
63200
  );
62914
63201
  VisuallyHidden.displayName = NAME$3;
62915
- var Root$7 = VisuallyHidden;
63202
+ var Root$8 = VisuallyHidden;
62916
63203
 
62917
63204
  var [createTooltipContext, createTooltipScope] = createContextScope$1("Tooltip", [
62918
63205
  createPopperScope
@@ -63245,7 +63532,7 @@ var TooltipContentImpl = React.forwardRef(
63245
63532
  },
63246
63533
  children: [
63247
63534
  /* @__PURE__ */ jsx(Slottable$2, { children }),
63248
- /* @__PURE__ */ jsx(VisuallyHiddenContentContextProvider, { scope: __scopeTooltip, isInside: true, children: /* @__PURE__ */ jsx(Root$7, { id: context.contentId, role: "tooltip", children: ariaLabel || children }) })
63535
+ /* @__PURE__ */ jsx(VisuallyHiddenContentContextProvider, { scope: __scopeTooltip, isInside: true, children: /* @__PURE__ */ jsx(Root$8, { id: context.contentId, role: "tooltip", children: ariaLabel || children }) })
63249
63536
  ]
63250
63537
  }
63251
63538
  )
@@ -63402,6 +63689,150 @@ function TooltipContent({ className, sideOffset = 0, children, ...props }) {
63402
63689
  return (jsx(Portal$2, { children: jsxs(Content2$4, { "data-slot": "tooltip-content", sideOffset: sideOffset, className: cn("bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance", className), ...props, children: [children, jsx(Arrow2$1, { className: "bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" })] }) }));
63403
63690
  }
63404
63691
 
63692
+ var SWITCH_NAME = "Switch";
63693
+ var [createSwitchContext, createSwitchScope] = createContextScope$1(SWITCH_NAME);
63694
+ var [SwitchProvider, useSwitchContext] = createSwitchContext(SWITCH_NAME);
63695
+ var Switch$1 = React.forwardRef(
63696
+ (props, forwardedRef) => {
63697
+ const {
63698
+ __scopeSwitch,
63699
+ name,
63700
+ checked: checkedProp,
63701
+ defaultChecked,
63702
+ required,
63703
+ disabled,
63704
+ value = "on",
63705
+ onCheckedChange,
63706
+ form,
63707
+ ...switchProps
63708
+ } = props;
63709
+ const [button, setButton] = React.useState(null);
63710
+ const composedRefs = useComposedRefs$1(forwardedRef, (node) => setButton(node));
63711
+ const hasConsumerStoppedPropagationRef = React.useRef(false);
63712
+ const isFormControl = button ? form || !!button.closest("form") : true;
63713
+ const [checked, setChecked] = useControllableState$1({
63714
+ prop: checkedProp,
63715
+ defaultProp: defaultChecked ?? false,
63716
+ onChange: onCheckedChange,
63717
+ caller: SWITCH_NAME
63718
+ });
63719
+ return /* @__PURE__ */ jsxs(SwitchProvider, { scope: __scopeSwitch, checked, disabled, children: [
63720
+ /* @__PURE__ */ jsx(
63721
+ Primitive$3.button,
63722
+ {
63723
+ type: "button",
63724
+ role: "switch",
63725
+ "aria-checked": checked,
63726
+ "aria-required": required,
63727
+ "data-state": getState$2(checked),
63728
+ "data-disabled": disabled ? "" : void 0,
63729
+ disabled,
63730
+ value,
63731
+ ...switchProps,
63732
+ ref: composedRefs,
63733
+ onClick: composeEventHandlers$1(props.onClick, (event) => {
63734
+ setChecked((prevChecked) => !prevChecked);
63735
+ if (isFormControl) {
63736
+ hasConsumerStoppedPropagationRef.current = event.isPropagationStopped();
63737
+ if (!hasConsumerStoppedPropagationRef.current) event.stopPropagation();
63738
+ }
63739
+ })
63740
+ }
63741
+ ),
63742
+ isFormControl && /* @__PURE__ */ jsx(
63743
+ SwitchBubbleInput,
63744
+ {
63745
+ control: button,
63746
+ bubbles: !hasConsumerStoppedPropagationRef.current,
63747
+ name,
63748
+ value,
63749
+ checked,
63750
+ required,
63751
+ disabled,
63752
+ form,
63753
+ style: { transform: "translateX(-100%)" }
63754
+ }
63755
+ )
63756
+ ] });
63757
+ }
63758
+ );
63759
+ Switch$1.displayName = SWITCH_NAME;
63760
+ var THUMB_NAME = "SwitchThumb";
63761
+ var SwitchThumb = React.forwardRef(
63762
+ (props, forwardedRef) => {
63763
+ const { __scopeSwitch, ...thumbProps } = props;
63764
+ const context = useSwitchContext(THUMB_NAME, __scopeSwitch);
63765
+ return /* @__PURE__ */ jsx(
63766
+ Primitive$3.span,
63767
+ {
63768
+ "data-state": getState$2(context.checked),
63769
+ "data-disabled": context.disabled ? "" : void 0,
63770
+ ...thumbProps,
63771
+ ref: forwardedRef
63772
+ }
63773
+ );
63774
+ }
63775
+ );
63776
+ SwitchThumb.displayName = THUMB_NAME;
63777
+ var BUBBLE_INPUT_NAME = "SwitchBubbleInput";
63778
+ var SwitchBubbleInput = React.forwardRef(
63779
+ ({
63780
+ __scopeSwitch,
63781
+ control,
63782
+ checked,
63783
+ bubbles = true,
63784
+ ...props
63785
+ }, forwardedRef) => {
63786
+ const ref = React.useRef(null);
63787
+ const composedRefs = useComposedRefs$1(ref, forwardedRef);
63788
+ const prevChecked = usePrevious$1(checked);
63789
+ const controlSize = useSize$1(control);
63790
+ React.useEffect(() => {
63791
+ const input = ref.current;
63792
+ if (!input) return;
63793
+ const inputProto = window.HTMLInputElement.prototype;
63794
+ const descriptor = Object.getOwnPropertyDescriptor(
63795
+ inputProto,
63796
+ "checked"
63797
+ );
63798
+ const setChecked = descriptor.set;
63799
+ if (prevChecked !== checked && setChecked) {
63800
+ const event = new Event("click", { bubbles });
63801
+ setChecked.call(input, checked);
63802
+ input.dispatchEvent(event);
63803
+ }
63804
+ }, [prevChecked, checked, bubbles]);
63805
+ return /* @__PURE__ */ jsx(
63806
+ "input",
63807
+ {
63808
+ type: "checkbox",
63809
+ "aria-hidden": true,
63810
+ defaultChecked: checked,
63811
+ ...props,
63812
+ tabIndex: -1,
63813
+ ref: composedRefs,
63814
+ style: {
63815
+ ...props.style,
63816
+ ...controlSize,
63817
+ position: "absolute",
63818
+ pointerEvents: "none",
63819
+ opacity: 0,
63820
+ margin: 0
63821
+ }
63822
+ }
63823
+ );
63824
+ }
63825
+ );
63826
+ SwitchBubbleInput.displayName = BUBBLE_INPUT_NAME;
63827
+ function getState$2(checked) {
63828
+ return checked ? "checked" : "unchecked";
63829
+ }
63830
+ var Root$7 = Switch$1;
63831
+ var Thumb = SwitchThumb;
63832
+
63833
+ const Switch = React.forwardRef(({ className, ...props }, ref) => (jsx(Root$7, { className: cn("peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input", className), ...props, ref: ref, children: jsx(Thumb, { className: cn("pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0") }) })));
63834
+ Switch.displayName = Root$7.displayName;
63835
+
63405
63836
  // packages/react/context/src/createContext.tsx
63406
63837
  function createContextScope(scopeName, createContextScopeDeps = []) {
63407
63838
  let defaultContexts = [];
@@ -63695,7 +64126,323 @@ var Indicator$1 = ProgressIndicator;
63695
64126
  const Progress = React.forwardRef(({ className, value, ...props }, ref) => (jsx(Root$6, { ref: ref, className: cn('bg-secondary relative h-4 w-full overflow-hidden rounded-full', className), ...props, children: jsx(Indicator$1, { className: "bg-primary h-full w-full flex-1 transition-all", style: { transform: `translateX(-${100 - (value || 0)}%)` } }) })));
63696
64127
  Progress.displayName = Root$6.displayName;
63697
64128
 
64129
+ var SLOTTABLE_IDENTIFIER = Symbol("radix.slottable");
64130
+ // @__NO_SIDE_EFFECTS__
64131
+ function createSlottable(ownerName) {
64132
+ const Slottable2 = ({ children }) => {
64133
+ return /* @__PURE__ */ jsx(Fragment$1, { children });
64134
+ };
64135
+ Slottable2.displayName = `${ownerName}.Slottable`;
64136
+ Slottable2.__radixId = SLOTTABLE_IDENTIFIER;
64137
+ return Slottable2;
64138
+ }
64139
+
64140
+ var ROOT_NAME = "AlertDialog";
64141
+ var [createAlertDialogContext, createAlertDialogScope] = createContextScope$1(ROOT_NAME, [
64142
+ createDialogScope
64143
+ ]);
64144
+ var useDialogScope = createDialogScope();
64145
+ var AlertDialog$1 = (props) => {
64146
+ const { __scopeAlertDialog, ...alertDialogProps } = props;
64147
+ const dialogScope = useDialogScope(__scopeAlertDialog);
64148
+ return /* @__PURE__ */ jsx(DialogPrimitive.Root, { ...dialogScope, ...alertDialogProps, modal: true });
64149
+ };
64150
+ AlertDialog$1.displayName = ROOT_NAME;
64151
+ var TRIGGER_NAME$3 = "AlertDialogTrigger";
64152
+ var AlertDialogTrigger = React.forwardRef(
64153
+ (props, forwardedRef) => {
64154
+ const { __scopeAlertDialog, ...triggerProps } = props;
64155
+ const dialogScope = useDialogScope(__scopeAlertDialog);
64156
+ return /* @__PURE__ */ jsx(DialogPrimitive.Trigger, { ...dialogScope, ...triggerProps, ref: forwardedRef });
64157
+ }
64158
+ );
64159
+ AlertDialogTrigger.displayName = TRIGGER_NAME$3;
64160
+ var PORTAL_NAME$3 = "AlertDialogPortal";
64161
+ var AlertDialogPortal$1 = (props) => {
64162
+ const { __scopeAlertDialog, ...portalProps } = props;
64163
+ const dialogScope = useDialogScope(__scopeAlertDialog);
64164
+ return /* @__PURE__ */ jsx(DialogPrimitive.Portal, { ...dialogScope, ...portalProps });
64165
+ };
64166
+ AlertDialogPortal$1.displayName = PORTAL_NAME$3;
64167
+ var OVERLAY_NAME = "AlertDialogOverlay";
64168
+ var AlertDialogOverlay$1 = React.forwardRef(
64169
+ (props, forwardedRef) => {
64170
+ const { __scopeAlertDialog, ...overlayProps } = props;
64171
+ const dialogScope = useDialogScope(__scopeAlertDialog);
64172
+ return /* @__PURE__ */ jsx(DialogPrimitive.Overlay, { ...dialogScope, ...overlayProps, ref: forwardedRef });
64173
+ }
64174
+ );
64175
+ AlertDialogOverlay$1.displayName = OVERLAY_NAME;
64176
+ var CONTENT_NAME$4 = "AlertDialogContent";
64177
+ var [AlertDialogContentProvider, useAlertDialogContentContext] = createAlertDialogContext(CONTENT_NAME$4);
64178
+ var Slottable = createSlottable("AlertDialogContent");
64179
+ var AlertDialogContent$1 = React.forwardRef(
64180
+ (props, forwardedRef) => {
64181
+ const { __scopeAlertDialog, children, ...contentProps } = props;
64182
+ const dialogScope = useDialogScope(__scopeAlertDialog);
64183
+ const contentRef = React.useRef(null);
64184
+ const composedRefs = useComposedRefs$1(forwardedRef, contentRef);
64185
+ const cancelRef = React.useRef(null);
64186
+ return /* @__PURE__ */ jsx(
64187
+ DialogPrimitive.WarningProvider,
64188
+ {
64189
+ contentName: CONTENT_NAME$4,
64190
+ titleName: TITLE_NAME,
64191
+ docsSlug: "alert-dialog",
64192
+ children: /* @__PURE__ */ jsx(AlertDialogContentProvider, { scope: __scopeAlertDialog, cancelRef, children: /* @__PURE__ */ jsxs(
64193
+ DialogPrimitive.Content,
64194
+ {
64195
+ role: "alertdialog",
64196
+ ...dialogScope,
64197
+ ...contentProps,
64198
+ ref: composedRefs,
64199
+ onOpenAutoFocus: composeEventHandlers$2(contentProps.onOpenAutoFocus, (event) => {
64200
+ event.preventDefault();
64201
+ cancelRef.current?.focus({ preventScroll: true });
64202
+ }),
64203
+ onPointerDownOutside: (event) => event.preventDefault(),
64204
+ onInteractOutside: (event) => event.preventDefault(),
64205
+ children: [
64206
+ /* @__PURE__ */ jsx(Slottable, { children }),
64207
+ /* @__PURE__ */ jsx(DescriptionWarning, { contentRef })
64208
+ ]
64209
+ }
64210
+ ) })
64211
+ }
64212
+ );
64213
+ }
64214
+ );
64215
+ AlertDialogContent$1.displayName = CONTENT_NAME$4;
64216
+ var TITLE_NAME = "AlertDialogTitle";
64217
+ var AlertDialogTitle$1 = React.forwardRef(
64218
+ (props, forwardedRef) => {
64219
+ const { __scopeAlertDialog, ...titleProps } = props;
64220
+ const dialogScope = useDialogScope(__scopeAlertDialog);
64221
+ return /* @__PURE__ */ jsx(DialogPrimitive.Title, { ...dialogScope, ...titleProps, ref: forwardedRef });
64222
+ }
64223
+ );
64224
+ AlertDialogTitle$1.displayName = TITLE_NAME;
64225
+ var DESCRIPTION_NAME = "AlertDialogDescription";
64226
+ var AlertDialogDescription$1 = React.forwardRef((props, forwardedRef) => {
64227
+ const { __scopeAlertDialog, ...descriptionProps } = props;
64228
+ const dialogScope = useDialogScope(__scopeAlertDialog);
64229
+ return /* @__PURE__ */ jsx(DialogPrimitive.Description, { ...dialogScope, ...descriptionProps, ref: forwardedRef });
64230
+ });
64231
+ AlertDialogDescription$1.displayName = DESCRIPTION_NAME;
64232
+ var ACTION_NAME = "AlertDialogAction";
64233
+ var AlertDialogAction$1 = React.forwardRef(
64234
+ (props, forwardedRef) => {
64235
+ const { __scopeAlertDialog, ...actionProps } = props;
64236
+ const dialogScope = useDialogScope(__scopeAlertDialog);
64237
+ return /* @__PURE__ */ jsx(DialogPrimitive.Close, { ...dialogScope, ...actionProps, ref: forwardedRef });
64238
+ }
64239
+ );
64240
+ AlertDialogAction$1.displayName = ACTION_NAME;
64241
+ var CANCEL_NAME = "AlertDialogCancel";
64242
+ var AlertDialogCancel$1 = React.forwardRef(
64243
+ (props, forwardedRef) => {
64244
+ const { __scopeAlertDialog, ...cancelProps } = props;
64245
+ const { cancelRef } = useAlertDialogContentContext(CANCEL_NAME, __scopeAlertDialog);
64246
+ const dialogScope = useDialogScope(__scopeAlertDialog);
64247
+ const ref = useComposedRefs$1(forwardedRef, cancelRef);
64248
+ return /* @__PURE__ */ jsx(DialogPrimitive.Close, { ...dialogScope, ...cancelProps, ref });
64249
+ }
64250
+ );
64251
+ AlertDialogCancel$1.displayName = CANCEL_NAME;
64252
+ var DescriptionWarning = ({ contentRef }) => {
64253
+ const MESSAGE = `\`${CONTENT_NAME$4}\` requires a description for the component to be accessible for screen reader users.
64254
+
64255
+ You can add a description to the \`${CONTENT_NAME$4}\` by passing a \`${DESCRIPTION_NAME}\` component as a child, which also benefits sighted users by adding visible context to the dialog.
64256
+
64257
+ Alternatively, you can use your own component as a description by assigning it an \`id\` and passing the same value to the \`aria-describedby\` prop in \`${CONTENT_NAME$4}\`. If the description is confusing or duplicative for sighted users, you can use the \`@radix-ui/react-visually-hidden\` primitive as a wrapper around your description component.
64258
+
64259
+ For more information, see https://radix-ui.com/primitives/docs/components/alert-dialog`;
64260
+ React.useEffect(() => {
64261
+ const hasDescription = document.getElementById(
64262
+ contentRef.current?.getAttribute("aria-describedby")
64263
+ );
64264
+ if (!hasDescription) console.warn(MESSAGE);
64265
+ }, [MESSAGE, contentRef]);
64266
+ return null;
64267
+ };
64268
+ var Root2$4 = AlertDialog$1;
64269
+ var Portal2$1 = AlertDialogPortal$1;
64270
+ var Overlay2 = AlertDialogOverlay$1;
64271
+ var Content2$3 = AlertDialogContent$1;
64272
+ var Action = AlertDialogAction$1;
64273
+ var Cancel = AlertDialogCancel$1;
64274
+ var Title2 = AlertDialogTitle$1;
64275
+ var Description2 = AlertDialogDescription$1;
64276
+
64277
+ const AlertDialog = Root2$4;
64278
+ const AlertDialogPortal = Portal2$1;
64279
+ const AlertDialogOverlay = React.forwardRef(({ className, ...props }, ref) => (jsx(Overlay2, { className: cn('data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80', className), ...props, ref: ref })));
64280
+ AlertDialogOverlay.displayName = Overlay2.displayName;
64281
+ const AlertDialogContent = React.forwardRef(({ className, ...props }, ref) => (jsxs(AlertDialogPortal, { children: [jsx(AlertDialogOverlay, {}), jsx(Content2$3, { ref: ref, className: cn('bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg', className), ...props })] })));
64282
+ AlertDialogContent.displayName = Content2$3.displayName;
64283
+ const AlertDialogHeader = ({ className, ...props }) => (jsx("div", { className: cn('flex flex-col space-y-2 text-center sm:text-left', className), ...props }));
64284
+ AlertDialogHeader.displayName = 'AlertDialogHeader';
64285
+ const AlertDialogFooter = ({ className, ...props }) => (jsx("div", { className: cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className), ...props }));
64286
+ AlertDialogFooter.displayName = 'AlertDialogFooter';
64287
+ const AlertDialogTitle = React.forwardRef(({ className, ...props }, ref) => (jsx(Title2, { ref: ref, className: cn('text-lg font-semibold', className), ...props })));
64288
+ AlertDialogTitle.displayName = Title2.displayName;
64289
+ const AlertDialogDescription = React.forwardRef(({ className, ...props }, ref) => (jsx(Description2, { ref: ref, className: cn('text-muted-foreground text-sm', className), ...props })));
64290
+ AlertDialogDescription.displayName = Description2.displayName;
64291
+ const AlertDialogAction = React.forwardRef(({ className, ...props }, ref) => (jsx(Action, { ref: ref, className: cn(buttonVariants(), className), ...props })));
64292
+ AlertDialogAction.displayName = Action.displayName;
64293
+ const AlertDialogCancel = React.forwardRef(({ className, ...props }, ref) => (jsx(Cancel, { ref: ref, className: cn(buttonVariants({ variant: 'outline' }), 'mt-2 sm:mt-0', className), ...props })));
64294
+ AlertDialogCancel.displayName = Cancel.displayName;
64295
+
63698
64296
  const LOCAL_LLM_ENABLED_KEY = 'ibl_local_llm_enabled';
64297
+ const LOCAL_LLM_MODEL_KEY = 'ibl_local_llm_model';
64298
+ const LOCAL_LLM_TOOL_SUPPORT_KEY = 'ibl_local_llm_tool_support';
64299
+ /**
64300
+ * Curated catalog of small, on-device-friendly models from the Ollama library
64301
+ * (https://ollama.com/library). The model manager itself (Ollama) is not a
64302
+ * model and is intentionally absent — enabling Local Models installs it.
64303
+ */
64304
+ // `tool_support` reflects whether the model advertises Tools / function calling
64305
+ // on its Ollama library page (ollama.com/library/<model>), used by the host to
64306
+ // route to the MCP/tool proxy on :8000 vs plain Ollama on :11434. Verified Jun
64307
+ // 2026 from the per-model capability badges; adjust as Ollama support changes.
64308
+ // Only tool / function-calling capable models are listed (the local manager is
64309
+ // for tool-using chat). `tool_support` is kept on the type/contract — persisted
64310
+ // on select and read by the host to route to the MCP/tool proxy (:8000).
64311
+ const LOCAL_MODELS = [
64312
+ { name: 'Phi-4 Mini', provider: 'Microsoft', id: 'phi4-mini:latest', size: '2.5 GB', tool_support: true },
64313
+ { name: 'Llama 3.2', provider: 'Meta', id: 'llama3.2', size: '2.0 GB', tool_support: true },
64314
+ { name: 'Qwen 3', provider: 'Alibaba', id: 'qwen3', size: '5.2 GB', tool_support: true },
64315
+ { name: 'Mistral', provider: 'Mistral AI', id: 'mistral', size: '4.4 GB', tool_support: true },
64316
+ { name: 'DeepSeek-R1', provider: 'DeepSeek', id: 'deepseek-r1', size: '5.2 GB', tool_support: true },
64317
+ { name: 'Granite 4.1', provider: 'IBM', id: 'granite4.1:8b', size: '5.3 GB', tool_support: true },
64318
+ { name: 'GPT-OSS 20B', provider: 'OpenAI', id: 'gpt-oss:20b', size: '14 GB', tool_support: true },
64319
+ // Larger models. Sizes use "GB" so they parse for the System Control size gate
64320
+ // (only models above the configured gate can use System Control).
64321
+ { name: 'Qwen 3.6', provider: 'Alibaba', id: 'qwen3.6:latest', size: '24 GB', tool_support: true },
64322
+ { name: 'Gemma 4 31B', provider: 'Google', id: 'gemma4:31b', size: '20 GB', tool_support: true },
64323
+ { name: 'Nemotron 3 33B', provider: 'NVIDIA', id: 'nemotron3:33b', size: '28 GB', tool_support: true },
64324
+ { name: 'Nemotron 3 Super 120B', provider: 'NVIDIA', id: 'nemotron-3-super:120b', size: '87 GB', tool_support: true },
64325
+ ];
64326
+ /** The model wired to the existing single-model download flow (default selection). */
64327
+ const PRIMARY_MODEL_ID = 'phi4-mini:latest';
64328
+ /**
64329
+ * Whether a catalog model id (e.g. "llama3.2", "phi3:mini") is present among the
64330
+ * installed Ollama tags reported by the backend (e.g. "llama3.2:latest"). Matches
64331
+ * an exact tag or the same base model with any tag suffix, so a model pulled as
64332
+ * `<id>:latest` still counts as installed.
64333
+ */
64334
+ function isModelInstalled(modelId, installedTags) {
64335
+ if (!installedTags)
64336
+ return false;
64337
+ return installedTags.some((tag) => tag === modelId || tag.startsWith(`${modelId}:`));
64338
+ }
64339
+ /**
64340
+ * Whether a model id is an Ollama cloud-hosted model — either the plain ":cloud"
64341
+ * tag (e.g. "glm-5.2:cloud") or a sized cloud tag (e.g. "gemma4:31b-cloud").
64342
+ * Cloud models run on Ollama's servers, so they are available by default — never
64343
+ * downloaded, no local memory required, always "ready".
64344
+ */
64345
+ function isCloudModelId(modelId) {
64346
+ return (modelId.endsWith(':cloud') ||
64347
+ (modelId.includes(':') && modelId.endsWith('-cloud')));
64348
+ }
64349
+ /**
64350
+ * Fraction of the machine's memory above which a model is treated as "too large"
64351
+ * and a confirmation is required before downloading. TESTING VALUE — set low (1%)
64352
+ * so the warning is easy to trigger; raise toward real capacity (e.g. 0.8) later.
64353
+ */
64354
+ const MODEL_SIZE_WARN_FRACTION = 0.01;
64355
+ /** Multipliers for the size units used in the catalog (binary / 1024-based). */
64356
+ const SIZE_UNIT_BYTES = {
64357
+ B: 1,
64358
+ KB: 1024,
64359
+ MB: 1024 ** 2,
64360
+ GB: 1024 ** 3,
64361
+ TB: 1024 ** 4,
64362
+ };
64363
+ /**
64364
+ * Parse a human catalog size like "2.2 GB" into bytes, or null if unrecognized.
64365
+ */
64366
+ function parseModelSizeBytes(size) {
64367
+ var _a;
64368
+ const match = /([\d.]+)\s*(TB|GB|MB|KB|B)/i.exec(size);
64369
+ if (!match)
64370
+ return null;
64371
+ const value = parseFloat(match[1]);
64372
+ if (Number.isNaN(value))
64373
+ return null;
64374
+ return value * ((_a = SIZE_UNIT_BYTES[match[2].toUpperCase()]) !== null && _a !== void 0 ? _a : 1);
64375
+ }
64376
+ /** Format a byte count as a short, human-readable size (e.g. "16.0 GB"). */
64377
+ function formatBytes(bytes) {
64378
+ if (bytes <= 0)
64379
+ return '0 GB';
64380
+ const gb = bytes / 1024 ** 3;
64381
+ if (gb >= 1)
64382
+ return `${gb.toFixed(1)} GB`;
64383
+ return `${Math.round(bytes / 1024 ** 2)} MB`;
64384
+ }
64385
+ /**
64386
+ * The memory a model can use on this machine: the larger of system RAM and GPU
64387
+ * VRAM (a model runs in one or the other). Returns 0 when memory is unknown.
64388
+ */
64389
+ function usableMemoryBytes(systemMemory) {
64390
+ if (!systemMemory)
64391
+ return 0;
64392
+ return Math.max(systemMemory.ram_total, systemMemory.vram_total);
64393
+ }
64394
+ /**
64395
+ * Whether `model` is large enough relative to this machine's memory to warrant a
64396
+ * "might not run" confirmation. False when memory or the model size is unknown,
64397
+ * so the download simply proceeds rather than warning on incomplete data.
64398
+ */
64399
+ function modelExceedsCapacity(model, systemMemory) {
64400
+ const capacity = usableMemoryBytes(systemMemory);
64401
+ const modelBytes = parseModelSizeBytes(model.size);
64402
+ if (modelBytes == null)
64403
+ return false;
64404
+ return modelBytes > capacity * MODEL_SIZE_WARN_FRACTION;
64405
+ }
64406
+ /**
64407
+ * Default minimum model size (GB) that can use the System Control Manager
64408
+ * (GhostOS MCP/tools). Smaller models don't support tools/MCP well, so the
64409
+ * manager is gated to models above this size. Per-app overridable via the
64410
+ * System Control card's `requiredSizeGb` prop (see SystemControlTabProps).
64411
+ */
64412
+ const DEFAULT_SYSTEM_CONTROL_REQUIRED_SIZE_GB = 12;
64413
+ /**
64414
+ * Whether the given model (by Ollama id) is large enough to use the System
64415
+ * Control Manager — i.e. its catalog size exceeds `gb` (default
64416
+ * {@link DEFAULT_SYSTEM_CONTROL_REQUIRED_SIZE_GB}). Unknown ids or unparseable
64417
+ * sizes return false (gated off).
64418
+ */
64419
+ function modelSupportsSystemControl(modelId, gb = DEFAULT_SYSTEM_CONTROL_REQUIRED_SIZE_GB) {
64420
+ if (!modelId)
64421
+ return false;
64422
+ const model = LOCAL_MODELS.find((m) => m.id === modelId);
64423
+ if (!model)
64424
+ return false;
64425
+ const bytes = parseModelSizeBytes(model.size);
64426
+ if (bytes == null)
64427
+ return false;
64428
+ return bytes > gb * 1024 ** 3;
64429
+ }
64430
+ /**
64431
+ * The smallest catalog model that can use the System Control Manager (size
64432
+ * exceeds `gb`), or null if none qualify. Used by the "Upgrade" action to pick
64433
+ * the lightest capable model. Ties / unparseable sizes sort last.
64434
+ */
64435
+ function smallestSystemControlModel(gb = DEFAULT_SYSTEM_CONTROL_REQUIRED_SIZE_GB) {
64436
+ const usable = LOCAL_MODELS.filter((m) => modelSupportsSystemControl(m.id, gb));
64437
+ if (usable.length === 0)
64438
+ return null;
64439
+ return usable.reduce((smallest, m) => {
64440
+ var _a, _b;
64441
+ const a = (_a = parseModelSizeBytes(m.size)) !== null && _a !== void 0 ? _a : Infinity;
64442
+ const b = (_b = parseModelSizeBytes(smallest.size)) !== null && _b !== void 0 ? _b : Infinity;
64443
+ return a < b ? m : smallest;
64444
+ });
64445
+ }
63699
64446
  /**
63700
64447
  * Check if local LLM is enabled from localStorage
63701
64448
  */
@@ -63712,13 +64459,75 @@ function setLocalLLMEnabled(enabled) {
63712
64459
  return;
63713
64460
  localStorage.setItem(LOCAL_LLM_ENABLED_KEY, String(enabled));
63714
64461
  }
63715
- function LocalLLMTab({ isAvailable, state, ollamaStatus, isUsingFoundry = false, foundryModels = [], selectedFoundryModel = null, foundryStatus, onStartDownload, onCancelDownload, onInstallOllama, onInstallFoundry, onCheckStatus, onResetState, onSelectFoundryModel, }) {
63716
- var _a, _b, _c, _d, _e;
64462
+ /**
64463
+ * Get the model the user has chosen to chat with (Ollama pull id), or null.
64464
+ */
64465
+ function getLocalLLMModel() {
64466
+ if (typeof window === 'undefined')
64467
+ return null;
64468
+ return localStorage.getItem(LOCAL_LLM_MODEL_KEY);
64469
+ }
64470
+ /**
64471
+ * Set the model the user has chosen to chat with (Ollama pull id).
64472
+ */
64473
+ function setLocalLLMModel(modelId) {
64474
+ if (typeof window === 'undefined')
64475
+ return;
64476
+ localStorage.setItem(LOCAL_LLM_MODEL_KEY, modelId);
64477
+ }
64478
+ /**
64479
+ * Whether the model the user selected supports tools / function calling
64480
+ * (persisted alongside the model id). The host (e.g. ghost-os) reads this to
64481
+ * route chat to the MCP/tool proxy (:8000) vs plain Ollama (:11434). Defaults to
64482
+ * false when unknown. See {@link LocalModel.tool_support}.
64483
+ */
64484
+ function getLocalLLMToolSupport() {
64485
+ if (typeof window === 'undefined')
64486
+ return false;
64487
+ return localStorage.getItem(LOCAL_LLM_TOOL_SUPPORT_KEY) === 'true';
64488
+ }
64489
+ /**
64490
+ * Persist whether the selected model supports tools (set when a model is chosen).
64491
+ */
64492
+ function setLocalLLMToolSupport(toolSupport) {
64493
+ if (typeof window === 'undefined')
64494
+ return;
64495
+ localStorage.setItem(LOCAL_LLM_TOOL_SUPPORT_KEY, String(toolSupport));
64496
+ }
64497
+ function LocalLLMTab({ isAvailable, state, ollamaStatus, systemMemory, isUsingFoundry = false, foundryModels = [], selectedFoundryModel = null, foundryStatus, onStartDownload, onCancelDownload, onInstallOllama, onStopManager, onInstallFoundry, onCheckStatus, onResetState, onSelectFoundryModel, }) {
64498
+ var _a, _b, _c, _d, _e, _f, _g;
64499
+ // Direct Tauri access so the model-size check can read system memory fresh at
64500
+ // download-click time (the threaded `systemMemory` prop is only a fast path).
64501
+ const { invoke } = useTauri();
63717
64502
  const isDownloading = state.status === 'downloading';
63718
- const isModelReady = state.status === 'completed' || (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.model_installed);
63719
64503
  const isManagerInstalling = state.managerInstalling || (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installing);
63720
64504
  // User preference state - independent of whether model is installed
63721
64505
  const [isEnabled, setIsEnabled] = useState(() => isLocalLLMEnabled());
64506
+ // Which model the shared download flow currently targets. Prefer the model
64507
+ // recorded in the persisted download state, so the correct row shows progress
64508
+ // even after the dialog is closed and reopened mid-download; fall back to a
64509
+ // local value for immediate feedback the instant a Download button is clicked.
64510
+ const [localActiveModelId, setLocalActiveModelId] = useState(PRIMARY_MODEL_ID);
64511
+ const activeModelId = state.status === 'downloading' && state.activeModel ? state.activeModel : localActiveModelId;
64512
+ // Which model the user has chosen to chat with (exclusive selection).
64513
+ const [selectedModelId, setSelectedModelId] = useState(() => getLocalLLMModel() || PRIMARY_MODEL_ID);
64514
+ // A model the user asked to download that is large relative to this machine's
64515
+ // memory. Set when we need the user to confirm a "might not run" warning before
64516
+ // starting the download; null when no confirmation is pending.
64517
+ const [pendingModel, setPendingModel] = useState(null);
64518
+ // "Enable Local Models" === run the model manager (Ollama). The toggle is a
64519
+ // user preference that is always operable: turning it on installs (if needed)
64520
+ // and starts the manager; turning it off stops it. The card + model table are
64521
+ // shown whenever the toggle is on (or mid-install), independent of install
64522
+ // state, so the user always gets feedback for their choice.
64523
+ const managerRunning = (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.running) === true;
64524
+ const localModelsEnabled = isEnabled || isManagerInstalling;
64525
+ // A model can be chosen for chat only once it is downloaded/ready. The backend
64526
+ // reports every installed model tag, so any downloaded model qualifies.
64527
+ const selectedModelReady = isCloudModelId(selectedModelId) ||
64528
+ isModelInstalled(selectedModelId, ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed_models) ||
64529
+ (selectedModelId === PRIMARY_MODEL_ID &&
64530
+ (state.status === 'completed' || (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.model_installed) === true));
63722
64531
  // Track previous model installation state to detect when it first becomes installed
63723
64532
  const [, setWasModelInstalled] = useState(() => {
63724
64533
  return (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.model_installed) === true;
@@ -63737,21 +64546,35 @@ function LocalLLMTab({ isAvailable, state, ollamaStatus, isUsingFoundry = false,
63737
64546
  const isNowInstalled = (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.model_installed) === true;
63738
64547
  setWasModelInstalled(isNowInstalled);
63739
64548
  }, [ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.model_installed]);
63740
- // Sync localStorage when user preference changes
64549
+ // Sync the app-facing "local LLM enabled" flag. It means "local models are
64550
+ // usable" (manager + a model ready), which is what the rest of the app reads.
63741
64551
  useEffect(() => {
63742
- // Save enabled state: when user enables it AND system is ready,
63743
- // it should stay enabled (even in offline mode)
63744
- if (isEnabled && isFullyReady) {
63745
- setLocalLLMEnabled(true);
63746
- }
63747
- else if (!isEnabled) {
63748
- // User explicitly disabled it
63749
- setLocalLLMEnabled(false);
64552
+ if (isUsingFoundry) {
64553
+ if (isEnabled && isFullyReady) {
64554
+ setLocalLLMEnabled(true);
64555
+ }
64556
+ else if (!isEnabled) {
64557
+ setLocalLLMEnabled(false);
64558
+ }
63750
64559
  }
63751
- // If user enabled but system not ready, don't save yet
63752
- }, [isEnabled, isFullyReady]);
64560
+ else {
64561
+ // Ollama path: the app-facing flag mirrors the user's toggle choice so the
64562
+ // rest of the app uses local models exactly when the user asked for it.
64563
+ setLocalLLMEnabled(isEnabled);
64564
+ }
64565
+ }, [isEnabled, isFullyReady, isUsingFoundry]);
64566
+ // While Local Models is enabled but the manager isn't running yet (it may still
64567
+ // be starting, or an earlier status check ran before Ollama was up and answered),
64568
+ // keep re-checking so the card flips to "Running" as soon as Ollama answers —
64569
+ // instead of being stuck showing a stale "stopped". Stops once running/disabled.
64570
+ useEffect(() => {
64571
+ if (isUsingFoundry || !isEnabled || managerRunning)
64572
+ return;
64573
+ const id = setInterval(() => onCheckStatus(), 2500);
64574
+ return () => clearInterval(id);
64575
+ }, [isUsingFoundry, isEnabled, managerRunning, onCheckStatus]);
63753
64576
  if (!isAvailable) {
63754
- return (jsx("div", { className: "max-w-2xl space-y-6", children: jsx("div", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Local LLM features are only available in the desktop app." }) }));
64577
+ return (jsx("div", { className: "space-y-6", children: jsx("div", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Local Models features are only available in the desktop app." }) }));
63755
64578
  }
63756
64579
  // Check if we should show Foundry installation UI
63757
64580
  const shouldShowFoundryInstall = foundryStatus && foundryStatus.is_supported && !foundryStatus.has_models && !isUsingFoundry;
@@ -63798,56 +64621,328 @@ function LocalLLMTab({ isAvailable, state, ollamaStatus, isUsingFoundry = false,
63798
64621
  }, 100);
63799
64622
  }
63800
64623
  }, [shouldShowFoundryInstall, onInstallFoundry, hasAutoStarted, state.status]);
63801
- const showInstallManagerButton = ollamaStatus !== null && !(ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed);
63802
- const needsModelDownload = (state.status === 'idle' || state.status === 'cancelled' || state.status === 'error') &&
63803
- (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed) &&
63804
- !(ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.model_installed);
63805
64624
  const handleToggle = (checked) => {
64625
+ // Always reflect the user's intent — the toggle is operable in both directions.
64626
+ setIsEnabled(checked);
64627
+ // Foundry readiness is driven separately (download/load a model), so for the
64628
+ // Foundry path the toggle is just a preference.
64629
+ if (isUsingFoundry)
64630
+ return;
64631
+ // Ollama path: "Enable Local Models" === run the model manager.
63806
64632
  if (checked) {
63807
- // User wants to enable
63808
- if (isModelReady) {
63809
- // Model already installed, just enable the preference
63810
- setIsEnabled(true);
63811
- }
63812
- else if (showInstallManagerButton && !isManagerInstalling) {
63813
- // Need to install Model Manager first
64633
+ // Ensure the manager is installed AND running (install_ollama does both;
64634
+ // it also starts it if it's installed but stopped).
64635
+ if (!isManagerInstalling) {
63814
64636
  onInstallOllama();
63815
64637
  }
63816
- else if (needsModelDownload) {
63817
- // Need to download the model
63818
- onStartDownload();
63819
- }
63820
64638
  }
63821
64639
  else {
63822
- // User wants to disable - always allow this
63823
- setIsEnabled(false);
64640
+ // Disabling stops the model manager.
64641
+ onStopManager === null || onStopManager === void 0 ? void 0 : onStopManager();
64642
+ }
64643
+ };
64644
+ const startDownloadNow = (modelId) => {
64645
+ setLocalActiveModelId(modelId);
64646
+ onStartDownload(modelId);
64647
+ };
64648
+ const handleDownloadModel = async (modelId) => {
64649
+ // Always read system memory FIRST — this is the call that hits the backend
64650
+ // `get_system_memory`. Doing it before the catalog lookup guarantees it runs
64651
+ // on every Download click (falling back to the value fetched on mount).
64652
+ const model = LOCAL_MODELS.find((m) => modelId.startsWith(m.id));
64653
+ if (!model) {
64654
+ await invoke(TAURI_COMMANDS.LOG_STDOUT, { s: `[Local Models] -> Download: bad download request, model ${model}` });
64655
+ console.log(`[Local Models] -> Download: bad download request, model ${model}`);
64656
+ return;
63824
64657
  }
64658
+ let mem = null;
64659
+ try {
64660
+ mem = await invoke(TAURI_COMMANDS.GET_SYSTEM_MEMORY);
64661
+ }
64662
+ catch (e) {
64663
+ await invoke(TAURI_COMMANDS.LOG_STDOUT, { s: `[Local Models] -> Download: couldn't detect system memory ${modelId} ${e}` });
64664
+ console.log(`[Local Models] -> Download: couldn't detect system memory {e}`);
64665
+ return;
64666
+ }
64667
+ const exceeds = modelExceedsCapacity(model, mem);
64668
+ console.warn('[Local Models] -> Download: download click', {
64669
+ modelId,
64670
+ systemMemory: mem,
64671
+ capacityBytes: usableMemoryBytes(mem),
64672
+ modelBytes: parseModelSizeBytes(model.size),
64673
+ thresholdBytes: usableMemoryBytes(mem) * MODEL_SIZE_WARN_FRACTION,
64674
+ exceeds,
64675
+ });
64676
+ if (exceeds) {
64677
+ setPendingModel(model);
64678
+ return;
64679
+ }
64680
+ startDownloadNow(modelId);
63825
64681
  };
63826
- // The switch should be checked if user preference is enabled AND system is ready
63827
- const switchChecked = isEnabled && isFullyReady;
64682
+ const confirmPendingDownload = () => {
64683
+ if (pendingModel) {
64684
+ startDownloadNow(pendingModel.id);
64685
+ }
64686
+ setPendingModel(null);
64687
+ };
64688
+ const handleSelectModel = (modelId) => {
64689
+ var _a, _b;
64690
+ setSelectedModelId(modelId);
64691
+ setLocalLLMModel(modelId);
64692
+ // Persist the model's tool-calling support so the host can route chat to the
64693
+ // MCP/tool proxy (:8000) vs plain Ollama (:11434).
64694
+ setLocalLLMToolSupport((_b = (_a = LOCAL_MODELS.find((m) => m.id === modelId)) === null || _a === void 0 ? void 0 : _a.tool_support) !== null && _b !== void 0 ? _b : false);
64695
+ };
64696
+ // For Ollama the switch reflects the user's toggle preference (always
64697
+ // operable, so it can be turned off). Foundry additionally requires a
64698
+ // downloaded model to be considered "on".
64699
+ const switchChecked = isUsingFoundry ? isEnabled && isFullyReady : isEnabled;
63828
64700
  // Determine switch disabled state based on which system is being used:
63829
- // For Foundry:
63830
- // - Disabled if Foundry is supported but no models are downloaded
63831
- // - Disabled if downloading or checking
63832
- // For Ollama (fallback):
63833
- // - Disabled if Ollama is not installed
63834
- // - Disabled if Phi model is not downloaded
63835
- // - Disabled if downloading, installing, or checking
64701
+ // For Foundry: disabled if no downloaded models, or while downloading/checking.
64702
+ // For Ollama: disabled only during a transient operation (installing/starting,
64703
+ // a model download, or a status check) — when idle it is always operable so
64704
+ // the user can turn local models off. (The "can't disable" bug was the
64705
+ // checked state being forced on, not this; see switchChecked.)
63836
64706
  const switchDisabled = isUsingFoundry
63837
- ? // Foundry: disable if no downloaded models or if currently downloading
63838
- !hasDownloadedFoundryModel || isDownloading || state.status === 'checking'
63839
- : // Ollama: disable if not fully set up
63840
- isDownloading ||
63841
- isManagerInstalling ||
63842
- state.status === 'checking' ||
63843
- !(ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed) ||
63844
- !(ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.model_installed);
63845
- return (jsx("div", { className: "max-w-2xl space-y-6", children: jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between rounded-lg border px-6 py-4", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-[#646464]", children: "Enable Local LLM" }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": "More info about Local LLM", className: "hidden sm:block", children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { className: "rounded-lg bg-gray-700 px-3 py-2 text-sm font-medium max-w-xs text-white shadow-sm transition-opacity duration-300 z-50", children: jsxs("div", { className: "space-y-2", children: [jsx("p", { children: "Work offline with AI capabilities on your device." }), (foundryStatus === null || foundryStatus === void 0 ? void 0 : foundryStatus.is_supported) && (jsx("p", { className: "text-xs text-gray-300", children: "Your device automatically uses the best offline AI option available." }))] }) })] }) })] }), jsx(Switch, { checked: switchChecked, onCheckedChange: handleToggle, disabled: switchDisabled, "aria-label": `Enable Local LLM ${switchChecked ? 'enabled' : 'disabled'}`, className: "cursor-pointer data-[state=checked]:bg-blue-500" })] }), shouldShowFoundryInstall ? (jsx("div", { className: "rounded-lg border px-6 py-4 bg-blue-50/30 dark:bg-blue-950/10", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs("div", { className: "space-y-4", children: [jsx("div", { className: "flex items-start gap-3", children: jsxs("div", { className: "flex items-center gap-2 flex-shrink-0 mt-0.5", children: [jsx(Star$1, { className: "h-5 w-5 text-blue-600 fill-blue-600" }), jsx("span", { className: "px-2 py-0.5 text-xs font-semibold bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300 rounded-full", children: "PREFERRED" })] }) }), jsxs("div", { className: "flex items-start gap-3", children: [jsx(Info$3, { className: "h-5 w-5 text-blue-500 flex-shrink-0 mt-0.5" }), jsxs("div", { className: "flex-1", children: [jsx("h3", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: "Setting up offline AI" }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: "Downloading optimized AI capabilities for your device. This enables you to work offline with full AI features." })] })] }), state.status === 'downloading' || state.status === 'checking' ? (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-700 dark:text-gray-300", children: state.message || 'Preparing download...' })] }), state.progress > 0 && jsx(Progress, { value: state.progress, className: "h-2" })] })) : state.status === 'error' ? (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2 text-red-600 dark:text-red-400", children: [jsx(CircleX, { className: "h-4 w-4" }), jsx("span", { className: "text-sm", children: state.error || 'Download failed' })] }), jsx("div", { className: "flex gap-2", children: jsxs(Button$1, { onClick: onInstallFoundry, size: "sm", variant: "outline", children: [jsx(RefreshCw, { className: "h-4 w-4 mr-2" }), "Try Again"] }) })] })) : (jsx("div", { className: "space-y-2", children: jsxs("div", { className: "flex items-center gap-2", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-700 dark:text-gray-300", children: "Starting download..." })] }) })), jsxs("div", { className: "text-xs text-gray-500 dark:text-gray-400", children: [jsx("p", { className: "font-medium mb-1", children: "Download size: ~500MB" }), jsx("p", { children: "This is a one-time setup to enable offline capabilities." })] })] }) })) : /* Requirements Table - Hidden when using Foundry Local */ !isUsingFoundry ? (jsxs(Fragment$1, { children: [(foundryStatus === null || foundryStatus === void 0 ? void 0 : foundryStatus.is_supported) && (jsx("div", { className: "rounded-lg border px-4 py-3 bg-blue-50/20 dark:bg-blue-950/10", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs("div", { className: "flex items-start gap-2", children: [jsx(Info$3, { className: "h-4 w-4 text-blue-600 flex-shrink-0 mt-0.5" }), jsxs("div", { className: "text-xs text-gray-600 dark:text-gray-400", children: [jsx("span", { className: "font-medium text-gray-900 dark:text-gray-100", children: "Note:" }), " Your device supports an optimized offline AI option. Currently using alternative setup. For best performance, download the recommended option above."] })] }) })), jsx("div", { className: "rounded-lg border overflow-hidden", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs("table", { className: "w-full", children: [jsx("thead", { children: jsxs("tr", { className: "bg-gray-50 dark:bg-gray-800/50", children: [jsx("th", { className: "px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider", children: "Component" }), jsx("th", { className: "px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider", children: "Status" }), jsx("th", { className: "px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider", children: "Action" })] }) }), jsxs("tbody", { className: "bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-800", children: [jsxs("tr", { children: [jsxs("td", { className: "px-6 py-4 whitespace-nowrap", children: [jsx("div", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: "Model Manager" }), jsx("div", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Required to run AI models locally" })] }), jsx("td", { className: "px-6 py-4", children: jsx("div", { className: "space-y-2", children: isManagerInstalling ? (jsxs("div", { className: "space-y-2", children: [jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300 rounded-full", children: [jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" }), "Installing..."] }), jsx("div", { className: "w-full max-w-[200px]", children: jsx(Progress, { value: state.managerInstallProgress || 0, className: "h-1.5" }) })] })) : (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed) ? (jsxs("div", { className: "flex items-center gap-2", children: [jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300 rounded-full", children: [jsx(CircleCheckBig, { className: "h-3 w-3" }), "Installed"] }), ollamaStatus.running && (jsx("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300 rounded-full", children: "Running" }))] })) : (jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300 rounded-full", children: [jsx(CircleX, { className: "h-3 w-3" }), "Not Installed"] })) }) }), jsxs("td", { className: "px-6 py-4 text-right", children: [showInstallManagerButton && !isManagerInstalling && (jsxs(Button$1, { onClick: onInstallOllama, size: "sm", variant: "outline", children: [jsx(Download, { className: "h-4 w-4 mr-2" }), "Install"] })), (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed) && (jsx(Button$1, { onClick: onCheckStatus, variant: "ghost", size: "sm", children: jsx(RefreshCw, { className: "h-4 w-4" }) }))] })] }), jsxs("tr", { children: [jsxs("td", { className: "px-6 py-4 whitespace-nowrap", children: [jsx("div", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: "AI Model (Phi-3 Mini)" }), jsx("div", { className: "text-xs text-gray-500 dark:text-gray-400", children: isDownloading ? state.message : 'Local language model for offline use' })] }), jsx("td", { className: "px-6 py-4", children: jsx("div", { className: "space-y-2", children: isDownloading ? (jsxs("div", { className: "space-y-2", children: [jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300 rounded-full", children: [jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" }), Math.round(state.progress), "%"] }), jsx("div", { className: "w-full max-w-[200px]", children: jsx(Progress, { value: state.progress, className: "h-1.5" }) })] })) : state.status === 'checking' ? (jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300 rounded-full", children: [jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" }), "Checking"] })) : state.status === 'completed' || (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.model_installed) ? (jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300 rounded-full", children: [jsx(CircleCheckBig, { className: "h-3 w-3" }), "Ready"] })) : state.status === 'error' ? (jsxs("div", { className: "space-y-1", children: [jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300 rounded-full", children: [jsx(CircleX, { className: "h-3 w-3" }), "Error"] }), state.error && (jsx("p", { className: "text-xs text-red-600 dark:text-red-400 max-w-[200px]", children: state.error }))] })) : state.status === 'cancelled' ? (jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300 rounded-full", children: [jsx(X$1, { className: "h-3 w-3" }), "Cancelled"] })) : (jsx("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300 rounded-full", children: "Not Downloaded" })) }) }), jsx("td", { className: "px-6 py-4 text-right", children: jsxs("div", { className: "flex items-center justify-end gap-2", children: [isDownloading && (jsxs(Button$1, { onClick: onCancelDownload, variant: "outline", size: "sm", children: [jsx(X$1, { className: "h-4 w-4 mr-2" }), "Cancel"] })), needsModelDownload && !isDownloading && (jsxs(Button$1, { onClick: onStartDownload, size: "sm", variant: "outline", children: [jsx(Download, { className: "h-4 w-4 mr-2" }), "Download"] })), state.status === 'error' && (jsx(Button$1, { onClick: onResetState, variant: "ghost", size: "sm", children: "Reset" })), (state.status === 'completed' || state.status === 'cancelled') && (jsx(Button$1, { onClick: onCheckStatus, variant: "ghost", size: "sm", children: jsx(RefreshCw, { className: "h-4 w-4" }) }))] }) })] })] })] }) })] })) : (jsx("div", { className: "rounded-lg border px-6 py-4 bg-green-50/30 dark:bg-green-950/10", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs("div", { className: "space-y-4", children: [jsx("div", { className: "flex items-center justify-between", children: jsxs("div", { className: "flex items-center gap-3", children: [jsx(CircleCheckBig, { className: "h-8 w-8 text-green-500 flex-shrink-0" }), jsxs("div", { className: "flex-1", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("h3", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: "Offline AI Ready" }), jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-semibold bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300 rounded-full", children: [jsx(Star$1, { className: "h-3 w-3 fill-blue-700 dark:fill-blue-300" }), "PREFERRED"] })] }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: "Your device is using the optimized offline AI setup. You can work with full capabilities even without internet." })] })] }) }), foundryModels.length > 0 && (jsxs("div", { className: "space-y-2", children: [jsx("label", { className: "text-xs font-medium text-gray-700 dark:text-gray-300", children: "Select Model" }), jsxs(Select$1, { value: selectedFoundryModel || ((_b = foundryModels[0]) === null || _b === void 0 ? void 0 : _b.id), onValueChange: (value) => onSelectFoundryModel === null || onSelectFoundryModel === void 0 ? void 0 : onSelectFoundryModel(value), children: [jsx(SelectTrigger, { className: "w-full bg-gray-50 border-gray-200 dark:bg-gray-800 dark:border-gray-700", children: jsx(SelectValue, { placeholder: "Select a model" }) }), jsx(SelectContent, { children: foundryModels.map((model) => (jsx(SelectItem, { value: model.id, children: jsxs("div", { className: "flex items-center justify-between w-full gap-4", children: [jsx("span", { className: "font-medium", children: model.name || model.id }), jsxs("div", { className: "flex items-center gap-2 text-xs text-gray-500", children: [model.device && (jsx("span", { className: "px-2 py-0.5 bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300 rounded", children: model.device })), model.size && jsx("span", { children: model.size }), !model.is_downloaded && (jsx("span", { className: "px-2 py-0.5 bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-300 rounded", children: "Not Downloaded" })), model.is_downloaded && (jsx("span", { className: "px-2 py-0.5 bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-300 rounded", children: "Downloaded" }))] })] }) }, model.id))) })] }), jsxs("div", { className: "flex flex-col gap-1", children: [jsxs("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: [foundryModels.length, " model", foundryModels.length !== 1 ? 's' : '', " available"] }), selectedFoundryModel && (jsxs("div", { className: "flex items-center gap-1.5 text-xs text-green-600 dark:text-green-400", children: [jsx(CircleCheckBig, { className: "h-3.5 w-3.5" }), jsxs("span", { children: ["Using:", ' ', ((_c = foundryModels.find((m) => m.id === selectedFoundryModel)) === null || _c === void 0 ? void 0 : _c.name) ||
63846
- selectedFoundryModel, ((_d = foundryModels.find((m) => m.id === selectedFoundryModel)) === null || _d === void 0 ? void 0 : _d.device) && (jsxs("span", { className: "ml-1 text-gray-500 dark:text-gray-400", children: ["(", (_e = foundryModels.find((m) => m.id === selectedFoundryModel)) === null || _e === void 0 ? void 0 : _e.device, ")"] }))] })] }))] })] })), state.status === 'downloading' && (jsxs("div", { className: "mt-4 p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx("div", { className: "animate-spin h-5 w-5 border-2 border-blue-600 dark:border-blue-400 border-t-transparent rounded-full" }), jsxs("div", { className: "flex-1", children: [jsx("p", { className: "text-sm font-medium text-blue-900 dark:text-blue-100", children: state.message }), state.progress > 0 && (jsx("div", { className: "mt-2 w-full bg-blue-200 dark:bg-blue-800 rounded-full h-2", children: jsx("div", { className: "bg-blue-600 dark:bg-blue-400 h-2 rounded-full transition-all duration-300", style: { width: `${state.progress}%` } }) }))] })] }), state.logs.length > 0 && (jsx("div", { className: "mt-3 max-h-32 overflow-y-auto bg-white dark:bg-gray-800 rounded border border-blue-200 dark:border-blue-700 p-2", children: state.logs.slice(-10).map((log, idx) => (jsx("div", { className: `text-xs font-mono ${log.level === 'error'
63847
- ? 'text-red-600 dark:text-red-400'
63848
- : log.level === 'warn'
63849
- ? 'text-yellow-600 dark:text-yellow-400'
63850
- : 'text-gray-700 dark:text-gray-300'}`, children: log.message }, idx))) }))] }))] }) }))] }) }));
64707
+ ? !hasDownloadedFoundryModel || isDownloading || state.status === 'checking'
64708
+ : isDownloading || isManagerInstalling || state.status === 'checking';
64709
+ return (jsxs("div", { className: "space-y-6", children: [jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between rounded-lg border px-6 py-4", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-[#646464]", children: "Enable Local Models" }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": "More info about Local Models", className: "hidden sm:block", children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { className: "rounded-lg bg-gray-700 px-3 py-2 text-sm font-medium max-w-xs text-white shadow-sm transition-opacity duration-300 z-50", children: jsxs("div", { className: "space-y-2", children: [jsx("p", { children: "Work offline with AI capabilities on your device." }), (foundryStatus === null || foundryStatus === void 0 ? void 0 : foundryStatus.is_supported) && (jsx("p", { className: "text-xs text-gray-300", children: "Your device automatically uses the best offline AI option available." }))] }) })] }) })] }), jsxs("div", { className: "flex items-center gap-2", children: [isManagerInstalling && !isUsingFoundry && (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500", "aria-label": "Starting model manager" })), jsx(Switch, { checked: switchChecked, onCheckedChange: handleToggle, disabled: switchDisabled, "aria-label": `Enable Local Models ${switchChecked ? 'enabled' : 'disabled'}`, className: "cursor-pointer data-[state=checked]:bg-blue-500" })] })] }), shouldShowFoundryInstall ? (jsx("div", { className: "rounded-lg border px-6 py-4 bg-blue-50/30 dark:bg-blue-950/10", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs("div", { className: "space-y-4", children: [jsx("div", { className: "flex items-start gap-3", children: jsxs("div", { className: "flex items-center gap-2 flex-shrink-0 mt-0.5", children: [jsx(Star$1, { className: "h-5 w-5 text-blue-600 fill-blue-600" }), jsx("span", { className: "px-2 py-0.5 text-xs font-semibold bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300 rounded-full", children: "PREFERRED" })] }) }), jsxs("div", { className: "flex items-start gap-3", children: [jsx(Info$3, { className: "h-5 w-5 text-blue-500 flex-shrink-0 mt-0.5" }), jsxs("div", { className: "flex-1", children: [jsx("h3", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: "Setting up offline AI" }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: "Downloading optimized AI capabilities for your device. This enables you to work offline with full AI features." })] })] }), state.status === 'downloading' || state.status === 'checking' ? (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-700 dark:text-gray-300", children: state.message || 'Preparing download...' })] }), state.progress > 0 && jsx(Progress, { value: state.progress, className: "h-2" })] })) : state.status === 'error' ? (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2 text-red-600 dark:text-red-400", children: [jsx(CircleX, { className: "h-4 w-4" }), jsx("span", { className: "text-sm", children: state.error || 'Download failed' })] }), jsx("div", { className: "flex gap-2", children: jsxs(Button$1, { onClick: onInstallFoundry, size: "sm", variant: "outline", children: [jsx(RefreshCw, { className: "h-4 w-4 mr-2" }), "Try Again"] }) })] })) : (jsx("div", { className: "space-y-2", children: jsxs("div", { className: "flex items-center gap-2", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-700 dark:text-gray-300", children: "Starting download..." })] }) })), jsxs("div", { className: "text-xs text-gray-500 dark:text-gray-400", children: [jsx("p", { className: "font-medium mb-1", children: "Download size: ~500MB" }), jsx("p", { children: "This is a one-time setup to enable offline capabilities." })] })] }) })) : /* Requirements Table - Hidden when using Foundry Local */ !isUsingFoundry ? (jsxs(Fragment$1, { children: [(foundryStatus === null || foundryStatus === void 0 ? void 0 : foundryStatus.is_supported) && (jsx("div", { className: "rounded-lg border px-4 py-3 bg-blue-50/20 dark:bg-blue-950/10", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs("div", { className: "flex items-start gap-2", children: [jsx(Info$3, { className: "h-4 w-4 text-blue-600 flex-shrink-0 mt-0.5" }), jsxs("div", { className: "text-xs text-gray-600 dark:text-gray-400", children: [jsx("span", { className: "font-medium text-gray-900 dark:text-gray-100", children: "Note:" }), " Your device supports an optimized offline AI option. Currently using alternative setup. For best performance, download the recommended option above."] })] }) })), localModelsEnabled && (jsxs("div", { className: "rounded-lg border px-6 py-4", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx(Server, { className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }), jsxs("div", { children: [jsx("div", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: "Model Manager" }), jsx("div", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Model Manager runs the models on your device" })] })] }), jsx("div", { className: "flex items-center gap-2", children: managerRunning ? (jsxs(Fragment$1, { children: [jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300 rounded-full", children: [jsx(CircleCheckBig, { className: "h-3 w-3" }), "Running"] }), jsx(Button$1, { onClick: onCheckStatus, variant: "ghost", size: "sm", "aria-label": "Refresh model manager status", children: jsx(RefreshCw, { className: "h-4 w-4" }) })] })) : (jsxs(Fragment$1, { children: [jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300 rounded-full", children: [jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" }), "Starting\u2026"] }), jsx(Button$1, { onClick: onCheckStatus, variant: "ghost", size: "sm", "aria-label": "Refresh model manager status", children: jsx(RefreshCw, { className: "h-4 w-4" }) })] })) })] }), isManagerInstalling && (jsx("div", { className: "mt-3 w-full max-w-[240px]", children: jsx(Progress, { value: state.managerInstallProgress || 0, className: "h-1.5" }) }))] })), localModelsEnabled && (jsxs("div", { className: "rounded-lg border overflow-hidden", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsxs("table", { className: "w-full", children: [jsx("thead", { children: jsxs("tr", { className: "bg-gray-50 dark:bg-gray-800/50", children: [jsx("th", { className: "px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider w-12", children: "Use" }), jsx("th", { className: "px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider", children: "Model" }), jsx("th", { className: "px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider", children: "Status" }), jsx("th", { className: "px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider", children: "Action" })] }) }), jsx("tbody", { className: "bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-800", children: LOCAL_MODELS.map((model) => {
64710
+ const isPrimary = model.id === PRIMARY_MODEL_ID;
64711
+ const isActive = activeModelId === model.id;
64712
+ // Cloud-hosted models are always available — they run on
64713
+ // Ollama's cloud, so there's nothing to download.
64714
+ const isCloud = isCloudModelId(model.id);
64715
+ // A model is ready once Ollama reports its tag as installed.
64716
+ // Fall back to (a) this row's own download having just
64717
+ // completed — so it flips to "Ready" before the status
64718
+ // refresh lands — and (b) the primary-model status flag.
64719
+ // Cloud models are ready by default.
64720
+ const isInstalled = isCloud ||
64721
+ isModelInstalled(model.id, ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed_models) ||
64722
+ (isActive && state.status === 'completed') ||
64723
+ (isPrimary && (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.model_installed) === true);
64724
+ // An installed model must never render a download/cancel
64725
+ // state — guards against a stale persisted "downloading"
64726
+ // status making an already-ready model look like it's
64727
+ // still downloading (and wrongly cancellable) on reopen.
64728
+ const rowDownloading = isActive && isDownloading && !isInstalled;
64729
+ const rowChecking = isActive && state.status === 'checking';
64730
+ const rowError = isActive && state.status === 'error';
64731
+ const rowCancelled = isActive && state.status === 'cancelled';
64732
+ const canDownload = !!(ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed) &&
64733
+ !isInstalled &&
64734
+ !rowDownloading &&
64735
+ !rowChecking;
64736
+ const isSelected = selectedModelId === model.id;
64737
+ return (jsxs("tr", { className: isSelected ? 'bg-blue-50/40 dark:bg-blue-950/20' : undefined, children: [jsx("td", { className: "px-6 py-4", children: jsx("input", { type: "radio", name: "local-llm-model", checked: isSelected, disabled: !isInstalled, onChange: () => handleSelectModel(model.id), "aria-label": `Use ${model.name} for chat`, title: isInstalled ? undefined : 'Download this model to chat with it', className: isInstalled
64738
+ ? 'h-4 w-4 cursor-pointer accent-blue-500'
64739
+ : 'h-4 w-4 cursor-not-allowed opacity-40' }) }), jsxs("td", { className: "px-6 py-4 whitespace-nowrap", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: model.name }), jsx("span", { className: "text-xs text-gray-400 dark:text-gray-500", children: model.size })] }), jsx("div", { className: "text-xs text-gray-500 dark:text-gray-400", children: model.provider })] }), jsx("td", { className: "px-6 py-4", children: jsx("div", { className: "space-y-2", children: isCloud ? (jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300 rounded-full", children: [jsx(Cloud, { className: "h-3 w-3" }), "Cloud"] })) : rowDownloading ? (jsxs("div", { className: "space-y-2", children: [jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300 rounded-full", children: [jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" }), Math.round(state.progress), "%"] }), jsx("div", { className: "w-full max-w-[200px]", children: jsx(Progress, { value: state.progress, className: "h-1.5" }) })] })) : rowChecking ? (jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300 rounded-full", children: [jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" }), "Checking"] })) : isInstalled ? (jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300 rounded-full", children: [jsx(CircleCheckBig, { className: "h-3 w-3" }), "Ready"] })) : rowError ? (jsxs("div", { className: "space-y-1", children: [jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300 rounded-full", children: [jsx(CircleX, { className: "h-3 w-3" }), "Error"] }), state.error && (jsx("p", { className: "text-xs text-red-600 dark:text-red-400 max-w-[200px]", children: state.error }))] })) : rowCancelled ? (jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300 rounded-full", children: [jsx(X$1, { className: "h-3 w-3" }), "Cancelled"] })) : (jsx("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300 rounded-full", children: "Not Downloaded" })) }) }), jsx("td", { className: "px-6 py-4 text-right", children: jsxs("div", { className: "flex items-center justify-end gap-2", children: [rowDownloading && (jsxs(Button$1, { onClick: onCancelDownload, variant: "outline", size: "sm", children: [jsx(X$1, { className: "h-4 w-4 mr-2" }), "Cancel"] })), canDownload && (jsxs(Button$1, { onClick: () => handleDownloadModel(model.id), size: "sm", variant: "outline", children: [jsx(Download, { className: "h-4 w-4 mr-2" }), "Download"] })), rowError && (jsx(Button$1, { onClick: onResetState, variant: "ghost", size: "sm", children: "Reset" })), isInstalled && !isCloud && (jsx(Button$1, { onClick: onCheckStatus, variant: "ghost", size: "sm", children: jsx(RefreshCw, { className: "h-4 w-4" }) }))] }) })] }, model.id));
64740
+ }) })] }), jsx("div", { className: "px-6 py-3 border-t text-xs text-gray-500 dark:text-gray-400", style: { borderColor: 'oklch(.922 0 0)' }, children: selectedModelReady ? (jsxs(Fragment$1, { children: ["Chatting with:", ' ', jsx("span", { className: "font-medium text-gray-900 dark:text-gray-100", children: (_c = (_b = LOCAL_MODELS.find((m) => m.id === selectedModelId)) === null || _b === void 0 ? void 0 : _b.name) !== null && _c !== void 0 ? _c : selectedModelId })] })) : (jsx(Fragment$1, { children: "Download a model and select it to start chatting." })) })] }))] })) : (jsx("div", { className: "rounded-lg border px-6 py-4 bg-green-50/30 dark:bg-green-950/10", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs("div", { className: "space-y-4", children: [jsx("div", { className: "flex items-center justify-between", children: jsxs("div", { className: "flex items-center gap-3", children: [jsx(CircleCheckBig, { className: "h-8 w-8 text-green-500 flex-shrink-0" }), jsxs("div", { className: "flex-1", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("h3", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: "Offline AI Ready" }), jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-semibold bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300 rounded-full", children: [jsx(Star$1, { className: "h-3 w-3 fill-blue-700 dark:fill-blue-300" }), "PREFERRED"] })] }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: "Your device is using the optimized offline AI setup. You can work with full capabilities even without internet." })] })] }) }), foundryModels.length > 0 && (jsxs("div", { className: "space-y-2", children: [jsx("label", { className: "text-xs font-medium text-gray-700 dark:text-gray-300", children: "Select Model" }), jsxs(Select$1, { value: selectedFoundryModel || ((_d = foundryModels[0]) === null || _d === void 0 ? void 0 : _d.id), onValueChange: (value) => onSelectFoundryModel === null || onSelectFoundryModel === void 0 ? void 0 : onSelectFoundryModel(value), children: [jsx(SelectTrigger, { className: "w-full bg-gray-50 border-gray-200 dark:bg-gray-800 dark:border-gray-700", children: jsx(SelectValue, { placeholder: "Select a model" }) }), jsx(SelectContent, { children: foundryModels.map((model) => (jsx(SelectItem, { value: model.id, children: jsxs("div", { className: "flex items-center justify-between w-full gap-4", children: [jsx("span", { className: "font-medium", children: model.name || model.id }), jsxs("div", { className: "flex items-center gap-2 text-xs text-gray-500", children: [model.device && (jsx("span", { className: "px-2 py-0.5 bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300 rounded", children: model.device })), model.size && jsx("span", { children: model.size }), !model.is_downloaded && (jsx("span", { className: "px-2 py-0.5 bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-300 rounded", children: "Not Downloaded" })), model.is_downloaded && (jsx("span", { className: "px-2 py-0.5 bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-300 rounded", children: "Downloaded" }))] })] }) }, model.id))) })] }), jsxs("div", { className: "flex flex-col gap-1", children: [jsxs("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: [foundryModels.length, " model", foundryModels.length !== 1 ? 's' : '', " available"] }), selectedFoundryModel && (jsxs("div", { className: "flex items-center gap-1.5 text-xs text-green-600 dark:text-green-400", children: [jsx(CircleCheckBig, { className: "h-3.5 w-3.5" }), jsxs("span", { children: ["Using:", ' ', ((_e = foundryModels.find((m) => m.id === selectedFoundryModel)) === null || _e === void 0 ? void 0 : _e.name) ||
64741
+ selectedFoundryModel, ((_f = foundryModels.find((m) => m.id === selectedFoundryModel)) === null || _f === void 0 ? void 0 : _f.device) && (jsxs("span", { className: "ml-1 text-gray-500 dark:text-gray-400", children: ["(", (_g = foundryModels.find((m) => m.id === selectedFoundryModel)) === null || _g === void 0 ? void 0 : _g.device, ")"] }))] })] }))] })] })), state.status === 'downloading' && (jsxs("div", { className: "mt-4 p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx("div", { className: "animate-spin h-5 w-5 border-2 border-blue-600 dark:border-blue-400 border-t-transparent rounded-full" }), jsxs("div", { className: "flex-1", children: [jsx("p", { className: "text-sm font-medium text-blue-900 dark:text-blue-100", children: state.message }), state.progress > 0 && (jsx("div", { className: "mt-2 w-full bg-blue-200 dark:bg-blue-800 rounded-full h-2", children: jsx("div", { className: "bg-blue-600 dark:bg-blue-400 h-2 rounded-full transition-all duration-300", style: { width: `${state.progress}%` } }) }))] })] }), state.logs.length > 0 && (jsx("div", { className: "mt-3 max-h-32 overflow-y-auto bg-white dark:bg-gray-800 rounded border border-blue-200 dark:border-blue-700 p-2", children: state.logs.slice(-10).map((log, idx) => (jsx("div", { className: `text-xs font-mono ${log.level === 'error'
64742
+ ? 'text-red-600 dark:text-red-400'
64743
+ : log.level === 'warn'
64744
+ ? 'text-yellow-600 dark:text-yellow-400'
64745
+ : 'text-gray-700 dark:text-gray-300'}`, children: log.message }, idx))) }))] }))] }) }))] }), jsx(AlertDialog, { open: !!pendingModel, onOpenChange: (open) => {
64746
+ if (!open)
64747
+ setPendingModel(null);
64748
+ }, children: jsxs(AlertDialogContent, { children: [jsxs(AlertDialogHeader, { children: [jsx(AlertDialogTitle, { children: "This model may be too large for your system" }), jsxs(AlertDialogDescription, { children: [pendingModel === null || pendingModel === void 0 ? void 0 : pendingModel.name, " needs about ", pendingModel === null || pendingModel === void 0 ? void 0 : pendingModel.size, ", but your system has", ' ', formatBytes(usableMemoryBytes(systemMemory)), " of memory available to run it. It may run very slowly or fail to load. Download anyway?"] })] }), jsxs(AlertDialogFooter, { children: [jsx(AlertDialogCancel, { onClick: () => setPendingModel(null), children: "Cancel" }), jsx(AlertDialogAction, { onClick: confirmPendingDownload, children: "Download anyway" })] })] }) })] }));
64749
+ }
64750
+
64751
+ function LocalModelsContent(props) {
64752
+ const [isCollapsed, setIsCollapsed] = useState(true);
64753
+ if (!props.isAvailable) {
64754
+ return null;
64755
+ }
64756
+ return (jsxs("div", { className: "rounded-lg px-6 py-5 border border-gray-200 dark:border-gray-700", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsxs("div", { className: "flex items-center justify-between", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx("span", { className: "text-sm font-medium text-[#646464]", children: "Local Models" }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": "More info about Local Models", className: "hidden sm:block", children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { className: "rounded-lg bg-gray-700 px-3 py-2 text-sm font-medium max-w-xs text-white shadow-sm transition-opacity duration-300 z-50", children: jsx("p", { children: "Manage on-device AI models for offline use." }) })] }) })] }), jsx("button", { type: "button", onClick: () => setIsCollapsed((previous) => !previous), className: "p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1", "aria-label": isCollapsed ? 'Expand Local Models' : 'Collapse Local Models', children: isCollapsed ? (jsx(ChevronDown, { className: "h-5 w-5 text-gray-400", "aria-hidden": "true" })) : (jsx(ChevronUp, { className: "h-5 w-5 text-gray-400", "aria-hidden": "true" })) })] }), !isCollapsed && (jsx("div", { className: "mt-4", children: jsx(LocalLLMTab, { ...props }) }))] }));
64757
+ }
64758
+
64759
+ const SYSTEM_CONTROL_ENABLED_KEY = 'ibl_system_control_enabled';
64760
+ /**
64761
+ * Whether the Computer Assistant is enabled, read from localStorage. This is a
64762
+ * user preference (mirrors {@link isLocalLLMEnabled}); it reflects the toggle the
64763
+ * user last chose, independent of whether the helper is installed yet.
64764
+ */
64765
+ function isSystemControlEnabled() {
64766
+ if (typeof window === 'undefined')
64767
+ return false;
64768
+ return localStorage.getItem(SYSTEM_CONTROL_ENABLED_KEY) === 'true';
64769
+ }
64770
+ /**
64771
+ * Persist the Computer Assistant enabled preference to localStorage.
64772
+ */
64773
+ function setSystemControlEnabled(enabled) {
64774
+ if (typeof window === 'undefined')
64775
+ return;
64776
+ localStorage.setItem(SYSTEM_CONTROL_ENABLED_KEY, String(enabled));
64777
+ }
64778
+ /** Green "done" pill. */
64779
+ function DonePill({ children }) {
64780
+ return (jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-800 dark:bg-green-900/30 dark:text-green-300", children: [jsx(Check, { className: "h-3 w-3" }), children] }));
64781
+ }
64782
+ /** Blue "in progress" pill. */
64783
+ function WorkingPill({ children }) {
64784
+ return (jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-blue-100 px-2 py-0.5 text-xs font-medium text-blue-800 dark:bg-blue-900/30 dark:text-blue-300", children: [jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" }), children] }));
64785
+ }
64786
+ /** A single numbered step row. */
64787
+ function Step$2({ number, done, title, description, action, }) {
64788
+ return (jsxs("div", { className: "flex items-start justify-between gap-3", children: [jsxs("div", { className: "flex items-start gap-3", children: [jsx("span", { className: `flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full text-xs font-semibold ${done
64789
+ ? 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-300'
64790
+ : 'bg-gray-100 text-gray-500 dark:bg-gray-800 dark:text-gray-400'}`, "aria-hidden": "true", children: done ? jsx(Check, { className: "h-3.5 w-3.5" }) : number }), jsxs("div", { children: [jsx("div", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: title }), jsx("div", { className: "mt-0.5 text-xs text-gray-500 dark:text-gray-400", children: description })] })] }), jsx("div", { className: "flex-shrink-0", children: action })] }));
64791
+ }
64792
+ /**
64793
+ * Body of the "Computer Assistant" card: a plain-language on/off with two simple
64794
+ * steps — set up, then allow control — so non-technical users can follow along.
64795
+ * Mirrors the Local Models tab so the two cards behave the same.
64796
+ */
64797
+ function SystemControlTab({ isAvailable, state, status, requiredSizeGb = DEFAULT_SYSTEM_CONTROL_REQUIRED_SIZE_GB, ollamaStatus, systemMemory, accessibilityPermission, onInstall, onStop, onCheckStatus, onResetState, onRequestAccessibilityPermission, onDownloadModel, }) {
64798
+ const isInstalling = state.status === 'installing' || (status === null || status === void 0 ? void 0 : status.installing) === true;
64799
+ // User preference — independent of whether the helper is installed. Always
64800
+ // operable so the user can turn it off again.
64801
+ const [isEnabled, setIsEnabled] = useState(() => isSystemControlEnabled());
64802
+ // The currently-selected local model (persisted by the Local Models card).
64803
+ // Polled so a selection change in the sibling card is reflected here without a
64804
+ // remount. The assistant only works well with larger models, so it's gated to
64805
+ // a selected model above the size threshold.
64806
+ const [selectedModel, setSelectedModel] = useState(() => getLocalLLMModel());
64807
+ // Whether "Local Models" is turned on. The assistant runs on a local model, so
64808
+ // it's gated off until Local Models is enabled. Polled alongside the model so a
64809
+ // toggle in the sibling card is reflected without a remount.
64810
+ const [localModelsEnabled, setLocalModelsEnabled] = useState(() => isLocalLLMEnabled());
64811
+ useEffect(() => {
64812
+ const id = setInterval(() => {
64813
+ setSelectedModel(getLocalLLMModel());
64814
+ setLocalModelsEnabled(isLocalLLMEnabled());
64815
+ }, 1500);
64816
+ return () => clearInterval(id);
64817
+ }, []);
64818
+ const localModelsOff = !localModelsEnabled;
64819
+ const modelTooSmall = !modelSupportsSystemControl(selectedModel, requiredSizeGb);
64820
+ // "Upgrade" target: the smallest catalog model that clears the size gate.
64821
+ const upgradeTarget = smallestSystemControlModel(requiredSizeGb);
64822
+ // Set while an upgrade is downloading a model, before we auto-enable.
64823
+ const [pendingEnableModelId, setPendingEnableModelId] = useState(null);
64824
+ // Model awaiting a RAM/VRAM "may be too large" confirmation before download.
64825
+ const [pendingCapacityModel, setPendingCapacityModel] = useState(null);
64826
+ const isUpgrading = pendingEnableModelId !== null;
64827
+ const managerRunning = (status === null || status === void 0 ? void 0 : status.running) === true;
64828
+ // Steps are shown whenever the toggle is on (or mid-setup), so the user always
64829
+ // gets feedback for their choice.
64830
+ const managerEnabled = isEnabled || isInstalling;
64831
+ // Permission is known (macOS + plugin wired) and granted.
64832
+ const permissionKnown = typeof accessibilityPermission === 'boolean';
64833
+ const permissionGranted = accessibilityPermission === true;
64834
+ const allSet = managerRunning && (!permissionKnown || permissionGranted);
64835
+ // Keep the app-facing preference flag in sync with the toggle.
64836
+ useEffect(() => {
64837
+ setSystemControlEnabled(isEnabled);
64838
+ }, [isEnabled]);
64839
+ // While enabled but not yet running, keep polling so the step flips to "Ready"
64840
+ // as soon as the host reports the helper is up.
64841
+ useEffect(() => {
64842
+ if (!isEnabled || managerRunning)
64843
+ return;
64844
+ const id = setInterval(() => onCheckStatus(), 2500);
64845
+ return () => clearInterval(id);
64846
+ }, [isEnabled, managerRunning, onCheckStatus]);
64847
+ // While permission isn't granted yet, keep re-checking (the grant happens in
64848
+ // System Settings) so the step flips to "Allowed" on its own.
64849
+ useEffect(() => {
64850
+ if (accessibilityPermission !== false)
64851
+ return;
64852
+ const id = setInterval(() => onCheckStatus(), 2500);
64853
+ return () => clearInterval(id);
64854
+ }, [accessibilityPermission, onCheckStatus]);
64855
+ // After an upgrade kicks off a download, turn the assistant on once the model
64856
+ // finishes downloading (it shows up in the installed list).
64857
+ useEffect(() => {
64858
+ if (!pendingEnableModelId)
64859
+ return;
64860
+ if (isModelInstalled(pendingEnableModelId, ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed_models)) {
64861
+ setPendingEnableModelId(null);
64862
+ setIsEnabled(true);
64863
+ onInstall();
64864
+ }
64865
+ }, [pendingEnableModelId, ollamaStatus, onInstall]);
64866
+ if (!isAvailable) {
64867
+ return (jsx("div", { className: "text-sm text-gray-500 dark:text-gray-400", children: "The Computer Assistant is only available in the desktop app." }));
64868
+ }
64869
+ const handleToggle = (checked) => {
64870
+ // Guard: needs Local Models on and a large-enough model.
64871
+ if (checked && (localModelsOff || modelTooSmall))
64872
+ return;
64873
+ setIsEnabled(checked);
64874
+ if (checked) {
64875
+ if (!isInstalling)
64876
+ onInstall();
64877
+ }
64878
+ else {
64879
+ onStop === null || onStop === void 0 ? void 0 : onStop();
64880
+ }
64881
+ };
64882
+ // Upgrade = switch to the smallest usable model: select it, then (if it isn't
64883
+ // already downloaded) download it and auto-enable the assistant once it's
64884
+ // ready. The RAM/VRAM check is preserved via the confirm below.
64885
+ const runUpgrade = (model) => {
64886
+ setLocalLLMModel(model.id);
64887
+ setLocalLLMToolSupport(model.tool_support);
64888
+ setLocalLLMEnabled(true);
64889
+ setSelectedModel(model.id); // recompute the size gate immediately
64890
+ if (isModelInstalled(model.id, ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed_models)) {
64891
+ // Already downloaded → enable now.
64892
+ setIsEnabled(true);
64893
+ if (!isInstalling)
64894
+ onInstall();
64895
+ }
64896
+ else {
64897
+ // Not downloaded → download, then auto-enable when it lands (effect above).
64898
+ setPendingEnableModelId(model.id);
64899
+ onDownloadModel === null || onDownloadModel === void 0 ? void 0 : onDownloadModel(model.id);
64900
+ }
64901
+ };
64902
+ const handleUpgrade = () => {
64903
+ if (!upgradeTarget)
64904
+ return;
64905
+ // Keep the RAM/VRAM check: confirm before pulling a model that may not fit.
64906
+ if (modelExceedsCapacity(upgradeTarget, systemMemory)) {
64907
+ setPendingCapacityModel(upgradeTarget);
64908
+ return;
64909
+ }
64910
+ runUpgrade(upgradeTarget);
64911
+ };
64912
+ const switchChecked = isEnabled;
64913
+ const switchDisabled = isInstalling ||
64914
+ state.status === 'checking' ||
64915
+ ((localModelsOff || modelTooSmall) && !isEnabled);
64916
+ return (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between gap-4 rounded-lg border px-6 py-4", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsxs("div", { children: [jsx("div", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: "Let your assistant control this computer" }), jsx("div", { className: "mt-0.5 text-xs text-gray-500 dark:text-gray-400", children: "It can click, type, and open apps to do tasks for you. You stay in control and can turn this off anytime." })] }), jsxs("div", { className: "flex flex-shrink-0 items-center gap-2", children: [isInstalling && (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500", "aria-label": "Setting up" })), jsx(Switch, { checked: switchChecked, onCheckedChange: handleToggle, disabled: switchDisabled, "aria-label": "Let your assistant control this computer", className: "cursor-pointer data-[state=checked]:bg-blue-500" })] })] }), localModelsOff && (jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 dark:border-amber-900/40 dark:bg-amber-900/10", children: [jsx(Info$3, { className: "mt-0.5 h-4 w-4 flex-shrink-0 text-amber-600", "aria-hidden": "true" }), jsx("p", { className: "text-xs text-amber-800 dark:text-amber-300", children: "Turn on \u201CLocal Models\u201D above first \u2014 the Computer Assistant uses a local AI model to do its work." })] })), !localModelsOff && modelTooSmall && (jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 dark:border-amber-900/40 dark:bg-amber-900/10", children: [jsx(Info$3, { className: "mt-0.5 h-4 w-4 flex-shrink-0 text-amber-600", "aria-hidden": "true" }), jsxs("div", { className: "flex-1", children: [jsxs("p", { className: "text-xs text-amber-800 dark:text-amber-300", children: ["Your current AI model is too small for this.", ' ', upgradeTarget && onDownloadModel
64917
+ ? `Upgrade to ${upgradeTarget.name} (${upgradeTarget.size}) to use it.`
64918
+ : 'Pick a larger one under “Local Models” above, then come back.'] }), upgradeTarget && onDownloadModel && (jsx(Button$1, { onClick: handleUpgrade, size: "sm", className: "mt-2", disabled: isUpgrading, "aria-label": `Upgrade to ${upgradeTarget.name}`, children: isUpgrading ? (jsxs(Fragment$1, { children: [jsx(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), "Upgrading\u2026"] })) : (jsxs(Fragment$1, { children: [jsx(CircleArrowUp, { className: "mr-2 h-4 w-4" }), "Upgrade to ", upgradeTarget.name] })) }))] })] })), isUpgrading && !modelTooSmall && (jsxs("div", { className: "flex items-start gap-2 rounded-lg border px-4 py-3", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsx(LoaderCircle, { className: "mt-0.5 h-4 w-4 flex-shrink-0 animate-spin text-blue-500", "aria-hidden": "true" }), jsx("p", { className: "text-xs text-gray-600 dark:text-gray-300", children: "Downloading your new model\u2026 it\u2019ll turn on automatically when it\u2019s ready. You can watch progress under \u201CLocal Models\u201D above." })] })), managerEnabled && (jsxs("div", { className: "space-y-4 rounded-lg border px-6 py-5", style: { borderColor: 'oklch(.922 0 0)' }, children: [allSet ? (jsxs("div", { className: "flex items-start gap-2", children: [jsx(Check, { className: "mt-0.5 h-4 w-4 flex-shrink-0 text-green-600", "aria-hidden": "true" }), jsx("p", { className: "text-sm text-gray-700 dark:text-gray-300", children: "You\u2019re all set \u2014 your assistant can now help out on this computer." })] })) : (jsx("div", { className: "text-xs font-medium uppercase tracking-wide text-gray-400", children: "A couple of quick steps" })), jsx(Step$2, { number: 1, done: managerRunning, title: "Set up your assistant", description: "A quick, one-time setup so it can work on this computer.", action: managerRunning ? (jsx(DonePill, { children: "Ready" })) : (jsx(WorkingPill, { children: isInstalling ? 'Setting up…' : 'Starting…' })) }), (state.status === 'installing' || state.status === 'checking') && state.progress > 0 && (jsx(Progress, { value: state.progress, className: "h-1.5" })), permissionKnown && (jsx(Step$2, { number: 2, done: permissionGranted, title: "Allow it to control the computer", description: "Your Mac will ask you to confirm. This lets your assistant move the mouse and type for you.", action: permissionGranted ? (jsx(DonePill, { children: "Allowed" })) : onRequestAccessibilityPermission ? (jsx(Button$1, { onClick: onRequestAccessibilityPermission, size: "sm", "aria-label": "Allow your assistant to control the computer", children: "Allow" })) : (jsx("span", { className: "inline-flex items-center rounded-full bg-amber-100 px-2 py-0.5 text-xs font-medium text-amber-800 dark:bg-amber-900/30 dark:text-amber-300", children: "Needed" })) }))] })), state.status === 'error' && (jsxs("div", { className: "rounded-lg border border-red-200 bg-red-50 px-4 py-3 dark:border-red-900/40 dark:bg-red-900/10", children: [jsxs("div", { className: "flex items-center gap-2 text-sm text-red-700 dark:text-red-300", children: [jsx(CircleX, { className: "h-4 w-4 flex-shrink-0" }), jsx("span", { children: "Something went wrong while setting up. Please try again." })] }), jsxs(Button$1, { onClick: () => {
64919
+ onResetState();
64920
+ onInstall();
64921
+ }, size: "sm", variant: "outline", className: "mt-3", children: [jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), "Try again"] })] })), jsx(AlertDialog, { open: pendingCapacityModel !== null, onOpenChange: (open) => {
64922
+ if (!open)
64923
+ setPendingCapacityModel(null);
64924
+ }, children: jsxs(AlertDialogContent, { children: [jsxs(AlertDialogHeader, { children: [jsx(AlertDialogTitle, { children: "This model may be large for your computer" }), jsxs(AlertDialogDescription, { children: [pendingCapacityModel === null || pendingCapacityModel === void 0 ? void 0 : pendingCapacityModel.name, " (", pendingCapacityModel === null || pendingCapacityModel === void 0 ? void 0 : pendingCapacityModel.size, ") may be more than your computer\u2019s memory can handle, so it could run slowly or fail to load. Download and use it anyway?"] })] }), jsxs(AlertDialogFooter, { children: [jsx(AlertDialogCancel, { children: "Cancel" }), jsx(AlertDialogAction, { onClick: () => {
64925
+ const model = pendingCapacityModel;
64926
+ setPendingCapacityModel(null);
64927
+ if (model)
64928
+ runUpgrade(model);
64929
+ }, children: "Download anyway" })] })] }) })] }));
64930
+ }
64931
+
64932
+ /**
64933
+ * Collapsible "System Control" card for the UserProfile → Advanced section.
64934
+ * Mirrors {@link LocalModelsContent}: a purely presentational, titled,
64935
+ * collapsible container whose body is the {@link SystemControlTab}. Availability
64936
+ * and handlers are threaded in (see UserProfileDropdown, which falls back to
64937
+ * {@link useGhostOs} when the host doesn't supply them). Renders nothing outside
64938
+ * the desktop app.
64939
+ */
64940
+ function SystemControlContent(props) {
64941
+ const [isCollapsed, setIsCollapsed] = useState(true);
64942
+ if (!props.isAvailable) {
64943
+ return null;
64944
+ }
64945
+ return (jsxs("div", { className: "rounded-lg px-6 py-5 border border-gray-200 dark:border-gray-700", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsxs("div", { className: "flex items-center justify-between", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx("span", { className: "text-sm font-medium text-[#646464]", children: "Computer Assistant" }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": "More info about the Computer Assistant", className: "hidden sm:block", children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { className: "rounded-lg bg-gray-700 px-3 py-2 text-sm font-medium max-w-xs text-white shadow-sm transition-opacity duration-300 z-50", children: jsx("p", { children: "Let your assistant do things on your computer \u2014 click, type, and open apps. You stay in control and can turn it off anytime." }) })] }) })] }), jsx("button", { type: "button", onClick: () => setIsCollapsed((previous) => !previous), className: "p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1", "aria-label": isCollapsed ? 'Expand Computer Assistant' : 'Collapse Computer Assistant', children: isCollapsed ? (jsx(ChevronDown, { className: "h-5 w-5 text-gray-400", "aria-hidden": "true" })) : (jsx(ChevronUp, { className: "h-5 w-5 text-gray-400", "aria-hidden": "true" })) })] }), !isCollapsed && (jsx("div", { className: "mt-4", children: jsx(SystemControlTab, { ...props }) }))] }));
63851
64946
  }
63852
64947
 
63853
64948
  // src/primitive.tsx
@@ -86951,7 +88046,7 @@ function ChatPrivacyTab({ org, username }) {
86951
88046
  const renderLucideIcon = (Icon) => function RenderedIcon(props) {
86952
88047
  return jsx(Icon, { ...props });
86953
88048
  };
86954
- function Profile({ tenant, username, tenants, onClose, customization = {}, isAdmin = false, targetTab = 'basic', onAccountDeleted, enableMemoryTab = false, localLLMProps, }) {
88049
+ function Profile({ tenant, username, tenants, onClose, customization = {}, isAdmin = false, targetTab = 'basic', onAccountDeleted, enableMemoryTab = false, localLLMProps, systemControlProps, }) {
86955
88050
  var _a, _b, _c, _d, _e, _f, _g, _h;
86956
88051
  console.log('[Profile] localLLMProps received:', {
86957
88052
  isAvailable: localLLMProps === null || localLLMProps === void 0 ? void 0 : localLLMProps.isAvailable,
@@ -86996,8 +88091,10 @@ function Profile({ tenant, username, tenants, onClose, customization = {}, isAdm
86996
88091
  : []),
86997
88092
  { id: 'security', label: 'Security', renderIcon: renderLucideIcon(Shield) },
86998
88093
  ];
86999
- // Add Advanced tab only when in Tauri app (localLLMProps is provided and available)
87000
- const TABS = (localLLMProps === null || localLLMProps === void 0 ? void 0 : localLLMProps.isAvailable)
88094
+ // Add Advanced tab only when in Tauri app (Local Models or System Control is
88095
+ // provided and available)
88096
+ const isAdvancedAvailable = (localLLMProps === null || localLLMProps === void 0 ? void 0 : localLLMProps.isAvailable) === true || (systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.isAvailable) === true;
88097
+ const TABS = isAdvancedAvailable
87001
88098
  ? [...baseTabs, { id: 'advanced', label: 'Advanced', renderIcon: renderLucideIcon(Settings) }]
87002
88099
  : baseTabs;
87003
88100
  const RoleIcon = renderLucideIcon(User);
@@ -87140,7 +88237,7 @@ function Profile({ tenant, username, tenants, onClose, customization = {}, isAdm
87140
88237
  var _a;
87141
88238
  return (jsxs(Fragment$1, { children: [jsxs("div", { className: "relative mb-0", children: [jsx("div", { className: "absolute inset-y-0 left-4 flex items-center pointer-events-none", "aria-hidden": "true", children: jsx("div", { className: "bg-black text-white rounded w-8 h-8 flex items-center justify-center", children: jsx("span", { className: "font-bold text-sm", children: "X" }) }) }), jsx(Input, { id: "x", className: "w-full bg-gray-50 border-gray-200 focus:ring-blue-500 focus:border-blue-500 text-base py-3 pl-16 h-10", placeholder: "X", value: field.state.value, onChange: (e) => handleSocialLinkChange(e.target.value, field.handleChange, X_URL_PREFIX), disabled: socialForm.state.isSubmitting })] }), jsx("p", { className: "text-red-500 dark:text-gray-400 text-sm", role: ((_a = field.state.meta.errors) === null || _a === void 0 ? void 0 : _a.length) ? 'alert' : undefined, "aria-live": "polite", children: field.state.meta.errors })] }));
87142
88239
  },
87143
- })] })] }) })), activeTab === 'education' && jsx(EducationTab, { org: tenant, username: username }), activeTab === 'experience' && jsx(ExperienceTab, { org: tenant, username: username }), activeTab === 'resume' && jsx(ResumeTab, { org: tenant, username: username }), activeTab === 'purchases' && jsx(PurchasesTab, { org: tenant, username: username }), activeTab === 'memory' && jsx(MemoryTab, { org: tenant, username: username }), activeTab === 'privacy' && jsx(ChatPrivacyTab, { org: tenant, username: username }), activeTab === 'security' && (jsx(Security, { email: userMetadata === null || userMetadata === void 0 ? void 0 : userMetadata.email, onAccountDeleted: onAccountDeleted })), activeTab === 'advanced' && localLLMProps && (jsx(LocalLLMTab, { isAvailable: localLLMProps.isAvailable, state: localLLMProps.state, ollamaStatus: localLLMProps.ollamaStatus, isUsingFoundry: localLLMProps.isUsingFoundry, foundryModels: localLLMProps.foundryModels, selectedFoundryModel: localLLMProps.selectedFoundryModel, foundryStatus: localLLMProps.foundryStatus, onStartDownload: localLLMProps.onStartDownload, onCancelDownload: localLLMProps.onCancelDownload, onInstallOllama: localLLMProps.onInstallOllama, onInstallFoundry: localLLMProps.onInstallFoundry, onCheckStatus: localLLMProps.onCheckStatus, onResetState: localLLMProps.onResetState, onSelectFoundryModel: localLLMProps.onSelectFoundryModel }))] }), ['basic', 'social'].includes(activeTab) && (jsx("div", { className: "flex-shrink-0 border-t border-gray-200 p-6 bg-white dark:bg-gray-900", children: jsxs("div", { className: "flex justify-end gap-3", children: [jsx(Button$1, { onClick: onClose, variant: "outline", children: "Cancel" }), jsx(Button$1, { onClick: () => {
88240
+ })] })] }) })), activeTab === 'education' && jsx(EducationTab, { org: tenant, username: username }), activeTab === 'experience' && jsx(ExperienceTab, { org: tenant, username: username }), activeTab === 'resume' && jsx(ResumeTab, { org: tenant, username: username }), activeTab === 'purchases' && jsx(PurchasesTab, { org: tenant, username: username }), activeTab === 'memory' && jsx(MemoryTab, { org: tenant, username: username }), activeTab === 'privacy' && jsx(ChatPrivacyTab, { org: tenant, username: username }), activeTab === 'security' && (jsx(Security, { email: userMetadata === null || userMetadata === void 0 ? void 0 : userMetadata.email, onAccountDeleted: onAccountDeleted })), activeTab === 'advanced' && (localLLMProps || systemControlProps) && (jsxs("div", { className: "space-y-6", children: [localLLMProps && (jsx(LocalModelsContent, { isAvailable: localLLMProps.isAvailable, state: localLLMProps.state, ollamaStatus: localLLMProps.ollamaStatus, systemMemory: localLLMProps.systemMemory, isUsingFoundry: localLLMProps.isUsingFoundry, foundryModels: localLLMProps.foundryModels, selectedFoundryModel: localLLMProps.selectedFoundryModel, foundryStatus: localLLMProps.foundryStatus, onStartDownload: localLLMProps.onStartDownload, onCancelDownload: localLLMProps.onCancelDownload, onInstallOllama: localLLMProps.onInstallOllama, onStopManager: localLLMProps.onStopManager, onInstallFoundry: localLLMProps.onInstallFoundry, onCheckStatus: localLLMProps.onCheckStatus, onResetState: localLLMProps.onResetState, onSelectFoundryModel: localLLMProps.onSelectFoundryModel })), systemControlProps && (jsx(SystemControlContent, { isAvailable: systemControlProps.isAvailable, state: systemControlProps.state, status: systemControlProps.status, requiredSizeGb: systemControlProps.requiredSizeGb, ollamaStatus: systemControlProps.ollamaStatus, systemMemory: systemControlProps.systemMemory, accessibilityPermission: systemControlProps.accessibilityPermission, onInstall: systemControlProps.onInstall, onStop: systemControlProps.onStop, onCheckStatus: systemControlProps.onCheckStatus, onResetState: systemControlProps.onResetState, onRequestAccessibilityPermission: systemControlProps.onRequestAccessibilityPermission, onDownloadModel: systemControlProps.onDownloadModel }))] }))] }), ['basic', 'social'].includes(activeTab) && (jsx("div", { className: "flex-shrink-0 border-t border-gray-200 p-6 bg-white dark:bg-gray-900", children: jsxs("div", { className: "flex justify-end gap-3", children: [jsx(Button$1, { onClick: onClose, variant: "outline", children: "Cancel" }), jsx(Button$1, { onClick: () => {
87144
88241
  if (activeTab === 'basic') {
87145
88242
  basicForm.handleSubmit();
87146
88243
  }
@@ -87567,11 +88664,11 @@ var TabsList$1 = React.forwardRef(
87567
88664
  }
87568
88665
  );
87569
88666
  TabsList$1.displayName = TAB_LIST_NAME;
87570
- var TRIGGER_NAME$3 = "TabsTrigger";
88667
+ var TRIGGER_NAME$2 = "TabsTrigger";
87571
88668
  var TabsTrigger$1 = React.forwardRef(
87572
88669
  (props, forwardedRef) => {
87573
88670
  const { __scopeTabs, value, disabled = false, ...triggerProps } = props;
87574
- const context = useTabsContext(TRIGGER_NAME$3, __scopeTabs);
88671
+ const context = useTabsContext(TRIGGER_NAME$2, __scopeTabs);
87575
88672
  const rovingFocusGroupScope = useRovingFocusGroupScope$2(__scopeTabs);
87576
88673
  const triggerId = makeTriggerId(context.baseId, value);
87577
88674
  const contentId = makeContentId(context.baseId, value);
@@ -87618,12 +88715,12 @@ var TabsTrigger$1 = React.forwardRef(
87618
88715
  );
87619
88716
  }
87620
88717
  );
87621
- TabsTrigger$1.displayName = TRIGGER_NAME$3;
87622
- var CONTENT_NAME$4 = "TabsContent";
88718
+ TabsTrigger$1.displayName = TRIGGER_NAME$2;
88719
+ var CONTENT_NAME$3 = "TabsContent";
87623
88720
  var TabsContent$1 = React.forwardRef(
87624
88721
  (props, forwardedRef) => {
87625
88722
  const { __scopeTabs, value, forceMount, children, ...contentProps } = props;
87626
- const context = useTabsContext(CONTENT_NAME$4, __scopeTabs);
88723
+ const context = useTabsContext(CONTENT_NAME$3, __scopeTabs);
87627
88724
  const triggerId = makeTriggerId(context.baseId, value);
87628
88725
  const contentId = makeContentId(context.baseId, value);
87629
88726
  const isSelected = value === context.value;
@@ -87653,19 +88750,19 @@ var TabsContent$1 = React.forwardRef(
87653
88750
  ) });
87654
88751
  }
87655
88752
  );
87656
- TabsContent$1.displayName = CONTENT_NAME$4;
88753
+ TabsContent$1.displayName = CONTENT_NAME$3;
87657
88754
  function makeTriggerId(baseId, value) {
87658
88755
  return `${baseId}-trigger-${value}`;
87659
88756
  }
87660
88757
  function makeContentId(baseId, value) {
87661
88758
  return `${baseId}-content-${value}`;
87662
88759
  }
87663
- var Root2$4 = Tabs$1;
88760
+ var Root2$3 = Tabs$1;
87664
88761
  var List = TabsList$1;
87665
88762
  var Trigger$2 = TabsTrigger$1;
87666
88763
  var Content = TabsContent$1;
87667
88764
 
87668
- const Tabs = Root2$4;
88765
+ const Tabs = Root2$3;
87669
88766
  const TabsList = React.forwardRef(({ className, ...props }, ref) => (jsx(List, { ref: ref, className: cn("bg-muted text-muted-foreground inline-flex h-9 items-center justify-center rounded-lg p-1", className), ...props })));
87670
88767
  TabsList.displayName = List.displayName;
87671
88768
  const TabsTrigger = React.forwardRef(({ className, ...props }, ref) => (jsx(Trigger$2, { ref: ref, className: cn("ring-offset-background focus-visible:ring-ring data-[state=active]:bg-background data-[state=active]:text-foreground inline-flex items-center justify-center rounded-md px-3 py-1 text-sm font-medium whitespace-nowrap transition-all focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow", className), ...props })));
@@ -88948,11 +90045,11 @@ var PopoverAnchor$1 = React.forwardRef(
88948
90045
  }
88949
90046
  );
88950
90047
  PopoverAnchor$1.displayName = ANCHOR_NAME$1;
88951
- var TRIGGER_NAME$2 = "PopoverTrigger";
90048
+ var TRIGGER_NAME$1 = "PopoverTrigger";
88952
90049
  var PopoverTrigger$1 = React.forwardRef(
88953
90050
  (props, forwardedRef) => {
88954
90051
  const { __scopePopover, ...triggerProps } = props;
88955
- const context = usePopoverContext(TRIGGER_NAME$2, __scopePopover);
90052
+ const context = usePopoverContext(TRIGGER_NAME$1, __scopePopover);
88956
90053
  const popperScope = usePopperScope$1(__scopePopover);
88957
90054
  const composedTriggerRef = useComposedRefs$1(forwardedRef, context.triggerRef);
88958
90055
  const trigger = /* @__PURE__ */ jsx(
@@ -88971,31 +90068,31 @@ var PopoverTrigger$1 = React.forwardRef(
88971
90068
  return context.hasCustomAnchor ? trigger : /* @__PURE__ */ jsx(Anchor$1, { asChild: true, ...popperScope, children: trigger });
88972
90069
  }
88973
90070
  );
88974
- PopoverTrigger$1.displayName = TRIGGER_NAME$2;
88975
- var PORTAL_NAME$3 = "PopoverPortal";
88976
- var [PortalProvider$1, usePortalContext$1] = createPopoverContext(PORTAL_NAME$3, {
90071
+ PopoverTrigger$1.displayName = TRIGGER_NAME$1;
90072
+ var PORTAL_NAME$2 = "PopoverPortal";
90073
+ var [PortalProvider$1, usePortalContext$1] = createPopoverContext(PORTAL_NAME$2, {
88977
90074
  forceMount: void 0
88978
90075
  });
88979
90076
  var PopoverPortal = (props) => {
88980
90077
  const { __scopePopover, forceMount, children, container } = props;
88981
- const context = usePopoverContext(PORTAL_NAME$3, __scopePopover);
90078
+ const context = usePopoverContext(PORTAL_NAME$2, __scopePopover);
88982
90079
  return /* @__PURE__ */ jsx(PortalProvider$1, { scope: __scopePopover, forceMount, children: /* @__PURE__ */ jsx(Presence$1, { present: forceMount || context.open, children: /* @__PURE__ */ jsx(Portal$6, { asChild: true, container, children }) }) });
88983
90080
  };
88984
- PopoverPortal.displayName = PORTAL_NAME$3;
88985
- var CONTENT_NAME$3 = "PopoverContent";
90081
+ PopoverPortal.displayName = PORTAL_NAME$2;
90082
+ var CONTENT_NAME$2 = "PopoverContent";
88986
90083
  var PopoverContent$1 = React.forwardRef(
88987
90084
  (props, forwardedRef) => {
88988
- const portalContext = usePortalContext$1(CONTENT_NAME$3, props.__scopePopover);
90085
+ const portalContext = usePortalContext$1(CONTENT_NAME$2, props.__scopePopover);
88989
90086
  const { forceMount = portalContext.forceMount, ...contentProps } = props;
88990
- const context = usePopoverContext(CONTENT_NAME$3, props.__scopePopover);
90087
+ const context = usePopoverContext(CONTENT_NAME$2, props.__scopePopover);
88991
90088
  return /* @__PURE__ */ jsx(Presence$1, { present: forceMount || context.open, children: context.modal ? /* @__PURE__ */ jsx(PopoverContentModal, { ...contentProps, ref: forwardedRef }) : /* @__PURE__ */ jsx(PopoverContentNonModal, { ...contentProps, ref: forwardedRef }) });
88992
90089
  }
88993
90090
  );
88994
- PopoverContent$1.displayName = CONTENT_NAME$3;
90091
+ PopoverContent$1.displayName = CONTENT_NAME$2;
88995
90092
  var Slot$1 = createSlot$1("PopoverContent.RemoveScroll");
88996
90093
  var PopoverContentModal = React.forwardRef(
88997
90094
  (props, forwardedRef) => {
88998
- const context = usePopoverContext(CONTENT_NAME$3, props.__scopePopover);
90095
+ const context = usePopoverContext(CONTENT_NAME$2, props.__scopePopover);
88999
90096
  const contentRef = React.useRef(null);
89000
90097
  const composedRefs = useComposedRefs$1(forwardedRef, contentRef);
89001
90098
  const isRightClickOutsideRef = React.useRef(false);
@@ -89035,7 +90132,7 @@ var PopoverContentModal = React.forwardRef(
89035
90132
  );
89036
90133
  var PopoverContentNonModal = React.forwardRef(
89037
90134
  (props, forwardedRef) => {
89038
- const context = usePopoverContext(CONTENT_NAME$3, props.__scopePopover);
90135
+ const context = usePopoverContext(CONTENT_NAME$2, props.__scopePopover);
89039
90136
  const hasInteractedOutsideRef = React.useRef(false);
89040
90137
  const hasPointerDownOutsideRef = React.useRef(false);
89041
90138
  return /* @__PURE__ */ jsx(
@@ -89087,7 +90184,7 @@ var PopoverContentImpl = React.forwardRef(
89087
90184
  onInteractOutside,
89088
90185
  ...contentProps
89089
90186
  } = props;
89090
- const context = usePopoverContext(CONTENT_NAME$3, __scopePopover);
90187
+ const context = usePopoverContext(CONTENT_NAME$2, __scopePopover);
89091
90188
  const popperScope = usePopperScope$1(__scopePopover);
89092
90189
  useFocusGuards();
89093
90190
  return /* @__PURE__ */ jsx(
@@ -89165,26 +90262,26 @@ PopoverArrow.displayName = ARROW_NAME$2;
89165
90262
  function getState$1(open) {
89166
90263
  return open ? "open" : "closed";
89167
90264
  }
89168
- var Root2$3 = Popover$1;
90265
+ var Root2$2 = Popover$1;
89169
90266
  var Anchor2$1 = PopoverAnchor$1;
89170
90267
  var Trigger$1 = PopoverTrigger$1;
89171
90268
  var Portal$1 = PopoverPortal;
89172
- var Content2$3 = PopoverContent$1;
90269
+ var Content2$2 = PopoverContent$1;
89173
90270
 
89174
- const Popover = Root2$3;
90271
+ const Popover = Root2$2;
89175
90272
  const PopoverTrigger = Trigger$1;
89176
90273
  const PopoverAnchor = Anchor2$1;
89177
90274
  const PopoverContent = React.forwardRef(({ className, align = 'center', sideOffset = 4, portalled = true, container, ...props }, ref) => {
89178
90275
  var _a;
89179
90276
  const portalContainer = useFloatingPortalContainer();
89180
90277
  const resolvedContainer = (_a = container !== null && container !== void 0 ? container : portalContainer) !== null && _a !== void 0 ? _a : undefined;
89181
- const content = (jsx(Content2$3, { ref: ref, "data-iblai-dialog-interaction-layer": true, align: align, sideOffset: sideOffset, className: cn('bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-md outline-none', className), ...props }));
90278
+ const content = (jsx(Content2$2, { ref: ref, "data-iblai-dialog-interaction-layer": true, align: align, sideOffset: sideOffset, className: cn('bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-md outline-none', className), ...props }));
89182
90279
  if (!portalled) {
89183
90280
  return content;
89184
90281
  }
89185
90282
  return jsx(Portal$1, { container: resolvedContainer, children: content });
89186
90283
  });
89187
- PopoverContent.displayName = Content2$3.displayName;
90284
+ PopoverContent.displayName = Content2$2.displayName;
89188
90285
 
89189
90286
  function UsersTab({ tenant, onInviteClick }) {
89190
90287
  const dispatch = useDispatch();
@@ -126301,30 +127398,30 @@ var MenuAnchor = React.forwardRef(
126301
127398
  }
126302
127399
  );
126303
127400
  MenuAnchor.displayName = ANCHOR_NAME;
126304
- var PORTAL_NAME$2 = "MenuPortal";
126305
- var [PortalProvider, usePortalContext] = createMenuContext(PORTAL_NAME$2, {
127401
+ var PORTAL_NAME$1 = "MenuPortal";
127402
+ var [PortalProvider, usePortalContext] = createMenuContext(PORTAL_NAME$1, {
126306
127403
  forceMount: void 0
126307
127404
  });
126308
127405
  var MenuPortal = (props) => {
126309
127406
  const { __scopeMenu, forceMount, children, container } = props;
126310
- const context = useMenuContext(PORTAL_NAME$2, __scopeMenu);
127407
+ const context = useMenuContext(PORTAL_NAME$1, __scopeMenu);
126311
127408
  return /* @__PURE__ */ jsx(PortalProvider, { scope: __scopeMenu, forceMount, children: /* @__PURE__ */ jsx(Presence$1, { present: forceMount || context.open, children: /* @__PURE__ */ jsx(Portal$6, { asChild: true, container, children }) }) });
126312
127409
  };
126313
- MenuPortal.displayName = PORTAL_NAME$2;
126314
- var CONTENT_NAME$2 = "MenuContent";
126315
- var [MenuContentProvider, useMenuContentContext] = createMenuContext(CONTENT_NAME$2);
127410
+ MenuPortal.displayName = PORTAL_NAME$1;
127411
+ var CONTENT_NAME$1 = "MenuContent";
127412
+ var [MenuContentProvider, useMenuContentContext] = createMenuContext(CONTENT_NAME$1);
126316
127413
  var MenuContent = React.forwardRef(
126317
127414
  (props, forwardedRef) => {
126318
- const portalContext = usePortalContext(CONTENT_NAME$2, props.__scopeMenu);
127415
+ const portalContext = usePortalContext(CONTENT_NAME$1, props.__scopeMenu);
126319
127416
  const { forceMount = portalContext.forceMount, ...contentProps } = props;
126320
- const context = useMenuContext(CONTENT_NAME$2, props.__scopeMenu);
126321
- const rootContext = useMenuRootContext(CONTENT_NAME$2, props.__scopeMenu);
127417
+ const context = useMenuContext(CONTENT_NAME$1, props.__scopeMenu);
127418
+ const rootContext = useMenuRootContext(CONTENT_NAME$1, props.__scopeMenu);
126322
127419
  return /* @__PURE__ */ jsx(Collection$1.Provider, { scope: props.__scopeMenu, children: /* @__PURE__ */ jsx(Presence$1, { present: forceMount || context.open, children: /* @__PURE__ */ jsx(Collection$1.Slot, { scope: props.__scopeMenu, children: rootContext.modal ? /* @__PURE__ */ jsx(MenuRootContentModal, { ...contentProps, ref: forwardedRef }) : /* @__PURE__ */ jsx(MenuRootContentNonModal, { ...contentProps, ref: forwardedRef }) }) }) });
126323
127420
  }
126324
127421
  );
126325
127422
  var MenuRootContentModal = React.forwardRef(
126326
127423
  (props, forwardedRef) => {
126327
- const context = useMenuContext(CONTENT_NAME$2, props.__scopeMenu);
127424
+ const context = useMenuContext(CONTENT_NAME$1, props.__scopeMenu);
126328
127425
  const ref = React.useRef(null);
126329
127426
  const composedRefs = useComposedRefs$1(forwardedRef, ref);
126330
127427
  React.useEffect(() => {
@@ -126350,7 +127447,7 @@ var MenuRootContentModal = React.forwardRef(
126350
127447
  }
126351
127448
  );
126352
127449
  var MenuRootContentNonModal = React.forwardRef((props, forwardedRef) => {
126353
- const context = useMenuContext(CONTENT_NAME$2, props.__scopeMenu);
127450
+ const context = useMenuContext(CONTENT_NAME$1, props.__scopeMenu);
126354
127451
  return /* @__PURE__ */ jsx(
126355
127452
  MenuContentImpl,
126356
127453
  {
@@ -126382,8 +127479,8 @@ var MenuContentImpl = React.forwardRef(
126382
127479
  disableOutsideScroll,
126383
127480
  ...contentProps
126384
127481
  } = props;
126385
- const context = useMenuContext(CONTENT_NAME$2, __scopeMenu);
126386
- const rootContext = useMenuRootContext(CONTENT_NAME$2, __scopeMenu);
127482
+ const context = useMenuContext(CONTENT_NAME$1, __scopeMenu);
127483
+ const rootContext = useMenuRootContext(CONTENT_NAME$1, __scopeMenu);
126387
127484
  const popperScope = usePopperScope(__scopeMenu);
126388
127485
  const rovingFocusGroupScope = useRovingFocusGroupScope$1(__scopeMenu);
126389
127486
  const getItems = useCollection$1(__scopeMenu);
@@ -126546,7 +127643,7 @@ var MenuContentImpl = React.forwardRef(
126546
127643
  );
126547
127644
  }
126548
127645
  );
126549
- MenuContent.displayName = CONTENT_NAME$2;
127646
+ MenuContent.displayName = CONTENT_NAME$1;
126550
127647
  var GROUP_NAME$2 = "MenuGroup";
126551
127648
  var MenuGroup = React.forwardRef(
126552
127649
  (props, forwardedRef) => {
@@ -126920,10 +128017,10 @@ MenuSubTrigger.displayName = SUB_TRIGGER_NAME$1;
126920
128017
  var SUB_CONTENT_NAME$1 = "MenuSubContent";
126921
128018
  var MenuSubContent = React.forwardRef(
126922
128019
  (props, forwardedRef) => {
126923
- const portalContext = usePortalContext(CONTENT_NAME$2, props.__scopeMenu);
128020
+ const portalContext = usePortalContext(CONTENT_NAME$1, props.__scopeMenu);
126924
128021
  const { forceMount = portalContext.forceMount, ...subContentProps } = props;
126925
- const context = useMenuContext(CONTENT_NAME$2, props.__scopeMenu);
126926
- const rootContext = useMenuRootContext(CONTENT_NAME$2, props.__scopeMenu);
128022
+ const context = useMenuContext(CONTENT_NAME$1, props.__scopeMenu);
128023
+ const rootContext = useMenuRootContext(CONTENT_NAME$1, props.__scopeMenu);
126927
128024
  const subContext = useMenuSubContext(SUB_CONTENT_NAME$1, props.__scopeMenu);
126928
128025
  const ref = React.useRef(null);
126929
128026
  const composedRefs = useComposedRefs$1(forwardedRef, ref);
@@ -127021,7 +128118,7 @@ function whenMouse(handler) {
127021
128118
  var Root3 = Menu;
127022
128119
  var Anchor2 = MenuAnchor;
127023
128120
  var Portal = MenuPortal;
127024
- var Content2$2 = MenuContent;
128121
+ var Content2$1 = MenuContent;
127025
128122
  var Group = MenuGroup;
127026
128123
  var Label$1 = MenuLabel;
127027
128124
  var Item2$2 = MenuItem;
@@ -127075,11 +128172,11 @@ var DropdownMenu$1 = (props) => {
127075
128172
  );
127076
128173
  };
127077
128174
  DropdownMenu$1.displayName = DROPDOWN_MENU_NAME;
127078
- var TRIGGER_NAME$1 = "DropdownMenuTrigger";
128175
+ var TRIGGER_NAME = "DropdownMenuTrigger";
127079
128176
  var DropdownMenuTrigger$1 = React.forwardRef(
127080
128177
  (props, forwardedRef) => {
127081
128178
  const { __scopeDropdownMenu, disabled = false, ...triggerProps } = props;
127082
- const context = useDropdownMenuContext(TRIGGER_NAME$1, __scopeDropdownMenu);
128179
+ const context = useDropdownMenuContext(TRIGGER_NAME, __scopeDropdownMenu);
127083
128180
  const menuScope = useMenuScope(__scopeDropdownMenu);
127084
128181
  return /* @__PURE__ */ jsx(Anchor2, { asChild: true, ...menuScope, children: /* @__PURE__ */ jsx(
127085
128182
  Primitive$4.button,
@@ -127110,23 +128207,23 @@ var DropdownMenuTrigger$1 = React.forwardRef(
127110
128207
  ) });
127111
128208
  }
127112
128209
  );
127113
- DropdownMenuTrigger$1.displayName = TRIGGER_NAME$1;
127114
- var PORTAL_NAME$1 = "DropdownMenuPortal";
128210
+ DropdownMenuTrigger$1.displayName = TRIGGER_NAME;
128211
+ var PORTAL_NAME = "DropdownMenuPortal";
127115
128212
  var DropdownMenuPortal$1 = (props) => {
127116
128213
  const { __scopeDropdownMenu, ...portalProps } = props;
127117
128214
  const menuScope = useMenuScope(__scopeDropdownMenu);
127118
128215
  return /* @__PURE__ */ jsx(Portal, { ...menuScope, ...portalProps });
127119
128216
  };
127120
- DropdownMenuPortal$1.displayName = PORTAL_NAME$1;
127121
- var CONTENT_NAME$1 = "DropdownMenuContent";
128217
+ DropdownMenuPortal$1.displayName = PORTAL_NAME;
128218
+ var CONTENT_NAME = "DropdownMenuContent";
127122
128219
  var DropdownMenuContent$1 = React.forwardRef(
127123
128220
  (props, forwardedRef) => {
127124
128221
  const { __scopeDropdownMenu, ...contentProps } = props;
127125
- const context = useDropdownMenuContext(CONTENT_NAME$1, __scopeDropdownMenu);
128222
+ const context = useDropdownMenuContext(CONTENT_NAME, __scopeDropdownMenu);
127126
128223
  const menuScope = useMenuScope(__scopeDropdownMenu);
127127
128224
  const hasInteractedOutsideRef = React.useRef(false);
127128
128225
  return /* @__PURE__ */ jsx(
127129
- Content2$2,
128226
+ Content2$1,
127130
128227
  {
127131
128228
  id: context.contentId,
127132
128229
  "aria-labelledby": context.triggerId,
@@ -127159,7 +128256,7 @@ var DropdownMenuContent$1 = React.forwardRef(
127159
128256
  );
127160
128257
  }
127161
128258
  );
127162
- DropdownMenuContent$1.displayName = CONTENT_NAME$1;
128259
+ DropdownMenuContent$1.displayName = CONTENT_NAME;
127163
128260
  var GROUP_NAME$1 = "DropdownMenuGroup";
127164
128261
  var DropdownMenuGroup$1 = React.forwardRef(
127165
128262
  (props, forwardedRef) => {
@@ -127273,10 +128370,10 @@ var DropdownMenuSubContent$1 = React.forwardRef((props, forwardedRef) => {
127273
128370
  );
127274
128371
  });
127275
128372
  DropdownMenuSubContent$1.displayName = SUB_CONTENT_NAME;
127276
- var Root2$2 = DropdownMenu$1;
128373
+ var Root2$1 = DropdownMenu$1;
127277
128374
  var Trigger = DropdownMenuTrigger$1;
127278
- var Portal2$1 = DropdownMenuPortal$1;
127279
- var Content2$1 = DropdownMenuContent$1;
128375
+ var Portal2 = DropdownMenuPortal$1;
128376
+ var Content2 = DropdownMenuContent$1;
127280
128377
  var Group2 = DropdownMenuGroup$1;
127281
128378
  var Label2 = DropdownMenuLabel$1;
127282
128379
  var Item2$1 = DropdownMenuItem$1;
@@ -127290,17 +128387,17 @@ var SubTrigger2 = DropdownMenuSubTrigger$1;
127290
128387
  var SubContent2 = DropdownMenuSubContent$1;
127291
128388
 
127292
128389
  function DropdownMenu({ ...props }) {
127293
- return jsx(Root2$2, { "data-slot": "dropdown-menu", ...props });
128390
+ return jsx(Root2$1, { "data-slot": "dropdown-menu", ...props });
127294
128391
  }
127295
128392
  function DropdownMenuPortal({ ...props }) {
127296
- return jsx(Portal2$1, { "data-slot": "dropdown-menu-portal", ...props });
128393
+ return jsx(Portal2, { "data-slot": "dropdown-menu-portal", ...props });
127297
128394
  }
127298
128395
  function DropdownMenuTrigger({ ...props }) {
127299
128396
  return jsx(Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
127300
128397
  }
127301
128398
  function DropdownMenuContent({ className, sideOffset = 4, ...props }) {
127302
128399
  const portalContainer = useFloatingPortalContainer();
127303
- return (jsx(Portal2$1, { container: portalContainer !== null && portalContainer !== void 0 ? portalContainer : undefined, children: jsx(Content2$1, { "data-slot": "dropdown-menu-content", "data-iblai-dialog-interaction-layer": true, sideOffset: sideOffset, className: cn('bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md', className), ...props }) }));
128400
+ return (jsx(Portal2, { container: portalContainer !== null && portalContainer !== void 0 ? portalContainer : undefined, children: jsx(Content2, { "data-slot": "dropdown-menu-content", "data-iblai-dialog-interaction-layer": true, sideOffset: sideOffset, className: cn('bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md', className), ...props }) }));
127304
128401
  }
127305
128402
  function DropdownMenuGroup({ ...props }) {
127306
128403
  return jsx(Group2, { "data-slot": "dropdown-menu-group", ...props });
@@ -128137,12 +129234,12 @@ var RadioGroupIndicator = React.forwardRef(
128137
129234
  }
128138
129235
  );
128139
129236
  RadioGroupIndicator.displayName = INDICATOR_NAME2;
128140
- var Root2$1 = RadioGroup$1;
129237
+ var Root2 = RadioGroup$1;
128141
129238
  var Item2 = RadioGroupItem$1;
128142
129239
  var Indicator = RadioGroupIndicator;
128143
129240
 
128144
129241
  function RadioGroup({ className, ...props }) {
128145
- return (jsx(Root2$1, { "data-slot": "radio-group", className: cn('grid gap-3', className), ...props }));
129242
+ return (jsx(Root2, { "data-slot": "radio-group", className: cn('grid gap-3', className), ...props }));
128146
129243
  }
128147
129244
  function RadioGroupItem({ className, ...props }) {
128148
129245
  return (jsx(Item2, { "data-slot": "radio-group-item", className: cn('border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50', className), ...props, children: jsx(Indicator, { "data-slot": "radio-group-indicator", className: "relative flex items-center justify-center", children: jsx(Circle, { className: "fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" }) }) }));
@@ -129604,173 +130701,6 @@ function NotificationDisplay({ org, userId, isAdmin = false, selectedNotificatio
129604
130701
  } }), jsx(Dialog, { open: isMobileModalOpen, onOpenChange: setIsMobileModalOpen, children: jsx(DialogContent, { className: "max-h-[85vh] overflow-y-auto max-w-[95vw]", children: selectedNotification && (jsxs(Fragment$1, { children: [jsxs(DialogHeader, { children: [jsx(DialogTitle, { className: "text-xl font-semibold text-gray-900 pr-6", children: selectedNotification.title }), jsxs("div", { className: "flex items-center gap-2 text-sm text-gray-500 pt-2", children: [jsx(Clock, { className: "h-4 w-4", "aria-hidden": "true" }), jsx("time", { dateTime: selectedNotification.timestamp.toISOString(), children: format$1(selectedNotification.timestamp, "MMMM d, yyyy 'at' h:mm a") })] })] }), jsx("div", { className: "prose prose-sm max-w-none text-gray-700 mt-4", dangerouslySetInnerHTML: { __html: sanitizeHtml(selectedNotification.body) }, "aria-labelledby": "mobile-notification-title" })] })) }) })] }));
129605
130702
  }
129606
130703
 
129607
- var SLOTTABLE_IDENTIFIER = Symbol("radix.slottable");
129608
- // @__NO_SIDE_EFFECTS__
129609
- function createSlottable(ownerName) {
129610
- const Slottable2 = ({ children }) => {
129611
- return /* @__PURE__ */ jsx(Fragment$1, { children });
129612
- };
129613
- Slottable2.displayName = `${ownerName}.Slottable`;
129614
- Slottable2.__radixId = SLOTTABLE_IDENTIFIER;
129615
- return Slottable2;
129616
- }
129617
-
129618
- var ROOT_NAME = "AlertDialog";
129619
- var [createAlertDialogContext, createAlertDialogScope] = createContextScope$1(ROOT_NAME, [
129620
- createDialogScope
129621
- ]);
129622
- var useDialogScope = createDialogScope();
129623
- var AlertDialog$1 = (props) => {
129624
- const { __scopeAlertDialog, ...alertDialogProps } = props;
129625
- const dialogScope = useDialogScope(__scopeAlertDialog);
129626
- return /* @__PURE__ */ jsx(DialogPrimitive.Root, { ...dialogScope, ...alertDialogProps, modal: true });
129627
- };
129628
- AlertDialog$1.displayName = ROOT_NAME;
129629
- var TRIGGER_NAME = "AlertDialogTrigger";
129630
- var AlertDialogTrigger = React.forwardRef(
129631
- (props, forwardedRef) => {
129632
- const { __scopeAlertDialog, ...triggerProps } = props;
129633
- const dialogScope = useDialogScope(__scopeAlertDialog);
129634
- return /* @__PURE__ */ jsx(DialogPrimitive.Trigger, { ...dialogScope, ...triggerProps, ref: forwardedRef });
129635
- }
129636
- );
129637
- AlertDialogTrigger.displayName = TRIGGER_NAME;
129638
- var PORTAL_NAME = "AlertDialogPortal";
129639
- var AlertDialogPortal$1 = (props) => {
129640
- const { __scopeAlertDialog, ...portalProps } = props;
129641
- const dialogScope = useDialogScope(__scopeAlertDialog);
129642
- return /* @__PURE__ */ jsx(DialogPrimitive.Portal, { ...dialogScope, ...portalProps });
129643
- };
129644
- AlertDialogPortal$1.displayName = PORTAL_NAME;
129645
- var OVERLAY_NAME = "AlertDialogOverlay";
129646
- var AlertDialogOverlay$1 = React.forwardRef(
129647
- (props, forwardedRef) => {
129648
- const { __scopeAlertDialog, ...overlayProps } = props;
129649
- const dialogScope = useDialogScope(__scopeAlertDialog);
129650
- return /* @__PURE__ */ jsx(DialogPrimitive.Overlay, { ...dialogScope, ...overlayProps, ref: forwardedRef });
129651
- }
129652
- );
129653
- AlertDialogOverlay$1.displayName = OVERLAY_NAME;
129654
- var CONTENT_NAME = "AlertDialogContent";
129655
- var [AlertDialogContentProvider, useAlertDialogContentContext] = createAlertDialogContext(CONTENT_NAME);
129656
- var Slottable = createSlottable("AlertDialogContent");
129657
- var AlertDialogContent$1 = React.forwardRef(
129658
- (props, forwardedRef) => {
129659
- const { __scopeAlertDialog, children, ...contentProps } = props;
129660
- const dialogScope = useDialogScope(__scopeAlertDialog);
129661
- const contentRef = React.useRef(null);
129662
- const composedRefs = useComposedRefs$1(forwardedRef, contentRef);
129663
- const cancelRef = React.useRef(null);
129664
- return /* @__PURE__ */ jsx(
129665
- DialogPrimitive.WarningProvider,
129666
- {
129667
- contentName: CONTENT_NAME,
129668
- titleName: TITLE_NAME,
129669
- docsSlug: "alert-dialog",
129670
- children: /* @__PURE__ */ jsx(AlertDialogContentProvider, { scope: __scopeAlertDialog, cancelRef, children: /* @__PURE__ */ jsxs(
129671
- DialogPrimitive.Content,
129672
- {
129673
- role: "alertdialog",
129674
- ...dialogScope,
129675
- ...contentProps,
129676
- ref: composedRefs,
129677
- onOpenAutoFocus: composeEventHandlers$2(contentProps.onOpenAutoFocus, (event) => {
129678
- event.preventDefault();
129679
- cancelRef.current?.focus({ preventScroll: true });
129680
- }),
129681
- onPointerDownOutside: (event) => event.preventDefault(),
129682
- onInteractOutside: (event) => event.preventDefault(),
129683
- children: [
129684
- /* @__PURE__ */ jsx(Slottable, { children }),
129685
- /* @__PURE__ */ jsx(DescriptionWarning, { contentRef })
129686
- ]
129687
- }
129688
- ) })
129689
- }
129690
- );
129691
- }
129692
- );
129693
- AlertDialogContent$1.displayName = CONTENT_NAME;
129694
- var TITLE_NAME = "AlertDialogTitle";
129695
- var AlertDialogTitle$1 = React.forwardRef(
129696
- (props, forwardedRef) => {
129697
- const { __scopeAlertDialog, ...titleProps } = props;
129698
- const dialogScope = useDialogScope(__scopeAlertDialog);
129699
- return /* @__PURE__ */ jsx(DialogPrimitive.Title, { ...dialogScope, ...titleProps, ref: forwardedRef });
129700
- }
129701
- );
129702
- AlertDialogTitle$1.displayName = TITLE_NAME;
129703
- var DESCRIPTION_NAME = "AlertDialogDescription";
129704
- var AlertDialogDescription$1 = React.forwardRef((props, forwardedRef) => {
129705
- const { __scopeAlertDialog, ...descriptionProps } = props;
129706
- const dialogScope = useDialogScope(__scopeAlertDialog);
129707
- return /* @__PURE__ */ jsx(DialogPrimitive.Description, { ...dialogScope, ...descriptionProps, ref: forwardedRef });
129708
- });
129709
- AlertDialogDescription$1.displayName = DESCRIPTION_NAME;
129710
- var ACTION_NAME = "AlertDialogAction";
129711
- var AlertDialogAction$1 = React.forwardRef(
129712
- (props, forwardedRef) => {
129713
- const { __scopeAlertDialog, ...actionProps } = props;
129714
- const dialogScope = useDialogScope(__scopeAlertDialog);
129715
- return /* @__PURE__ */ jsx(DialogPrimitive.Close, { ...dialogScope, ...actionProps, ref: forwardedRef });
129716
- }
129717
- );
129718
- AlertDialogAction$1.displayName = ACTION_NAME;
129719
- var CANCEL_NAME = "AlertDialogCancel";
129720
- var AlertDialogCancel$1 = React.forwardRef(
129721
- (props, forwardedRef) => {
129722
- const { __scopeAlertDialog, ...cancelProps } = props;
129723
- const { cancelRef } = useAlertDialogContentContext(CANCEL_NAME, __scopeAlertDialog);
129724
- const dialogScope = useDialogScope(__scopeAlertDialog);
129725
- const ref = useComposedRefs$1(forwardedRef, cancelRef);
129726
- return /* @__PURE__ */ jsx(DialogPrimitive.Close, { ...dialogScope, ...cancelProps, ref });
129727
- }
129728
- );
129729
- AlertDialogCancel$1.displayName = CANCEL_NAME;
129730
- var DescriptionWarning = ({ contentRef }) => {
129731
- const MESSAGE = `\`${CONTENT_NAME}\` requires a description for the component to be accessible for screen reader users.
129732
-
129733
- You can add a description to the \`${CONTENT_NAME}\` by passing a \`${DESCRIPTION_NAME}\` component as a child, which also benefits sighted users by adding visible context to the dialog.
129734
-
129735
- Alternatively, you can use your own component as a description by assigning it an \`id\` and passing the same value to the \`aria-describedby\` prop in \`${CONTENT_NAME}\`. If the description is confusing or duplicative for sighted users, you can use the \`@radix-ui/react-visually-hidden\` primitive as a wrapper around your description component.
129736
-
129737
- For more information, see https://radix-ui.com/primitives/docs/components/alert-dialog`;
129738
- React.useEffect(() => {
129739
- const hasDescription = document.getElementById(
129740
- contentRef.current?.getAttribute("aria-describedby")
129741
- );
129742
- if (!hasDescription) console.warn(MESSAGE);
129743
- }, [MESSAGE, contentRef]);
129744
- return null;
129745
- };
129746
- var Root2 = AlertDialog$1;
129747
- var Portal2 = AlertDialogPortal$1;
129748
- var Overlay2 = AlertDialogOverlay$1;
129749
- var Content2 = AlertDialogContent$1;
129750
- var Action = AlertDialogAction$1;
129751
- var Cancel = AlertDialogCancel$1;
129752
- var Title2 = AlertDialogTitle$1;
129753
- var Description2 = AlertDialogDescription$1;
129754
-
129755
- const AlertDialog = Root2;
129756
- const AlertDialogPortal = Portal2;
129757
- const AlertDialogOverlay = React.forwardRef(({ className, ...props }, ref) => (jsx(Overlay2, { className: cn('data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80', className), ...props, ref: ref })));
129758
- AlertDialogOverlay.displayName = Overlay2.displayName;
129759
- const AlertDialogContent = React.forwardRef(({ className, ...props }, ref) => (jsxs(AlertDialogPortal, { children: [jsx(AlertDialogOverlay, {}), jsx(Content2, { ref: ref, className: cn('bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg', className), ...props })] })));
129760
- AlertDialogContent.displayName = Content2.displayName;
129761
- const AlertDialogHeader = ({ className, ...props }) => (jsx("div", { className: cn('flex flex-col space-y-2 text-center sm:text-left', className), ...props }));
129762
- AlertDialogHeader.displayName = 'AlertDialogHeader';
129763
- const AlertDialogFooter = ({ className, ...props }) => (jsx("div", { className: cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className), ...props }));
129764
- AlertDialogFooter.displayName = 'AlertDialogFooter';
129765
- const AlertDialogTitle = React.forwardRef(({ className, ...props }, ref) => (jsx(Title2, { ref: ref, className: cn('text-lg font-semibold', className), ...props })));
129766
- AlertDialogTitle.displayName = Title2.displayName;
129767
- const AlertDialogDescription = React.forwardRef(({ className, ...props }, ref) => (jsx(Description2, { ref: ref, className: cn('text-muted-foreground text-sm', className), ...props })));
129768
- AlertDialogDescription.displayName = Description2.displayName;
129769
- const AlertDialogAction = React.forwardRef(({ className, ...props }, ref) => (jsx(Action, { ref: ref, className: cn(buttonVariants(), className), ...props })));
129770
- AlertDialogAction.displayName = Action.displayName;
129771
- const AlertDialogCancel = React.forwardRef(({ className, ...props }, ref) => (jsx(Cancel, { ref: ref, className: cn(buttonVariants({ variant: 'outline' }), 'mt-2 sm:mt-0', className), ...props })));
129772
- AlertDialogCancel.displayName = Cancel.displayName;
129773
-
129774
130704
  /**
129775
130705
  * **Private mode** toggle for the platform nav-bar. A single pill that
129776
130706
  * collapses to an icon-only chip when off, and expands with a cool
@@ -198727,7 +199657,7 @@ function ProjectsPage({ tenantKey, username, onOpenProject, navigateToMentorInPr
198727
199657
  if (error) {
198728
199658
  return (jsx("div", { className: "flex h-full items-center justify-center", children: jsxs("div", { className: "text-center", children: [jsx(CircleAlert, { className: "mx-auto mb-4 h-12 w-12 text-red-500" }), jsx("p", { className: "text-gray-600", children: "Failed to load projects" })] }) }));
198729
199659
  }
198730
- return (jsxs("div", { className: "flex h-full overflow-hidden", children: [jsx("div", { className: "scrollbar-hide flex-1 overflow-y-auto", children: jsxs("div", { className: "mx-auto max-w-[920px] px-3 py-6 md:px-6 md:py-8", children: [jsxs("div", { className: "mb-6", children: [jsx("h1", { className: "mb-2 text-2xl font-semibold text-gray-700", children: "Projects" }), jsx("p", { className: "text-sm text-gray-600", children: "Organize your agents, files, and instructions into dedicated projects" })] }), jsxs("div", { className: "mb-6 flex flex-col gap-4 sm:flex-row", children: [jsxs("div", { className: "relative flex-1", children: [jsx(Search, { className: "absolute top-1/2 left-4 h-5 w-5 -translate-y-1/2 transform text-gray-400" }), jsx(Input, { placeholder: "Search projects...", value: searchValue, onChange: (e) => setSearchValue(e.target.value), className: "w-full rounded-lg border-gray-300 py-3 pr-4 pl-12 text-base focus:border-blue-500 focus:ring-2 focus:ring-blue-500" })] }), jsxs(Button$1, { className: "rounded-lg bg-gradient-to-r from-[#38A1E5] to-[#7284FF] px-6 py-3 whitespace-nowrap text-white hover:from-[#2E8BD1] hover:to-[#5F6FE8]", onClick: () => executeWithTrialCheck(() => setIsCreateModalOpen(true)), children: [jsx(Plus, { className: "mr-2 h-5 w-5" }), "New Project"] })] }), isLoading ? (jsx("div", { className: "flex items-center justify-center py-12", children: jsx(LoaderCircle, { className: "h-8 w-8 animate-spin text-gray-400" }) })) : (jsxs(Fragment$1, { children: [jsx("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2", children: projects.map((project) => (jsx(Card, { className: "cursor-pointer rounded-lg border border-[#D0E0FF] bg-[#F5F8FF] transition-shadow hover:shadow-md", onClick: () => executeWithTrialCheck(() => onOpenProject(project)), children: jsxs(CardContent, { className: "p-6", children: [jsxs("div", { className: "mb-3 flex items-start justify-between gap-2", children: [jsx("h3", { className: "text-base font-semibold text-gray-900", children: project.name }), jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button$1, { variant: "ghost", size: "icon", className: "h-7 w-7 flex-shrink-0 text-gray-500 hover:bg-[#c9d8f8]", "aria-label": "Project actions", onClick: (e) => e.stopPropagation(), children: jsx(EllipsisVertical, { className: "h-4 w-4" }) }) }), jsxs(DropdownMenuContent, { align: "end", onClick: (e) => e.stopPropagation(), children: [jsxs(DropdownMenuItem, { onClick: (e) => {
199660
+ return (jsxs("div", { className: "flex h-full overflow-hidden", children: [jsx("div", { className: "scrollbar-hide flex-1 overflow-y-auto", children: jsxs("div", { className: "mx-auto max-w-[920px] px-3 py-6 md:px-6 md:py-8", children: [jsxs("div", { className: "mb-6", children: [jsx("h1", { className: "mb-2 text-2xl font-semibold text-gray-700", children: "Projects" }), jsx("p", { className: "text-sm text-gray-600", children: "Organize your agents, files, and instructions into dedicated projects" })] }), jsxs("div", { className: "mb-6 flex flex-col gap-4 sm:flex-row", children: [jsxs("div", { className: "relative flex-1", children: [jsx(Search, { className: "absolute top-1/2 left-4 h-5 w-5 -translate-y-1/2 transform text-gray-400" }), jsx(Input, { placeholder: "Search projects...", value: searchValue, onChange: (e) => setSearchValue(e.target.value), className: "w-full rounded-lg border-gray-300 py-3 pr-4 pl-12 text-base focus:border-blue-500 focus:ring-2 focus:ring-blue-500" })] }), jsxs(Button$1, { className: "rounded-lg bg-gradient-to-r from-[#38A1E5] to-[#7284FF] px-6 py-3 whitespace-nowrap text-white hover:from-[#2E8BD1] hover:to-[#5F6FE8]", onClick: () => executeWithTrialCheck(() => setIsCreateModalOpen(true)), children: [jsx(Plus, { className: "mr-2 h-5 w-5" }), "New Project"] })] }), isLoading ? (jsx("div", { className: "flex items-center justify-center py-12", children: jsx(LoaderCircle, { className: "h-8 w-8 animate-spin text-gray-400" }) })) : (jsxs(Fragment$1, { children: [jsx("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2", children: projects.map((project) => (jsx(Card, { className: "cursor-pointer rounded-lg border border-[#D0E0FF] bg-[#F5F8FF] transition-shadow hover:shadow-md", onClick: () => executeWithTrialCheck(() => onOpenProject(project)), children: jsxs(CardContent, { className: "p-6", children: [jsxs("div", { className: "mb-3 flex items-start justify-between gap-2", children: [jsx("h3", { className: "text-base font-semibold text-gray-900", children: project.name }), jsxs(DropdownMenu, { modal: false, children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button$1, { variant: "ghost", size: "icon", className: "h-7 w-7 flex-shrink-0 text-gray-500 hover:bg-[#c9d8f8]", "aria-label": "Project actions", onClick: (e) => e.stopPropagation(), children: jsx(EllipsisVertical, { className: "h-4 w-4" }) }) }), jsxs(DropdownMenuContent, { align: "end", onClick: (e) => e.stopPropagation(), children: [jsxs(DropdownMenuItem, { onClick: (e) => {
198731
199661
  e.stopPropagation();
198732
199662
  executeWithTrialCheck(() => handleRenameProject(String(project.id), project.name));
198733
199663
  }, children: [jsx(Pencil, { className: "mr-2 h-4 w-4" }), "Rename"] }), jsxs(DropdownMenuItem, { className: "text-red-600 focus:text-red-600", onClick: (e) => {
@@ -203243,5 +204173,5 @@ var trainOrDeleteModal = /*#__PURE__*/Object.freeze({
203243
204173
  TrainOrDeleteModal: TrainOrDeleteModal
203244
204174
  });
203245
204175
 
203246
- export { ACCESS_COURSE_LABEL, AccessTimeHeatmap, AccessiblePaginate, AddMentorToProjectModal, AddSkillDialog, Admin, AdvancedTab, AgentConfigPrompts, AgentSkills, AlertsTab, AnalyticsAuditLogStats, AnalyticsCourseDetail, AnalyticsCourses, AnalyticsFinancialStats, AnalyticsLayout, AnalyticsMonetizationStats, AnalyticsOverview, AnalyticsProgramDetail, AnalyticsPrograms, AnalyticsReportDownload, AnalyticsReports, AnalyticsSettingsProvider, AnalyticsTopicsStats, AnalyticsTranscriptsStats, AnalyticsUsersStats, AppleRestrictionModal, BUY_NOW_LABEL, BillingTab, CREATE_AGENT_LABELS, CategorizedDropdownMenu, ChartCardWrapper, ChartFiltersProvider, ChatContext, ChatPrivacyToggle, ChatProvider, CompanyDialog, ConnectorManagementDialog, CopyButtonIcon, CourseAccessGuard, CourseCardSkeleton, CourseContentLoading, CourseOutline, CourseOutlineContext, CourseOutlineDrawer, CreateAgentForm, CreateAgentModal, CreateProjectModal, CreateWorkflowModal, CredentialBox, CredentialMiniBoxSkeleton, CreditBalance, CustomDateRangePicker, CustomTooltip, DefaultEmptyBox, DeleteProjectModal, DeleteWorkflowModal, DiscoverContentCard, DiscoverFacetsFilter, DiscoverFilterDrawer, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, ENROLL_NOW_COURSE_STARTING_SOON_LABEL, ENROLL_NOW_LABEL, EditAlertDialog, EducationBox, EducationDialog, EducationTab, EdxIframeContext, EmptyStats, ExperienceBox, ExperienceDialog, ExperienceTab, FacetFilterContext, Footer, GroupsFilterDropdown, INVITATION_ONLY_LABEL, InstitutionDialog, IntegrationsTab, InviteUserContent, InviteUserDialog, InvitedUsersDialog, Loader, LocalLLMTab, LoginButton, Markdown, MinimumMentorAlert, MonetizationTab, NotificationDisplay, NotificationDropdown, ONBOARDING_SECTORS, OnboardingShell, OnboardingWizard, PaywallModal, Profile, ProfileTimeChart, ProgressDots, ProjectActionButtons, ProjectFilesModal, ProjectInstructionsModal, ProjectLandingPage, ProjectMentorsList, ProjectsPage, REQUEST_ACCESS_COURSE_STARTING_SOON_LABEL, REQUEST_ACCESS_LABEL, RenameProjectModal, ResumeBox, ResumeTab, RichTextEditor, SandboxConfig, SearchableMultiSelect, SendNotificationDialog, SignupButton, SkeletonActivityStatBox, SkeletonAddSkillsLoading, SkeletonCreatePathwaySearchList, SkeletonDiscoverFilterBox, SkeletonEducationBox, SkeletonMultiplier, SkeletonPathwayBox, SkeletonProfileInfoCard, SkeletonSkillBox, SkillBox, SkillDetailModal, SkillLeaderboardChart, SkillsBox, Spinner, StatCard, StepHeader, TAURI_COMMANDS, TAURI_EVENTS, TenantSwitcher, TimeFilter, TimeTrackingProvider, TimedExam, ToolDialogs, TopBanner, UpgradePackageModal, UserAvatar, Version, WorkflowSidebar, addBookmarksTab, findLastResumeBlock, findSequentialParent, flattenVerticalBlocks, getFirstAvailableUnit, getNextUnitIframe, getOrg, getParentBlockById, getParentsInfosFromSublessonId, getPreviousUnitIframe, getRandomCourseImage, getSectorById, getTenant, getUnitToIframe, getUserId, getUserName, inBrowserPrint, inIframe, initialModelDownloadState, isLocalLLMEnabled, isTauriApp, components as markdownComponents, onboardingPrimaryButtonClass, onboardingSecondaryButtonClass, resolveCreateAgentLabels, sanitizeCss, setLocalLLMEnabled, useAnalyticsSettings, useAuditLog, useCatalogSearch, useChartFilters, useChatPrivacy, useChatState, useCourseDetail, useCourseMetadata, useCourses, useDiscover, useEdxIframe, useFinancial, useIframeMessageHandler, useLocalStorage, useModelDownload, useMonetization, useOverview, useProfileActivityStats, useProfileCredentials, useProfilePathways, useProfilePrograms, useProfileSkills, useProfileTimeSpent, usePrograms, useReports, useTauri, useTimeTracking, useTopics, useTranscripts, useUserCourses, useUserMetadata, useUsers };
204176
+ export { ACCESS_COURSE_LABEL, AccessTimeHeatmap, AccessiblePaginate, AddMentorToProjectModal, AddSkillDialog, Admin, AdvancedTab, AgentConfigPrompts, AgentSkills, AlertsTab, AnalyticsAuditLogStats, AnalyticsCourseDetail, AnalyticsCourses, AnalyticsFinancialStats, AnalyticsLayout, AnalyticsMonetizationStats, AnalyticsOverview, AnalyticsProgramDetail, AnalyticsPrograms, AnalyticsReportDownload, AnalyticsReports, AnalyticsSettingsProvider, AnalyticsTopicsStats, AnalyticsTranscriptsStats, AnalyticsUsersStats, AppleRestrictionModal, BUY_NOW_LABEL, BillingTab, CREATE_AGENT_LABELS, CategorizedDropdownMenu, ChartCardWrapper, ChartFiltersProvider, ChatContext, ChatPrivacyToggle, ChatProvider, CompanyDialog, ConnectorManagementDialog, CopyButtonIcon, CourseAccessGuard, CourseCardSkeleton, CourseContentLoading, CourseOutline, CourseOutlineContext, CourseOutlineDrawer, CreateAgentForm, CreateAgentModal, CreateProjectModal, CreateWorkflowModal, CredentialBox, CredentialMiniBoxSkeleton, CreditBalance, CustomDateRangePicker, CustomTooltip, DEFAULT_SYSTEM_CONTROL_REQUIRED_SIZE_GB, DefaultEmptyBox, DeleteProjectModal, DeleteWorkflowModal, DiscoverContentCard, DiscoverFacetsFilter, DiscoverFilterDrawer, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, ENROLL_NOW_COURSE_STARTING_SOON_LABEL, ENROLL_NOW_LABEL, EditAlertDialog, EducationBox, EducationDialog, EducationTab, EdxIframeContext, EmptyStats, ExperienceBox, ExperienceDialog, ExperienceTab, FacetFilterContext, Footer, GHOST_OS_REPO_URL, GHOST_OS_TAURI_COMMANDS, GHOST_OS_TAURI_EVENTS, GroupsFilterDropdown, INVITATION_ONLY_LABEL, InstitutionDialog, IntegrationsTab, InviteUserContent, InviteUserDialog, InvitedUsersDialog, LOCAL_MODELS, Loader, LocalLLMTab, LocalModelsContent, LoginButton, MACOS_PERMISSIONS_COMMANDS, Markdown, MinimumMentorAlert, MonetizationTab, NotificationDisplay, NotificationDropdown, ONBOARDING_SECTORS, OnboardingShell, OnboardingWizard, PaywallModal, Profile, ProfileTimeChart, ProgressDots, ProjectActionButtons, ProjectFilesModal, ProjectInstructionsModal, ProjectLandingPage, ProjectMentorsList, ProjectsPage, REQUEST_ACCESS_COURSE_STARTING_SOON_LABEL, REQUEST_ACCESS_LABEL, RenameProjectModal, ResumeBox, ResumeTab, RichTextEditor, SandboxConfig, SearchableMultiSelect, SendNotificationDialog, SignupButton, SkeletonActivityStatBox, SkeletonAddSkillsLoading, SkeletonCreatePathwaySearchList, SkeletonDiscoverFilterBox, SkeletonEducationBox, SkeletonMultiplier, SkeletonPathwayBox, SkeletonProfileInfoCard, SkeletonSkillBox, SkillBox, SkillDetailModal, SkillLeaderboardChart, SkillsBox, Spinner, StatCard, StepHeader, SystemControlContent, SystemControlTab, TAURI_COMMANDS, TAURI_EVENTS, TenantSwitcher, TimeFilter, TimeTrackingProvider, TimedExam, ToolDialogs, TopBanner, UpgradePackageModal, UserAvatar, Version, WorkflowSidebar, addBookmarksTab, findLastResumeBlock, findSequentialParent, flattenVerticalBlocks, getFirstAvailableUnit, getLocalLLMModel, getLocalLLMToolSupport, getNextUnitIframe, getOrg, getParentBlockById, getParentsInfosFromSublessonId, getPreviousUnitIframe, getRandomCourseImage, getSectorById, getTenant, getUnitToIframe, getUserId, getUserName, inBrowserPrint, inIframe, initialGhostOsInstallState, initialModelDownloadState, isLocalLLMEnabled, isSystemControlEnabled, isTauriApp, components as markdownComponents, modelSupportsSystemControl, onboardingPrimaryButtonClass, onboardingSecondaryButtonClass, resolveCreateAgentLabels, sanitizeCss, setLocalLLMEnabled, setLocalLLMModel, setLocalLLMToolSupport, setSystemControlEnabled, smallestSystemControlModel, useAnalyticsSettings, useAuditLog, useCatalogSearch, useChartFilters, useChatPrivacy, useChatState, useCourseDetail, useCourseMetadata, useCourses, useDiscover, useEdxIframe, useFinancial, useGhostOs, useIframeMessageHandler, useLocalStorage, useModelDownload, useMonetization, useOverview, useProfileActivityStats, useProfileCredentials, useProfilePathways, useProfilePrograms, useProfileSkills, useProfileTimeSpent, usePrograms, useReports, useTauri, useTimeTracking, useTopics, useTranscripts, useUserCourses, useUserMetadata, useUsers };
203247
204177
  //# sourceMappingURL=index.esm.js.map