@iblai/iblai-js 2.3.9 → 2.3.11

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.
@@ -1134,7 +1134,9 @@ function useCuaDriver() {
1134
1134
  // treating null as denied would make Cowork unusable on Linux and Windows.
1135
1135
  const [accessibilityPermission, setAccessibilityPermission] = useState(null);
1136
1136
  const [screenRecordingPermission, setScreenRecordingPermission] = useState(null);
1137
- const hasCheckedStatus = useRef(false);
1137
+ // True once the host has answered a status check this mount — the retry
1138
+ // loop's stop condition, NOT a "ran once" guard (that was the bug).
1139
+ const statusSettled = useRef(false);
1138
1140
  /**
1139
1141
  * Read one permission. Checking never prompts (`AXIsProcessTrusted` /
1140
1142
  * `CGPreflightScreenCaptureAccess`), which is what makes it safe to do on mount.
@@ -1232,11 +1234,13 @@ function useCuaDriver() {
1232
1234
  }));
1233
1235
  }, [setState]);
1234
1236
  /**
1235
- * Query driver install status + session support from the host.
1237
+ * Query driver install status + session support from the host. Returns
1238
+ * whether the host actually answered — the mount effect retries on `false`,
1239
+ * because one failed check must not disable Cowork for the whole session.
1236
1240
  */
1237
1241
  const checkStatus = useCallback(async () => {
1238
1242
  if (!isAvailable)
1239
- return;
1243
+ return false;
1240
1244
  // Refresh both permissions alongside install status (independent, no prompt).
1241
1245
  refreshPermissions();
1242
1246
  try {
@@ -1249,10 +1253,12 @@ function useCuaDriver() {
1249
1253
  progress: result.installed ? 100 : prev.progress,
1250
1254
  lastUpdated: new Date().toISOString(),
1251
1255
  }));
1256
+ return true;
1252
1257
  }
1253
1258
  catch (error) {
1254
1259
  console.error('[useCuaDriver] Failed to check status:', error);
1255
1260
  setState((prev) => ({ ...prev, status: 'idle' }));
1261
+ return false;
1256
1262
  }
1257
1263
  }, [isAvailable, invoke, setState, refreshPermissions]);
1258
1264
  /**
@@ -1372,12 +1378,41 @@ function useCuaDriver() {
1372
1378
  };
1373
1379
  // Only re-subscribe if the host itself changes — never on state.
1374
1380
  }, [isAvailable, listen]);
1375
- // Check status once on mount (in the desktop app).
1381
+ // Check status on mount, and RETRY until the host answers once.
1382
+ //
1383
+ // This used to be one-shot behind a ref, which is why a built app could show
1384
+ // Cowork grey for a whole session: the single check raced the IPC bridge
1385
+ // being injected into the (remote) app origin, failed, and nothing ever asked
1386
+ // again — `status` stayed null and null renders as "not supported". Dev never
1387
+ // showed it because fast-refresh remounts re-ran the check constantly; a
1388
+ // production build gets exactly one mount, so it retries with backoff instead.
1389
+ // Capped: a host that still hasn't answered after ~75s is genuinely broken,
1390
+ // and install()/stop() re-check on their own paths anyway.
1376
1391
  useEffect(() => {
1377
- if (!isAvailable || hasCheckedStatus.current)
1392
+ if (!isAvailable)
1378
1393
  return;
1379
- hasCheckedStatus.current = true;
1380
- checkStatus();
1394
+ let cancelled = false;
1395
+ let timer;
1396
+ let attempt = 0;
1397
+ const MAX_ATTEMPTS = 8;
1398
+ const run = async () => {
1399
+ if (cancelled || statusSettled.current)
1400
+ return;
1401
+ if (await checkStatus()) {
1402
+ statusSettled.current = true;
1403
+ return;
1404
+ }
1405
+ attempt += 1;
1406
+ if (cancelled || attempt >= MAX_ATTEMPTS)
1407
+ return;
1408
+ timer = setTimeout(run, Math.min(1000 * 2 ** attempt, 15000));
1409
+ };
1410
+ run();
1411
+ return () => {
1412
+ cancelled = true;
1413
+ if (timer)
1414
+ clearTimeout(timer);
1415
+ };
1381
1416
  }, [isAvailable, checkStatus]);
1382
1417
  // Only expose the feature as available inside the desktop (Tauri) app.
1383
1418
  const finalIsAvailable = isAvailable && isTauriApp();
@@ -155392,6 +155427,19 @@ function StringSettingInput({ value, defaultValue, disabled, onSave, }) {
155392
155427
  };
155393
155428
  return (jsxs("div", { className: "flex items-center gap-2", children: [isDirty && (jsx(Button$1, { type: "button", size: "sm", onClick: handleSave, disabled: disabled, className: "h-8 bg-blue-500 hover:bg-blue-600 text-white", children: t('advancedAdvanced.save') })), jsx(Input, { value: localValue, onChange: (e) => setLocalValue(e.target.value), disabled: disabled, className: "max-w-[240px] w-[110px] sm:w-[230px] font-medium text-[#646464] text-sm" }), disabled && (jsx("div", { className: "w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" }))] }));
155394
155429
  }
155430
+ /**
155431
+ * A setting whose value is constrained to a fixed list of options declared in the
155432
+ * tenant metadata config, rendered as a dropdown.
155433
+ */
155434
+ function hasSelectableOptions(metadataItem) {
155435
+ return Array.isArray(metadataItem.options) && metadataItem.options.length > 0;
155436
+ }
155437
+ function SelectSettingInput({ label, options, value, defaultValue, disabled, triggerClassName, onSelect, }) {
155438
+ // Values saved before an option was renamed/removed fall back to the default
155439
+ // so the trigger never renders an empty selection.
155440
+ const selectedValue = options.some((option) => option.value === value) ? value : defaultValue;
155441
+ return (jsxs("div", { className: "flex items-center gap-2", children: [jsxs(Select$1, { value: selectedValue, onValueChange: onSelect, disabled: disabled, children: [jsx(SelectTrigger, { "aria-label": label, className: triggerClassName, children: jsx(SelectValue, {}) }), jsx(SelectContent, { className: "font-medium text-[#646464]", children: options.map((option) => (jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] }), disabled && (jsx("div", { className: "w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" }))] }));
155442
+ }
155395
155443
  function AdvancedTab({ platformKey, username, currentSPA, authURL, currentPlatformBaseDomain, }) {
155396
155444
  const t = useT();
155397
155445
  const [updateTenantMetadata, { isLoading: isUpdatingTenantMetadata }] = useUpdateTenantMetadataMutation();
@@ -155427,33 +155475,35 @@ function AdvancedTab({ platformKey, username, currentSPA, authURL, currentPlatfo
155427
155475
  'enable_profile_screen_on_start_page',
155428
155476
  'enable_get_started_screen_on_start_page',
155429
155477
  ];
155478
+ // String settings rendered as a free-text input; every other string setting is
155479
+ // either handled by a dedicated component or exposed through its own options list
155480
+ const stringSettingSlugs = [
155481
+ 'overall_default_mentor',
155482
+ 'help_center_url',
155483
+ 'monetization_base_path',
155484
+ 'skills_welcome_tagline',
155485
+ ];
155486
+ const getConfigurableMetadatas = () => {
155487
+ // Include boolean, select and whitelisted string settings, but exclude start
155488
+ // screen settings which are handled by the StartScreenContent component
155489
+ const configurableMetadatas = getAllMetadatas().filter((metadata) => (typeof metadata.defaultValue === 'boolean' ||
155490
+ hasSelectableOptions(metadata) ||
155491
+ (typeof metadata.defaultValue === 'string' &&
155492
+ stringSettingSlugs.includes(metadata.slug))) &&
155493
+ !startScreenSlugs.includes(metadata.slug));
155494
+ // Show all configurable settings when no SPA is specified
155495
+ if (!currentSPA)
155496
+ return configurableMetadatas;
155497
+ // Filter by current SPA if specified (case-insensitive partial matching)
155498
+ return configurableMetadatas.filter((metadata) => {
155499
+ const spaName = String(metadata.SPA || '').toLowerCase();
155500
+ const searchTerm = String(currentSPA).toLowerCase();
155501
+ return spaName.includes(searchTerm) || searchTerm.includes(spaName);
155502
+ });
155503
+ };
155430
155504
  useEffect(() => {
155431
155505
  if (metadataLoaded) {
155432
- const allMetadatas = getAllMetadatas();
155433
- // Include both boolean and string settings, but exclude start screen settings
155434
- // which are handled by the StartScreenContent component
155435
- const stringSettingSlugs = [
155436
- 'overall_default_mentor',
155437
- 'help_center_url',
155438
- 'monetization_base_path',
155439
- 'skills_welcome_tagline',
155440
- ];
155441
- const configurableMetadatas = allMetadatas.filter((metadata) => (typeof metadata.defaultValue === 'boolean' ||
155442
- (typeof metadata.defaultValue === 'string' &&
155443
- stringSettingSlugs.includes(metadata.slug))) &&
155444
- !startScreenSlugs.includes(metadata.slug));
155445
- if (currentSPA) {
155446
- // Filter by current SPA if specified (case-insensitive partial matching)
155447
- setFlagTenantMetadatas(configurableMetadatas.filter((metadata) => {
155448
- const spaName = String(metadata.SPA || '').toLowerCase();
155449
- const searchTerm = String(currentSPA).toLowerCase();
155450
- return spaName.includes(searchTerm) || searchTerm.includes(spaName);
155451
- }));
155452
- }
155453
- else {
155454
- // Show all configurable settings when no SPA is specified
155455
- setFlagTenantMetadatas(configurableMetadatas);
155456
- }
155506
+ setFlagTenantMetadatas(getConfigurableMetadatas());
155457
155507
  }
155458
155508
  }, [metadataLoaded, currentSPA]);
155459
155509
  const updateOrganizationMetadata = async (key, value, callback) => {
@@ -155497,8 +155547,7 @@ function AdvancedTab({ platformKey, username, currentSPA, authURL, currentPlatfo
155497
155547
  updateOrganizationMetadata(slug, newValue, () => {
155498
155548
  toast.success(t('advancedAdvanced.settingUpdatedSuccessfully'));
155499
155549
  // Update local state by refreshing the metadata
155500
- setFlagTenantMetadatas(getAllMetadatas().filter((metadata) => String(metadata.SPA).toLowerCase().includes(String(currentSPA).toLowerCase()) &&
155501
- typeof metadata.defaultValue === 'boolean'));
155550
+ setFlagTenantMetadatas(getConfigurableMetadatas());
155502
155551
  });
155503
155552
  };
155504
155553
  const handleMentorSelection = async (slug, mentorUniqueId) => {
@@ -155550,6 +155599,13 @@ function AdvancedTab({ platformKey, username, currentSPA, authURL, currentPlatfo
155550
155599
  toast.success(t('advancedAdvanced.settingUpdatedSuccessfully'));
155551
155600
  });
155552
155601
  };
155602
+ const handleSelectSettingUpdate = async (slug, value) => {
155603
+ updateOrganizationMetadata(slug, value, () => {
155604
+ toast.success(t('advancedAdvanced.settingUpdatedSuccessfully'));
155605
+ // Update local state so the dropdown reflects the saved value
155606
+ setFlagTenantMetadatas(getConfigurableMetadatas());
155607
+ });
155608
+ };
155553
155609
  // Helper function to get mentor name from JSON string, object, or unique_id
155554
155610
  const getMentorName = (mentorValue) => {
155555
155611
  var _a;
@@ -155584,11 +155640,17 @@ function AdvancedTab({ platformKey, username, currentSPA, authURL, currentPlatfo
155584
155640
  ? 'None'
155585
155641
  : ((_a = metadataItem.value) !== null && _a !== void 0 ? _a : metadataItem.defaultValue);
155586
155642
  const isMentorSetting = metadataItem.slug === 'overall_default_mentor';
155587
- const isStringSetting = typeof metadataItem.defaultValue === 'string' && !isMentorSetting;
155588
- return (jsxs("div", { className: `flex items-center justify-between rounded-lg border px-6 ${isMentorSetting || isStringSetting ? 'py-4' : 'py-6'}`, 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: metadataItem.label }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": t('advancedAdvanced.moreInfoAbout', {
155643
+ const selectOptions = hasSelectableOptions(metadataItem)
155644
+ ? metadataItem.options
155645
+ : null;
155646
+ const isSelectSetting = selectOptions !== null;
155647
+ const isStringSetting = typeof metadataItem.defaultValue === 'string' &&
155648
+ !isMentorSetting &&
155649
+ !isSelectSetting;
155650
+ return (jsxs("div", { className: `flex items-center justify-between rounded-lg border px-6 ${isMentorSetting || isStringSetting || isSelectSetting ? 'py-4' : 'py-6'}`, 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: metadataItem.label }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": t('advancedAdvanced.moreInfoAbout', {
155589
155651
  label: metadataItem.label,
155590
155652
  }), 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 whitespace-nowrap text-white shadow-sm transition-opacity duration-300 z-50", children: jsx("p", { children: metadataItem.description ||
155591
- t('advancedAdvanced.noDescriptionAvailable') }) })] }) })] }), jsx("div", { className: "flex items-center gap-2", children: isMentorSetting ? (jsxs("div", { className: "flex items-center gap-2", children: [jsxs(Select$1, { value: currentValue || '', onValueChange: (value) => handleMentorSelection(metadataItem.slug, value), disabled: isUpdatingTenantMetadata, children: [jsx(SelectTrigger, { className: "max-w-[240px] w-[110px] sm:w-[230px] font-medium text-[#646464]", children: jsx(SelectValue, { placeholder: t('advancedAdvanced.selectAgent'), children: currentValue ? getMentorName(currentValue) : '' }) }), jsxs(SelectContent, { className: "font-medium text-[#646464]", children: [jsx("div", { className: "p-2", children: jsx(Input, { placeholder: t('advancedAdvanced.searchAgents'), value: mentorSearchQuery, onChange: (e) => handleMentorSearch(e.target.value), className: "mb-2 font-medium text-[#646464]" }) }), jsx(SelectItem, { value: "none", children: t('advancedAdvanced.none') }), isMentorsLoading ? (jsx(SelectItem, { "aria-label": t('advancedAdvanced.loadingAgents'), value: "loading", disabled: true, children: t('advancedAdvanced.loadingAgents') })) : ((_b = mentorsData === null || mentorsData === void 0 ? void 0 : mentorsData.results) === null || _b === void 0 ? void 0 : _b.length) ? (mentorsData.results.map((mentor) => (jsx(SelectItem, { value: mentor.unique_id, children: mentor.name }, mentor.unique_id)))) : (jsx(SelectItem, { value: "no-results", disabled: true, children: t('advancedAdvanced.noAgentsFound') }))] })] }), isUpdatingTenantMetadata && (jsx("div", { "aria-label": t('advancedAdvanced.updatingAgentSelection'), role: "status", className: "w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" }))] })) : isStringSetting ? (jsx(StringSettingInput, { value: currentValue, defaultValue: metadataItem.defaultValue, disabled: isUpdatingTenantMetadata, onSave: (value) => handleStringSettingUpdate(metadataItem.slug, value) })) : (jsxs(Fragment$1, { children: [jsx(Switch, { checked: currentValue, onCheckedChange: async () => {
155653
+ t('advancedAdvanced.noDescriptionAvailable') }) })] }) })] }), jsx("div", { className: "flex items-center gap-2", children: isMentorSetting ? (jsxs("div", { className: "flex items-center gap-2", children: [jsxs(Select$1, { value: currentValue || '', onValueChange: (value) => handleMentorSelection(metadataItem.slug, value), disabled: isUpdatingTenantMetadata, children: [jsx(SelectTrigger, { className: "max-w-[240px] w-[110px] sm:w-[230px] font-medium text-[#646464]", children: jsx(SelectValue, { placeholder: t('advancedAdvanced.selectAgent'), children: currentValue ? getMentorName(currentValue) : '' }) }), jsxs(SelectContent, { className: "font-medium text-[#646464]", children: [jsx("div", { className: "p-2", children: jsx(Input, { placeholder: t('advancedAdvanced.searchAgents'), value: mentorSearchQuery, onChange: (e) => handleMentorSearch(e.target.value), className: "mb-2 font-medium text-[#646464]" }) }), jsx(SelectItem, { value: "none", children: t('advancedAdvanced.none') }), isMentorsLoading ? (jsx(SelectItem, { "aria-label": t('advancedAdvanced.loadingAgents'), value: "loading", disabled: true, children: t('advancedAdvanced.loadingAgents') })) : ((_b = mentorsData === null || mentorsData === void 0 ? void 0 : mentorsData.results) === null || _b === void 0 ? void 0 : _b.length) ? (mentorsData.results.map((mentor) => (jsx(SelectItem, { value: mentor.unique_id, children: mentor.name }, mentor.unique_id)))) : (jsx(SelectItem, { value: "no-results", disabled: true, children: t('advancedAdvanced.noAgentsFound') }))] })] }), isUpdatingTenantMetadata && (jsx("div", { "aria-label": t('advancedAdvanced.updatingAgentSelection'), role: "status", className: "w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" }))] })) : selectOptions ? (jsx(SelectSettingInput, { label: metadataItem.label, options: selectOptions, value: metadataItem.value, defaultValue: metadataItem.defaultValue, disabled: isUpdatingTenantMetadata, triggerClassName: "max-w-[240px] w-[110px] sm:w-[230px] font-medium text-[#646464]", onSelect: (value) => handleSelectSettingUpdate(metadataItem.slug, value) })) : isStringSetting ? (jsx(StringSettingInput, { value: currentValue, defaultValue: metadataItem.defaultValue, disabled: isUpdatingTenantMetadata, onSave: (value) => handleStringSettingUpdate(metadataItem.slug, value) })) : (jsxs(Fragment$1, { children: [jsx(Switch, { checked: currentValue, onCheckedChange: async () => {
155592
155654
  await handleToggleSetting(metadataItem.slug, currentValue);
155593
155655
  }, disabled: isUpdatingTenantMetadata, "aria-label": `${metadataItem.label} ${currentValue ? t('advancedAdvanced.enabled') : t('advancedAdvanced.disabled')}`, className: "cursor-pointer data-[state=checked]:bg-blue-500" }), isUpdatingTenantMetadata && (jsx("div", { className: "w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" }))] })) })] }, metadataItem.slug));
155594
155656
  }) })) : (
@@ -155606,11 +155668,17 @@ function AdvancedTab({ platformKey, username, currentSPA, authURL, currentPlatfo
155606
155668
  var _a, _b;
155607
155669
  const currentValue = (_a = metadataItem.value) !== null && _a !== void 0 ? _a : metadataItem.defaultValue;
155608
155670
  const isMentorSetting = metadataItem.slug === 'overall_default_mentor';
155609
- const isStringSetting = typeof metadataItem.defaultValue === 'string' && !isMentorSetting;
155610
- return (jsxs("div", { className: `flex items-center justify-between rounded-lg border px-6 ${isMentorSetting || isStringSetting ? 'py-4' : 'py-6'}`, 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: metadataItem.label }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": t('advancedAdvanced.moreInfoAbout', {
155671
+ const selectOptions = hasSelectableOptions(metadataItem)
155672
+ ? metadataItem.options
155673
+ : null;
155674
+ const isSelectSetting = selectOptions !== null;
155675
+ const isStringSetting = typeof metadataItem.defaultValue === 'string' &&
155676
+ !isMentorSetting &&
155677
+ !isSelectSetting;
155678
+ return (jsxs("div", { className: `flex items-center justify-between rounded-lg border px-6 ${isMentorSetting || isStringSetting || isSelectSetting ? 'py-4' : 'py-6'}`, 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: metadataItem.label }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": t('advancedAdvanced.moreInfoAbout', {
155611
155679
  label: metadataItem.label,
155612
155680
  }), className: "hidden sm:block", children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { className: "ibl-tooltip-content", children: jsx("p", { children: metadataItem.description ||
155613
- t('advancedAdvanced.noDescriptionAvailable') }) })] }) })] }), jsx("div", { className: "flex items-center gap-2", children: isMentorSetting ? (jsxs("div", { className: "flex items-center gap-2", children: [jsxs(Select$1, { value: currentValue || '', onValueChange: (value) => handleMentorSelection(metadataItem.slug, value), disabled: isUpdatingTenantMetadata, children: [jsx(SelectTrigger, { className: "max-w-[240px] w-[230px] sm:w-[150px] font-medium text-[#646464]", children: jsx(SelectValue, { placeholder: t('advancedAdvanced.selectAgent'), children: currentValue ? getMentorName(currentValue) : '' }) }), jsxs(SelectContent, { className: "font-medium text-[#646464]", children: [jsx("div", { className: "p-2", children: jsx(Input, { placeholder: t('advancedAdvanced.searchAgents'), value: mentorSearchQuery, onChange: (e) => handleMentorSearch(e.target.value), className: "mb-2 font-medium text-[#646464]" }) }), jsx(SelectItem, { value: "none", children: t('advancedAdvanced.none') }), isMentorsLoading ? (jsx(SelectItem, { value: "loading", disabled: true, children: t('advancedAdvanced.loadingAgents') })) : ((_b = mentorsData === null || mentorsData === void 0 ? void 0 : mentorsData.results) === null || _b === void 0 ? void 0 : _b.length) ? (mentorsData.results.map((mentor) => (jsx(SelectItem, { value: mentor.unique_id, children: mentor.name }, mentor.unique_id)))) : (jsx(SelectItem, { value: "no-results", disabled: true, children: t('advancedAdvanced.noAgentsFound') }))] })] }), isUpdatingTenantMetadata && (jsx("div", { className: "w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" }))] })) : isStringSetting ? (jsx(StringSettingInput, { value: currentValue, defaultValue: metadataItem.defaultValue, disabled: isUpdatingTenantMetadata, onSave: (value) => handleStringSettingUpdate(metadataItem.slug, value) })) : (jsxs(Fragment$1, { children: [jsx(Switch, { checked: currentValue, onCheckedChange: async () => {
155681
+ t('advancedAdvanced.noDescriptionAvailable') }) })] }) })] }), jsx("div", { className: "flex items-center gap-2", children: isMentorSetting ? (jsxs("div", { className: "flex items-center gap-2", children: [jsxs(Select$1, { value: currentValue || '', onValueChange: (value) => handleMentorSelection(metadataItem.slug, value), disabled: isUpdatingTenantMetadata, children: [jsx(SelectTrigger, { className: "max-w-[240px] w-[230px] sm:w-[150px] font-medium text-[#646464]", children: jsx(SelectValue, { placeholder: t('advancedAdvanced.selectAgent'), children: currentValue ? getMentorName(currentValue) : '' }) }), jsxs(SelectContent, { className: "font-medium text-[#646464]", children: [jsx("div", { className: "p-2", children: jsx(Input, { placeholder: t('advancedAdvanced.searchAgents'), value: mentorSearchQuery, onChange: (e) => handleMentorSearch(e.target.value), className: "mb-2 font-medium text-[#646464]" }) }), jsx(SelectItem, { value: "none", children: t('advancedAdvanced.none') }), isMentorsLoading ? (jsx(SelectItem, { value: "loading", disabled: true, children: t('advancedAdvanced.loadingAgents') })) : ((_b = mentorsData === null || mentorsData === void 0 ? void 0 : mentorsData.results) === null || _b === void 0 ? void 0 : _b.length) ? (mentorsData.results.map((mentor) => (jsx(SelectItem, { value: mentor.unique_id, children: mentor.name }, mentor.unique_id)))) : (jsx(SelectItem, { value: "no-results", disabled: true, children: t('advancedAdvanced.noAgentsFound') }))] })] }), isUpdatingTenantMetadata && (jsx("div", { className: "w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" }))] })) : selectOptions ? (jsx(SelectSettingInput, { label: metadataItem.label, options: selectOptions, value: metadataItem.value, defaultValue: metadataItem.defaultValue, disabled: isUpdatingTenantMetadata, triggerClassName: "max-w-[240px] w-[230px] sm:w-[150px] font-medium text-[#646464]", onSelect: (value) => handleSelectSettingUpdate(metadataItem.slug, value) })) : isStringSetting ? (jsx(StringSettingInput, { value: currentValue, defaultValue: metadataItem.defaultValue, disabled: isUpdatingTenantMetadata, onSave: (value) => handleStringSettingUpdate(metadataItem.slug, value) })) : (jsxs(Fragment$1, { children: [jsx(Switch, { checked: currentValue, onCheckedChange: async () => {
155614
155682
  await handleToggleSetting(metadataItem.slug, currentValue);
155615
155683
  }, disabled: isUpdatingTenantMetadata, "aria-label": `${metadataItem.label} ${currentValue ? t('advancedAdvanced.enabled') : t('advancedAdvanced.disabled')}`, className: "cursor-pointer data-[state=checked]:bg-blue-500" }), isUpdatingTenantMetadata && (jsx("div", { className: "w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" }))] })) })] }, metadataItem.slug));
155616
155684
  }) })] }, spa)));
@@ -189684,6 +189684,19 @@ function StringSettingInput({ value, defaultValue, disabled, onSave, }) {
189684
189684
  };
189685
189685
  return (jsxs("div", { className: "flex items-center gap-2", children: [isDirty && (jsx(Button$1, { type: "button", size: "sm", onClick: handleSave, disabled: disabled, className: "h-8 bg-blue-500 hover:bg-blue-600 text-white", children: t('advancedAdvanced.save') })), jsx(Input, { value: localValue, onChange: (e) => setLocalValue(e.target.value), disabled: disabled, className: "max-w-[240px] w-[110px] sm:w-[230px] font-medium text-[#646464] text-sm" }), disabled && (jsx("div", { className: "w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" }))] }));
189686
189686
  }
189687
+ /**
189688
+ * A setting whose value is constrained to a fixed list of options declared in the
189689
+ * tenant metadata config, rendered as a dropdown.
189690
+ */
189691
+ function hasSelectableOptions(metadataItem) {
189692
+ return Array.isArray(metadataItem.options) && metadataItem.options.length > 0;
189693
+ }
189694
+ function SelectSettingInput({ label, options, value, defaultValue, disabled, triggerClassName, onSelect, }) {
189695
+ // Values saved before an option was renamed/removed fall back to the default
189696
+ // so the trigger never renders an empty selection.
189697
+ const selectedValue = options.some((option) => option.value === value) ? value : defaultValue;
189698
+ return (jsxs("div", { className: "flex items-center gap-2", children: [jsxs(Select$1, { value: selectedValue, onValueChange: onSelect, disabled: disabled, children: [jsx(SelectTrigger, { "aria-label": label, className: triggerClassName, children: jsx(SelectValue, {}) }), jsx(SelectContent, { className: "font-medium text-[#646464]", children: options.map((option) => (jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] }), disabled && (jsx("div", { className: "w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" }))] }));
189699
+ }
189687
189700
  function AdvancedTab({ platformKey, username, currentSPA, authURL, currentPlatformBaseDomain, }) {
189688
189701
  const t = useT();
189689
189702
  const [updateTenantMetadata, { isLoading: isUpdatingTenantMetadata }] = useUpdateTenantMetadataMutation();
@@ -189719,33 +189732,35 @@ function AdvancedTab({ platformKey, username, currentSPA, authURL, currentPlatfo
189719
189732
  'enable_profile_screen_on_start_page',
189720
189733
  'enable_get_started_screen_on_start_page',
189721
189734
  ];
189735
+ // String settings rendered as a free-text input; every other string setting is
189736
+ // either handled by a dedicated component or exposed through its own options list
189737
+ const stringSettingSlugs = [
189738
+ 'overall_default_mentor',
189739
+ 'help_center_url',
189740
+ 'monetization_base_path',
189741
+ 'skills_welcome_tagline',
189742
+ ];
189743
+ const getConfigurableMetadatas = () => {
189744
+ // Include boolean, select and whitelisted string settings, but exclude start
189745
+ // screen settings which are handled by the StartScreenContent component
189746
+ const configurableMetadatas = getAllMetadatas().filter((metadata) => (typeof metadata.defaultValue === 'boolean' ||
189747
+ hasSelectableOptions(metadata) ||
189748
+ (typeof metadata.defaultValue === 'string' &&
189749
+ stringSettingSlugs.includes(metadata.slug))) &&
189750
+ !startScreenSlugs.includes(metadata.slug));
189751
+ // Show all configurable settings when no SPA is specified
189752
+ if (!currentSPA)
189753
+ return configurableMetadatas;
189754
+ // Filter by current SPA if specified (case-insensitive partial matching)
189755
+ return configurableMetadatas.filter((metadata) => {
189756
+ const spaName = String(metadata.SPA || '').toLowerCase();
189757
+ const searchTerm = String(currentSPA).toLowerCase();
189758
+ return spaName.includes(searchTerm) || searchTerm.includes(spaName);
189759
+ });
189760
+ };
189722
189761
  useEffect(() => {
189723
189762
  if (metadataLoaded) {
189724
- const allMetadatas = getAllMetadatas();
189725
- // Include both boolean and string settings, but exclude start screen settings
189726
- // which are handled by the StartScreenContent component
189727
- const stringSettingSlugs = [
189728
- 'overall_default_mentor',
189729
- 'help_center_url',
189730
- 'monetization_base_path',
189731
- 'skills_welcome_tagline',
189732
- ];
189733
- const configurableMetadatas = allMetadatas.filter((metadata) => (typeof metadata.defaultValue === 'boolean' ||
189734
- (typeof metadata.defaultValue === 'string' &&
189735
- stringSettingSlugs.includes(metadata.slug))) &&
189736
- !startScreenSlugs.includes(metadata.slug));
189737
- if (currentSPA) {
189738
- // Filter by current SPA if specified (case-insensitive partial matching)
189739
- setFlagTenantMetadatas(configurableMetadatas.filter((metadata) => {
189740
- const spaName = String(metadata.SPA || '').toLowerCase();
189741
- const searchTerm = String(currentSPA).toLowerCase();
189742
- return spaName.includes(searchTerm) || searchTerm.includes(spaName);
189743
- }));
189744
- }
189745
- else {
189746
- // Show all configurable settings when no SPA is specified
189747
- setFlagTenantMetadatas(configurableMetadatas);
189748
- }
189763
+ setFlagTenantMetadatas(getConfigurableMetadatas());
189749
189764
  }
189750
189765
  }, [metadataLoaded, currentSPA]);
189751
189766
  const updateOrganizationMetadata = async (key, value, callback) => {
@@ -189789,8 +189804,7 @@ function AdvancedTab({ platformKey, username, currentSPA, authURL, currentPlatfo
189789
189804
  updateOrganizationMetadata(slug, newValue, () => {
189790
189805
  toast.success(t('advancedAdvanced.settingUpdatedSuccessfully'));
189791
189806
  // Update local state by refreshing the metadata
189792
- setFlagTenantMetadatas(getAllMetadatas().filter((metadata) => String(metadata.SPA).toLowerCase().includes(String(currentSPA).toLowerCase()) &&
189793
- typeof metadata.defaultValue === 'boolean'));
189807
+ setFlagTenantMetadatas(getConfigurableMetadatas());
189794
189808
  });
189795
189809
  };
189796
189810
  const handleMentorSelection = async (slug, mentorUniqueId) => {
@@ -189842,6 +189856,13 @@ function AdvancedTab({ platformKey, username, currentSPA, authURL, currentPlatfo
189842
189856
  toast.success(t('advancedAdvanced.settingUpdatedSuccessfully'));
189843
189857
  });
189844
189858
  };
189859
+ const handleSelectSettingUpdate = async (slug, value) => {
189860
+ updateOrganizationMetadata(slug, value, () => {
189861
+ toast.success(t('advancedAdvanced.settingUpdatedSuccessfully'));
189862
+ // Update local state so the dropdown reflects the saved value
189863
+ setFlagTenantMetadatas(getConfigurableMetadatas());
189864
+ });
189865
+ };
189845
189866
  // Helper function to get mentor name from JSON string, object, or unique_id
189846
189867
  const getMentorName = (mentorValue) => {
189847
189868
  var _a;
@@ -189876,11 +189897,17 @@ function AdvancedTab({ platformKey, username, currentSPA, authURL, currentPlatfo
189876
189897
  ? 'None'
189877
189898
  : ((_a = metadataItem.value) !== null && _a !== void 0 ? _a : metadataItem.defaultValue);
189878
189899
  const isMentorSetting = metadataItem.slug === 'overall_default_mentor';
189879
- const isStringSetting = typeof metadataItem.defaultValue === 'string' && !isMentorSetting;
189880
- return (jsxs("div", { className: `flex items-center justify-between rounded-lg border px-6 ${isMentorSetting || isStringSetting ? 'py-4' : 'py-6'}`, 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: metadataItem.label }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": t('advancedAdvanced.moreInfoAbout', {
189900
+ const selectOptions = hasSelectableOptions(metadataItem)
189901
+ ? metadataItem.options
189902
+ : null;
189903
+ const isSelectSetting = selectOptions !== null;
189904
+ const isStringSetting = typeof metadataItem.defaultValue === 'string' &&
189905
+ !isMentorSetting &&
189906
+ !isSelectSetting;
189907
+ return (jsxs("div", { className: `flex items-center justify-between rounded-lg border px-6 ${isMentorSetting || isStringSetting || isSelectSetting ? 'py-4' : 'py-6'}`, 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: metadataItem.label }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": t('advancedAdvanced.moreInfoAbout', {
189881
189908
  label: metadataItem.label,
189882
189909
  }), 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 whitespace-nowrap text-white shadow-sm transition-opacity duration-300 z-50", children: jsx("p", { children: metadataItem.description ||
189883
- t('advancedAdvanced.noDescriptionAvailable') }) })] }) })] }), jsx("div", { className: "flex items-center gap-2", children: isMentorSetting ? (jsxs("div", { className: "flex items-center gap-2", children: [jsxs(Select$1, { value: currentValue || '', onValueChange: (value) => handleMentorSelection(metadataItem.slug, value), disabled: isUpdatingTenantMetadata, children: [jsx(SelectTrigger, { className: "max-w-[240px] w-[110px] sm:w-[230px] font-medium text-[#646464]", children: jsx(SelectValue, { placeholder: t('advancedAdvanced.selectAgent'), children: currentValue ? getMentorName(currentValue) : '' }) }), jsxs(SelectContent, { className: "font-medium text-[#646464]", children: [jsx("div", { className: "p-2", children: jsx(Input, { placeholder: t('advancedAdvanced.searchAgents'), value: mentorSearchQuery, onChange: (e) => handleMentorSearch(e.target.value), className: "mb-2 font-medium text-[#646464]" }) }), jsx(SelectItem, { value: "none", children: t('advancedAdvanced.none') }), isMentorsLoading ? (jsx(SelectItem, { "aria-label": t('advancedAdvanced.loadingAgents'), value: "loading", disabled: true, children: t('advancedAdvanced.loadingAgents') })) : ((_b = mentorsData === null || mentorsData === void 0 ? void 0 : mentorsData.results) === null || _b === void 0 ? void 0 : _b.length) ? (mentorsData.results.map((mentor) => (jsx(SelectItem, { value: mentor.unique_id, children: mentor.name }, mentor.unique_id)))) : (jsx(SelectItem, { value: "no-results", disabled: true, children: t('advancedAdvanced.noAgentsFound') }))] })] }), isUpdatingTenantMetadata && (jsx("div", { "aria-label": t('advancedAdvanced.updatingAgentSelection'), role: "status", className: "w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" }))] })) : isStringSetting ? (jsx(StringSettingInput, { value: currentValue, defaultValue: metadataItem.defaultValue, disabled: isUpdatingTenantMetadata, onSave: (value) => handleStringSettingUpdate(metadataItem.slug, value) })) : (jsxs(Fragment$1, { children: [jsx(Switch, { checked: currentValue, onCheckedChange: async () => {
189910
+ t('advancedAdvanced.noDescriptionAvailable') }) })] }) })] }), jsx("div", { className: "flex items-center gap-2", children: isMentorSetting ? (jsxs("div", { className: "flex items-center gap-2", children: [jsxs(Select$1, { value: currentValue || '', onValueChange: (value) => handleMentorSelection(metadataItem.slug, value), disabled: isUpdatingTenantMetadata, children: [jsx(SelectTrigger, { className: "max-w-[240px] w-[110px] sm:w-[230px] font-medium text-[#646464]", children: jsx(SelectValue, { placeholder: t('advancedAdvanced.selectAgent'), children: currentValue ? getMentorName(currentValue) : '' }) }), jsxs(SelectContent, { className: "font-medium text-[#646464]", children: [jsx("div", { className: "p-2", children: jsx(Input, { placeholder: t('advancedAdvanced.searchAgents'), value: mentorSearchQuery, onChange: (e) => handleMentorSearch(e.target.value), className: "mb-2 font-medium text-[#646464]" }) }), jsx(SelectItem, { value: "none", children: t('advancedAdvanced.none') }), isMentorsLoading ? (jsx(SelectItem, { "aria-label": t('advancedAdvanced.loadingAgents'), value: "loading", disabled: true, children: t('advancedAdvanced.loadingAgents') })) : ((_b = mentorsData === null || mentorsData === void 0 ? void 0 : mentorsData.results) === null || _b === void 0 ? void 0 : _b.length) ? (mentorsData.results.map((mentor) => (jsx(SelectItem, { value: mentor.unique_id, children: mentor.name }, mentor.unique_id)))) : (jsx(SelectItem, { value: "no-results", disabled: true, children: t('advancedAdvanced.noAgentsFound') }))] })] }), isUpdatingTenantMetadata && (jsx("div", { "aria-label": t('advancedAdvanced.updatingAgentSelection'), role: "status", className: "w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" }))] })) : selectOptions ? (jsx(SelectSettingInput, { label: metadataItem.label, options: selectOptions, value: metadataItem.value, defaultValue: metadataItem.defaultValue, disabled: isUpdatingTenantMetadata, triggerClassName: "max-w-[240px] w-[110px] sm:w-[230px] font-medium text-[#646464]", onSelect: (value) => handleSelectSettingUpdate(metadataItem.slug, value) })) : isStringSetting ? (jsx(StringSettingInput, { value: currentValue, defaultValue: metadataItem.defaultValue, disabled: isUpdatingTenantMetadata, onSave: (value) => handleStringSettingUpdate(metadataItem.slug, value) })) : (jsxs(Fragment$1, { children: [jsx(Switch, { checked: currentValue, onCheckedChange: async () => {
189884
189911
  await handleToggleSetting(metadataItem.slug, currentValue);
189885
189912
  }, disabled: isUpdatingTenantMetadata, "aria-label": `${metadataItem.label} ${currentValue ? t('advancedAdvanced.enabled') : t('advancedAdvanced.disabled')}`, className: "cursor-pointer data-[state=checked]:bg-blue-500" }), isUpdatingTenantMetadata && (jsx("div", { className: "w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" }))] })) })] }, metadataItem.slug));
189886
189913
  }) })) : (
@@ -189898,11 +189925,17 @@ function AdvancedTab({ platformKey, username, currentSPA, authURL, currentPlatfo
189898
189925
  var _a, _b;
189899
189926
  const currentValue = (_a = metadataItem.value) !== null && _a !== void 0 ? _a : metadataItem.defaultValue;
189900
189927
  const isMentorSetting = metadataItem.slug === 'overall_default_mentor';
189901
- const isStringSetting = typeof metadataItem.defaultValue === 'string' && !isMentorSetting;
189902
- return (jsxs("div", { className: `flex items-center justify-between rounded-lg border px-6 ${isMentorSetting || isStringSetting ? 'py-4' : 'py-6'}`, 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: metadataItem.label }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": t('advancedAdvanced.moreInfoAbout', {
189928
+ const selectOptions = hasSelectableOptions(metadataItem)
189929
+ ? metadataItem.options
189930
+ : null;
189931
+ const isSelectSetting = selectOptions !== null;
189932
+ const isStringSetting = typeof metadataItem.defaultValue === 'string' &&
189933
+ !isMentorSetting &&
189934
+ !isSelectSetting;
189935
+ return (jsxs("div", { className: `flex items-center justify-between rounded-lg border px-6 ${isMentorSetting || isStringSetting || isSelectSetting ? 'py-4' : 'py-6'}`, 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: metadataItem.label }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": t('advancedAdvanced.moreInfoAbout', {
189903
189936
  label: metadataItem.label,
189904
189937
  }), className: "hidden sm:block", children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { className: "ibl-tooltip-content", children: jsx("p", { children: metadataItem.description ||
189905
- t('advancedAdvanced.noDescriptionAvailable') }) })] }) })] }), jsx("div", { className: "flex items-center gap-2", children: isMentorSetting ? (jsxs("div", { className: "flex items-center gap-2", children: [jsxs(Select$1, { value: currentValue || '', onValueChange: (value) => handleMentorSelection(metadataItem.slug, value), disabled: isUpdatingTenantMetadata, children: [jsx(SelectTrigger, { className: "max-w-[240px] w-[230px] sm:w-[150px] font-medium text-[#646464]", children: jsx(SelectValue, { placeholder: t('advancedAdvanced.selectAgent'), children: currentValue ? getMentorName(currentValue) : '' }) }), jsxs(SelectContent, { className: "font-medium text-[#646464]", children: [jsx("div", { className: "p-2", children: jsx(Input, { placeholder: t('advancedAdvanced.searchAgents'), value: mentorSearchQuery, onChange: (e) => handleMentorSearch(e.target.value), className: "mb-2 font-medium text-[#646464]" }) }), jsx(SelectItem, { value: "none", children: t('advancedAdvanced.none') }), isMentorsLoading ? (jsx(SelectItem, { value: "loading", disabled: true, children: t('advancedAdvanced.loadingAgents') })) : ((_b = mentorsData === null || mentorsData === void 0 ? void 0 : mentorsData.results) === null || _b === void 0 ? void 0 : _b.length) ? (mentorsData.results.map((mentor) => (jsx(SelectItem, { value: mentor.unique_id, children: mentor.name }, mentor.unique_id)))) : (jsx(SelectItem, { value: "no-results", disabled: true, children: t('advancedAdvanced.noAgentsFound') }))] })] }), isUpdatingTenantMetadata && (jsx("div", { className: "w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" }))] })) : isStringSetting ? (jsx(StringSettingInput, { value: currentValue, defaultValue: metadataItem.defaultValue, disabled: isUpdatingTenantMetadata, onSave: (value) => handleStringSettingUpdate(metadataItem.slug, value) })) : (jsxs(Fragment$1, { children: [jsx(Switch, { checked: currentValue, onCheckedChange: async () => {
189938
+ t('advancedAdvanced.noDescriptionAvailable') }) })] }) })] }), jsx("div", { className: "flex items-center gap-2", children: isMentorSetting ? (jsxs("div", { className: "flex items-center gap-2", children: [jsxs(Select$1, { value: currentValue || '', onValueChange: (value) => handleMentorSelection(metadataItem.slug, value), disabled: isUpdatingTenantMetadata, children: [jsx(SelectTrigger, { className: "max-w-[240px] w-[230px] sm:w-[150px] font-medium text-[#646464]", children: jsx(SelectValue, { placeholder: t('advancedAdvanced.selectAgent'), children: currentValue ? getMentorName(currentValue) : '' }) }), jsxs(SelectContent, { className: "font-medium text-[#646464]", children: [jsx("div", { className: "p-2", children: jsx(Input, { placeholder: t('advancedAdvanced.searchAgents'), value: mentorSearchQuery, onChange: (e) => handleMentorSearch(e.target.value), className: "mb-2 font-medium text-[#646464]" }) }), jsx(SelectItem, { value: "none", children: t('advancedAdvanced.none') }), isMentorsLoading ? (jsx(SelectItem, { value: "loading", disabled: true, children: t('advancedAdvanced.loadingAgents') })) : ((_b = mentorsData === null || mentorsData === void 0 ? void 0 : mentorsData.results) === null || _b === void 0 ? void 0 : _b.length) ? (mentorsData.results.map((mentor) => (jsx(SelectItem, { value: mentor.unique_id, children: mentor.name }, mentor.unique_id)))) : (jsx(SelectItem, { value: "no-results", disabled: true, children: t('advancedAdvanced.noAgentsFound') }))] })] }), isUpdatingTenantMetadata && (jsx("div", { className: "w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" }))] })) : selectOptions ? (jsx(SelectSettingInput, { label: metadataItem.label, options: selectOptions, value: metadataItem.value, defaultValue: metadataItem.defaultValue, disabled: isUpdatingTenantMetadata, triggerClassName: "max-w-[240px] w-[230px] sm:w-[150px] font-medium text-[#646464]", onSelect: (value) => handleSelectSettingUpdate(metadataItem.slug, value) })) : isStringSetting ? (jsx(StringSettingInput, { value: currentValue, defaultValue: metadataItem.defaultValue, disabled: isUpdatingTenantMetadata, onSave: (value) => handleStringSettingUpdate(metadataItem.slug, value) })) : (jsxs(Fragment$1, { children: [jsx(Switch, { checked: currentValue, onCheckedChange: async () => {
189906
189939
  await handleToggleSetting(metadataItem.slug, currentValue);
189907
189940
  }, disabled: isUpdatingTenantMetadata, "aria-label": `${metadataItem.label} ${currentValue ? t('advancedAdvanced.enabled') : t('advancedAdvanced.disabled')}`, className: "cursor-pointer data-[state=checked]:bg-blue-500" }), isUpdatingTenantMetadata && (jsx("div", { className: "w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" }))] })) })] }, metadataItem.slug));
189908
189941
  }) })] }, spa)));
@@ -255692,7 +255725,9 @@ function useCuaDriver() {
255692
255725
  // treating null as denied would make Cowork unusable on Linux and Windows.
255693
255726
  const [accessibilityPermission, setAccessibilityPermission] = useState(null);
255694
255727
  const [screenRecordingPermission, setScreenRecordingPermission] = useState(null);
255695
- const hasCheckedStatus = useRef(false);
255728
+ // True once the host has answered a status check this mount — the retry
255729
+ // loop's stop condition, NOT a "ran once" guard (that was the bug).
255730
+ const statusSettled = useRef(false);
255696
255731
  /**
255697
255732
  * Read one permission. Checking never prompts (`AXIsProcessTrusted` /
255698
255733
  * `CGPreflightScreenCaptureAccess`), which is what makes it safe to do on mount.
@@ -255790,11 +255825,13 @@ function useCuaDriver() {
255790
255825
  }));
255791
255826
  }, [setState]);
255792
255827
  /**
255793
- * Query driver install status + session support from the host.
255828
+ * Query driver install status + session support from the host. Returns
255829
+ * whether the host actually answered — the mount effect retries on `false`,
255830
+ * because one failed check must not disable Cowork for the whole session.
255794
255831
  */
255795
255832
  const checkStatus = useCallback(async () => {
255796
255833
  if (!isAvailable)
255797
- return;
255834
+ return false;
255798
255835
  // Refresh both permissions alongside install status (independent, no prompt).
255799
255836
  refreshPermissions();
255800
255837
  try {
@@ -255807,10 +255844,12 @@ function useCuaDriver() {
255807
255844
  progress: result.installed ? 100 : prev.progress,
255808
255845
  lastUpdated: new Date().toISOString(),
255809
255846
  }));
255847
+ return true;
255810
255848
  }
255811
255849
  catch (error) {
255812
255850
  console.error('[useCuaDriver] Failed to check status:', error);
255813
255851
  setState((prev) => ({ ...prev, status: 'idle' }));
255852
+ return false;
255814
255853
  }
255815
255854
  }, [isAvailable, invoke, setState, refreshPermissions]);
255816
255855
  /**
@@ -255930,12 +255969,41 @@ function useCuaDriver() {
255930
255969
  };
255931
255970
  // Only re-subscribe if the host itself changes — never on state.
255932
255971
  }, [isAvailable, listen]);
255933
- // Check status once on mount (in the desktop app).
255972
+ // Check status on mount, and RETRY until the host answers once.
255973
+ //
255974
+ // This used to be one-shot behind a ref, which is why a built app could show
255975
+ // Cowork grey for a whole session: the single check raced the IPC bridge
255976
+ // being injected into the (remote) app origin, failed, and nothing ever asked
255977
+ // again — `status` stayed null and null renders as "not supported". Dev never
255978
+ // showed it because fast-refresh remounts re-ran the check constantly; a
255979
+ // production build gets exactly one mount, so it retries with backoff instead.
255980
+ // Capped: a host that still hasn't answered after ~75s is genuinely broken,
255981
+ // and install()/stop() re-check on their own paths anyway.
255934
255982
  useEffect(() => {
255935
- if (!isAvailable || hasCheckedStatus.current)
255983
+ if (!isAvailable)
255936
255984
  return;
255937
- hasCheckedStatus.current = true;
255938
- checkStatus();
255985
+ let cancelled = false;
255986
+ let timer;
255987
+ let attempt = 0;
255988
+ const MAX_ATTEMPTS = 8;
255989
+ const run = async () => {
255990
+ if (cancelled || statusSettled.current)
255991
+ return;
255992
+ if (await checkStatus()) {
255993
+ statusSettled.current = true;
255994
+ return;
255995
+ }
255996
+ attempt += 1;
255997
+ if (cancelled || attempt >= MAX_ATTEMPTS)
255998
+ return;
255999
+ timer = setTimeout(run, Math.min(1000 * 2 ** attempt, 15000));
256000
+ };
256001
+ run();
256002
+ return () => {
256003
+ cancelled = true;
256004
+ if (timer)
256005
+ clearTimeout(timer);
256006
+ };
255939
256007
  }, [isAvailable, checkStatus]);
255940
256008
  // Only expose the feature as available inside the desktop (Tauri) app.
255941
256009
  const finalIsAvailable = isAvailable && isTauriApp$1();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iblai/iblai-js",
3
- "version": "2.3.9",
3
+ "version": "2.3.11",
4
4
  "description": "Unified JavaScript SDK for IBL.ai — re-exports data-layer, web-containers, and web-utils under a single package",
5
5
  "type": "module",
6
6
  "engines": {
@@ -76,10 +76,10 @@
76
76
  "axios": "1.13.6",
77
77
  "dotenv": "16.6.1",
78
78
  "winston": "3.19.0",
79
+ "@iblai/mcp": "1.8.11",
79
80
  "@iblai/data-layer": "1.12.3",
80
- "@iblai/mcp": "1.8.10",
81
- "@iblai/web-containers": "1.16.5",
82
- "@iblai/web-utils": "2.1.11"
81
+ "@iblai/web-containers": "1.16.7",
82
+ "@iblai/web-utils": "2.1.12"
83
83
  },
84
84
  "peerDependencies": {
85
85
  "@iblai/iblai-api": "4.166.0-ai",