@iblai/iblai-js 2.2.8 → 2.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import React__default, { useState, useEffect, forwardRef, createElement as createElement$3, useLayoutEffect, createContext, useContext, useMemo,
|
|
3
|
+
import React__default, { useState, useEffect, forwardRef, createElement as createElement$3, useLayoutEffect, createContext, useContext, useMemo, useReducer, useRef, useImperativeHandle, useCallback, isValidElement, Children, PureComponent, cloneElement, Component as Component$1, useId as useId$2, useDebugValue, lazy, Suspense } from 'react';
|
|
4
4
|
import * as dataLayer from '@iblai/data-layer';
|
|
5
5
|
import { useGetUserMetadataQuery, useGetUserMetadataEdxQuery, useUpdateUserMetadataMutation, useUpdateUserMetadataEdxMutation, useUploadProfileImageMutation, useResetPasswordMutation, useSelfRetireMutation, useCreateUserInstitutionMutation, useGetUserInstitutionsQuery, useCreateUserEducationMutation, useUpdateUserEducationMutation, useDeleteUserEducationMutation, useGetUserEducationQuery, useCreateUserCompanyMutation, useGetUserCompaniesQuery, useCreateUserExperienceMutation, useUpdateUserExperienceMutation, useDeleteUserExperienceMutation, useGetUserExperienceQuery, useGetUserResumeQuery, useCreateUserResumeMutation, useGetMySubscriptionsQuery, useGetItemSubscriptionQuery, useCancelSubscriptionMutation, useGetLearnerDetailsQuery, useGetUserEnrolledCoursesQuery, useGetUserEnrolledProgramsQuery, useGetUserCatalogPathwaysQuery, useGetUsersAsAssertionsQuery, useGetUserEarnedSkillsQuery, useGetUserReportedSkillsQuery, useGetUserDesiredSkillsQuery, useCreateGlobalMemoryMutation, useGetMemsearchStatusQuery, useGetUserMemorySettingsQuery, useUpdateUserMemorySettingsMutation, useGetGlobalMemoriesQuery, useDeleteGlobalMemoryMutation, useInviteUserMutation, usePlatformInvitationsQuery, useCreateCatalogInvitationCourseBulkMutation, useGetCatalogInvitationsCourseQuery, useLazyPlatformUsersQuery, useLazyPlatformUserGroupsQuery, useGetPersonnalizedSearchQuery, useCreateCatalogInvitationProgramBulkMutation, useGetCatalogInvitationsProgramQuery, useUpdateUserRoleMutation, useUpdateUserStatusMutation, useUpdatePlatformUserRoleWithPoliciesMutation, usePlatformUsersQuery, isPoliciesResponse, platformApiSlice, featureTags, useLazyGetRbacTeamsAccessListQuery, useCreateRbacTeamsAccessMutation, useGetRbacGroupsQuery, usePlatformUserGroupsQuery, useCreateRbacGroupMutation, useUpdateRbacGroupMutation, useDeleteRbacGroupMutation, useCreatePlatformUserGroupMutation, useUpdatePlatformUserGroupMutation, useDeletePlatformUserGroupMutation, useGetRbacGroupDetailsQuery, useGetPlatformUserGroupDetailsQuery, useGetRbacPermissionsMutation, useGetRbacRolesQuery, useCreateRbacRoleMutation, useUpdateRbacRoleMutation, useDeleteRbacRoleMutation, useGetRbacRoleDetailsQuery, useGetRbacActionsDefinitionQuery, useGetRbacResourceDiscoveryQuery, useGetRbacResourceListQuery, useGetRbacPoliciesQuery, useCreateRbacPolicyMutation, useUpdateRbacPolicyMutation, useDeleteRbacPolicyMutation, useGetRbacPolicyDetailsQuery, useGetWatchedGroupsQuery, useCreateWatchedGroupMutation, useUpdateWatchedGroupMutation, useDeleteWatchedGroupMutation, useAddWatchedUserMutation, useRemoveWatchedUserMutation, useAddWatcherMutation, useUpdateWatcherMutation, useDeleteWatcherMutation, useGetWatchedUsersQuery, useGetWatchersQuery, WATCHER_NOTIFICATION_EVENTS, WATCHER_NOTIFICATION_EVENT_LABELS, useGetApplicationFormsQuery, useGetApplicationFormDetailQuery, useCreateApplicationFormMutation, useUpdateApplicationFormMutation, useGetApplicationAdminDetailQuery, useInviteApplicationCandidateMutation, useLazyGetApplicationAttachmentFileQuery, useCreateApplicationWaiverMutation, useDeleteApplicationWaiverMutation, useSubmitApplicationOverrideMutation, useUpdateApplicationPlacementMutation, useDeleteApplicationCourseAssignmentMutation, useCreateApplicationNoteMutation, useUpdateApplicationNoteMutation, useDeleteApplicationNoteMutation, useTransitionApplicationMutation, useLinkApplicationCandidateMutation, useCreateApplicationPlacementsMutation, useGetCustomMentorsQuery, useCreateApplicationCourseAssignmentsMutation, useGetApplicationBlocksQuery, useDeleteApplicationBlockMutation, useGetApplicationsPipelineStatsQuery, useGetApplicationsPipelineQuery, useDeleteApiKeyMutation, useGetApiKeysQuery, useCreateApiKeyMutation, useCreateLLMCredentialMutation, useGetCredentialsSchemaQuery, useGetMaskedLLMCredentialsQuery, useGetLlmsQuery, useDeleteIntegrationCredentialMutation, useDeleteCredentialMutation, useCreateIntegrationCredentialMutation, useGetIntegrationCredentialsSchemaQuery, useGetMaskedIntegrationCredentialsQuery, useGetAccountBillingInfoQuery, useUpdateAutoRechargeInfoMutation, useTriggerAutoRechargeMutation, useCreateStripeCustomerPortalMutation, useSetPlatformConfigurationsMutation, useGetPlatformConfigurationsQuery, useUpdatePlatformMembershipMutation, useGetPlatformMembershipQuery, useGetCustomDomainsQuery, useCreateCustomDomainMutation, useDeleteCustomDomainMutation, useGetStudentMentorCreationStatusQuery, useSetStudentMentorCreationStatusMutation, coreApiSlice, recommendationPromptTypeEnum, useGetRecommendedPromptsListQuery, useCreateRecommendedPromptMutation, useUpdateRecommendedPromptMutation, useDeleteRecommendedPromptMutation, useLazyGetPublicPlatformImageAssetFileUrlQuery, useUpdateTenantMetadataMutation, useCreatePlatformImageAssetMutation, useGetProviderConfigQuery, useCreateProviderConfigMutation, useDeleteProviderConfigMutation, useGetExternalMappingQuery, useGetCredentialsListQuery, useCreateExternalMappingMutation, useDeleteExternalMappingMutation, useGetMemsearchConfigQuery, useUpdateMemsearchConfigMutation, useGetStripeConnectStatusQuery, useStartStripeConnectOnboardingMutation, useLazyGetStripeConnectDashboardQuery, useGetAiSearchMentorsQuery, useListPaywallsQuery, useListPricesQuery, useCreatePriceMutation, useUpdatePriceMutation, useDeletePriceMutation, useGetPaywallConfigQuery, useEnablePaywallMutation, useUpdatePaywallMutation, useLazyGetCourseMetaDataQuery, useLazyGetCourseCompletionOutlinesQuery, useLazyGetCourseEligibilityQuery, useLazyGetEdxSSOTokenQuery, useCreateCourseEnrollmentMutation, useCreateStripeCheckoutSessionMutation, useLazyGetCourseProgressQuery, useLazyGetCourseCompletionQuery, useUpdateExamAttemptMutation, useStartExamMutation, useLazyGetExamInfoQuery, useUpdateUserProjectMutation, useGetTrainingDocumentsQuery, useGetVectorDocumentsQuery, useGetMentorMemoriesListQuery, useGetMemoryCategoriesAdminQuery, useDeleteMentorMemoryMutation, useUpdateMentorMemoryMutation, useCreateMentorMemoryMutation, useLazyGetConnectedServiceAuthUrlQuery, useStarMentorMutation, useUnstarMentorMutation, useCreateUserProjectMutation, useDeleteUserProjectMutation, useGetUserProjectDetailsQuery, useEditTrainingDocumentMutation, useAddTrainingDocumentMutation, useLazyGetCredentialsQuery, useGetMentorSettingsQuery, useEditMentorMutation, useUploadLightLogoMutation, useUploadDarkLogoMutation, useUpdatePlatformInfoMutation, LOGO_ENDPOINTS, useCreateEvalDatasetMutation, useAddEvalDatasetItemsMutation, useUploadEvalDatasetCsvMutation, useDeleteEvalDatasetItemMutation, useListEvalDatasetItemsQuery, evalTotalPages, useListEvalDatasetsQuery, useGetUserProjectsQuery, useCreateSessionIdMutation, useGetMentorCategoriesQuery, useGetTenantChatPrivacyConfigQuery as useGetTenantChatPrivacyConfigQuery$1, useGetCallConfigurationsQuery, useCreateCallConfigurationMutation, useUpdateCallConfigurationMutation, chatPrivacyApiSlice, useDeleteMentorMutation, useForkMentorMutation, useGetToolsQuery, useLazyGetMCPServersQuery, useOauthFindMutation, useLazyStartOAuthFlowQuery, useCreateMCPServerMutation, usePartialUpdateMCPServerMutation, useCreateMCPServerConnectionMutation, usePatchMCPServerConnectionMutation, useGetConnectedServicesQuery, useGetMCPServersQuery, useGetMCPServerConnectionsQuery, useUpdateMCPServerMutation, useDeleteMCPServerMutation, useEditMentorJsonMutation, useDisconnectServiceMutation, useGetPromptCategoriesQuery, PRIVACY_ACTIONS, PRIVACY_ENTITY_TYPES, useGetVoicesQuery, useGetVoiceQuery, useGetMentorGraderConfigurationQuery, useListGraderCriteriaQuery, useCreateMentorGraderConfigurationMutation, useUpdateMentorGraderConfigurationMutation, useCreateGraderCriterionMutation, useUpdateGraderCriterionMutation, useDeleteGraderCriterionMutation, useGetMentorPublicSettingsQuery, useGetChatHistoryFilterQuery, useGetChatHistoryQuery, useGetMentorSummariesQuery, useGetConversationMemoriesQuery, useGetSupportTicketsQuery, useGetSupportTicketMessagesQuery, useCreateSupportTicketMessageMutation, usePatchSupportTicketMutation, useCloseSupportTicketMutation, useCreateLtiMentorMutation, useUpdateLtiMentorMutation, useGetLtiMentorsQuery, useCreateLtiKeyMutation, useUpdateLtiKeyMutation, useDeleteLtiKeyMutation, useGetLtiKeysQuery, useCreateLtiToolMutation, useUpdateLtiToolMutation, useGetLtiToolsQuery, useGetPlatformInfoQuery, useCreatePromptMutation, useGetPromptsSearchQuery, useUpdatePromptMutation, useCreateRedirectTokenMutation, useGetShareableLinkQuery, useCreateShareableLinkMutation, useUpdateShareableLinkMutation, useCreateDisclaimerMutation, useUpdateDisclaimerMutation, useGetDisclaimersQuery, useUpdateRbacMentorAccessMutation, useGetRbacMentorAccessListQuery, useStartEvalRunMutation, useEvaluateEvalRunMutation, useGetEvalRunQuery, useDeleteEvalScoreMutation, useListEvalRunJudgesQuery, useCreateEvalScoreMutation, useDeleteEvalRunMutation, useExportEvalRunMutation, useListEvalRunsQuery, useLazyGetEvalRunQuery, evaluationsApiSlice, EVALUATIONS_TAGS, useGetPersonnalizedMentorsQuery, useCreateCallCredentialsMutation, useGetGuidedPromptsQuery, useUpdateChatSessionSharedMutation, useUpdateMessageFeedbackMutation, useLazyGetPromptsSearchQuery, useLazyGetGuidedPromptsQuery, useGetPublicMentorsQuery, useGetPeriodicAgentsQuery, useGetPeriodicAgentLogsListQuery, useCreatePeriodicAgentMutation, useDeletePeriodicAgentMutation, useDeletePromptMutation, useDeleteTrainingDocumentMutation, useGetTrainingDocumentRetrainScheduleQuery, useCreateTrainingDocumentRetrainScheduleMutation, useCreateMemoryCategoryMutation, useUpdateMemoryCategoryMutation, useDeleteMemoryCategoryMutation, useUpdateArtifactMutation, useLazyGetArtifactVersionQuery, useLazyListArtifactVersionsQuery, useSetCurrentVersionMutation, useListArtifactVersionsQuery, useLazyGetArtifactQuery, useLazyListArtifactsQuery, useEditSessionMutation } from '@iblai/data-layer';
|
|
6
|
-
import { getInitials, useTenantMetadata, WithPermissions, useStripeUpgrade, openExternalUrl, CHAT_AREA_SIZE, isAlphaNumeric32, checkRbacPermission, selectNumberOfActiveChatMessages, useUsername, selectStreaming, isLoggedIn, TOOLS, isSafariBrowser, useShowAttachment, useShowVoiceCall, useShowVoiceRecorder, useMentorSettings, selectShowingSharedChat, selectRbacPermissions, useShowFreeTrialDialog, useEmbedMode, chatInputSliceSelectors, useResponsive, useAccessingPublicRoute, useVisitingTenant, useModelFileUploadCapabilities, useChatFileUpload, useVoiceChat, selectAttachedFiles, MENTOR_CHAT_DOCUMENTS_EXTENSIONS, removeFile, chatInputSliceActions, chatActions, WithFormPermissions, useTenantContext, TimeTracker, advancedTabsProperties, defaultSessionIds, pickWritableFields, ANONYMOUS_USERNAME as ANONYMOUS_USERNAME$3, redirectToAuthSpaJoinTenant, selectActiveTab, useAxdToken, useWelcomeMessage, markdownToPlainText, useCachedSessionId, use402ErrorCheck, selectTokenEnabled, selectToken, useServiceWorker, useUserAgreement, useAdvancedChat, sendMessageToParentWebsite, useMentorTools, useFileDragDrop, eventBus, RemoteEvents, selectEnableChatActionsPopup, advancedTabs, isInIframe, getAuthSpaJoinUrl, addMessage, clearFiles, MENTOR_VISIBILITY } from '@iblai/web-utils';
|
|
6
|
+
import { getInitials, useTenantMetadata, WithPermissions, useStripeUpgrade, openExternalUrl, CHAT_AREA_SIZE, isAlphaNumeric32, checkRbacPermission, selectNumberOfActiveChatMessages, useUsername, selectStreaming, isLoggedIn, TOOLS, hasRemoteAiConfig, isSafariBrowser, useShowAttachment, useShowVoiceCall, useShowVoiceRecorder, useMentorSettings, selectShowingSharedChat, selectRbacPermissions, useShowFreeTrialDialog, useEmbedMode, chatInputSliceSelectors, useResponsive, useAccessingPublicRoute, useVisitingTenant, useModelFileUploadCapabilities, useChatFileUpload, useVoiceChat, selectAttachedFiles, MENTOR_CHAT_DOCUMENTS_EXTENSIONS, removeFile, chatInputSliceActions, chatActions, WithFormPermissions, useTenantContext, TimeTracker, advancedTabsProperties, defaultSessionIds, pickWritableFields, ANONYMOUS_USERNAME as ANONYMOUS_USERNAME$3, redirectToAuthSpaJoinTenant, selectActiveTab, useAxdToken, useWelcomeMessage, markdownToPlainText, useCachedSessionId, use402ErrorCheck, selectTokenEnabled, selectToken, useServiceWorker, useUserAgreement, useAdvancedChat, sendMessageToParentWebsite, useMentorTools, useFileDragDrop, eventBus, RemoteEvents, selectEnableChatActionsPopup, advancedTabs, isInIframe, getAuthSpaJoinUrl, addMessage, clearFiles, MENTOR_VISIBILITY } from '@iblai/web-utils';
|
|
7
7
|
import { useDispatch, useSelector } from 'react-redux';
|
|
8
8
|
import { toast } from 'sonner';
|
|
9
9
|
import { useSearchParams, useParams, useRouter, usePathname } from 'next/navigation';
|
|
@@ -98334,6 +98334,9 @@ var chatInputFormInsideButtons$3 = {
|
|
|
98334
98334
|
studyMode: "Study Mode",
|
|
98335
98335
|
deepResearch: "Deep Research",
|
|
98336
98336
|
memory: "Memory",
|
|
98337
|
+
cowork: "Cowork",
|
|
98338
|
+
coworkNeedsBackend: "Enable a large local model or sign in to a workspace to use Cowork.",
|
|
98339
|
+
coworkModelTooSmall: "Your local model is too small for Cowork. Pick a model of at least 14GB in Local Models.",
|
|
98337
98340
|
moreOptions: "More options"
|
|
98338
98341
|
};
|
|
98339
98342
|
var chatInputFormMemoryMenu$3 = {
|
|
@@ -104452,6 +104455,9 @@ var chatInputFormInsideButtons$2 = {
|
|
|
104452
104455
|
studyMode: "Mode Étude",
|
|
104453
104456
|
deepResearch: "Recherche Approfondie",
|
|
104454
104457
|
memory: "Mémoire",
|
|
104458
|
+
cowork: "Cowork",
|
|
104459
|
+
coworkNeedsBackend: "Activez un grand modèle local ou connectez-vous à un espace de travail pour utiliser Cowork.",
|
|
104460
|
+
coworkModelTooSmall: "Votre modèle local est trop petit pour Cowork. Choisissez un modèle d’au moins 14 Go dans Modèles Locaux.",
|
|
104455
104461
|
moreOptions: "Plus d'options"
|
|
104456
104462
|
};
|
|
104457
104463
|
var chatInputFormMemoryMenu$2 = {
|
|
@@ -110570,6 +110576,9 @@ var chatInputFormInsideButtons$1 = {
|
|
|
110570
110576
|
studyMode: "Modo Estudio",
|
|
110571
110577
|
deepResearch: "Investigación Profunda",
|
|
110572
110578
|
memory: "Memoria",
|
|
110579
|
+
cowork: "Cowork",
|
|
110580
|
+
coworkNeedsBackend: "Activa un modelo local grande o inicia sesión en un espacio de trabajo para usar Cowork.",
|
|
110581
|
+
coworkModelTooSmall: "Tu modelo local es demasiado pequeño para Cowork. Elige un modelo de al menos 14 GB en Modelos Locales.",
|
|
110573
110582
|
moreOptions: "Más opciones"
|
|
110574
110583
|
};
|
|
110575
110584
|
var chatInputFormMemoryMenu$1 = {
|
|
@@ -116688,6 +116697,9 @@ var chatInputFormInsideButtons = {
|
|
|
116688
116697
|
studyMode: "学习模式",
|
|
116689
116698
|
deepResearch: "深度研究",
|
|
116690
116699
|
memory: "记忆",
|
|
116700
|
+
cowork: "Cowork",
|
|
116701
|
+
coworkNeedsBackend: "启用大型本地模型或登录工作区即可使用 Cowork。",
|
|
116702
|
+
coworkModelTooSmall: "您的本地模型太小,无法用于 Cowork。请在“本地模型”中选择至少 14GB 的模型。",
|
|
116691
116703
|
moreOptions: "更多选项"
|
|
116692
116704
|
};
|
|
116693
116705
|
var chatInputFormMemoryMenu = {
|
|
@@ -127458,344 +127470,8 @@ var Indicator$2 = ProgressIndicator;
|
|
|
127458
127470
|
const Progress = React.forwardRef(({ className, value, ...props }, ref) => (jsx(Root$9, { ref: ref, className: cn('bg-secondary relative h-4 w-full overflow-hidden rounded-full', className), ...props, children: jsx(Indicator$2, { className: "bg-primary h-full w-full flex-1 transition-all", style: { transform: `translateX(-${100 - (value || 0)}%)` } }) })));
|
|
127459
127471
|
Progress.displayName = Root$9.displayName;
|
|
127460
127472
|
|
|
127461
|
-
var SLOTTABLE_IDENTIFIER = Symbol("radix.slottable");
|
|
127462
|
-
// @__NO_SIDE_EFFECTS__
|
|
127463
|
-
function createSlottable(ownerName) {
|
|
127464
|
-
const Slottable2 = ({ children }) => {
|
|
127465
|
-
return /* @__PURE__ */ jsx(Fragment$1, { children });
|
|
127466
|
-
};
|
|
127467
|
-
Slottable2.displayName = `${ownerName}.Slottable`;
|
|
127468
|
-
Slottable2.__radixId = SLOTTABLE_IDENTIFIER;
|
|
127469
|
-
return Slottable2;
|
|
127470
|
-
}
|
|
127471
|
-
|
|
127472
|
-
var ROOT_NAME = "AlertDialog";
|
|
127473
|
-
var [createAlertDialogContext] = createContextScope$1(ROOT_NAME, [
|
|
127474
|
-
createDialogScope
|
|
127475
|
-
]);
|
|
127476
|
-
var useDialogScope = createDialogScope();
|
|
127477
|
-
var AlertDialog$1 = (props) => {
|
|
127478
|
-
const { __scopeAlertDialog, ...alertDialogProps } = props;
|
|
127479
|
-
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
127480
|
-
return /* @__PURE__ */ jsx(DialogPrimitive.Root, { ...dialogScope, ...alertDialogProps, modal: true });
|
|
127481
|
-
};
|
|
127482
|
-
AlertDialog$1.displayName = ROOT_NAME;
|
|
127483
|
-
var TRIGGER_NAME$3 = "AlertDialogTrigger";
|
|
127484
|
-
var AlertDialogTrigger = React.forwardRef(
|
|
127485
|
-
(props, forwardedRef) => {
|
|
127486
|
-
const { __scopeAlertDialog, ...triggerProps } = props;
|
|
127487
|
-
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
127488
|
-
return /* @__PURE__ */ jsx(DialogPrimitive.Trigger, { ...dialogScope, ...triggerProps, ref: forwardedRef });
|
|
127489
|
-
}
|
|
127490
|
-
);
|
|
127491
|
-
AlertDialogTrigger.displayName = TRIGGER_NAME$3;
|
|
127492
|
-
var PORTAL_NAME$2 = "AlertDialogPortal";
|
|
127493
|
-
var AlertDialogPortal$1 = (props) => {
|
|
127494
|
-
const { __scopeAlertDialog, ...portalProps } = props;
|
|
127495
|
-
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
127496
|
-
return /* @__PURE__ */ jsx(DialogPrimitive.Portal, { ...dialogScope, ...portalProps });
|
|
127497
|
-
};
|
|
127498
|
-
AlertDialogPortal$1.displayName = PORTAL_NAME$2;
|
|
127499
|
-
var OVERLAY_NAME = "AlertDialogOverlay";
|
|
127500
|
-
var AlertDialogOverlay$1 = React.forwardRef(
|
|
127501
|
-
(props, forwardedRef) => {
|
|
127502
|
-
const { __scopeAlertDialog, ...overlayProps } = props;
|
|
127503
|
-
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
127504
|
-
return /* @__PURE__ */ jsx(DialogPrimitive.Overlay, { ...dialogScope, ...overlayProps, ref: forwardedRef });
|
|
127505
|
-
}
|
|
127506
|
-
);
|
|
127507
|
-
AlertDialogOverlay$1.displayName = OVERLAY_NAME;
|
|
127508
|
-
var CONTENT_NAME$4 = "AlertDialogContent";
|
|
127509
|
-
var [AlertDialogContentProvider, useAlertDialogContentContext] = createAlertDialogContext(CONTENT_NAME$4);
|
|
127510
|
-
var Slottable = createSlottable("AlertDialogContent");
|
|
127511
|
-
var AlertDialogContent$1 = React.forwardRef(
|
|
127512
|
-
(props, forwardedRef) => {
|
|
127513
|
-
const { __scopeAlertDialog, children, ...contentProps } = props;
|
|
127514
|
-
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
127515
|
-
const contentRef = React.useRef(null);
|
|
127516
|
-
const composedRefs = useComposedRefs$1(forwardedRef, contentRef);
|
|
127517
|
-
const cancelRef = React.useRef(null);
|
|
127518
|
-
return /* @__PURE__ */ jsx(
|
|
127519
|
-
DialogPrimitive.WarningProvider,
|
|
127520
|
-
{
|
|
127521
|
-
contentName: CONTENT_NAME$4,
|
|
127522
|
-
titleName: TITLE_NAME,
|
|
127523
|
-
docsSlug: "alert-dialog",
|
|
127524
|
-
children: /* @__PURE__ */ jsx(AlertDialogContentProvider, { scope: __scopeAlertDialog, cancelRef, children: /* @__PURE__ */ jsxs(
|
|
127525
|
-
DialogPrimitive.Content,
|
|
127526
|
-
{
|
|
127527
|
-
role: "alertdialog",
|
|
127528
|
-
...dialogScope,
|
|
127529
|
-
...contentProps,
|
|
127530
|
-
ref: composedRefs,
|
|
127531
|
-
onOpenAutoFocus: composeEventHandlers$2(contentProps.onOpenAutoFocus, (event) => {
|
|
127532
|
-
event.preventDefault();
|
|
127533
|
-
cancelRef.current?.focus({ preventScroll: true });
|
|
127534
|
-
}),
|
|
127535
|
-
onPointerDownOutside: (event) => event.preventDefault(),
|
|
127536
|
-
onInteractOutside: (event) => event.preventDefault(),
|
|
127537
|
-
children: [
|
|
127538
|
-
/* @__PURE__ */ jsx(Slottable, { children }),
|
|
127539
|
-
/* @__PURE__ */ jsx(DescriptionWarning, { contentRef })
|
|
127540
|
-
]
|
|
127541
|
-
}
|
|
127542
|
-
) })
|
|
127543
|
-
}
|
|
127544
|
-
);
|
|
127545
|
-
}
|
|
127546
|
-
);
|
|
127547
|
-
AlertDialogContent$1.displayName = CONTENT_NAME$4;
|
|
127548
|
-
var TITLE_NAME = "AlertDialogTitle";
|
|
127549
|
-
var AlertDialogTitle$1 = React.forwardRef(
|
|
127550
|
-
(props, forwardedRef) => {
|
|
127551
|
-
const { __scopeAlertDialog, ...titleProps } = props;
|
|
127552
|
-
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
127553
|
-
return /* @__PURE__ */ jsx(DialogPrimitive.Title, { ...dialogScope, ...titleProps, ref: forwardedRef });
|
|
127554
|
-
}
|
|
127555
|
-
);
|
|
127556
|
-
AlertDialogTitle$1.displayName = TITLE_NAME;
|
|
127557
|
-
var DESCRIPTION_NAME = "AlertDialogDescription";
|
|
127558
|
-
var AlertDialogDescription$1 = React.forwardRef((props, forwardedRef) => {
|
|
127559
|
-
const { __scopeAlertDialog, ...descriptionProps } = props;
|
|
127560
|
-
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
127561
|
-
return /* @__PURE__ */ jsx(DialogPrimitive.Description, { ...dialogScope, ...descriptionProps, ref: forwardedRef });
|
|
127562
|
-
});
|
|
127563
|
-
AlertDialogDescription$1.displayName = DESCRIPTION_NAME;
|
|
127564
|
-
var ACTION_NAME = "AlertDialogAction";
|
|
127565
|
-
var AlertDialogAction$1 = React.forwardRef(
|
|
127566
|
-
(props, forwardedRef) => {
|
|
127567
|
-
const { __scopeAlertDialog, ...actionProps } = props;
|
|
127568
|
-
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
127569
|
-
return /* @__PURE__ */ jsx(DialogPrimitive.Close, { ...dialogScope, ...actionProps, ref: forwardedRef });
|
|
127570
|
-
}
|
|
127571
|
-
);
|
|
127572
|
-
AlertDialogAction$1.displayName = ACTION_NAME;
|
|
127573
|
-
var CANCEL_NAME = "AlertDialogCancel";
|
|
127574
|
-
var AlertDialogCancel$1 = React.forwardRef(
|
|
127575
|
-
(props, forwardedRef) => {
|
|
127576
|
-
const { __scopeAlertDialog, ...cancelProps } = props;
|
|
127577
|
-
const { cancelRef } = useAlertDialogContentContext(CANCEL_NAME, __scopeAlertDialog);
|
|
127578
|
-
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
127579
|
-
const ref = useComposedRefs$1(forwardedRef, cancelRef);
|
|
127580
|
-
return /* @__PURE__ */ jsx(DialogPrimitive.Close, { ...dialogScope, ...cancelProps, ref });
|
|
127581
|
-
}
|
|
127582
|
-
);
|
|
127583
|
-
AlertDialogCancel$1.displayName = CANCEL_NAME;
|
|
127584
|
-
var DescriptionWarning = ({ contentRef }) => {
|
|
127585
|
-
const MESSAGE = `\`${CONTENT_NAME$4}\` requires a description for the component to be accessible for screen reader users.
|
|
127586
|
-
|
|
127587
|
-
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.
|
|
127588
|
-
|
|
127589
|
-
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.
|
|
127590
|
-
|
|
127591
|
-
For more information, see https://radix-ui.com/primitives/docs/components/alert-dialog`;
|
|
127592
|
-
React.useEffect(() => {
|
|
127593
|
-
const hasDescription = document.getElementById(
|
|
127594
|
-
contentRef.current?.getAttribute("aria-describedby")
|
|
127595
|
-
);
|
|
127596
|
-
if (!hasDescription) console.warn(MESSAGE);
|
|
127597
|
-
}, [MESSAGE, contentRef]);
|
|
127598
|
-
return null;
|
|
127599
|
-
};
|
|
127600
|
-
var Root2$4 = AlertDialog$1;
|
|
127601
|
-
var Portal2 = AlertDialogPortal$1;
|
|
127602
|
-
var Overlay2 = AlertDialogOverlay$1;
|
|
127603
|
-
var Content2$2 = AlertDialogContent$1;
|
|
127604
|
-
var Action = AlertDialogAction$1;
|
|
127605
|
-
var Cancel = AlertDialogCancel$1;
|
|
127606
|
-
var Title2 = AlertDialogTitle$1;
|
|
127607
|
-
var Description2 = AlertDialogDescription$1;
|
|
127608
|
-
|
|
127609
|
-
const AlertDialog = Root2$4;
|
|
127610
|
-
const AlertDialogPortal = Portal2;
|
|
127611
|
-
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 })));
|
|
127612
|
-
AlertDialogOverlay.displayName = Overlay2.displayName;
|
|
127613
|
-
const AlertDialogContent = React.forwardRef(({ className, ...props }, ref) => (jsxs(AlertDialogPortal, { children: [jsx(AlertDialogOverlay, {}), jsx(Content2$2, { 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 })] })));
|
|
127614
|
-
AlertDialogContent.displayName = Content2$2.displayName;
|
|
127615
|
-
const AlertDialogHeader = ({ className, ...props }) => (jsx("div", { className: cn('flex flex-col space-y-2 text-center sm:text-left', className), ...props }));
|
|
127616
|
-
AlertDialogHeader.displayName = 'AlertDialogHeader';
|
|
127617
|
-
const AlertDialogFooter = ({ className, ...props }) => (jsx("div", { className: cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className), ...props }));
|
|
127618
|
-
AlertDialogFooter.displayName = 'AlertDialogFooter';
|
|
127619
|
-
const AlertDialogTitle = React.forwardRef(({ className, ...props }, ref) => (jsx(Title2, { ref: ref, className: cn('text-lg font-semibold', className), ...props })));
|
|
127620
|
-
AlertDialogTitle.displayName = Title2.displayName;
|
|
127621
|
-
const AlertDialogDescription = React.forwardRef(({ className, ...props }, ref) => (jsx(Description2, { ref: ref, className: cn('text-muted-foreground text-sm', className), ...props })));
|
|
127622
|
-
AlertDialogDescription.displayName = Description2.displayName;
|
|
127623
|
-
const AlertDialogAction = React.forwardRef(({ className, ...props }, ref) => (jsx(Action, { ref: ref, className: cn(buttonVariants(), className), ...props })));
|
|
127624
|
-
AlertDialogAction.displayName = Action.displayName;
|
|
127625
|
-
const AlertDialogCancel = React.forwardRef(({ className, ...props }, ref) => (jsx(Cancel, { ref: ref, className: cn(buttonVariants({ variant: 'outline' }), 'mt-2 sm:mt-0', className), ...props })));
|
|
127626
|
-
AlertDialogCancel.displayName = Cancel.displayName;
|
|
127627
|
-
|
|
127628
|
-
// Tauri types for model download functionality
|
|
127629
|
-
/**
|
|
127630
|
-
* Initial state for model download
|
|
127631
|
-
*/
|
|
127632
|
-
const initialModelDownloadState = {
|
|
127633
|
-
status: 'idle',
|
|
127634
|
-
progress: 0,
|
|
127635
|
-
message: '',
|
|
127636
|
-
logs: [],
|
|
127637
|
-
lastUpdated: new Date().toISOString(),
|
|
127638
|
-
};
|
|
127639
|
-
/**
|
|
127640
|
-
* Check if the app is running inside Tauri
|
|
127641
|
-
* In Tauri 2.0, the global is __TAURI_INTERNALS__ (with withGlobalTauri: true)
|
|
127642
|
-
* We also check for __TAURI__ for backwards compatibility
|
|
127643
|
-
*/
|
|
127644
|
-
const isTauriApp$1 = () => {
|
|
127645
|
-
if (typeof window === 'undefined')
|
|
127646
|
-
return false;
|
|
127647
|
-
return '__TAURI_INTERNALS__' in window || '__TAURI__' in window;
|
|
127648
|
-
};
|
|
127649
|
-
/**
|
|
127650
|
-
* Tauri event names
|
|
127651
|
-
*/
|
|
127652
|
-
const TAURI_EVENTS = {
|
|
127653
|
-
DOWNLOAD_PROGRESS: 'model:download-progress',
|
|
127654
|
-
INSTALLATION_LOG: 'model:installation-log',
|
|
127655
|
-
DISK_SPACE_ERROR: 'model:disk-space-error',
|
|
127656
|
-
OLLAMA_STATUS: 'model:ollama-status',
|
|
127657
|
-
};
|
|
127658
|
-
/**
|
|
127659
|
-
* Tauri command names
|
|
127660
|
-
*/
|
|
127661
|
-
const TAURI_COMMANDS = {
|
|
127662
|
-
INSTALL_OLLAMA: 'install_ollama',
|
|
127663
|
-
STOP_OLLAMA: 'stop_ollama',
|
|
127664
|
-
CHECK_OLLAMA_STATUS: 'check_ollama_status',
|
|
127665
|
-
CHECK_DISK_SPACE: 'check_disk_space_for_model',
|
|
127666
|
-
GET_SYSTEM_MEMORY: 'get_system_memory',
|
|
127667
|
-
DOWNLOAD_MODEL: 'download_model',
|
|
127668
|
-
CANCEL_DOWNLOAD: 'cancel_model_download',
|
|
127669
|
-
CHECK_NETWORK_STATUS: 'check_network_status',
|
|
127670
|
-
GET_OS_TYPE: 'get_os_type',
|
|
127671
|
-
CHECK_FOUNDRY_STATUS: 'check_foundry_local_status',
|
|
127672
|
-
START_FOUNDRY_SERVICE: 'start_foundry_local_service',
|
|
127673
|
-
LOAD_FOUNDRY_MODEL: 'load_foundry_local_model',
|
|
127674
|
-
SET_SELECTED_FOUNDRY_MODEL: 'set_selected_foundry_model',
|
|
127675
|
-
GET_SELECTED_FOUNDRY_MODEL: 'get_selected_foundry_model',
|
|
127676
|
-
INSTALL_FOUNDRY: 'install_foundry',
|
|
127677
|
-
DOWNLOAD_FOUNDRY_MODEL: 'download_foundry_model_cmd',
|
|
127678
|
-
GET_RECOMMENDED_FOUNDRY_MODELS: 'get_recommended_foundry_models',
|
|
127679
|
-
LOG_STDOUT: 'log_stdout',
|
|
127680
|
-
};
|
|
127681
|
-
/**
|
|
127682
|
-
* Initial state for the System Control install flow.
|
|
127683
|
-
*/
|
|
127684
|
-
const initialGhostOsInstallState = {
|
|
127685
|
-
status: 'idle',
|
|
127686
|
-
progress: 0,
|
|
127687
|
-
message: '',
|
|
127688
|
-
logs: [],
|
|
127689
|
-
lastUpdated: new Date().toISOString(),
|
|
127690
|
-
};
|
|
127691
|
-
/**
|
|
127692
|
-
* Tauri event names emitted by the host during GhostOS install/setup.
|
|
127693
|
-
*/
|
|
127694
|
-
const GHOST_OS_TAURI_EVENTS = {
|
|
127695
|
-
INSTALL_PROGRESS: 'ghost-os:install-progress',
|
|
127696
|
-
INSTALLATION_LOG: 'ghost-os:installation-log',
|
|
127697
|
-
STATUS: 'ghost-os:status',
|
|
127698
|
-
};
|
|
127699
|
-
/**
|
|
127700
|
-
* Tauri command names the host implements for GhostOS install/setup. The web
|
|
127701
|
-
* layer invokes these; the native side performs the clone + setup.
|
|
127702
|
-
*/
|
|
127703
|
-
const GHOST_OS_TAURI_COMMANDS = {
|
|
127704
|
-
/** Install and set up GhostOS (clone repo + run setup). */
|
|
127705
|
-
INSTALL_GHOST_OS: 'install_ghost_os',
|
|
127706
|
-
/** Stop the running GhostOS manager. */
|
|
127707
|
-
STOP_GHOST_OS: 'stop_ghost_os',
|
|
127708
|
-
/** Report current {@link GhostOsStatus}. */
|
|
127709
|
-
CHECK_GHOST_OS_STATUS: 'check_ghost_os_status',
|
|
127710
|
-
};
|
|
127711
|
-
/**
|
|
127712
|
-
* Tauri command strings exposed by `tauri-plugin-macos-permissions`
|
|
127713
|
-
* (https://github.com/ayangweb/tauri-plugin-macos-permissions). GhostOS needs
|
|
127714
|
-
* macOS Accessibility permission to control the device, so the System Control
|
|
127715
|
-
* card surfaces it. These are invoked directly via `useTauri().invoke(...)` —
|
|
127716
|
-
* no extra npm dependency. The host must register the plugin in its Tauri app
|
|
127717
|
-
* (`tauri_plugin_macos_permissions::init()`). Each `CHECK_*` returns a boolean;
|
|
127718
|
-
* each `REQUEST_*` prompts / opens the relevant System Settings pane.
|
|
127719
|
-
*/
|
|
127720
|
-
const MACOS_PERMISSIONS_COMMANDS = {
|
|
127721
|
-
CHECK_ACCESSIBILITY: 'plugin:macos-permissions|check_accessibility_permission',
|
|
127722
|
-
REQUEST_ACCESSIBILITY: 'plugin:macos-permissions|request_accessibility_permission',
|
|
127723
|
-
CHECK_SCREEN_RECORDING: 'plugin:macos-permissions|check_screen_recording_permission',
|
|
127724
|
-
REQUEST_SCREEN_RECORDING: 'plugin:macos-permissions|request_screen_recording_permission',
|
|
127725
|
-
CHECK_INPUT_MONITORING: 'plugin:macos-permissions|check_input_monitoring_permission',
|
|
127726
|
-
REQUEST_INPUT_MONITORING: 'plugin:macos-permissions|request_input_monitoring_permission',
|
|
127727
|
-
CHECK_FULL_DISK_ACCESS: 'plugin:macos-permissions|check_full_disk_access_permission',
|
|
127728
|
-
REQUEST_FULL_DISK_ACCESS: 'plugin:macos-permissions|request_full_disk_access_permission',
|
|
127729
|
-
};
|
|
127730
|
-
|
|
127731
|
-
/**
|
|
127732
|
-
* Dynamically import Tauri APIs to avoid SSR issues
|
|
127733
|
-
*/
|
|
127734
|
-
const getTauriAPIs = async () => {
|
|
127735
|
-
try {
|
|
127736
|
-
const { invoke } = await import('@tauri-apps/api/core');
|
|
127737
|
-
const { listen } = await import('@tauri-apps/api/event');
|
|
127738
|
-
return { invoke, listen };
|
|
127739
|
-
}
|
|
127740
|
-
catch (error) {
|
|
127741
|
-
console.error('Failed to load Tauri APIs:', error);
|
|
127742
|
-
return null;
|
|
127743
|
-
}
|
|
127744
|
-
};
|
|
127745
|
-
/**
|
|
127746
|
-
* Hook to access Tauri APIs with SSR safety
|
|
127747
|
-
*
|
|
127748
|
-
* @returns Object with isAvailable flag and Tauri invoke/listen functions
|
|
127749
|
-
*/
|
|
127750
|
-
function useTauri() {
|
|
127751
|
-
const [isAvailable, setIsAvailable] = useState(false);
|
|
127752
|
-
const [apis, setApis] = useState(null);
|
|
127753
|
-
useEffect(() => {
|
|
127754
|
-
// Check if we're in a Tauri environment
|
|
127755
|
-
const inTauri = isTauriApp$1();
|
|
127756
|
-
if (inTauri) {
|
|
127757
|
-
getTauriAPIs().then((result) => {
|
|
127758
|
-
setApis(result);
|
|
127759
|
-
setIsAvailable(!!result);
|
|
127760
|
-
});
|
|
127761
|
-
}
|
|
127762
|
-
}, []);
|
|
127763
|
-
/**
|
|
127764
|
-
* Invoke a Tauri command
|
|
127765
|
-
*/
|
|
127766
|
-
const invoke = useCallback(async (command, args) => {
|
|
127767
|
-
if (!(apis === null || apis === void 0 ? void 0 : apis.invoke)) {
|
|
127768
|
-
throw new Error('Tauri is not available');
|
|
127769
|
-
}
|
|
127770
|
-
return apis.invoke(command, args);
|
|
127771
|
-
}, [apis]);
|
|
127772
|
-
/**
|
|
127773
|
-
* Listen to a Tauri event
|
|
127774
|
-
* Returns an unlisten function that should be called on cleanup
|
|
127775
|
-
*/
|
|
127776
|
-
const listen = useCallback(async (event, handler) => {
|
|
127777
|
-
// The synchronous global (`__TAURI_INTERNALS__`) exposes `invoke` but
|
|
127778
|
-
// frequently NOT `event.listen`, so `apis.listen` can be undefined even
|
|
127779
|
-
// though Tauri is fully available. Fall back to the real event API via
|
|
127780
|
-
// dynamic import so download progress/completion events are actually
|
|
127781
|
-
// delivered — otherwise the UI never leaves the "downloading" state.
|
|
127782
|
-
let listenFn = apis === null || apis === void 0 ? void 0 : apis.listen;
|
|
127783
|
-
if (!listenFn) {
|
|
127784
|
-
const { listen: importedListen } = await import('@tauri-apps/api/event');
|
|
127785
|
-
listenFn = importedListen;
|
|
127786
|
-
}
|
|
127787
|
-
return listenFn(event, (e) => handler(e.payload));
|
|
127788
|
-
}, [apis]);
|
|
127789
|
-
return {
|
|
127790
|
-
isAvailable,
|
|
127791
|
-
invoke,
|
|
127792
|
-
listen,
|
|
127793
|
-
};
|
|
127794
|
-
}
|
|
127795
|
-
|
|
127796
127473
|
const LOCAL_LLM_ENABLED_KEY = 'ibl_local_llm_enabled';
|
|
127797
127474
|
const LOCAL_LLM_MODEL_KEY = 'ibl_local_llm_model';
|
|
127798
|
-
const LOCAL_LLM_TOOL_SUPPORT_KEY = 'ibl_local_llm_tool_support';
|
|
127799
127475
|
/**
|
|
127800
127476
|
* Curated catalog of small, on-device-friendly models from the Ollama library
|
|
127801
127477
|
* (https://ollama.com/library). The model manager itself (Ollama) is not a
|
|
@@ -127828,8 +127504,8 @@ const LOCAL_MODELS = [
|
|
|
127828
127504
|
},
|
|
127829
127505
|
{ name: 'Granite 4.1', provider: 'IBM', id: 'granite4.1:8b', size: '5.3 GB', tool_support: true },
|
|
127830
127506
|
{ name: 'GPT-OSS 20B', provider: 'OpenAI', id: 'gpt-oss:20b', size: '14 GB', tool_support: true },
|
|
127831
|
-
// Larger models. Sizes use "GB" so they parse for the
|
|
127832
|
-
// (only models above the configured gate can use
|
|
127507
|
+
// Larger models. Sizes use "GB" so they parse for the Cowork size gate
|
|
127508
|
+
// (only models above the configured gate can use Cowork).
|
|
127833
127509
|
{
|
|
127834
127510
|
name: 'Qwen 3.6',
|
|
127835
127511
|
provider: 'Alibaba',
|
|
@@ -127853,34 +127529,6 @@ const LOCAL_MODELS = [
|
|
|
127853
127529
|
tool_support: true,
|
|
127854
127530
|
},
|
|
127855
127531
|
];
|
|
127856
|
-
/** The model wired to the existing single-model download flow (default selection). */
|
|
127857
|
-
const PRIMARY_MODEL_ID = 'phi4-mini:latest';
|
|
127858
|
-
/**
|
|
127859
|
-
* Whether a catalog model id (e.g. "llama3.2", "phi3:mini") is present among the
|
|
127860
|
-
* installed Ollama tags reported by the backend (e.g. "llama3.2:latest"). Matches
|
|
127861
|
-
* an exact tag or the same base model with any tag suffix, so a model pulled as
|
|
127862
|
-
* `<id>:latest` still counts as installed.
|
|
127863
|
-
*/
|
|
127864
|
-
function isModelInstalled(modelId, installedTags) {
|
|
127865
|
-
if (!installedTags)
|
|
127866
|
-
return false;
|
|
127867
|
-
return installedTags.some((tag) => tag === modelId || tag.startsWith(`${modelId}:`));
|
|
127868
|
-
}
|
|
127869
|
-
/**
|
|
127870
|
-
* Whether a model id is an Ollama cloud-hosted model — either the plain ":cloud"
|
|
127871
|
-
* tag (e.g. "glm-5.2:cloud") or a sized cloud tag (e.g. "gemma4:31b-cloud").
|
|
127872
|
-
* Cloud models run on Ollama's servers, so they are available by default — never
|
|
127873
|
-
* downloaded, no local memory required, always "ready".
|
|
127874
|
-
*/
|
|
127875
|
-
function isCloudModelId(modelId) {
|
|
127876
|
-
return modelId.endsWith(':cloud') || (modelId.includes(':') && modelId.endsWith('-cloud'));
|
|
127877
|
-
}
|
|
127878
|
-
/**
|
|
127879
|
-
* Fraction of the machine's memory above which a model is treated as "too large"
|
|
127880
|
-
* and a confirmation is required before downloading. TESTING VALUE — set low (1%)
|
|
127881
|
-
* so the warning is easy to trigger; raise toward real capacity (e.g. 0.8) later.
|
|
127882
|
-
*/
|
|
127883
|
-
const MODEL_SIZE_WARN_FRACTION = 0.01;
|
|
127884
127532
|
/** Multipliers for the size units used in the catalog (binary / 1024-based). */
|
|
127885
127533
|
const SIZE_UNIT_BYTES = {
|
|
127886
127534
|
B: 1,
|
|
@@ -127902,54 +127550,19 @@ function parseModelSizeBytes(size) {
|
|
|
127902
127550
|
return null;
|
|
127903
127551
|
return value * ((_a = SIZE_UNIT_BYTES[match[2].toUpperCase()]) !== null && _a !== void 0 ? _a : 1);
|
|
127904
127552
|
}
|
|
127905
|
-
/** Format a byte count as a short, human-readable size (e.g. "16.0 GB"). */
|
|
127906
|
-
function formatBytes(bytes) {
|
|
127907
|
-
if (bytes <= 0)
|
|
127908
|
-
return '0 GB';
|
|
127909
|
-
const gb = bytes / 1024 ** 3;
|
|
127910
|
-
if (gb >= 1)
|
|
127911
|
-
return `${gb.toFixed(1)} GB`;
|
|
127912
|
-
return `${Math.round(bytes / 1024 ** 2)} MB`;
|
|
127913
|
-
}
|
|
127914
127553
|
/**
|
|
127915
|
-
*
|
|
127916
|
-
* VRAM (a model runs in one or the other). Returns 0 when memory is unknown.
|
|
127917
|
-
*/
|
|
127918
|
-
function usableMemoryBytes(systemMemory) {
|
|
127919
|
-
if (!systemMemory)
|
|
127920
|
-
return 0;
|
|
127921
|
-
return Math.max(systemMemory.ram_total, systemMemory.vram_total);
|
|
127922
|
-
}
|
|
127923
|
-
/**
|
|
127924
|
-
* Whether `model` is large enough relative to this machine's memory to warrant a
|
|
127925
|
-
* "might not run" confirmation. False when memory or the model size is unknown,
|
|
127926
|
-
* so the download simply proceeds rather than warning on incomplete data.
|
|
127927
|
-
*/
|
|
127928
|
-
function modelExceedsCapacity(model, systemMemory) {
|
|
127929
|
-
const capacity = usableMemoryBytes(systemMemory);
|
|
127930
|
-
const modelBytes = parseModelSizeBytes(model.size);
|
|
127931
|
-
if (modelBytes == null)
|
|
127932
|
-
return false;
|
|
127933
|
-
// Unknown memory (capacity 0) → don't warn; the download simply proceeds
|
|
127934
|
-
// rather than blocking on incomplete data.
|
|
127935
|
-
if (capacity <= 0)
|
|
127936
|
-
return false;
|
|
127937
|
-
return modelBytes > capacity * MODEL_SIZE_WARN_FRACTION;
|
|
127938
|
-
}
|
|
127939
|
-
/**
|
|
127940
|
-
* Default minimum model size (GB) that can use the System Control Manager
|
|
127554
|
+
* Default minimum model size (GB) that can use the Cowork
|
|
127941
127555
|
* (GhostOS MCP/tools). Smaller models don't support tools/MCP well, so the
|
|
127942
|
-
* manager is gated to models above this size.
|
|
127943
|
-
* System Control card's `requiredSizeGb` prop (see SystemControlTabProps).
|
|
127556
|
+
* manager is gated to models above this size.
|
|
127944
127557
|
*/
|
|
127945
|
-
const
|
|
127558
|
+
const DEFAULT_COWORK_REQUIRED_SIZE_GB = 12;
|
|
127946
127559
|
/**
|
|
127947
127560
|
* Whether the given model (by Ollama id) is large enough to use the System
|
|
127948
127561
|
* Control Manager — i.e. its catalog size exceeds `gb` (default
|
|
127949
|
-
* {@link
|
|
127562
|
+
* {@link DEFAULT_COWORK_REQUIRED_SIZE_GB}). Unknown ids or unparseable
|
|
127950
127563
|
* sizes return false (gated off).
|
|
127951
127564
|
*/
|
|
127952
|
-
function
|
|
127565
|
+
function modelSupportsCowork(modelId, gb = DEFAULT_COWORK_REQUIRED_SIZE_GB) {
|
|
127953
127566
|
if (!modelId)
|
|
127954
127567
|
return false;
|
|
127955
127568
|
const model = LOCAL_MODELS.find((m) => m.id === modelId);
|
|
@@ -127960,22 +127573,6 @@ function modelSupportsSystemControl(modelId, gb = DEFAULT_SYSTEM_CONTROL_REQUIRE
|
|
|
127960
127573
|
return false;
|
|
127961
127574
|
return bytes > gb * 1024 ** 3;
|
|
127962
127575
|
}
|
|
127963
|
-
/**
|
|
127964
|
-
* The smallest catalog model that can use the System Control Manager (size
|
|
127965
|
-
* exceeds `gb`), or null if none qualify. Used by the "Upgrade" action to pick
|
|
127966
|
-
* the lightest capable model. Ties / unparseable sizes sort last.
|
|
127967
|
-
*/
|
|
127968
|
-
function smallestSystemControlModel(gb = DEFAULT_SYSTEM_CONTROL_REQUIRED_SIZE_GB) {
|
|
127969
|
-
const usable = LOCAL_MODELS.filter((m) => modelSupportsSystemControl(m.id, gb));
|
|
127970
|
-
if (usable.length === 0)
|
|
127971
|
-
return null;
|
|
127972
|
-
return usable.reduce((smallest, m) => {
|
|
127973
|
-
var _a, _b;
|
|
127974
|
-
const a = (_a = parseModelSizeBytes(m.size)) !== null && _a !== void 0 ? _a : Infinity;
|
|
127975
|
-
const b = (_b = parseModelSizeBytes(smallest.size)) !== null && _b !== void 0 ? _b : Infinity;
|
|
127976
|
-
return a < b ? m : smallest;
|
|
127977
|
-
});
|
|
127978
|
-
}
|
|
127979
127576
|
/**
|
|
127980
127577
|
* Check if local LLM is enabled from localStorage
|
|
127981
127578
|
*/
|
|
@@ -128000,57 +127597,21 @@ function getLocalLLMModel() {
|
|
|
128000
127597
|
return null;
|
|
128001
127598
|
return localStorage.getItem(LOCAL_LLM_MODEL_KEY);
|
|
128002
127599
|
}
|
|
128003
|
-
|
|
128004
|
-
|
|
128005
|
-
*/
|
|
128006
|
-
function setLocalLLMModel(modelId) {
|
|
128007
|
-
if (typeof window === 'undefined')
|
|
128008
|
-
return;
|
|
128009
|
-
localStorage.setItem(LOCAL_LLM_MODEL_KEY, modelId);
|
|
128010
|
-
}
|
|
128011
|
-
/**
|
|
128012
|
-
* Persist whether the selected model supports tools (set when a model is chosen).
|
|
128013
|
-
*/
|
|
128014
|
-
function setLocalLLMToolSupport(toolSupport) {
|
|
128015
|
-
if (typeof window === 'undefined')
|
|
128016
|
-
return;
|
|
128017
|
-
localStorage.setItem(LOCAL_LLM_TOOL_SUPPORT_KEY, String(toolSupport));
|
|
128018
|
-
}
|
|
128019
|
-
function LocalLLMTab({ isAvailable, state, ollamaStatus, systemMemory, isUsingFoundry = false, foundryModels = [], selectedFoundryModel = null, foundryStatus, onStartDownload, onCancelDownload, onInstallOllama, onStopManager, onInstallFoundry, onCheckStatus, onResetState, onSelectFoundryModel, }) {
|
|
128020
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
127600
|
+
function LocalLLMTab({ isAvailable, state, ollamaStatus, isUsingFoundry = false, foundryModels = [], selectedFoundryModel = null, foundryStatus, onInstallOllama, onStopManager, onInstallFoundry, onCheckStatus, onSelectFoundryModel, }) {
|
|
127601
|
+
var _a, _b, _c, _d, _e;
|
|
128021
127602
|
const t = useT();
|
|
128022
|
-
// Direct Tauri access so the model-size check can read system memory fresh at
|
|
128023
|
-
// download-click time (the threaded `systemMemory` prop is only a fast path).
|
|
128024
|
-
const { invoke } = useTauri();
|
|
128025
127603
|
const isDownloading = state.status === 'downloading';
|
|
128026
127604
|
const isManagerInstalling = state.managerInstalling || (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installing);
|
|
128027
127605
|
// User preference state - independent of whether model is installed
|
|
128028
127606
|
const [isEnabled, setIsEnabled] = useState(() => isLocalLLMEnabled());
|
|
128029
|
-
// Which model the shared download flow currently targets. Prefer the model
|
|
128030
|
-
// recorded in the persisted download state, so the correct row shows progress
|
|
128031
|
-
// even after the dialog is closed and reopened mid-download; fall back to a
|
|
128032
|
-
// local value for immediate feedback the instant a Download button is clicked.
|
|
128033
|
-
const [localActiveModelId, setLocalActiveModelId] = useState(PRIMARY_MODEL_ID);
|
|
128034
|
-
const activeModelId = state.status === 'downloading' && state.activeModel ? state.activeModel : localActiveModelId;
|
|
128035
|
-
// Which model the user has chosen to chat with (exclusive selection).
|
|
128036
|
-
const [selectedModelId, setSelectedModelId] = useState(() => getLocalLLMModel() || PRIMARY_MODEL_ID);
|
|
128037
|
-
// A model the user asked to download that is large relative to this machine's
|
|
128038
|
-
// memory. Set when we need the user to confirm a "might not run" warning before
|
|
128039
|
-
// starting the download; null when no confirmation is pending.
|
|
128040
|
-
const [pendingModel, setPendingModel] = useState(null);
|
|
128041
127607
|
// "Enable Local Models" === run the model manager (Ollama). The toggle is a
|
|
128042
127608
|
// user preference that is always operable: turning it on installs (if needed)
|
|
128043
|
-
// and starts the manager; turning it off stops it.
|
|
128044
|
-
// shown whenever the toggle is on
|
|
128045
|
-
//
|
|
127609
|
+
// and starts the manager; turning it off stops it. Only the manager status
|
|
127610
|
+
// card is shown here (whenever the toggle is on or mid-install) — the per-model
|
|
127611
|
+
// list lives in Agent settings → LLM tab, where local models are picked and
|
|
127612
|
+
// downloaded alongside cloud models.
|
|
128046
127613
|
const managerRunning = (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.running) === true;
|
|
128047
127614
|
const localModelsEnabled = isEnabled || isManagerInstalling;
|
|
128048
|
-
// A model can be chosen for chat only once it is downloaded/ready. The backend
|
|
128049
|
-
// reports every installed model tag, so any downloaded model qualifies.
|
|
128050
|
-
const selectedModelReady = isCloudModelId(selectedModelId) ||
|
|
128051
|
-
isModelInstalled(selectedModelId, ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed_models) ||
|
|
128052
|
-
(selectedModelId === PRIMARY_MODEL_ID &&
|
|
128053
|
-
(state.status === 'completed' || (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.model_installed) === true));
|
|
128054
127615
|
// Track previous model installation state to detect when it first becomes installed
|
|
128055
127616
|
const [, setWasModelInstalled] = useState(() => {
|
|
128056
127617
|
return (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.model_installed) === true;
|
|
@@ -128164,62 +127725,6 @@ function LocalLLMTab({ isAvailable, state, ollamaStatus, systemMemory, isUsingFo
|
|
|
128164
127725
|
onStopManager === null || onStopManager === void 0 ? void 0 : onStopManager();
|
|
128165
127726
|
}
|
|
128166
127727
|
};
|
|
128167
|
-
const startDownloadNow = (modelId) => {
|
|
128168
|
-
setLocalActiveModelId(modelId);
|
|
128169
|
-
onStartDownload(modelId);
|
|
128170
|
-
};
|
|
128171
|
-
const handleDownloadModel = async (modelId) => {
|
|
128172
|
-
// Always read system memory FIRST — this is the call that hits the backend
|
|
128173
|
-
// `get_system_memory`. Doing it before the catalog lookup guarantees it runs
|
|
128174
|
-
// on every Download click (falling back to the value fetched on mount).
|
|
128175
|
-
const model = LOCAL_MODELS.find((m) => modelId.startsWith(m.id));
|
|
128176
|
-
if (!model) {
|
|
128177
|
-
await invoke(TAURI_COMMANDS.LOG_STDOUT, {
|
|
128178
|
-
s: `[Local Models] -> Download: bad download request, model ${model}`,
|
|
128179
|
-
});
|
|
128180
|
-
console.log(`[Local Models] -> Download: bad download request, model ${model}`);
|
|
128181
|
-
return;
|
|
128182
|
-
}
|
|
128183
|
-
let mem = null;
|
|
128184
|
-
try {
|
|
128185
|
-
mem = await invoke(TAURI_COMMANDS.GET_SYSTEM_MEMORY);
|
|
128186
|
-
}
|
|
128187
|
-
catch (e) {
|
|
128188
|
-
await invoke(TAURI_COMMANDS.LOG_STDOUT, {
|
|
128189
|
-
s: `[Local Models] -> Download: couldn't detect system memory ${modelId} ${e}`,
|
|
128190
|
-
});
|
|
128191
|
-
console.log(`[Local Models] -> Download: couldn't detect system memory {e}`);
|
|
128192
|
-
return;
|
|
128193
|
-
}
|
|
128194
|
-
const exceeds = modelExceedsCapacity(model, mem);
|
|
128195
|
-
console.warn('[Local Models] -> Download: download click', {
|
|
128196
|
-
modelId,
|
|
128197
|
-
systemMemory: mem,
|
|
128198
|
-
capacityBytes: usableMemoryBytes(mem),
|
|
128199
|
-
modelBytes: parseModelSizeBytes(model.size),
|
|
128200
|
-
thresholdBytes: usableMemoryBytes(mem) * MODEL_SIZE_WARN_FRACTION,
|
|
128201
|
-
exceeds,
|
|
128202
|
-
});
|
|
128203
|
-
if (exceeds) {
|
|
128204
|
-
setPendingModel(model);
|
|
128205
|
-
return;
|
|
128206
|
-
}
|
|
128207
|
-
startDownloadNow(modelId);
|
|
128208
|
-
};
|
|
128209
|
-
const confirmPendingDownload = () => {
|
|
128210
|
-
if (pendingModel) {
|
|
128211
|
-
startDownloadNow(pendingModel.id);
|
|
128212
|
-
}
|
|
128213
|
-
setPendingModel(null);
|
|
128214
|
-
};
|
|
128215
|
-
const handleSelectModel = (modelId) => {
|
|
128216
|
-
var _a, _b;
|
|
128217
|
-
setSelectedModelId(modelId);
|
|
128218
|
-
setLocalLLMModel(modelId);
|
|
128219
|
-
// Persist the model's tool-calling support so the host can route chat to the
|
|
128220
|
-
// MCP/tool proxy (:8000) vs plain Ollama (:11434).
|
|
128221
|
-
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);
|
|
128222
|
-
};
|
|
128223
127728
|
// For Ollama the switch reflects the user's toggle preference (always
|
|
128224
127729
|
// operable, so it can be turned off). Foundry additionally requires a
|
|
128225
127730
|
// downloaded model to be considered "on".
|
|
@@ -128233,54 +127738,16 @@ function LocalLLMTab({ isAvailable, state, ollamaStatus, systemMemory, isUsingFo
|
|
|
128233
127738
|
const switchDisabled = isUsingFoundry
|
|
128234
127739
|
? !hasDownloadedFoundryModel || isDownloading || state.status === 'checking'
|
|
128235
127740
|
: isDownloading || isManagerInstalling || state.status === 'checking';
|
|
128236
|
-
return (
|
|
128237
|
-
|
|
128238
|
-
|
|
128239
|
-
|
|
128240
|
-
|
|
128241
|
-
|
|
128242
|
-
|
|
128243
|
-
|
|
128244
|
-
|
|
128245
|
-
|
|
128246
|
-
// A model is ready once Ollama reports its tag as installed.
|
|
128247
|
-
// Fall back to (a) this row's own download having just
|
|
128248
|
-
// completed — so it flips to "Ready" before the status
|
|
128249
|
-
// refresh lands — and (b) the primary-model status flag.
|
|
128250
|
-
// Cloud models are ready by default.
|
|
128251
|
-
const isInstalled = isCloud ||
|
|
128252
|
-
isModelInstalled(model.id, ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed_models) ||
|
|
128253
|
-
(isActive && state.status === 'completed') ||
|
|
128254
|
-
(isPrimary && (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.model_installed) === true);
|
|
128255
|
-
// An installed model must never render a download/cancel
|
|
128256
|
-
// state — guards against a stale persisted "downloading"
|
|
128257
|
-
// status making an already-ready model look like it's
|
|
128258
|
-
// still downloading (and wrongly cancellable) on reopen.
|
|
128259
|
-
const rowDownloading = isActive && isDownloading && !isInstalled;
|
|
128260
|
-
const rowChecking = isActive && state.status === 'checking';
|
|
128261
|
-
const rowError = isActive && state.status === 'error';
|
|
128262
|
-
const rowCancelled = isActive && state.status === 'cancelled';
|
|
128263
|
-
const canDownload = !!(ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed) &&
|
|
128264
|
-
!isInstalled &&
|
|
128265
|
-
!rowDownloading &&
|
|
128266
|
-
!rowChecking;
|
|
128267
|
-
const isSelected = selectedModelId === model.id;
|
|
128268
|
-
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": t('localLlmLocalLlmTab.useModelForChatAriaLabel', {
|
|
128269
|
-
name: model.name,
|
|
128270
|
-
}), title: isInstalled
|
|
128271
|
-
? undefined
|
|
128272
|
-
: t('localLlmLocalLlmTab.downloadToChatTitle'), className: isInstalled
|
|
128273
|
-
? 'h-4 w-4 cursor-pointer accent-blue-500'
|
|
128274
|
-
: '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" }), t('localLlmLocalLlmTab.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" }), t('localLlmLocalLlmTab.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" }), t('localLlmLocalLlmTab.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" }), t('localLlmLocalLlmTab.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$2, { className: "h-3 w-3" }), t('localLlmLocalLlmTab.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: t('localLlmLocalLlmTab.notDownloaded') })) }) }), 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$2, { className: "h-4 w-4 mr-2" }), t('localLlmLocalLlmTab.cancel')] })), canDownload && (jsxs(Button$1, { onClick: () => handleDownloadModel(model.id), size: "sm", variant: "outline", children: [jsx(Download, { className: "h-4 w-4 mr-2" }), t('localLlmLocalLlmTab.download')] })), rowError && (jsx(Button$1, { onClick: onResetState, variant: "ghost", size: "sm", children: t('localLlmLocalLlmTab.reset') })), isInstalled && !isCloud && (jsx(Button$1, { onClick: onCheckStatus, variant: "ghost", size: "sm", children: jsx(RefreshCw, { className: "h-4 w-4" }) }))] }) })] }, model.id));
|
|
128275
|
-
}) })] }), 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: [t('localLlmLocalLlmTab.chattingWith'), ' ', 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: t('localLlmLocalLlmTab.noModelSelectedHint') })) })] }))] })) : (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: t('localLlmLocalLlmTab.offlineAiReady') }), 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" }), t('localLlmLocalLlmTab.preferredBadge')] })] }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: t('localLlmLocalLlmTab.foundryReadyDescription') })] })] }) }), 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: t('localLlmLocalLlmTab.selectModelLabel') }), 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: t('localLlmLocalLlmTab.selectModelPlaceholder') }) }), 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: t('localLlmLocalLlmTab.notDownloaded') })), 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: t('localLlmLocalLlmTab.downloaded') }))] })] }) }, model.id))) })] }), jsxs("div", { className: "flex flex-col gap-1", children: [jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: t('localLlmLocalLlmTab.modelsAvailable', { count: foundryModels.length }) }), 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: [t('localLlmLocalLlmTab.usingModelPrefix'), ' ', ((_e = foundryModels.find((m) => m.id === selectedFoundryModel)) === null || _e === void 0 ? void 0 : _e.name) ||
|
|
128276
|
-
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'
|
|
128277
|
-
? 'text-red-600 dark:text-red-400'
|
|
128278
|
-
: log.level === 'warn'
|
|
128279
|
-
? 'text-yellow-600 dark:text-yellow-400'
|
|
128280
|
-
: 'text-gray-700 dark:text-gray-300'}`, children: log.message }, idx))) }))] }))] }) }))] }), jsx(AlertDialog, { open: !!pendingModel, onOpenChange: (open) => {
|
|
128281
|
-
if (!open)
|
|
128282
|
-
setPendingModel(null);
|
|
128283
|
-
}, 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" })] })] }) })] }));
|
|
127741
|
+
return (jsx("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: t('localLlmLocalLlmTab.enableLocalLlm') }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": t('localLlmLocalLlmTab.moreInfoAriaLabel'), 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: t('localLlmLocalLlmTab.tooltipWorkOffline') }), (foundryStatus === null || foundryStatus === void 0 ? void 0 : foundryStatus.is_supported) && (jsx("p", { className: "text-xs text-gray-300", children: t('localLlmLocalLlmTab.tooltipFoundrySupported') }))] }) })] }) })] }), 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": t('localLlmLocalLlmTab.startingModelManagerAriaLabel') })), jsx(Switch, { checked: switchChecked, onCheckedChange: handleToggle, disabled: switchDisabled, "aria-label": t('localLlmLocalLlmTab.switchAriaLabel', {
|
|
127742
|
+
state: switchChecked
|
|
127743
|
+
? t('localLlmLocalLlmTab.switchStateEnabled')
|
|
127744
|
+
: t('localLlmLocalLlmTab.switchStateDisabled'),
|
|
127745
|
+
}), 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: t('localLlmLocalLlmTab.preferredBadge') })] }) }), 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: t('localLlmLocalLlmTab.settingUpOfflineAi') }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: t('localLlmLocalLlmTab.foundryInstallDescription') })] })] }), 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 || t('localLlmLocalLlmTab.preparingDownload') })] }), 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 || t('localLlmLocalLlmTab.downloadFailed') })] }), 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" }), t('localLlmLocalLlmTab.tryAgain')] }) })] })) : (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: t('localLlmLocalLlmTab.startingDownload') })] }) })), jsxs("div", { className: "text-xs text-gray-500 dark:text-gray-400", children: [jsx("p", { className: "font-medium mb-1", children: t('localLlmLocalLlmTab.downloadSize') }), jsx("p", { children: t('localLlmLocalLlmTab.oneTimeSetup') })] })] }) })) : /* 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: t('localLlmLocalLlmTab.noteLabel') }), ' ', t('localLlmLocalLlmTab.foundryAlternativeNote')] })] }) })), 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: t('localLlmLocalLlmTab.modelManagerName') }), jsx("div", { className: "text-xs text-gray-500 dark:text-gray-400", children: t('localLlmLocalLlmTab.modelManagerDescription') })] })] }), 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" }), t('localLlmLocalLlmTab.running')] }), jsx(Button$1, { onClick: onCheckStatus, variant: "ghost", size: "sm", "aria-label": t('localLlmLocalLlmTab.refreshManagerStatusAriaLabel'), 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" }), t('localLlmLocalLlmTab.starting')] }), jsx(Button$1, { onClick: onCheckStatus, variant: "ghost", size: "sm", "aria-label": t('localLlmLocalLlmTab.refreshManagerStatusAriaLabel'), 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" }) }))] }))] })) : (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: t('localLlmLocalLlmTab.offlineAiReady') }), 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" }), t('localLlmLocalLlmTab.preferredBadge')] })] }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: t('localLlmLocalLlmTab.foundryReadyDescription') })] })] }) }), 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: t('localLlmLocalLlmTab.selectModelLabel') }), 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: t('localLlmLocalLlmTab.selectModelPlaceholder') }) }), 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: t('localLlmLocalLlmTab.notDownloaded') })), 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: t('localLlmLocalLlmTab.downloaded') }))] })] }) }, model.id))) })] }), jsxs("div", { className: "flex flex-col gap-1", children: [jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: t('localLlmLocalLlmTab.modelsAvailable', { count: foundryModels.length }) }), 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: [t('localLlmLocalLlmTab.usingModelPrefix'), ' ', ((_c = foundryModels.find((m) => m.id === selectedFoundryModel)) === null || _c === void 0 ? void 0 : _c.name) ||
|
|
127746
|
+
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'
|
|
127747
|
+
? 'text-red-600 dark:text-red-400'
|
|
127748
|
+
: log.level === 'warn'
|
|
127749
|
+
? 'text-yellow-600 dark:text-yellow-400'
|
|
127750
|
+
: 'text-gray-700 dark:text-gray-300'}`, children: log.message }, idx))) }))] }))] }) }))] }) }));
|
|
128284
127751
|
}
|
|
128285
127752
|
|
|
128286
127753
|
function LocalModelsContent(props) {
|
|
@@ -128291,195 +127758,6 @@ function LocalModelsContent(props) {
|
|
|
128291
127758
|
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 }) }))] }));
|
|
128292
127759
|
}
|
|
128293
127760
|
|
|
128294
|
-
const SYSTEM_CONTROL_ENABLED_KEY = 'ibl_system_control_enabled';
|
|
128295
|
-
/**
|
|
128296
|
-
* Whether the Computer Assistant is enabled, read from localStorage. This is a
|
|
128297
|
-
* user preference (mirrors {@link isLocalLLMEnabled}); it reflects the toggle the
|
|
128298
|
-
* user last chose, independent of whether the helper is installed yet.
|
|
128299
|
-
*/
|
|
128300
|
-
function isSystemControlEnabled() {
|
|
128301
|
-
if (typeof window === 'undefined')
|
|
128302
|
-
return false;
|
|
128303
|
-
return localStorage.getItem(SYSTEM_CONTROL_ENABLED_KEY) === 'true';
|
|
128304
|
-
}
|
|
128305
|
-
/**
|
|
128306
|
-
* Persist the Computer Assistant enabled preference to localStorage.
|
|
128307
|
-
*/
|
|
128308
|
-
function setSystemControlEnabled(enabled) {
|
|
128309
|
-
if (typeof window === 'undefined')
|
|
128310
|
-
return;
|
|
128311
|
-
localStorage.setItem(SYSTEM_CONTROL_ENABLED_KEY, String(enabled));
|
|
128312
|
-
}
|
|
128313
|
-
/** Green "done" pill. */
|
|
128314
|
-
function DonePill({ children }) {
|
|
128315
|
-
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] }));
|
|
128316
|
-
}
|
|
128317
|
-
/** Blue "in progress" pill. */
|
|
128318
|
-
function WorkingPill({ children }) {
|
|
128319
|
-
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] }));
|
|
128320
|
-
}
|
|
128321
|
-
/** A single numbered step row. */
|
|
128322
|
-
function Step$2({ number, done, title, description, action, }) {
|
|
128323
|
-
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
|
|
128324
|
-
? 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-300'
|
|
128325
|
-
: '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 })] }));
|
|
128326
|
-
}
|
|
128327
|
-
/**
|
|
128328
|
-
* Body of the "Computer Assistant" card: a plain-language on/off with two simple
|
|
128329
|
-
* steps — set up, then allow control — so non-technical users can follow along.
|
|
128330
|
-
* Mirrors the Local Models tab so the two cards behave the same.
|
|
128331
|
-
*/
|
|
128332
|
-
function SystemControlTab({ isAvailable, state, status, requiredSizeGb = DEFAULT_SYSTEM_CONTROL_REQUIRED_SIZE_GB, ollamaStatus, systemMemory, accessibilityPermission, onInstall, onStop, onCheckStatus, onResetState, onRequestAccessibilityPermission, onDownloadModel, }) {
|
|
128333
|
-
const isInstalling = state.status === 'installing' || (status === null || status === void 0 ? void 0 : status.installing) === true;
|
|
128334
|
-
// User preference — independent of whether the helper is installed. Always
|
|
128335
|
-
// operable so the user can turn it off again.
|
|
128336
|
-
const [isEnabled, setIsEnabled] = useState(() => isSystemControlEnabled());
|
|
128337
|
-
// The currently-selected local model (persisted by the Local Models card).
|
|
128338
|
-
// Polled so a selection change in the sibling card is reflected here without a
|
|
128339
|
-
// remount. The assistant only works well with larger models, so it's gated to
|
|
128340
|
-
// a selected model above the size threshold.
|
|
128341
|
-
const [selectedModel, setSelectedModel] = useState(() => getLocalLLMModel());
|
|
128342
|
-
// Whether "Local Models" is turned on. The assistant runs on a local model, so
|
|
128343
|
-
// it's gated off until Local Models is enabled. Polled alongside the model so a
|
|
128344
|
-
// toggle in the sibling card is reflected without a remount.
|
|
128345
|
-
const [localModelsEnabled, setLocalModelsEnabled] = useState(() => isLocalLLMEnabled());
|
|
128346
|
-
useEffect(() => {
|
|
128347
|
-
const id = setInterval(() => {
|
|
128348
|
-
setSelectedModel(getLocalLLMModel());
|
|
128349
|
-
setLocalModelsEnabled(isLocalLLMEnabled());
|
|
128350
|
-
}, 1500);
|
|
128351
|
-
return () => clearInterval(id);
|
|
128352
|
-
}, []);
|
|
128353
|
-
const localModelsOff = !localModelsEnabled;
|
|
128354
|
-
const modelTooSmall = !modelSupportsSystemControl(selectedModel, requiredSizeGb);
|
|
128355
|
-
// "Upgrade" target: the smallest catalog model that clears the size gate.
|
|
128356
|
-
const upgradeTarget = smallestSystemControlModel(requiredSizeGb);
|
|
128357
|
-
// Set while an upgrade is downloading a model, before we auto-enable.
|
|
128358
|
-
const [pendingEnableModelId, setPendingEnableModelId] = useState(null);
|
|
128359
|
-
// Model awaiting a RAM/VRAM "may be too large" confirmation before download.
|
|
128360
|
-
const [pendingCapacityModel, setPendingCapacityModel] = useState(null);
|
|
128361
|
-
const isUpgrading = pendingEnableModelId !== null;
|
|
128362
|
-
const managerRunning = (status === null || status === void 0 ? void 0 : status.running) === true;
|
|
128363
|
-
// Steps are shown whenever the toggle is on (or mid-setup), so the user always
|
|
128364
|
-
// gets feedback for their choice.
|
|
128365
|
-
const managerEnabled = isEnabled || isInstalling;
|
|
128366
|
-
// Permission is known (macOS + plugin wired) and granted.
|
|
128367
|
-
const permissionKnown = typeof accessibilityPermission === 'boolean';
|
|
128368
|
-
const permissionGranted = accessibilityPermission === true;
|
|
128369
|
-
const allSet = managerRunning && (!permissionKnown || permissionGranted);
|
|
128370
|
-
// Keep the app-facing preference flag in sync with the toggle.
|
|
128371
|
-
useEffect(() => {
|
|
128372
|
-
setSystemControlEnabled(isEnabled);
|
|
128373
|
-
}, [isEnabled]);
|
|
128374
|
-
// While enabled but not yet running, keep polling so the step flips to "Ready"
|
|
128375
|
-
// as soon as the host reports the helper is up.
|
|
128376
|
-
useEffect(() => {
|
|
128377
|
-
if (!isEnabled || managerRunning)
|
|
128378
|
-
return;
|
|
128379
|
-
const id = setInterval(() => onCheckStatus(), 2500);
|
|
128380
|
-
return () => clearInterval(id);
|
|
128381
|
-
}, [isEnabled, managerRunning, onCheckStatus]);
|
|
128382
|
-
// While permission isn't granted yet, keep re-checking (the grant happens in
|
|
128383
|
-
// System Settings) so the step flips to "Allowed" on its own.
|
|
128384
|
-
useEffect(() => {
|
|
128385
|
-
if (accessibilityPermission !== false)
|
|
128386
|
-
return;
|
|
128387
|
-
const id = setInterval(() => onCheckStatus(), 2500);
|
|
128388
|
-
return () => clearInterval(id);
|
|
128389
|
-
}, [accessibilityPermission, onCheckStatus]);
|
|
128390
|
-
// After an upgrade kicks off a download, turn the assistant on once the model
|
|
128391
|
-
// finishes downloading (it shows up in the installed list).
|
|
128392
|
-
useEffect(() => {
|
|
128393
|
-
if (!pendingEnableModelId)
|
|
128394
|
-
return;
|
|
128395
|
-
if (isModelInstalled(pendingEnableModelId, ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed_models)) {
|
|
128396
|
-
setPendingEnableModelId(null);
|
|
128397
|
-
setIsEnabled(true);
|
|
128398
|
-
onInstall();
|
|
128399
|
-
}
|
|
128400
|
-
}, [pendingEnableModelId, ollamaStatus, onInstall]);
|
|
128401
|
-
if (!isAvailable) {
|
|
128402
|
-
return (jsx("div", { className: "text-sm text-gray-500 dark:text-gray-400", children: "The Computer Assistant is only available in the desktop app." }));
|
|
128403
|
-
}
|
|
128404
|
-
const handleToggle = (checked) => {
|
|
128405
|
-
// Guard: needs Local Models on and a large-enough model.
|
|
128406
|
-
if (checked && (localModelsOff || modelTooSmall))
|
|
128407
|
-
return;
|
|
128408
|
-
setIsEnabled(checked);
|
|
128409
|
-
if (checked) {
|
|
128410
|
-
if (!isInstalling)
|
|
128411
|
-
onInstall();
|
|
128412
|
-
}
|
|
128413
|
-
else {
|
|
128414
|
-
onStop === null || onStop === void 0 ? void 0 : onStop();
|
|
128415
|
-
}
|
|
128416
|
-
};
|
|
128417
|
-
// Upgrade = switch to the smallest usable model: select it, then (if it isn't
|
|
128418
|
-
// already downloaded) download it and auto-enable the assistant once it's
|
|
128419
|
-
// ready. The RAM/VRAM check is preserved via the confirm below.
|
|
128420
|
-
const runUpgrade = (model) => {
|
|
128421
|
-
setLocalLLMModel(model.id);
|
|
128422
|
-
setLocalLLMToolSupport(model.tool_support);
|
|
128423
|
-
setLocalLLMEnabled(true);
|
|
128424
|
-
setSelectedModel(model.id); // recompute the size gate immediately
|
|
128425
|
-
if (isModelInstalled(model.id, ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed_models)) {
|
|
128426
|
-
// Already downloaded → enable now.
|
|
128427
|
-
setIsEnabled(true);
|
|
128428
|
-
if (!isInstalling)
|
|
128429
|
-
onInstall();
|
|
128430
|
-
}
|
|
128431
|
-
else {
|
|
128432
|
-
// Not downloaded → download, then auto-enable when it lands (effect above).
|
|
128433
|
-
setPendingEnableModelId(model.id);
|
|
128434
|
-
onDownloadModel === null || onDownloadModel === void 0 ? void 0 : onDownloadModel(model.id);
|
|
128435
|
-
}
|
|
128436
|
-
};
|
|
128437
|
-
const handleUpgrade = () => {
|
|
128438
|
-
if (!upgradeTarget)
|
|
128439
|
-
return;
|
|
128440
|
-
// Keep the RAM/VRAM check: confirm before pulling a model that may not fit.
|
|
128441
|
-
if (modelExceedsCapacity(upgradeTarget, systemMemory)) {
|
|
128442
|
-
setPendingCapacityModel(upgradeTarget);
|
|
128443
|
-
return;
|
|
128444
|
-
}
|
|
128445
|
-
runUpgrade(upgradeTarget);
|
|
128446
|
-
};
|
|
128447
|
-
const switchChecked = isEnabled;
|
|
128448
|
-
const switchDisabled = isInstalling ||
|
|
128449
|
-
state.status === 'checking' ||
|
|
128450
|
-
((localModelsOff || modelTooSmall) && !isEnabled);
|
|
128451
|
-
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
|
|
128452
|
-
? `Upgrade to ${upgradeTarget.name} (${upgradeTarget.size}) to use it.`
|
|
128453
|
-
: '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: () => {
|
|
128454
|
-
onResetState();
|
|
128455
|
-
onInstall();
|
|
128456
|
-
}, 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) => {
|
|
128457
|
-
if (!open)
|
|
128458
|
-
setPendingCapacityModel(null);
|
|
128459
|
-
}, 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: () => {
|
|
128460
|
-
const model = pendingCapacityModel;
|
|
128461
|
-
setPendingCapacityModel(null);
|
|
128462
|
-
if (model)
|
|
128463
|
-
runUpgrade(model);
|
|
128464
|
-
}, children: "Download anyway" })] })] }) })] }));
|
|
128465
|
-
}
|
|
128466
|
-
|
|
128467
|
-
/**
|
|
128468
|
-
* Collapsible "System Control" card for the UserProfile → Advanced section.
|
|
128469
|
-
* Mirrors {@link LocalModelsContent}: a purely presentational, titled,
|
|
128470
|
-
* collapsible container whose body is the {@link SystemControlTab}. Availability
|
|
128471
|
-
* and handlers are threaded in (see UserProfileDropdown, which falls back to
|
|
128472
|
-
* {@link useGhostOs} when the host doesn't supply them). Renders nothing outside
|
|
128473
|
-
* the desktop app.
|
|
128474
|
-
*/
|
|
128475
|
-
function SystemControlContent(props) {
|
|
128476
|
-
const [isCollapsed, setIsCollapsed] = useState(true);
|
|
128477
|
-
if (!props.isAvailable) {
|
|
128478
|
-
return null;
|
|
128479
|
-
}
|
|
128480
|
-
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 }) }))] }));
|
|
128481
|
-
}
|
|
128482
|
-
|
|
128483
127761
|
// src/primitive.tsx
|
|
128484
127762
|
var NODES = [
|
|
128485
127763
|
"a",
|
|
@@ -176503,6 +175781,26 @@ function ChatPrivacyTab({ org, username }) {
|
|
|
176503
175781
|
}) })] }));
|
|
176504
175782
|
}
|
|
176505
175783
|
|
|
175784
|
+
const COWORK_ENABLED_KEY = 'ibl_cowork_enabled';
|
|
175785
|
+
/**
|
|
175786
|
+
* Whether Cowork is enabled, read from localStorage. This is a user preference
|
|
175787
|
+
* (mirrors isLocalLLMEnabled); it reflects the toggle the user last chose,
|
|
175788
|
+
* independent of whether the assistant is installed yet.
|
|
175789
|
+
*/
|
|
175790
|
+
function isCoworkEnabled() {
|
|
175791
|
+
if (typeof window === 'undefined')
|
|
175792
|
+
return false;
|
|
175793
|
+
return localStorage.getItem(COWORK_ENABLED_KEY) === 'true';
|
|
175794
|
+
}
|
|
175795
|
+
/**
|
|
175796
|
+
* Persist the Cowork enabled preference to localStorage.
|
|
175797
|
+
*/
|
|
175798
|
+
function setCoworkEnabled(enabled) {
|
|
175799
|
+
if (typeof window === 'undefined')
|
|
175800
|
+
return;
|
|
175801
|
+
localStorage.setItem(COWORK_ENABLED_KEY, String(enabled));
|
|
175802
|
+
}
|
|
175803
|
+
|
|
176506
175804
|
const renderLucideIcon = (Icon) => function RenderedIcon(props) {
|
|
176507
175805
|
return jsx(Icon, { ...props });
|
|
176508
175806
|
};
|
|
@@ -176529,7 +175827,7 @@ const TAB_DESC_PREVIEW_KEYS = {
|
|
|
176529
175827
|
memory: 'descMemoryPreview',
|
|
176530
175828
|
privacy: 'descPrivacyPreview',
|
|
176531
175829
|
};
|
|
176532
|
-
function Profile({ tenant, username, tenants, onClose, customization = {}, isAdmin = false, targetTab = 'basic', onAccountDeleted, enableMemoryTab = false, localLLMProps,
|
|
175830
|
+
function Profile({ tenant, username, tenants, onClose, customization = {}, isAdmin = false, targetTab = 'basic', onAccountDeleted, enableMemoryTab = false, localLLMProps, currentSPA = '', }) {
|
|
176533
175831
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
176534
175832
|
const t = useT();
|
|
176535
175833
|
const { data: memsearchStatus, isError: isMemsearchStatusError } = useGetMemsearchStatusQuery({ org: tenant, userId: username }, { skip: !enableMemoryTab });
|
|
@@ -176606,9 +175904,8 @@ function Profile({ tenant, username, tenants, onClose, customization = {}, isAdm
|
|
|
176606
175904
|
]
|
|
176607
175905
|
: []),
|
|
176608
175906
|
];
|
|
176609
|
-
// Add Advanced tab only when in Tauri app (Local Models
|
|
176610
|
-
|
|
176611
|
-
const isAdvancedAvailable = (localLLMProps === null || localLLMProps === void 0 ? void 0 : localLLMProps.isAvailable) === true || (systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.isAvailable) === true;
|
|
175907
|
+
// Add Advanced tab only when in Tauri app (Local Models is provided and available)
|
|
175908
|
+
const isAdvancedAvailable = (localLLMProps === null || localLLMProps === void 0 ? void 0 : localLLMProps.isAvailable) === true;
|
|
176612
175909
|
const TABS = isAdvancedAvailable
|
|
176613
175910
|
? [
|
|
176614
175911
|
...baseTabs,
|
|
@@ -176774,7 +176071,7 @@ function Profile({ tenant, username, tenants, onClose, customization = {}, isAdm
|
|
|
176774
176071
|
var _a;
|
|
176775
176072
|
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: t('profileIndex.placeholderX'), value: field.state.value, onChange: (e) => handleSocialLinkChange(e.target.value, field.handleChange, X_URL_PREFIX), disabled: socialForm.state.isSubmitting || isReadOnly })] }), 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 })] }));
|
|
176776
176073
|
},
|
|
176777
|
-
})] })] }) })), activeTab === 'education' && (jsxs(Tabs, { value: educationSubTab, onValueChange: setEducationSubTab, className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsxs(TabsList, { children: [jsx(TabsTrigger, { value: "education", children: t('profileIndex.tabEducation') }), jsx(TabsTrigger, { value: "credentials", children: t('gradebookGradebookTab.typeCredentials') }), jsx(TabsTrigger, { value: "skills", children: t('gradebookGradebookTab.typeSkills') })] }), headerAddButton] }), jsx(TabsContent, { value: "education", children: jsx(EducationTab, { org: tenant, username: username }) }), jsx(TabsContent, { value: "credentials", children: jsx(CredentialsList, { org: tenant, username: username }) }), jsx(TabsContent, { value: "skills", children: jsx(SkillsList, { org: tenant, username: username }) })] })), activeTab === 'gradebook' && jsx(GradebookTab, { org: tenant, username: username }), activeTab === 'experience' && (jsxs(Tabs, { value: experienceSubTab, onValueChange: setExperienceSubTab, className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsxs(TabsList, { children: [jsx(TabsTrigger, { value: "experience", children: t('profileIndex.tabExperience') }), jsx(TabsTrigger, { value: "resume", children: t('profileIndex.tabResume') })] }), headerAddButton] }), jsx(TabsContent, { value: "experience", children: jsx(ExperienceTab, { org: tenant, username: username }) }), jsx(TabsContent, { value: "resume", children: 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 }), !isReadOnly && activeTab === 'security' && (jsx(Security, { app: currentSPA || '', email: (userMetadata === null || userMetadata === void 0 ? void 0 : userMetadata.email) || '', platformKey: tenant, onAccountDeleted: onAccountDeleted })), activeTab === 'advanced' &&
|
|
176074
|
+
})] })] }) })), activeTab === 'education' && (jsxs(Tabs, { value: educationSubTab, onValueChange: setEducationSubTab, className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsxs(TabsList, { children: [jsx(TabsTrigger, { value: "education", children: t('profileIndex.tabEducation') }), jsx(TabsTrigger, { value: "credentials", children: t('gradebookGradebookTab.typeCredentials') }), jsx(TabsTrigger, { value: "skills", children: t('gradebookGradebookTab.typeSkills') })] }), headerAddButton] }), jsx(TabsContent, { value: "education", children: jsx(EducationTab, { org: tenant, username: username }) }), jsx(TabsContent, { value: "credentials", children: jsx(CredentialsList, { org: tenant, username: username }) }), jsx(TabsContent, { value: "skills", children: jsx(SkillsList, { org: tenant, username: username }) })] })), activeTab === 'gradebook' && jsx(GradebookTab, { org: tenant, username: username }), activeTab === 'experience' && (jsxs(Tabs, { value: experienceSubTab, onValueChange: setExperienceSubTab, className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsxs(TabsList, { children: [jsx(TabsTrigger, { value: "experience", children: t('profileIndex.tabExperience') }), jsx(TabsTrigger, { value: "resume", children: t('profileIndex.tabResume') })] }), headerAddButton] }), jsx(TabsContent, { value: "experience", children: jsx(ExperienceTab, { org: tenant, username: username }) }), jsx(TabsContent, { value: "resume", children: 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 }), !isReadOnly && activeTab === 'security' && (jsx(Security, { app: currentSPA || '', email: (userMetadata === null || userMetadata === void 0 ? void 0 : userMetadata.email) || '', platformKey: tenant, onAccountDeleted: onAccountDeleted })), activeTab === 'advanced' && localLLMProps && (jsx("div", { className: "space-y-6", children: 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 }) }))] }), !isReadOnly && ['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: t('profileIndex.buttonCancel') }), jsx(Button$1, { onClick: () => {
|
|
176778
176075
|
if (activeTab === 'basic') {
|
|
176779
176076
|
basicForm.handleSubmit();
|
|
176780
176077
|
}
|
|
@@ -178253,11 +177550,11 @@ var PopoverAnchor$1 = React.forwardRef(
|
|
|
178253
177550
|
}
|
|
178254
177551
|
);
|
|
178255
177552
|
PopoverAnchor$1.displayName = ANCHOR_NAME$1;
|
|
178256
|
-
var TRIGGER_NAME$
|
|
177553
|
+
var TRIGGER_NAME$3 = "PopoverTrigger";
|
|
178257
177554
|
var PopoverTrigger$1 = React.forwardRef(
|
|
178258
177555
|
(props, forwardedRef) => {
|
|
178259
177556
|
const { __scopePopover, ...triggerProps } = props;
|
|
178260
|
-
const context = usePopoverContext(TRIGGER_NAME$
|
|
177557
|
+
const context = usePopoverContext(TRIGGER_NAME$3, __scopePopover);
|
|
178261
177558
|
const popperScope = usePopperScope$1(__scopePopover);
|
|
178262
177559
|
const composedTriggerRef = useComposedRefs$1(forwardedRef, context.triggerRef);
|
|
178263
177560
|
const trigger = /* @__PURE__ */ jsx(
|
|
@@ -178276,31 +177573,31 @@ var PopoverTrigger$1 = React.forwardRef(
|
|
|
178276
177573
|
return context.hasCustomAnchor ? trigger : /* @__PURE__ */ jsx(Anchor$3, { asChild: true, ...popperScope, children: trigger });
|
|
178277
177574
|
}
|
|
178278
177575
|
);
|
|
178279
|
-
PopoverTrigger$1.displayName = TRIGGER_NAME$
|
|
178280
|
-
var PORTAL_NAME$
|
|
178281
|
-
var [PortalProvider$1, usePortalContext$1] = createPopoverContext(PORTAL_NAME$
|
|
177576
|
+
PopoverTrigger$1.displayName = TRIGGER_NAME$3;
|
|
177577
|
+
var PORTAL_NAME$2 = "PopoverPortal";
|
|
177578
|
+
var [PortalProvider$1, usePortalContext$1] = createPopoverContext(PORTAL_NAME$2, {
|
|
178282
177579
|
forceMount: void 0
|
|
178283
177580
|
});
|
|
178284
177581
|
var PopoverPortal = (props) => {
|
|
178285
177582
|
const { __scopePopover, forceMount, children, container } = props;
|
|
178286
|
-
const context = usePopoverContext(PORTAL_NAME$
|
|
177583
|
+
const context = usePopoverContext(PORTAL_NAME$2, __scopePopover);
|
|
178287
177584
|
return /* @__PURE__ */ jsx(PortalProvider$1, { scope: __scopePopover, forceMount, children: /* @__PURE__ */ jsx(Presence$3, { present: forceMount || context.open, children: /* @__PURE__ */ jsx(Portal$7, { asChild: true, container, children }) }) });
|
|
178288
177585
|
};
|
|
178289
|
-
PopoverPortal.displayName = PORTAL_NAME$
|
|
178290
|
-
var CONTENT_NAME$
|
|
177586
|
+
PopoverPortal.displayName = PORTAL_NAME$2;
|
|
177587
|
+
var CONTENT_NAME$4 = "PopoverContent";
|
|
178291
177588
|
var PopoverContent$1 = React.forwardRef(
|
|
178292
177589
|
(props, forwardedRef) => {
|
|
178293
|
-
const portalContext = usePortalContext$1(CONTENT_NAME$
|
|
177590
|
+
const portalContext = usePortalContext$1(CONTENT_NAME$4, props.__scopePopover);
|
|
178294
177591
|
const { forceMount = portalContext.forceMount, ...contentProps } = props;
|
|
178295
|
-
const context = usePopoverContext(CONTENT_NAME$
|
|
177592
|
+
const context = usePopoverContext(CONTENT_NAME$4, props.__scopePopover);
|
|
178296
177593
|
return /* @__PURE__ */ jsx(Presence$3, { present: forceMount || context.open, children: context.modal ? /* @__PURE__ */ jsx(PopoverContentModal, { ...contentProps, ref: forwardedRef }) : /* @__PURE__ */ jsx(PopoverContentNonModal, { ...contentProps, ref: forwardedRef }) });
|
|
178297
177594
|
}
|
|
178298
177595
|
);
|
|
178299
|
-
PopoverContent$1.displayName = CONTENT_NAME$
|
|
177596
|
+
PopoverContent$1.displayName = CONTENT_NAME$4;
|
|
178300
177597
|
var Slot = createSlot$1("PopoverContent.RemoveScroll");
|
|
178301
177598
|
var PopoverContentModal = React.forwardRef(
|
|
178302
177599
|
(props, forwardedRef) => {
|
|
178303
|
-
const context = usePopoverContext(CONTENT_NAME$
|
|
177600
|
+
const context = usePopoverContext(CONTENT_NAME$4, props.__scopePopover);
|
|
178304
177601
|
const contentRef = React.useRef(null);
|
|
178305
177602
|
const composedRefs = useComposedRefs$1(forwardedRef, contentRef);
|
|
178306
177603
|
const isRightClickOutsideRef = React.useRef(false);
|
|
@@ -178340,7 +177637,7 @@ var PopoverContentModal = React.forwardRef(
|
|
|
178340
177637
|
);
|
|
178341
177638
|
var PopoverContentNonModal = React.forwardRef(
|
|
178342
177639
|
(props, forwardedRef) => {
|
|
178343
|
-
const context = usePopoverContext(CONTENT_NAME$
|
|
177640
|
+
const context = usePopoverContext(CONTENT_NAME$4, props.__scopePopover);
|
|
178344
177641
|
const hasInteractedOutsideRef = React.useRef(false);
|
|
178345
177642
|
const hasPointerDownOutsideRef = React.useRef(false);
|
|
178346
177643
|
return /* @__PURE__ */ jsx(
|
|
@@ -178392,7 +177689,7 @@ var PopoverContentImpl = React.forwardRef(
|
|
|
178392
177689
|
onInteractOutside,
|
|
178393
177690
|
...contentProps
|
|
178394
177691
|
} = props;
|
|
178395
|
-
const context = usePopoverContext(CONTENT_NAME$
|
|
177692
|
+
const context = usePopoverContext(CONTENT_NAME$4, __scopePopover);
|
|
178396
177693
|
const popperScope = usePopperScope$1(__scopePopover);
|
|
178397
177694
|
useFocusGuards();
|
|
178398
177695
|
return /* @__PURE__ */ jsx(
|
|
@@ -178470,26 +177767,26 @@ PopoverArrow.displayName = ARROW_NAME$2;
|
|
|
178470
177767
|
function getState$2(open) {
|
|
178471
177768
|
return open ? "open" : "closed";
|
|
178472
177769
|
}
|
|
178473
|
-
var Root2$
|
|
177770
|
+
var Root2$4 = Popover$1;
|
|
178474
177771
|
var Anchor2 = PopoverAnchor$1;
|
|
178475
177772
|
var Trigger$1 = PopoverTrigger$1;
|
|
178476
177773
|
var Portal$1 = PopoverPortal;
|
|
178477
|
-
var Content2$
|
|
177774
|
+
var Content2$2 = PopoverContent$1;
|
|
178478
177775
|
|
|
178479
|
-
const Popover = Root2$
|
|
177776
|
+
const Popover = Root2$4;
|
|
178480
177777
|
const PopoverTrigger = Trigger$1;
|
|
178481
177778
|
const PopoverAnchor = Anchor2;
|
|
178482
177779
|
const PopoverContent = React.forwardRef(({ className, align = 'center', sideOffset = 4, portalled = true, container, ...props }, ref) => {
|
|
178483
177780
|
var _a;
|
|
178484
177781
|
const portalContainer = useFloatingPortalContainer();
|
|
178485
177782
|
const resolvedContainer = (_a = container !== null && container !== void 0 ? container : portalContainer) !== null && _a !== void 0 ? _a : undefined;
|
|
178486
|
-
const content = (jsx(Content2$
|
|
177783
|
+
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 }));
|
|
178487
177784
|
if (!portalled) {
|
|
178488
177785
|
return content;
|
|
178489
177786
|
}
|
|
178490
177787
|
return jsx(Portal$1, { container: resolvedContainer, children: content });
|
|
178491
177788
|
});
|
|
178492
|
-
PopoverContent.displayName = Content2$
|
|
177789
|
+
PopoverContent.displayName = Content2$2.displayName;
|
|
178493
177790
|
|
|
178494
177791
|
function UsersTab({ tenant, onInviteClick, currentSpa, showGradebookTab = false, }) {
|
|
178495
177792
|
const t = useT();
|
|
@@ -180371,11 +179668,11 @@ var Collapsible$1 = React.forwardRef(
|
|
|
180371
179668
|
}
|
|
180372
179669
|
);
|
|
180373
179670
|
Collapsible$1.displayName = COLLAPSIBLE_NAME;
|
|
180374
|
-
var TRIGGER_NAME$
|
|
179671
|
+
var TRIGGER_NAME$2 = "CollapsibleTrigger";
|
|
180375
179672
|
var CollapsibleTrigger$1 = React.forwardRef(
|
|
180376
179673
|
(props, forwardedRef) => {
|
|
180377
179674
|
const { __scopeCollapsible, ...triggerProps } = props;
|
|
180378
|
-
const context = useCollapsibleContext(TRIGGER_NAME$
|
|
179675
|
+
const context = useCollapsibleContext(TRIGGER_NAME$2, __scopeCollapsible);
|
|
180379
179676
|
return /* @__PURE__ */ jsx(
|
|
180380
179677
|
Primitive$2.button,
|
|
180381
179678
|
{
|
|
@@ -180392,19 +179689,19 @@ var CollapsibleTrigger$1 = React.forwardRef(
|
|
|
180392
179689
|
);
|
|
180393
179690
|
}
|
|
180394
179691
|
);
|
|
180395
|
-
CollapsibleTrigger$1.displayName = TRIGGER_NAME$
|
|
180396
|
-
var CONTENT_NAME$
|
|
179692
|
+
CollapsibleTrigger$1.displayName = TRIGGER_NAME$2;
|
|
179693
|
+
var CONTENT_NAME$3 = "CollapsibleContent";
|
|
180397
179694
|
var CollapsibleContent$1 = React.forwardRef(
|
|
180398
179695
|
(props, forwardedRef) => {
|
|
180399
179696
|
const { forceMount, ...contentProps } = props;
|
|
180400
|
-
const context = useCollapsibleContext(CONTENT_NAME$
|
|
179697
|
+
const context = useCollapsibleContext(CONTENT_NAME$3, props.__scopeCollapsible);
|
|
180401
179698
|
return /* @__PURE__ */ jsx(Presence$2, { present: forceMount || context.open, children: ({ present }) => /* @__PURE__ */ jsx(CollapsibleContentImpl, { ...contentProps, ref: forwardedRef, present }) });
|
|
180402
179699
|
}
|
|
180403
179700
|
);
|
|
180404
|
-
CollapsibleContent$1.displayName = CONTENT_NAME$
|
|
179701
|
+
CollapsibleContent$1.displayName = CONTENT_NAME$3;
|
|
180405
179702
|
var CollapsibleContentImpl = React.forwardRef((props, forwardedRef) => {
|
|
180406
179703
|
const { __scopeCollapsible, present, children, ...contentProps } = props;
|
|
180407
|
-
const context = useCollapsibleContext(CONTENT_NAME$
|
|
179704
|
+
const context = useCollapsibleContext(CONTENT_NAME$3, __scopeCollapsible);
|
|
180408
179705
|
const [isPresent, setIsPresent] = React.useState(present);
|
|
180409
179706
|
const ref = React.useRef(null);
|
|
180410
179707
|
const composedRefs = useComposedRefs$1(forwardedRef, ref);
|
|
@@ -203640,7 +202937,7 @@ var joinTextblockForward = () => ({ state, dispatch }) => {
|
|
|
203640
202937
|
};
|
|
203641
202938
|
|
|
203642
202939
|
// src/utilities/isMacOS.ts
|
|
203643
|
-
function isMacOS() {
|
|
202940
|
+
function isMacOS$1() {
|
|
203644
202941
|
return typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : false;
|
|
203645
202942
|
}
|
|
203646
202943
|
|
|
@@ -203666,7 +202963,7 @@ function normalizeKeyName(name) {
|
|
|
203666
202963
|
} else if (/^s(hift)?$/i.test(mod)) {
|
|
203667
202964
|
shift = true;
|
|
203668
202965
|
} else if (/^mod$/i.test(mod)) {
|
|
203669
|
-
if (isiOS() || isMacOS()) {
|
|
202966
|
+
if (isiOS() || isMacOS$1()) {
|
|
203670
202967
|
meta = true;
|
|
203671
202968
|
} else {
|
|
203672
202969
|
ctrl = true;
|
|
@@ -206643,7 +205940,7 @@ var Keymap = Extension.create({
|
|
|
206643
205940
|
"Ctrl-a": () => this.editor.commands.selectTextblockStart(),
|
|
206644
205941
|
"Ctrl-e": () => this.editor.commands.selectTextblockEnd()
|
|
206645
205942
|
};
|
|
206646
|
-
if (isiOS() || isMacOS()) {
|
|
205943
|
+
if (isiOS() || isMacOS$1()) {
|
|
206647
205944
|
return macKeymap;
|
|
206648
205945
|
}
|
|
206649
205946
|
return pcKeymap;
|
|
@@ -217172,17 +216469,184 @@ var RadioGroupIndicator = React.forwardRef(
|
|
|
217172
216469
|
}
|
|
217173
216470
|
);
|
|
217174
216471
|
RadioGroupIndicator.displayName = INDICATOR_NAME2;
|
|
217175
|
-
var Root2$
|
|
216472
|
+
var Root2$3 = RadioGroup$1;
|
|
217176
216473
|
var Item2 = RadioGroupItem$1;
|
|
217177
216474
|
var Indicator = RadioGroupIndicator;
|
|
217178
216475
|
|
|
217179
216476
|
function RadioGroup({ className, ...props }) {
|
|
217180
|
-
return (jsx(Root2$
|
|
216477
|
+
return (jsx(Root2$3, { "data-slot": "radio-group", className: cn('grid gap-3', className), ...props }));
|
|
217181
216478
|
}
|
|
217182
216479
|
function RadioGroupItem({ className, ...props }) {
|
|
217183
216480
|
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" }) }) }));
|
|
217184
216481
|
}
|
|
217185
216482
|
|
|
216483
|
+
var SLOTTABLE_IDENTIFIER = Symbol("radix.slottable");
|
|
216484
|
+
// @__NO_SIDE_EFFECTS__
|
|
216485
|
+
function createSlottable(ownerName) {
|
|
216486
|
+
const Slottable2 = ({ children }) => {
|
|
216487
|
+
return /* @__PURE__ */ jsx(Fragment$1, { children });
|
|
216488
|
+
};
|
|
216489
|
+
Slottable2.displayName = `${ownerName}.Slottable`;
|
|
216490
|
+
Slottable2.__radixId = SLOTTABLE_IDENTIFIER;
|
|
216491
|
+
return Slottable2;
|
|
216492
|
+
}
|
|
216493
|
+
|
|
216494
|
+
var ROOT_NAME = "AlertDialog";
|
|
216495
|
+
var [createAlertDialogContext] = createContextScope$1(ROOT_NAME, [
|
|
216496
|
+
createDialogScope
|
|
216497
|
+
]);
|
|
216498
|
+
var useDialogScope = createDialogScope();
|
|
216499
|
+
var AlertDialog$1 = (props) => {
|
|
216500
|
+
const { __scopeAlertDialog, ...alertDialogProps } = props;
|
|
216501
|
+
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
216502
|
+
return /* @__PURE__ */ jsx(DialogPrimitive.Root, { ...dialogScope, ...alertDialogProps, modal: true });
|
|
216503
|
+
};
|
|
216504
|
+
AlertDialog$1.displayName = ROOT_NAME;
|
|
216505
|
+
var TRIGGER_NAME$1 = "AlertDialogTrigger";
|
|
216506
|
+
var AlertDialogTrigger = React.forwardRef(
|
|
216507
|
+
(props, forwardedRef) => {
|
|
216508
|
+
const { __scopeAlertDialog, ...triggerProps } = props;
|
|
216509
|
+
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
216510
|
+
return /* @__PURE__ */ jsx(DialogPrimitive.Trigger, { ...dialogScope, ...triggerProps, ref: forwardedRef });
|
|
216511
|
+
}
|
|
216512
|
+
);
|
|
216513
|
+
AlertDialogTrigger.displayName = TRIGGER_NAME$1;
|
|
216514
|
+
var PORTAL_NAME$1 = "AlertDialogPortal";
|
|
216515
|
+
var AlertDialogPortal$1 = (props) => {
|
|
216516
|
+
const { __scopeAlertDialog, ...portalProps } = props;
|
|
216517
|
+
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
216518
|
+
return /* @__PURE__ */ jsx(DialogPrimitive.Portal, { ...dialogScope, ...portalProps });
|
|
216519
|
+
};
|
|
216520
|
+
AlertDialogPortal$1.displayName = PORTAL_NAME$1;
|
|
216521
|
+
var OVERLAY_NAME = "AlertDialogOverlay";
|
|
216522
|
+
var AlertDialogOverlay$1 = React.forwardRef(
|
|
216523
|
+
(props, forwardedRef) => {
|
|
216524
|
+
const { __scopeAlertDialog, ...overlayProps } = props;
|
|
216525
|
+
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
216526
|
+
return /* @__PURE__ */ jsx(DialogPrimitive.Overlay, { ...dialogScope, ...overlayProps, ref: forwardedRef });
|
|
216527
|
+
}
|
|
216528
|
+
);
|
|
216529
|
+
AlertDialogOverlay$1.displayName = OVERLAY_NAME;
|
|
216530
|
+
var CONTENT_NAME$2 = "AlertDialogContent";
|
|
216531
|
+
var [AlertDialogContentProvider, useAlertDialogContentContext] = createAlertDialogContext(CONTENT_NAME$2);
|
|
216532
|
+
var Slottable = createSlottable("AlertDialogContent");
|
|
216533
|
+
var AlertDialogContent$1 = React.forwardRef(
|
|
216534
|
+
(props, forwardedRef) => {
|
|
216535
|
+
const { __scopeAlertDialog, children, ...contentProps } = props;
|
|
216536
|
+
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
216537
|
+
const contentRef = React.useRef(null);
|
|
216538
|
+
const composedRefs = useComposedRefs$1(forwardedRef, contentRef);
|
|
216539
|
+
const cancelRef = React.useRef(null);
|
|
216540
|
+
return /* @__PURE__ */ jsx(
|
|
216541
|
+
DialogPrimitive.WarningProvider,
|
|
216542
|
+
{
|
|
216543
|
+
contentName: CONTENT_NAME$2,
|
|
216544
|
+
titleName: TITLE_NAME,
|
|
216545
|
+
docsSlug: "alert-dialog",
|
|
216546
|
+
children: /* @__PURE__ */ jsx(AlertDialogContentProvider, { scope: __scopeAlertDialog, cancelRef, children: /* @__PURE__ */ jsxs(
|
|
216547
|
+
DialogPrimitive.Content,
|
|
216548
|
+
{
|
|
216549
|
+
role: "alertdialog",
|
|
216550
|
+
...dialogScope,
|
|
216551
|
+
...contentProps,
|
|
216552
|
+
ref: composedRefs,
|
|
216553
|
+
onOpenAutoFocus: composeEventHandlers$2(contentProps.onOpenAutoFocus, (event) => {
|
|
216554
|
+
event.preventDefault();
|
|
216555
|
+
cancelRef.current?.focus({ preventScroll: true });
|
|
216556
|
+
}),
|
|
216557
|
+
onPointerDownOutside: (event) => event.preventDefault(),
|
|
216558
|
+
onInteractOutside: (event) => event.preventDefault(),
|
|
216559
|
+
children: [
|
|
216560
|
+
/* @__PURE__ */ jsx(Slottable, { children }),
|
|
216561
|
+
/* @__PURE__ */ jsx(DescriptionWarning, { contentRef })
|
|
216562
|
+
]
|
|
216563
|
+
}
|
|
216564
|
+
) })
|
|
216565
|
+
}
|
|
216566
|
+
);
|
|
216567
|
+
}
|
|
216568
|
+
);
|
|
216569
|
+
AlertDialogContent$1.displayName = CONTENT_NAME$2;
|
|
216570
|
+
var TITLE_NAME = "AlertDialogTitle";
|
|
216571
|
+
var AlertDialogTitle$1 = React.forwardRef(
|
|
216572
|
+
(props, forwardedRef) => {
|
|
216573
|
+
const { __scopeAlertDialog, ...titleProps } = props;
|
|
216574
|
+
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
216575
|
+
return /* @__PURE__ */ jsx(DialogPrimitive.Title, { ...dialogScope, ...titleProps, ref: forwardedRef });
|
|
216576
|
+
}
|
|
216577
|
+
);
|
|
216578
|
+
AlertDialogTitle$1.displayName = TITLE_NAME;
|
|
216579
|
+
var DESCRIPTION_NAME = "AlertDialogDescription";
|
|
216580
|
+
var AlertDialogDescription$1 = React.forwardRef((props, forwardedRef) => {
|
|
216581
|
+
const { __scopeAlertDialog, ...descriptionProps } = props;
|
|
216582
|
+
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
216583
|
+
return /* @__PURE__ */ jsx(DialogPrimitive.Description, { ...dialogScope, ...descriptionProps, ref: forwardedRef });
|
|
216584
|
+
});
|
|
216585
|
+
AlertDialogDescription$1.displayName = DESCRIPTION_NAME;
|
|
216586
|
+
var ACTION_NAME = "AlertDialogAction";
|
|
216587
|
+
var AlertDialogAction$1 = React.forwardRef(
|
|
216588
|
+
(props, forwardedRef) => {
|
|
216589
|
+
const { __scopeAlertDialog, ...actionProps } = props;
|
|
216590
|
+
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
216591
|
+
return /* @__PURE__ */ jsx(DialogPrimitive.Close, { ...dialogScope, ...actionProps, ref: forwardedRef });
|
|
216592
|
+
}
|
|
216593
|
+
);
|
|
216594
|
+
AlertDialogAction$1.displayName = ACTION_NAME;
|
|
216595
|
+
var CANCEL_NAME = "AlertDialogCancel";
|
|
216596
|
+
var AlertDialogCancel$1 = React.forwardRef(
|
|
216597
|
+
(props, forwardedRef) => {
|
|
216598
|
+
const { __scopeAlertDialog, ...cancelProps } = props;
|
|
216599
|
+
const { cancelRef } = useAlertDialogContentContext(CANCEL_NAME, __scopeAlertDialog);
|
|
216600
|
+
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
216601
|
+
const ref = useComposedRefs$1(forwardedRef, cancelRef);
|
|
216602
|
+
return /* @__PURE__ */ jsx(DialogPrimitive.Close, { ...dialogScope, ...cancelProps, ref });
|
|
216603
|
+
}
|
|
216604
|
+
);
|
|
216605
|
+
AlertDialogCancel$1.displayName = CANCEL_NAME;
|
|
216606
|
+
var DescriptionWarning = ({ contentRef }) => {
|
|
216607
|
+
const MESSAGE = `\`${CONTENT_NAME$2}\` requires a description for the component to be accessible for screen reader users.
|
|
216608
|
+
|
|
216609
|
+
You can add a description to the \`${CONTENT_NAME$2}\` by passing a \`${DESCRIPTION_NAME}\` component as a child, which also benefits sighted users by adding visible context to the dialog.
|
|
216610
|
+
|
|
216611
|
+
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$2}\`. 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.
|
|
216612
|
+
|
|
216613
|
+
For more information, see https://radix-ui.com/primitives/docs/components/alert-dialog`;
|
|
216614
|
+
React.useEffect(() => {
|
|
216615
|
+
const hasDescription = document.getElementById(
|
|
216616
|
+
contentRef.current?.getAttribute("aria-describedby")
|
|
216617
|
+
);
|
|
216618
|
+
if (!hasDescription) console.warn(MESSAGE);
|
|
216619
|
+
}, [MESSAGE, contentRef]);
|
|
216620
|
+
return null;
|
|
216621
|
+
};
|
|
216622
|
+
var Root2$2 = AlertDialog$1;
|
|
216623
|
+
var Portal2 = AlertDialogPortal$1;
|
|
216624
|
+
var Overlay2 = AlertDialogOverlay$1;
|
|
216625
|
+
var Content2$1 = AlertDialogContent$1;
|
|
216626
|
+
var Action = AlertDialogAction$1;
|
|
216627
|
+
var Cancel = AlertDialogCancel$1;
|
|
216628
|
+
var Title2 = AlertDialogTitle$1;
|
|
216629
|
+
var Description2 = AlertDialogDescription$1;
|
|
216630
|
+
|
|
216631
|
+
const AlertDialog = Root2$2;
|
|
216632
|
+
const AlertDialogPortal = Portal2;
|
|
216633
|
+
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 })));
|
|
216634
|
+
AlertDialogOverlay.displayName = Overlay2.displayName;
|
|
216635
|
+
const AlertDialogContent = React.forwardRef(({ className, ...props }, ref) => (jsxs(AlertDialogPortal, { children: [jsx(AlertDialogOverlay, {}), jsx(Content2$1, { 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 })] })));
|
|
216636
|
+
AlertDialogContent.displayName = Content2$1.displayName;
|
|
216637
|
+
const AlertDialogHeader = ({ className, ...props }) => (jsx("div", { className: cn('flex flex-col space-y-2 text-center sm:text-left', className), ...props }));
|
|
216638
|
+
AlertDialogHeader.displayName = 'AlertDialogHeader';
|
|
216639
|
+
const AlertDialogFooter = ({ className, ...props }) => (jsx("div", { className: cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className), ...props }));
|
|
216640
|
+
AlertDialogFooter.displayName = 'AlertDialogFooter';
|
|
216641
|
+
const AlertDialogTitle = React.forwardRef(({ className, ...props }, ref) => (jsx(Title2, { ref: ref, className: cn('text-lg font-semibold', className), ...props })));
|
|
216642
|
+
AlertDialogTitle.displayName = Title2.displayName;
|
|
216643
|
+
const AlertDialogDescription = React.forwardRef(({ className, ...props }, ref) => (jsx(Description2, { ref: ref, className: cn('text-muted-foreground text-sm', className), ...props })));
|
|
216644
|
+
AlertDialogDescription.displayName = Description2.displayName;
|
|
216645
|
+
const AlertDialogAction = React.forwardRef(({ className, ...props }, ref) => (jsx(Action, { ref: ref, className: cn(buttonVariants(), className), ...props })));
|
|
216646
|
+
AlertDialogAction.displayName = Action.displayName;
|
|
216647
|
+
const AlertDialogCancel = React.forwardRef(({ className, ...props }, ref) => (jsx(Cancel, { ref: ref, className: cn(buttonVariants({ variant: 'outline' }), 'mt-2 sm:mt-0', className), ...props })));
|
|
216648
|
+
AlertDialogCancel.displayName = Cancel.displayName;
|
|
216649
|
+
|
|
217186
216650
|
const THEMES = { light: '', dark: '.dark' };
|
|
217187
216651
|
const ChartContext = React.createContext(null);
|
|
217188
216652
|
function useChart() {
|
|
@@ -254021,8 +253485,501 @@ function MemoryButton({ mentorId, tenantKey, username }) {
|
|
|
254021
253485
|
} }))] }) }), jsx(PopoverContent, { className: "w-96 rounded-lg border border-gray-200 bg-white p-0 shadow-xl", children: jsx(MemoryMenu, { onClose: () => setIsOpen(false), mentorId: mentorId, tenantKey: tenantKey, username: username }) })] }));
|
|
254022
253486
|
}
|
|
254023
253487
|
|
|
253488
|
+
// Tauri types for model download functionality
|
|
253489
|
+
/**
|
|
253490
|
+
* Initial state for model download
|
|
253491
|
+
*/
|
|
253492
|
+
const initialModelDownloadState = {
|
|
253493
|
+
status: 'idle',
|
|
253494
|
+
progress: 0,
|
|
253495
|
+
message: '',
|
|
253496
|
+
logs: [],
|
|
253497
|
+
lastUpdated: new Date().toISOString(),
|
|
253498
|
+
};
|
|
253499
|
+
/**
|
|
253500
|
+
* Check if the app is running inside Tauri
|
|
253501
|
+
* In Tauri 2.0, the global is __TAURI_INTERNALS__ (with withGlobalTauri: true)
|
|
253502
|
+
* We also check for __TAURI__ for backwards compatibility
|
|
253503
|
+
*/
|
|
253504
|
+
const isTauriApp$1 = () => {
|
|
253505
|
+
if (typeof window === 'undefined')
|
|
253506
|
+
return false;
|
|
253507
|
+
return '__TAURI_INTERNALS__' in window || '__TAURI__' in window;
|
|
253508
|
+
};
|
|
253509
|
+
/**
|
|
253510
|
+
* Tauri event names
|
|
253511
|
+
*/
|
|
253512
|
+
const TAURI_EVENTS = {
|
|
253513
|
+
DOWNLOAD_PROGRESS: 'model:download-progress',
|
|
253514
|
+
INSTALLATION_LOG: 'model:installation-log',
|
|
253515
|
+
DISK_SPACE_ERROR: 'model:disk-space-error',
|
|
253516
|
+
OLLAMA_STATUS: 'model:ollama-status',
|
|
253517
|
+
};
|
|
253518
|
+
/**
|
|
253519
|
+
* Tauri command names
|
|
253520
|
+
*/
|
|
253521
|
+
const TAURI_COMMANDS = {
|
|
253522
|
+
INSTALL_OLLAMA: 'install_ollama',
|
|
253523
|
+
STOP_OLLAMA: 'stop_ollama',
|
|
253524
|
+
CHECK_OLLAMA_STATUS: 'check_ollama_status',
|
|
253525
|
+
CHECK_DISK_SPACE: 'check_disk_space_for_model',
|
|
253526
|
+
GET_SYSTEM_MEMORY: 'get_system_memory',
|
|
253527
|
+
DOWNLOAD_MODEL: 'download_model',
|
|
253528
|
+
CANCEL_DOWNLOAD: 'cancel_model_download',
|
|
253529
|
+
CHECK_NETWORK_STATUS: 'check_network_status',
|
|
253530
|
+
GET_OS_TYPE: 'get_os_type',
|
|
253531
|
+
CHECK_FOUNDRY_STATUS: 'check_foundry_local_status',
|
|
253532
|
+
START_FOUNDRY_SERVICE: 'start_foundry_local_service',
|
|
253533
|
+
LOAD_FOUNDRY_MODEL: 'load_foundry_local_model',
|
|
253534
|
+
SET_SELECTED_FOUNDRY_MODEL: 'set_selected_foundry_model',
|
|
253535
|
+
GET_SELECTED_FOUNDRY_MODEL: 'get_selected_foundry_model',
|
|
253536
|
+
INSTALL_FOUNDRY: 'install_foundry',
|
|
253537
|
+
DOWNLOAD_FOUNDRY_MODEL: 'download_foundry_model_cmd',
|
|
253538
|
+
GET_RECOMMENDED_FOUNDRY_MODELS: 'get_recommended_foundry_models',
|
|
253539
|
+
LOG_STDOUT: 'log_stdout',
|
|
253540
|
+
};
|
|
253541
|
+
/**
|
|
253542
|
+
* Initial state for the Cowork install flow.
|
|
253543
|
+
*/
|
|
253544
|
+
const initialGhostOsInstallState = {
|
|
253545
|
+
status: 'idle',
|
|
253546
|
+
progress: 0,
|
|
253547
|
+
message: '',
|
|
253548
|
+
logs: [],
|
|
253549
|
+
lastUpdated: new Date().toISOString(),
|
|
253550
|
+
};
|
|
253551
|
+
/**
|
|
253552
|
+
* Tauri event names emitted by the host during GhostOS install/setup.
|
|
253553
|
+
*/
|
|
253554
|
+
const GHOST_OS_TAURI_EVENTS = {
|
|
253555
|
+
INSTALL_PROGRESS: 'ghost-os:install-progress',
|
|
253556
|
+
INSTALLATION_LOG: 'ghost-os:installation-log',
|
|
253557
|
+
STATUS: 'ghost-os:status',
|
|
253558
|
+
};
|
|
253559
|
+
/**
|
|
253560
|
+
* Tauri command names the host implements for GhostOS install/setup. The web
|
|
253561
|
+
* layer invokes these; the native side performs the clone + setup.
|
|
253562
|
+
*/
|
|
253563
|
+
const GHOST_OS_TAURI_COMMANDS = {
|
|
253564
|
+
/** Install and set up GhostOS (clone repo + run setup). */
|
|
253565
|
+
INSTALL_GHOST_OS: 'install_ghost_os',
|
|
253566
|
+
/** Stop the running GhostOS manager. */
|
|
253567
|
+
STOP_GHOST_OS: 'stop_ghost_os',
|
|
253568
|
+
/** Report current {@link GhostOsStatus}. */
|
|
253569
|
+
CHECK_GHOST_OS_STATUS: 'check_ghost_os_status',
|
|
253570
|
+
};
|
|
253571
|
+
/**
|
|
253572
|
+
* Tauri command strings exposed by `tauri-plugin-macos-permissions`
|
|
253573
|
+
* (https://github.com/ayangweb/tauri-plugin-macos-permissions). GhostOS needs
|
|
253574
|
+
* macOS Accessibility permission to control the device, so the Cowork
|
|
253575
|
+
* card surfaces it. These are invoked directly via `useTauri().invoke(...)` —
|
|
253576
|
+
* no extra npm dependency. The host must register the plugin in its Tauri app
|
|
253577
|
+
* (`tauri_plugin_macos_permissions::init()`). Each `CHECK_*` returns a boolean;
|
|
253578
|
+
* each `REQUEST_*` prompts / opens the relevant System Settings pane.
|
|
253579
|
+
*/
|
|
253580
|
+
const MACOS_PERMISSIONS_COMMANDS = {
|
|
253581
|
+
CHECK_ACCESSIBILITY: 'plugin:macos-permissions|check_accessibility_permission',
|
|
253582
|
+
REQUEST_ACCESSIBILITY: 'plugin:macos-permissions|request_accessibility_permission',
|
|
253583
|
+
CHECK_SCREEN_RECORDING: 'plugin:macos-permissions|check_screen_recording_permission',
|
|
253584
|
+
REQUEST_SCREEN_RECORDING: 'plugin:macos-permissions|request_screen_recording_permission',
|
|
253585
|
+
CHECK_INPUT_MONITORING: 'plugin:macos-permissions|check_input_monitoring_permission',
|
|
253586
|
+
REQUEST_INPUT_MONITORING: 'plugin:macos-permissions|request_input_monitoring_permission',
|
|
253587
|
+
CHECK_FULL_DISK_ACCESS: 'plugin:macos-permissions|check_full_disk_access_permission',
|
|
253588
|
+
REQUEST_FULL_DISK_ACCESS: 'plugin:macos-permissions|request_full_disk_access_permission',
|
|
253589
|
+
};
|
|
253590
|
+
|
|
253591
|
+
/**
|
|
253592
|
+
* Dynamically import Tauri APIs to avoid SSR issues
|
|
253593
|
+
*/
|
|
253594
|
+
const getTauriAPIs = async () => {
|
|
253595
|
+
try {
|
|
253596
|
+
const { invoke } = await import('@tauri-apps/api/core');
|
|
253597
|
+
const { listen } = await import('@tauri-apps/api/event');
|
|
253598
|
+
return { invoke, listen };
|
|
253599
|
+
}
|
|
253600
|
+
catch (error) {
|
|
253601
|
+
console.error('Failed to load Tauri APIs:', error);
|
|
253602
|
+
return null;
|
|
253603
|
+
}
|
|
253604
|
+
};
|
|
253605
|
+
/**
|
|
253606
|
+
* Hook to access Tauri APIs with SSR safety
|
|
253607
|
+
*
|
|
253608
|
+
* @returns Object with isAvailable flag and Tauri invoke/listen functions
|
|
253609
|
+
*/
|
|
253610
|
+
function useTauri() {
|
|
253611
|
+
const [isAvailable, setIsAvailable] = useState(false);
|
|
253612
|
+
const [apis, setApis] = useState(null);
|
|
253613
|
+
useEffect(() => {
|
|
253614
|
+
// Check if we're in a Tauri environment
|
|
253615
|
+
const inTauri = isTauriApp$1();
|
|
253616
|
+
if (inTauri) {
|
|
253617
|
+
getTauriAPIs().then((result) => {
|
|
253618
|
+
setApis(result);
|
|
253619
|
+
setIsAvailable(!!result);
|
|
253620
|
+
});
|
|
253621
|
+
}
|
|
253622
|
+
}, []);
|
|
253623
|
+
/**
|
|
253624
|
+
* Invoke a Tauri command
|
|
253625
|
+
*/
|
|
253626
|
+
const invoke = useCallback(async (command, args) => {
|
|
253627
|
+
if (!(apis === null || apis === void 0 ? void 0 : apis.invoke)) {
|
|
253628
|
+
throw new Error('Tauri is not available');
|
|
253629
|
+
}
|
|
253630
|
+
return apis.invoke(command, args);
|
|
253631
|
+
}, [apis]);
|
|
253632
|
+
/**
|
|
253633
|
+
* Listen to a Tauri event
|
|
253634
|
+
* Returns an unlisten function that should be called on cleanup
|
|
253635
|
+
*/
|
|
253636
|
+
const listen = useCallback(async (event, handler) => {
|
|
253637
|
+
// The synchronous global (`__TAURI_INTERNALS__`) exposes `invoke` but
|
|
253638
|
+
// frequently NOT `event.listen`, so `apis.listen` can be undefined even
|
|
253639
|
+
// though Tauri is fully available. Fall back to the real event API via
|
|
253640
|
+
// dynamic import so download progress/completion events are actually
|
|
253641
|
+
// delivered — otherwise the UI never leaves the "downloading" state.
|
|
253642
|
+
let listenFn = apis === null || apis === void 0 ? void 0 : apis.listen;
|
|
253643
|
+
if (!listenFn) {
|
|
253644
|
+
const { listen: importedListen } = await import('@tauri-apps/api/event');
|
|
253645
|
+
listenFn = importedListen;
|
|
253646
|
+
}
|
|
253647
|
+
return listenFn(event, (e) => handler(e.payload));
|
|
253648
|
+
}, [apis]);
|
|
253649
|
+
return {
|
|
253650
|
+
isAvailable,
|
|
253651
|
+
invoke,
|
|
253652
|
+
listen,
|
|
253653
|
+
};
|
|
253654
|
+
}
|
|
253655
|
+
|
|
253656
|
+
const IS_SERVER = typeof window === 'undefined';
|
|
253657
|
+
/**
|
|
253658
|
+
* A simplified useLocalStorage hook for persisting state to localStorage
|
|
253659
|
+
* with SSR safety.
|
|
253660
|
+
*/
|
|
253661
|
+
function useLocalStorage(key, initialValue) {
|
|
253662
|
+
// Get the initial value
|
|
253663
|
+
const getInitialValue = useCallback(() => {
|
|
253664
|
+
const initial = initialValue instanceof Function ? initialValue() : initialValue;
|
|
253665
|
+
if (IS_SERVER) {
|
|
253666
|
+
return initial;
|
|
253667
|
+
}
|
|
253668
|
+
try {
|
|
253669
|
+
const item = window.localStorage.getItem(key);
|
|
253670
|
+
if (item === null) {
|
|
253671
|
+
return initial;
|
|
253672
|
+
}
|
|
253673
|
+
return JSON.parse(item);
|
|
253674
|
+
}
|
|
253675
|
+
catch (error) {
|
|
253676
|
+
console.warn(`Error reading localStorage key "${key}":`, error);
|
|
253677
|
+
return initial;
|
|
253678
|
+
}
|
|
253679
|
+
}, [key, initialValue]);
|
|
253680
|
+
const [storedValue, setStoredValue] = useState(getInitialValue);
|
|
253681
|
+
// Update stored value when key changes
|
|
253682
|
+
useEffect(() => {
|
|
253683
|
+
setStoredValue(getInitialValue());
|
|
253684
|
+
}, [key, getInitialValue]);
|
|
253685
|
+
// Persist to localStorage
|
|
253686
|
+
const setValue = useCallback((value) => {
|
|
253687
|
+
if (IS_SERVER) {
|
|
253688
|
+
console.warn(`Tried setting localStorage key "${key}" even though environment is not a client`);
|
|
253689
|
+
return;
|
|
253690
|
+
}
|
|
253691
|
+
try {
|
|
253692
|
+
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
253693
|
+
setStoredValue(valueToStore);
|
|
253694
|
+
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
|
253695
|
+
}
|
|
253696
|
+
catch (error) {
|
|
253697
|
+
console.warn(`Error setting localStorage key "${key}":`, error);
|
|
253698
|
+
}
|
|
253699
|
+
}, [key, storedValue]);
|
|
253700
|
+
// Remove from localStorage
|
|
253701
|
+
const removeValue = useCallback(() => {
|
|
253702
|
+
if (IS_SERVER) {
|
|
253703
|
+
console.warn(`Tried removing localStorage key "${key}" even though environment is not a client`);
|
|
253704
|
+
return;
|
|
253705
|
+
}
|
|
253706
|
+
try {
|
|
253707
|
+
const initial = initialValue instanceof Function ? initialValue() : initialValue;
|
|
253708
|
+
window.localStorage.removeItem(key);
|
|
253709
|
+
setStoredValue(initial);
|
|
253710
|
+
}
|
|
253711
|
+
catch (error) {
|
|
253712
|
+
console.warn(`Error removing localStorage key "${key}":`, error);
|
|
253713
|
+
}
|
|
253714
|
+
}, [key, initialValue]);
|
|
253715
|
+
return [storedValue, setValue, removeValue];
|
|
253716
|
+
}
|
|
253717
|
+
|
|
253718
|
+
const LOCAL_STORAGE_KEY$1 = 'ghost_os_install_state';
|
|
253719
|
+
/**
|
|
253720
|
+
* Manage installing & setting up GhostOS (https://github.com/ghostwright/ghost-os)
|
|
253721
|
+
* via the Tauri host. This is the self-contained backing hook for the System
|
|
253722
|
+
* Control card and deliberately mirrors `useModelDownload`:
|
|
253723
|
+
*
|
|
253724
|
+
* - checks GhostOS install/run status through the host
|
|
253725
|
+
* - installs/sets up GhostOS with real-time progress + logs
|
|
253726
|
+
* - persists state across app restarts
|
|
253727
|
+
*
|
|
253728
|
+
* Outside the desktop (Tauri) app every action is a no-op and `isAvailable` is
|
|
253729
|
+
* false, so the card hides itself.
|
|
253730
|
+
*/
|
|
253731
|
+
function useGhostOs() {
|
|
253732
|
+
const { isAvailable, invoke, listen } = useTauri();
|
|
253733
|
+
const [state, setState] = useLocalStorage(LOCAL_STORAGE_KEY$1, initialGhostOsInstallState);
|
|
253734
|
+
const [status, setStatus] = useState(null);
|
|
253735
|
+
// macOS Accessibility permission, which GhostOS needs to control the device.
|
|
253736
|
+
// null = unknown/not-yet-checked or unsupported (non-macOS / plugin absent).
|
|
253737
|
+
const [accessibilityPermission, setAccessibilityPermission] = useState(null);
|
|
253738
|
+
const unlistenRefs = useRef([]);
|
|
253739
|
+
const hasCheckedStatus = useRef(false);
|
|
253740
|
+
/**
|
|
253741
|
+
* Refresh the macOS Accessibility permission via tauri-plugin-macos-permissions.
|
|
253742
|
+
* Independent of the GhostOS status check so a missing host command for one
|
|
253743
|
+
* doesn't suppress the other. Stays null where unsupported.
|
|
253744
|
+
*/
|
|
253745
|
+
const refreshAccessibilityPermission = useCallback(async () => {
|
|
253746
|
+
if (!isAvailable)
|
|
253747
|
+
return;
|
|
253748
|
+
try {
|
|
253749
|
+
const granted = await invoke(MACOS_PERMISSIONS_COMMANDS.CHECK_ACCESSIBILITY);
|
|
253750
|
+
setAccessibilityPermission(granted);
|
|
253751
|
+
}
|
|
253752
|
+
catch (error) {
|
|
253753
|
+
// Plugin not registered or non-macOS host — leave permission unknown.
|
|
253754
|
+
console.warn('[useGhostOs] Accessibility permission check unavailable:', error);
|
|
253755
|
+
setAccessibilityPermission(null);
|
|
253756
|
+
}
|
|
253757
|
+
}, [isAvailable, invoke]);
|
|
253758
|
+
/**
|
|
253759
|
+
* Open the Accessibility pane / prompt so the user can grant permission, then
|
|
253760
|
+
* re-check (the grant happens in System Settings, so we refresh after).
|
|
253761
|
+
*/
|
|
253762
|
+
const requestAccessibilityPermission = useCallback(async () => {
|
|
253763
|
+
if (!isAvailable)
|
|
253764
|
+
return;
|
|
253765
|
+
try {
|
|
253766
|
+
await invoke(MACOS_PERMISSIONS_COMMANDS.REQUEST_ACCESSIBILITY);
|
|
253767
|
+
}
|
|
253768
|
+
catch (error) {
|
|
253769
|
+
console.error('[useGhostOs] Failed to request accessibility permission:', error);
|
|
253770
|
+
}
|
|
253771
|
+
await refreshAccessibilityPermission();
|
|
253772
|
+
}, [isAvailable, invoke, refreshAccessibilityPermission]);
|
|
253773
|
+
const addLog = useCallback((log) => {
|
|
253774
|
+
setState((prev) => ({
|
|
253775
|
+
...prev,
|
|
253776
|
+
logs: [...prev.logs.slice(-99), log],
|
|
253777
|
+
lastUpdated: new Date().toISOString(),
|
|
253778
|
+
}));
|
|
253779
|
+
}, [setState]);
|
|
253780
|
+
/**
|
|
253781
|
+
* Query GhostOS status from the host.
|
|
253782
|
+
*/
|
|
253783
|
+
const checkStatus = useCallback(async () => {
|
|
253784
|
+
if (!isAvailable)
|
|
253785
|
+
return;
|
|
253786
|
+
// Refresh the accessibility permission alongside install status (independent).
|
|
253787
|
+
refreshAccessibilityPermission();
|
|
253788
|
+
try {
|
|
253789
|
+
setState((prev) => ({ ...prev, status: 'checking' }));
|
|
253790
|
+
const result = await invoke(GHOST_OS_TAURI_COMMANDS.CHECK_GHOST_OS_STATUS);
|
|
253791
|
+
setStatus(result);
|
|
253792
|
+
setState((prev) => ({
|
|
253793
|
+
...prev,
|
|
253794
|
+
status: result.installed ? 'completed' : 'idle',
|
|
253795
|
+
progress: result.installed ? 100 : prev.progress,
|
|
253796
|
+
lastUpdated: new Date().toISOString(),
|
|
253797
|
+
}));
|
|
253798
|
+
}
|
|
253799
|
+
catch (error) {
|
|
253800
|
+
console.error('[useGhostOs] Failed to check status:', error);
|
|
253801
|
+
setState((prev) => ({ ...prev, status: 'idle' }));
|
|
253802
|
+
}
|
|
253803
|
+
}, [isAvailable, invoke, setState, refreshAccessibilityPermission]);
|
|
253804
|
+
/**
|
|
253805
|
+
* Install and set up GhostOS. The host clones the repo + runs setup and emits
|
|
253806
|
+
* progress/log/status events along the way.
|
|
253807
|
+
*/
|
|
253808
|
+
const install = useCallback(async () => {
|
|
253809
|
+
if (!isAvailable)
|
|
253810
|
+
return;
|
|
253811
|
+
try {
|
|
253812
|
+
setState((prev) => ({
|
|
253813
|
+
...prev,
|
|
253814
|
+
status: 'installing',
|
|
253815
|
+
progress: 0,
|
|
253816
|
+
message: 'Setting up your assistant…',
|
|
253817
|
+
error: undefined,
|
|
253818
|
+
logs: [],
|
|
253819
|
+
}));
|
|
253820
|
+
addLog({
|
|
253821
|
+
timestamp: new Date().toISOString(),
|
|
253822
|
+
level: 'info',
|
|
253823
|
+
message: 'Starting setup…',
|
|
253824
|
+
});
|
|
253825
|
+
const result = await invoke(GHOST_OS_TAURI_COMMANDS.INSTALL_GHOST_OS);
|
|
253826
|
+
addLog({
|
|
253827
|
+
timestamp: new Date().toISOString(),
|
|
253828
|
+
level: 'info',
|
|
253829
|
+
message: typeof result === 'string' && result ? result : 'Setup complete',
|
|
253830
|
+
});
|
|
253831
|
+
setState((prev) => ({
|
|
253832
|
+
...prev,
|
|
253833
|
+
status: 'completed',
|
|
253834
|
+
progress: 100,
|
|
253835
|
+
message: 'Your assistant is ready',
|
|
253836
|
+
lastUpdated: new Date().toISOString(),
|
|
253837
|
+
}));
|
|
253838
|
+
await checkStatus();
|
|
253839
|
+
}
|
|
253840
|
+
catch (error) {
|
|
253841
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
253842
|
+
setState((prev) => ({
|
|
253843
|
+
...prev,
|
|
253844
|
+
status: 'error',
|
|
253845
|
+
error: message,
|
|
253846
|
+
message: 'Setup didn’t finish',
|
|
253847
|
+
lastUpdated: new Date().toISOString(),
|
|
253848
|
+
}));
|
|
253849
|
+
addLog({
|
|
253850
|
+
timestamp: new Date().toISOString(),
|
|
253851
|
+
level: 'error',
|
|
253852
|
+
message: `Install failed: ${message}`,
|
|
253853
|
+
});
|
|
253854
|
+
}
|
|
253855
|
+
}, [isAvailable, invoke, addLog, checkStatus, setState]);
|
|
253856
|
+
/**
|
|
253857
|
+
* Stop the running GhostOS manager.
|
|
253858
|
+
*/
|
|
253859
|
+
const stop = useCallback(async () => {
|
|
253860
|
+
if (!isAvailable)
|
|
253861
|
+
return;
|
|
253862
|
+
try {
|
|
253863
|
+
await invoke(GHOST_OS_TAURI_COMMANDS.STOP_GHOST_OS);
|
|
253864
|
+
await checkStatus();
|
|
253865
|
+
}
|
|
253866
|
+
catch (error) {
|
|
253867
|
+
console.error('[useGhostOs] Failed to stop GhostOS:', error);
|
|
253868
|
+
}
|
|
253869
|
+
}, [isAvailable, invoke, checkStatus]);
|
|
253870
|
+
/**
|
|
253871
|
+
* Reset the install state (for retrying after an error).
|
|
253872
|
+
*/
|
|
253873
|
+
const resetState = useCallback(() => {
|
|
253874
|
+
setState(initialGhostOsInstallState);
|
|
253875
|
+
}, [setState]);
|
|
253876
|
+
// Wire up host event listeners (progress / logs / status).
|
|
253877
|
+
useEffect(() => {
|
|
253878
|
+
if (!isAvailable)
|
|
253879
|
+
return;
|
|
253880
|
+
const setupListeners = async () => {
|
|
253881
|
+
try {
|
|
253882
|
+
const unlistenProgress = await listen(GHOST_OS_TAURI_EVENTS.INSTALL_PROGRESS, (payload) => {
|
|
253883
|
+
const nextStatus = payload.status === 'completed'
|
|
253884
|
+
? 'completed'
|
|
253885
|
+
: payload.status === 'cancelled'
|
|
253886
|
+
? 'cancelled'
|
|
253887
|
+
: payload.status === 'error'
|
|
253888
|
+
? 'error'
|
|
253889
|
+
: 'installing';
|
|
253890
|
+
setState((prev) => ({
|
|
253891
|
+
...prev,
|
|
253892
|
+
status: nextStatus,
|
|
253893
|
+
progress: payload.percentage,
|
|
253894
|
+
message: payload.message,
|
|
253895
|
+
lastUpdated: new Date().toISOString(),
|
|
253896
|
+
}));
|
|
253897
|
+
});
|
|
253898
|
+
unlistenRefs.current.push(unlistenProgress);
|
|
253899
|
+
const unlistenLogs = await listen(GHOST_OS_TAURI_EVENTS.INSTALLATION_LOG, addLog);
|
|
253900
|
+
unlistenRefs.current.push(unlistenLogs);
|
|
253901
|
+
const unlistenStatus = await listen(GHOST_OS_TAURI_EVENTS.STATUS, setStatus);
|
|
253902
|
+
unlistenRefs.current.push(unlistenStatus);
|
|
253903
|
+
}
|
|
253904
|
+
catch (error) {
|
|
253905
|
+
console.error('[useGhostOs] Failed to setup event listeners:', error);
|
|
253906
|
+
}
|
|
253907
|
+
};
|
|
253908
|
+
setupListeners();
|
|
253909
|
+
return () => {
|
|
253910
|
+
unlistenRefs.current.forEach((unlisten) => unlisten());
|
|
253911
|
+
unlistenRefs.current = [];
|
|
253912
|
+
};
|
|
253913
|
+
}, [isAvailable, listen, setState, addLog]);
|
|
253914
|
+
// Check status once on mount (in the desktop app).
|
|
253915
|
+
useEffect(() => {
|
|
253916
|
+
if (!isAvailable || hasCheckedStatus.current)
|
|
253917
|
+
return;
|
|
253918
|
+
hasCheckedStatus.current = true;
|
|
253919
|
+
checkStatus();
|
|
253920
|
+
}, [isAvailable, checkStatus]);
|
|
253921
|
+
// Only expose the feature as available inside the desktop (Tauri) app.
|
|
253922
|
+
const finalIsAvailable = isAvailable && isTauriApp$1();
|
|
253923
|
+
return {
|
|
253924
|
+
isAvailable: finalIsAvailable,
|
|
253925
|
+
state,
|
|
253926
|
+
status,
|
|
253927
|
+
accessibilityPermission,
|
|
253928
|
+
install,
|
|
253929
|
+
stop,
|
|
253930
|
+
checkStatus,
|
|
253931
|
+
resetState,
|
|
253932
|
+
requestAccessibilityPermission,
|
|
253933
|
+
};
|
|
253934
|
+
}
|
|
253935
|
+
|
|
253936
|
+
// Cowork is macOS-only in prod; the env flag bypasses the OS check so the
|
|
253937
|
+
// toggle can be exercised on Linux/Windows desktop builds during testing.
|
|
253938
|
+
const isMacOS = () => {
|
|
253939
|
+
if (typeof navigator === 'undefined')
|
|
253940
|
+
return false;
|
|
253941
|
+
return /mac/i.test(navigator.userAgent || '');
|
|
253942
|
+
};
|
|
253943
|
+
const allowNonMacOSCowork = () => process.env.NEXT_PUBLIC_ALLOW_NON_MACOS_COMPUTER_USE_TOGGLE === 'true';
|
|
253944
|
+
// 14GB floor per spec; modelSupportsCowork gates size > gb, so a model of
|
|
253945
|
+
// exactly 14GB is also off (no 14.0GB model in the catalog). Only the local-model
|
|
253946
|
+
// backend needs this; the remote AI has no size requirement.
|
|
253947
|
+
const COWORK_MIN_MODEL_GB = 14;
|
|
254024
253948
|
const InsideButtons = ({ activeOptions, onOptionClick, deepResearch, studyMode, artifactsEnabled, containerWidth, disabled = false, onOpenPromptGallery, embedMode = false, promptsIsEnabled = false, memoryEnabled = false, mentorId, tenantKey, username, }) => {
|
|
254025
253949
|
const t = useT();
|
|
253950
|
+
// Cowork = the Tauri GhostOS assistant. GhostOS runs the tools on-device;
|
|
253951
|
+
// the "brain" is EITHER a large local model (Local Models / Ollama) OR the
|
|
253952
|
+
// remote AI (DM OpenAI-compatible endpoint), whichever is set up. useGhostOs
|
|
253953
|
+
// handles install/stop; the localStorage pref (isCoworkEnabled) is read
|
|
253954
|
+
// by the chat hook to route the turn. Reads the pref on mount.
|
|
253955
|
+
// Local state is `coworkOn` so it doesn't shadow the imported setCoworkEnabled.
|
|
253956
|
+
const ghostOs = useGhostOs();
|
|
253957
|
+
const [coworkOn, setCoworkOn] = useState(isCoworkEnabled);
|
|
253958
|
+
const toggleCowork = () => {
|
|
253959
|
+
const next = !coworkOn;
|
|
253960
|
+
// Guard only when turning on. Cowork runs on either a large local model
|
|
253961
|
+
// or the remote AI — allow enabling when either backend is ready (the local
|
|
253962
|
+
// model + Cowork combo still works). The chatbox has no inline notice
|
|
253963
|
+
// space, so remind via toast. (RBAC is enforced separately: this button is
|
|
253964
|
+
// `disabled` when the user lacks the mentor `#chat` permission — see
|
|
253965
|
+
// chat-input-form's isChatDisabledByRbac.)
|
|
253966
|
+
if (next) {
|
|
253967
|
+
const localReady = isLocalLLMEnabled() &&
|
|
253968
|
+
modelSupportsCowork(getLocalLLMModel(), COWORK_MIN_MODEL_GB);
|
|
253969
|
+
if (!localReady && !hasRemoteAiConfig()) {
|
|
253970
|
+
toast.warning(isLocalLLMEnabled()
|
|
253971
|
+
? t('chatInputFormInsideButtons.coworkModelTooSmall')
|
|
253972
|
+
: t('chatInputFormInsideButtons.coworkNeedsBackend'));
|
|
253973
|
+
return;
|
|
253974
|
+
}
|
|
253975
|
+
}
|
|
253976
|
+
setCoworkOn(next);
|
|
253977
|
+
setCoworkEnabled(next);
|
|
253978
|
+
if (next)
|
|
253979
|
+
ghostOs.install();
|
|
253980
|
+
else
|
|
253981
|
+
ghostOs.stop();
|
|
253982
|
+
};
|
|
254026
253983
|
const allInsideButtons = [
|
|
254027
253984
|
{
|
|
254028
253985
|
name: 'Canvas',
|
|
@@ -254066,6 +254023,14 @@ const InsideButtons = ({ activeOptions, onOptionClick, deepResearch, studyMode,
|
|
|
254066
254023
|
action: /* istanbul ignore next */ () => onOptionClick(TOOLS.MEMORY),
|
|
254067
254024
|
isEnabled: memoryEnabled && !embedMode && !!username,
|
|
254068
254025
|
},
|
|
254026
|
+
{
|
|
254027
|
+
name: 'Cowork',
|
|
254028
|
+
label: t('chatInputFormInsideButtons.cowork'),
|
|
254029
|
+
icon: jsx(Monitor, { className: "h-4 w-4" }),
|
|
254030
|
+
isActive: coworkOn,
|
|
254031
|
+
action: toggleCowork,
|
|
254032
|
+
isEnabled: ghostOs.isAvailable && (isMacOS() || allowNonMacOSCowork()),
|
|
254033
|
+
},
|
|
254069
254034
|
].filter((item) => item.isEnabled);
|
|
254070
254035
|
// Get visible inside buttons based on screen size
|
|
254071
254036
|
// Active buttons are always visible, inactive ones are hidden based on available width
|
|
@@ -257344,7 +257309,7 @@ function Account({ tenant, tenants = [], username, onInviteClick, email, mainPla
|
|
|
257344
257309
|
}, children: [jsxs("div", { className: "lg:hidden mb-6", children: [jsx("h3", { className: "text-lg font-medium text-gray-900 dark:text-gray-100 mb-2", children: (_d = (_c = TABS.find((t) => t.id === activeTab)) === null || _c === void 0 ? void 0 : _c.label) !== null && _d !== void 0 ? _d : activeTab }), jsxs("p", { className: "text-gray-600 dark:text-gray-400 text-sm", children: [activeTab === 'basic' && t('profileAccount.descBasic'), activeTab === 'social' && t('profileAccount.descSocial'), activeTab === 'security' && t('profileAccount.descSecurity'), activeTab === 'management' && t('profileAccount.descManagement'), activeTab === 'organization' && t('profileAccount.descOrganization'), activeTab === 'monetization' && t('profileAccount.descMonetization'), activeTab === 'datasets' && t('profileAccount.descBenchmarks'), activeTab === 'advanced' && t('profileAccount.descAdvanced')] })] }), activeTab === 'management' && hasManagementPermissions && (jsx(Admin, { authSpaUrl: authURL, onInviteClick: onInviteClick, tenant: tenant, currentSpa: currentSPA, hasUserTabPermission: hasUserTabPermission, hasGroupsTabPermission: hasGroupsTabPermission, hasPoliciesTabPermission: hasPoliciesTabPermission, hasRolesTabPermission: hasRolesTabPermission, hasTeamsTabPermission: hasTeamsTabPermission, hasInviteUserPermission: hasInviteUserPermission, hasCreateTeamPermission: hasCreateTeamPermission, onLoadGroupPermissions: onLoadGroupPermissions, hasAlertsTabPermission: hasAlertsTabPermission, rbacPermissions: rbacPermissions, enableRbac: enableRbac, showGradebookTab: showGradebookTab })), activeTab === 'organization' && (jsx(OrganizationTab, { platformKey: tenant, tenant: tenants.find((ten) => ten.key === tenant), onTenantUpdate: onTenantUpdate, setOrganizationLogoFromOutside: setOrganizationLogo, defaultSupportPhone: defaultSupportPhone, enableSupportPhone: enableSupportPhone })), activeTab === 'integrations' && (jsx(IntegrationsTab, { tenantKey: tenant, username: username })), activeTab === 'billing' && (jsx(BillingTab, { tenant: tenant, userActiveApp: userActiveApp, username: username, currentUserEmail: email, mainPlatformKey: mainPlatformKey })), activeTab === 'monetization' && (jsx(MonetizationTab, { platformKey: tenant, authURL: authURL })), activeTab === 'datasets' && showBenchmarks && (jsx(BenchmarksTab, { tenantKey: tenant, username: username })), activeTab === 'advanced' && (jsx(AdvancedTab, { platformKey: tenant, currentSPA: currentSPA, username: username, authURL: authURL, currentPlatformBaseDomain: currentPlatformBaseDomain }))] })] }), jsx(ToastProvider, {})] }));
|
|
257345
257310
|
}
|
|
257346
257311
|
|
|
257347
|
-
function UserProfileModal({ isOpen, onClose, params, email, mainPlatformKey, showMentorAIDisplayCheckbox = false, showLeaderboardDisplayCheckbox = false, showGradebookTab = false, showUsernameField = false, showPlatformName = false, useGravatarPicFallback = true, enableCatalogInvite = false, targetTab = 'basic', currentPlan = '', currentSPA = '', userActiveApp = null, authURL, tenants = [], onTenantUpdate, currentPlatformBaseDomain = '', rbacPermissions = {}, enableRbac = false, onLoadGroupPermissions, onTabChange, defaultSupportPhone = '', onBillingTabRequest, onAccountDeleted, enableMemoryTab = false, showBenchmarks = false, localLLMProps,
|
|
257312
|
+
function UserProfileModal({ isOpen, onClose, params, email, mainPlatformKey, showMentorAIDisplayCheckbox = false, showLeaderboardDisplayCheckbox = false, showGradebookTab = false, showUsernameField = false, showPlatformName = false, useGravatarPicFallback = true, enableCatalogInvite = false, targetTab = 'basic', currentPlan = '', currentSPA = '', userActiveApp = null, authURL, tenants = [], onTenantUpdate, currentPlatformBaseDomain = '', rbacPermissions = {}, enableRbac = false, onLoadGroupPermissions, onTabChange, defaultSupportPhone = '', onBillingTabRequest, onAccountDeleted, enableMemoryTab = false, showBenchmarks = false, localLLMProps, enableSupportPhone, }) {
|
|
257348
257313
|
const t = useT();
|
|
257349
257314
|
console.log('[UserProfileModal] localLLMProps received:', {
|
|
257350
257315
|
isAvailable: localLLMProps === null || localLLMProps === void 0 ? void 0 : localLLMProps.isAvailable,
|
|
@@ -257410,7 +257375,7 @@ function UserProfileModal({ isOpen, onClose, params, email, mainPlatformKey, sho
|
|
|
257410
257375
|
showPlatformName: showPlatformName,
|
|
257411
257376
|
useGravatarPicFallback: useGravatarPicFallback,
|
|
257412
257377
|
showGradebookTab: showGradebookTab,
|
|
257413
|
-
}, isAdmin: params.isAdmin, targetTab: targetTab, onClose: onClose, onAccountDeleted: onAccountDeleted, enableMemoryTab: enableMemoryTab, localLLMProps: localLLMProps
|
|
257378
|
+
}, isAdmin: params.isAdmin, targetTab: targetTab, onClose: onClose, onAccountDeleted: onAccountDeleted, enableMemoryTab: enableMemoryTab, localLLMProps: localLLMProps })), [
|
|
257414
257379
|
'organization',
|
|
257415
257380
|
'management',
|
|
257416
257381
|
'integrations',
|
|
@@ -257420,69 +257385,7 @@ function UserProfileModal({ isOpen, onClose, params, email, mainPlatformKey, sho
|
|
|
257420
257385
|
].includes(targetTab) && (jsxs(Fragment$1, { children: [jsx(Account, { onInviteClick: () => setIsInviteUserDialogOpen(true), tenant: params.tenantKey, tenants: tenants, username: getUserName$1(), email: email, mainPlatformKey: mainPlatformKey, showUsernameField: showUsernameField, showPlatformName: showPlatformName, useGravatarPicFallback: useGravatarPicFallback, onClose: onClose, isAdmin: params.isAdmin, targetTab: targetTab, currentPlan: currentPlan, currentSPA: currentSPA, userActiveApp: userActiveApp, authURL: authURL, onTenantUpdate: onTenantUpdate, currentPlatformBaseDomain: currentPlatformBaseDomain, rbacPermissions: rbacPermissions, enableRbac: enableRbac, onLoadGroupPermissions: onLoadGroupPermissions, onTabChange: onTabChange, defaultSupportPhone: defaultSupportPhone, showBenchmarks: showBenchmarks, enableSupportPhone: enableSupportPhone, showGradebookTab: showGradebookTab }), isInviteUserDialogOpen && (jsx(InviteUserDialog, { tenant: params.tenantKey, onClose: () => setIsInviteUserDialogOpen(false), isOpen: isInviteUserDialogOpen, enableCatalogInvite: enableCatalogInvite, hasManageUsersPermission: hasManageUsersPermission })), isInvitedUsersDialogOpen && (jsx(InvitedUsersDialog, { onClose: () => setIsInvitedUsersDialogOpen(false), tenant: params.tenantKey }))] }))] }) }) }));
|
|
257421
257386
|
}
|
|
257422
257387
|
|
|
257423
|
-
const
|
|
257424
|
-
/**
|
|
257425
|
-
* A simplified useLocalStorage hook for persisting state to localStorage
|
|
257426
|
-
* with SSR safety.
|
|
257427
|
-
*/
|
|
257428
|
-
function useLocalStorage(key, initialValue) {
|
|
257429
|
-
// Get the initial value
|
|
257430
|
-
const getInitialValue = useCallback(() => {
|
|
257431
|
-
const initial = initialValue instanceof Function ? initialValue() : initialValue;
|
|
257432
|
-
if (IS_SERVER) {
|
|
257433
|
-
return initial;
|
|
257434
|
-
}
|
|
257435
|
-
try {
|
|
257436
|
-
const item = window.localStorage.getItem(key);
|
|
257437
|
-
if (item === null) {
|
|
257438
|
-
return initial;
|
|
257439
|
-
}
|
|
257440
|
-
return JSON.parse(item);
|
|
257441
|
-
}
|
|
257442
|
-
catch (error) {
|
|
257443
|
-
console.warn(`Error reading localStorage key "${key}":`, error);
|
|
257444
|
-
return initial;
|
|
257445
|
-
}
|
|
257446
|
-
}, [key, initialValue]);
|
|
257447
|
-
const [storedValue, setStoredValue] = useState(getInitialValue);
|
|
257448
|
-
// Update stored value when key changes
|
|
257449
|
-
useEffect(() => {
|
|
257450
|
-
setStoredValue(getInitialValue());
|
|
257451
|
-
}, [key, getInitialValue]);
|
|
257452
|
-
// Persist to localStorage
|
|
257453
|
-
const setValue = useCallback((value) => {
|
|
257454
|
-
if (IS_SERVER) {
|
|
257455
|
-
console.warn(`Tried setting localStorage key "${key}" even though environment is not a client`);
|
|
257456
|
-
return;
|
|
257457
|
-
}
|
|
257458
|
-
try {
|
|
257459
|
-
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
257460
|
-
setStoredValue(valueToStore);
|
|
257461
|
-
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
|
257462
|
-
}
|
|
257463
|
-
catch (error) {
|
|
257464
|
-
console.warn(`Error setting localStorage key "${key}":`, error);
|
|
257465
|
-
}
|
|
257466
|
-
}, [key, storedValue]);
|
|
257467
|
-
// Remove from localStorage
|
|
257468
|
-
const removeValue = useCallback(() => {
|
|
257469
|
-
if (IS_SERVER) {
|
|
257470
|
-
console.warn(`Tried removing localStorage key "${key}" even though environment is not a client`);
|
|
257471
|
-
return;
|
|
257472
|
-
}
|
|
257473
|
-
try {
|
|
257474
|
-
const initial = initialValue instanceof Function ? initialValue() : initialValue;
|
|
257475
|
-
window.localStorage.removeItem(key);
|
|
257476
|
-
setStoredValue(initial);
|
|
257477
|
-
}
|
|
257478
|
-
catch (error) {
|
|
257479
|
-
console.warn(`Error removing localStorage key "${key}":`, error);
|
|
257480
|
-
}
|
|
257481
|
-
}, [key, initialValue]);
|
|
257482
|
-
return [storedValue, setValue, removeValue];
|
|
257483
|
-
}
|
|
257484
|
-
|
|
257485
|
-
const LOCAL_STORAGE_KEY$1 = 'model_download_state';
|
|
257388
|
+
const LOCAL_STORAGE_KEY = 'model_download_state';
|
|
257486
257389
|
const FIRST_LAUNCH_DISMISSED_KEY = 'model_download_prompt_dismissed';
|
|
257487
257390
|
// Manager/download status is authoritative from Tauri, never the persisted
|
|
257488
257391
|
// snapshot. This flips true the first time any hook instance mounts in a page
|
|
@@ -257502,7 +257405,7 @@ let didResetPersistedState = false;
|
|
|
257502
257405
|
*/
|
|
257503
257406
|
function useModelDownload() {
|
|
257504
257407
|
const { isAvailable, invoke, listen } = useTauri();
|
|
257505
|
-
const [state, setState] = useLocalStorage(LOCAL_STORAGE_KEY
|
|
257408
|
+
const [state, setState] = useLocalStorage(LOCAL_STORAGE_KEY, initialModelDownloadState);
|
|
257506
257409
|
const [ollamaStatus, setOllamaStatus] = useState(null);
|
|
257507
257410
|
const [systemMemory, setSystemMemory] = useState(null);
|
|
257508
257411
|
const [isFirstLaunchDismissed, setIsFirstLaunchDismissed] = useLocalStorage(FIRST_LAUNCH_DISMISSED_KEY, false);
|
|
@@ -257930,224 +257833,6 @@ function useModelDownload() {
|
|
|
257930
257833
|
};
|
|
257931
257834
|
}
|
|
257932
257835
|
|
|
257933
|
-
const LOCAL_STORAGE_KEY = 'ghost_os_install_state';
|
|
257934
|
-
/**
|
|
257935
|
-
* Manage installing & setting up GhostOS (https://github.com/ghostwright/ghost-os)
|
|
257936
|
-
* via the Tauri host. This is the self-contained backing hook for the System
|
|
257937
|
-
* Control card and deliberately mirrors `useModelDownload`:
|
|
257938
|
-
*
|
|
257939
|
-
* - checks GhostOS install/run status through the host
|
|
257940
|
-
* - installs/sets up GhostOS with real-time progress + logs
|
|
257941
|
-
* - persists state across app restarts
|
|
257942
|
-
*
|
|
257943
|
-
* Outside the desktop (Tauri) app every action is a no-op and `isAvailable` is
|
|
257944
|
-
* false, so the card hides itself.
|
|
257945
|
-
*/
|
|
257946
|
-
function useGhostOs() {
|
|
257947
|
-
const { isAvailable, invoke, listen } = useTauri();
|
|
257948
|
-
const [state, setState] = useLocalStorage(LOCAL_STORAGE_KEY, initialGhostOsInstallState);
|
|
257949
|
-
const [status, setStatus] = useState(null);
|
|
257950
|
-
// macOS Accessibility permission, which GhostOS needs to control the device.
|
|
257951
|
-
// null = unknown/not-yet-checked or unsupported (non-macOS / plugin absent).
|
|
257952
|
-
const [accessibilityPermission, setAccessibilityPermission] = useState(null);
|
|
257953
|
-
const unlistenRefs = useRef([]);
|
|
257954
|
-
const hasCheckedStatus = useRef(false);
|
|
257955
|
-
/**
|
|
257956
|
-
* Refresh the macOS Accessibility permission via tauri-plugin-macos-permissions.
|
|
257957
|
-
* Independent of the GhostOS status check so a missing host command for one
|
|
257958
|
-
* doesn't suppress the other. Stays null where unsupported.
|
|
257959
|
-
*/
|
|
257960
|
-
const refreshAccessibilityPermission = useCallback(async () => {
|
|
257961
|
-
if (!isAvailable)
|
|
257962
|
-
return;
|
|
257963
|
-
try {
|
|
257964
|
-
const granted = await invoke(MACOS_PERMISSIONS_COMMANDS.CHECK_ACCESSIBILITY);
|
|
257965
|
-
setAccessibilityPermission(granted);
|
|
257966
|
-
}
|
|
257967
|
-
catch (error) {
|
|
257968
|
-
// Plugin not registered or non-macOS host — leave permission unknown.
|
|
257969
|
-
console.warn('[useGhostOs] Accessibility permission check unavailable:', error);
|
|
257970
|
-
setAccessibilityPermission(null);
|
|
257971
|
-
}
|
|
257972
|
-
}, [isAvailable, invoke]);
|
|
257973
|
-
/**
|
|
257974
|
-
* Open the Accessibility pane / prompt so the user can grant permission, then
|
|
257975
|
-
* re-check (the grant happens in System Settings, so we refresh after).
|
|
257976
|
-
*/
|
|
257977
|
-
const requestAccessibilityPermission = useCallback(async () => {
|
|
257978
|
-
if (!isAvailable)
|
|
257979
|
-
return;
|
|
257980
|
-
try {
|
|
257981
|
-
await invoke(MACOS_PERMISSIONS_COMMANDS.REQUEST_ACCESSIBILITY);
|
|
257982
|
-
}
|
|
257983
|
-
catch (error) {
|
|
257984
|
-
console.error('[useGhostOs] Failed to request accessibility permission:', error);
|
|
257985
|
-
}
|
|
257986
|
-
await refreshAccessibilityPermission();
|
|
257987
|
-
}, [isAvailable, invoke, refreshAccessibilityPermission]);
|
|
257988
|
-
const addLog = useCallback((log) => {
|
|
257989
|
-
setState((prev) => ({
|
|
257990
|
-
...prev,
|
|
257991
|
-
logs: [...prev.logs.slice(-99), log],
|
|
257992
|
-
lastUpdated: new Date().toISOString(),
|
|
257993
|
-
}));
|
|
257994
|
-
}, [setState]);
|
|
257995
|
-
/**
|
|
257996
|
-
* Query GhostOS status from the host.
|
|
257997
|
-
*/
|
|
257998
|
-
const checkStatus = useCallback(async () => {
|
|
257999
|
-
if (!isAvailable)
|
|
258000
|
-
return;
|
|
258001
|
-
// Refresh the accessibility permission alongside install status (independent).
|
|
258002
|
-
refreshAccessibilityPermission();
|
|
258003
|
-
try {
|
|
258004
|
-
setState((prev) => ({ ...prev, status: 'checking' }));
|
|
258005
|
-
const result = await invoke(GHOST_OS_TAURI_COMMANDS.CHECK_GHOST_OS_STATUS);
|
|
258006
|
-
setStatus(result);
|
|
258007
|
-
setState((prev) => ({
|
|
258008
|
-
...prev,
|
|
258009
|
-
status: result.installed ? 'completed' : 'idle',
|
|
258010
|
-
progress: result.installed ? 100 : prev.progress,
|
|
258011
|
-
lastUpdated: new Date().toISOString(),
|
|
258012
|
-
}));
|
|
258013
|
-
}
|
|
258014
|
-
catch (error) {
|
|
258015
|
-
console.error('[useGhostOs] Failed to check status:', error);
|
|
258016
|
-
setState((prev) => ({ ...prev, status: 'idle' }));
|
|
258017
|
-
}
|
|
258018
|
-
}, [isAvailable, invoke, setState, refreshAccessibilityPermission]);
|
|
258019
|
-
/**
|
|
258020
|
-
* Install and set up GhostOS. The host clones the repo + runs setup and emits
|
|
258021
|
-
* progress/log/status events along the way.
|
|
258022
|
-
*/
|
|
258023
|
-
const install = useCallback(async () => {
|
|
258024
|
-
if (!isAvailable)
|
|
258025
|
-
return;
|
|
258026
|
-
try {
|
|
258027
|
-
setState((prev) => ({
|
|
258028
|
-
...prev,
|
|
258029
|
-
status: 'installing',
|
|
258030
|
-
progress: 0,
|
|
258031
|
-
message: 'Setting up your assistant…',
|
|
258032
|
-
error: undefined,
|
|
258033
|
-
logs: [],
|
|
258034
|
-
}));
|
|
258035
|
-
addLog({
|
|
258036
|
-
timestamp: new Date().toISOString(),
|
|
258037
|
-
level: 'info',
|
|
258038
|
-
message: 'Starting setup…',
|
|
258039
|
-
});
|
|
258040
|
-
const result = await invoke(GHOST_OS_TAURI_COMMANDS.INSTALL_GHOST_OS);
|
|
258041
|
-
addLog({
|
|
258042
|
-
timestamp: new Date().toISOString(),
|
|
258043
|
-
level: 'info',
|
|
258044
|
-
message: typeof result === 'string' && result ? result : 'Setup complete',
|
|
258045
|
-
});
|
|
258046
|
-
setState((prev) => ({
|
|
258047
|
-
...prev,
|
|
258048
|
-
status: 'completed',
|
|
258049
|
-
progress: 100,
|
|
258050
|
-
message: 'Your assistant is ready',
|
|
258051
|
-
lastUpdated: new Date().toISOString(),
|
|
258052
|
-
}));
|
|
258053
|
-
await checkStatus();
|
|
258054
|
-
}
|
|
258055
|
-
catch (error) {
|
|
258056
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
258057
|
-
setState((prev) => ({
|
|
258058
|
-
...prev,
|
|
258059
|
-
status: 'error',
|
|
258060
|
-
error: message,
|
|
258061
|
-
message: 'Setup didn’t finish',
|
|
258062
|
-
lastUpdated: new Date().toISOString(),
|
|
258063
|
-
}));
|
|
258064
|
-
addLog({
|
|
258065
|
-
timestamp: new Date().toISOString(),
|
|
258066
|
-
level: 'error',
|
|
258067
|
-
message: `Install failed: ${message}`,
|
|
258068
|
-
});
|
|
258069
|
-
}
|
|
258070
|
-
}, [isAvailable, invoke, addLog, checkStatus, setState]);
|
|
258071
|
-
/**
|
|
258072
|
-
* Stop the running GhostOS manager.
|
|
258073
|
-
*/
|
|
258074
|
-
const stop = useCallback(async () => {
|
|
258075
|
-
if (!isAvailable)
|
|
258076
|
-
return;
|
|
258077
|
-
try {
|
|
258078
|
-
await invoke(GHOST_OS_TAURI_COMMANDS.STOP_GHOST_OS);
|
|
258079
|
-
await checkStatus();
|
|
258080
|
-
}
|
|
258081
|
-
catch (error) {
|
|
258082
|
-
console.error('[useGhostOs] Failed to stop GhostOS:', error);
|
|
258083
|
-
}
|
|
258084
|
-
}, [isAvailable, invoke, checkStatus]);
|
|
258085
|
-
/**
|
|
258086
|
-
* Reset the install state (for retrying after an error).
|
|
258087
|
-
*/
|
|
258088
|
-
const resetState = useCallback(() => {
|
|
258089
|
-
setState(initialGhostOsInstallState);
|
|
258090
|
-
}, [setState]);
|
|
258091
|
-
// Wire up host event listeners (progress / logs / status).
|
|
258092
|
-
useEffect(() => {
|
|
258093
|
-
if (!isAvailable)
|
|
258094
|
-
return;
|
|
258095
|
-
const setupListeners = async () => {
|
|
258096
|
-
try {
|
|
258097
|
-
const unlistenProgress = await listen(GHOST_OS_TAURI_EVENTS.INSTALL_PROGRESS, (payload) => {
|
|
258098
|
-
const nextStatus = payload.status === 'completed'
|
|
258099
|
-
? 'completed'
|
|
258100
|
-
: payload.status === 'cancelled'
|
|
258101
|
-
? 'cancelled'
|
|
258102
|
-
: payload.status === 'error'
|
|
258103
|
-
? 'error'
|
|
258104
|
-
: 'installing';
|
|
258105
|
-
setState((prev) => ({
|
|
258106
|
-
...prev,
|
|
258107
|
-
status: nextStatus,
|
|
258108
|
-
progress: payload.percentage,
|
|
258109
|
-
message: payload.message,
|
|
258110
|
-
lastUpdated: new Date().toISOString(),
|
|
258111
|
-
}));
|
|
258112
|
-
});
|
|
258113
|
-
unlistenRefs.current.push(unlistenProgress);
|
|
258114
|
-
const unlistenLogs = await listen(GHOST_OS_TAURI_EVENTS.INSTALLATION_LOG, addLog);
|
|
258115
|
-
unlistenRefs.current.push(unlistenLogs);
|
|
258116
|
-
const unlistenStatus = await listen(GHOST_OS_TAURI_EVENTS.STATUS, setStatus);
|
|
258117
|
-
unlistenRefs.current.push(unlistenStatus);
|
|
258118
|
-
}
|
|
258119
|
-
catch (error) {
|
|
258120
|
-
console.error('[useGhostOs] Failed to setup event listeners:', error);
|
|
258121
|
-
}
|
|
258122
|
-
};
|
|
258123
|
-
setupListeners();
|
|
258124
|
-
return () => {
|
|
258125
|
-
unlistenRefs.current.forEach((unlisten) => unlisten());
|
|
258126
|
-
unlistenRefs.current = [];
|
|
258127
|
-
};
|
|
258128
|
-
}, [isAvailable, listen, setState, addLog]);
|
|
258129
|
-
// Check status once on mount (in the desktop app).
|
|
258130
|
-
useEffect(() => {
|
|
258131
|
-
if (!isAvailable || hasCheckedStatus.current)
|
|
258132
|
-
return;
|
|
258133
|
-
hasCheckedStatus.current = true;
|
|
258134
|
-
checkStatus();
|
|
258135
|
-
}, [isAvailable, checkStatus]);
|
|
258136
|
-
// Only expose the feature as available inside the desktop (Tauri) app.
|
|
258137
|
-
const finalIsAvailable = isAvailable && isTauriApp$1();
|
|
258138
|
-
return {
|
|
258139
|
-
isAvailable: finalIsAvailable,
|
|
258140
|
-
state,
|
|
258141
|
-
status,
|
|
258142
|
-
accessibilityPermission,
|
|
258143
|
-
install,
|
|
258144
|
-
stop,
|
|
258145
|
-
checkStatus,
|
|
258146
|
-
resetState,
|
|
258147
|
-
requestAccessibilityPermission,
|
|
258148
|
-
};
|
|
258149
|
-
}
|
|
258150
|
-
|
|
258151
257836
|
function UserProfileDropdown({ email, mainPlatformKey,
|
|
258152
257837
|
// User data
|
|
258153
257838
|
username, userIsAdmin = false, userIsStudent = false, userIsVisiting = false,
|
|
@@ -258171,11 +257856,9 @@ metadata, metadataLoaded = false,
|
|
|
258171
257856
|
currentSPA = '', showMentorAIDisplayCheckbox = false, showLeaderboardDisplayCheckbox = false, showGradebookTab = false, showUsernameField = false, showPlatformName = false, enableCatalogInvite = false, authURL, onTenantUpdate, currentPlatformBaseDomain = '', rbacPermissions = {}, enableRbac = false, onLoadGroupPermissions, defaultSupportPhone = '', enableSupportPhone,
|
|
258172
257857
|
// Local LLM props
|
|
258173
257858
|
localLLMProps,
|
|
258174
|
-
// System Control props
|
|
258175
|
-
systemControlProps,
|
|
258176
257859
|
// Controlled modal state
|
|
258177
257860
|
isModalOpen, onModalOpenChange, defaultActiveTab, onAccountDeleted, enableMemoryTab, showBenchmarks = false, }) {
|
|
258178
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k
|
|
257861
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
258179
257862
|
const t = useT();
|
|
258180
257863
|
// Use hooks to fetch user metadata
|
|
258181
257864
|
const { data: userMetadata } = useGetUserMetadataQuery({
|
|
@@ -258203,17 +257886,6 @@ isModalOpen, onModalOpenChange, defaultActiveTab, onAccountDeleted, enableMemory
|
|
|
258203
257886
|
const selectedFoundryModel = localLLMProps === null || localLLMProps === void 0 ? void 0 : localLLMProps.selectedFoundryModel;
|
|
258204
257887
|
const foundryStatus = localLLMProps === null || localLLMProps === void 0 ? void 0 : localLLMProps.foundryStatus;
|
|
258205
257888
|
const onSelectFoundryModel = localLLMProps === null || localLLMProps === void 0 ? void 0 : localLLMProps.onSelectFoundryModel;
|
|
258206
|
-
// System Control (GhostOS) state from props (if provided) or from hook (fallback)
|
|
258207
|
-
const ghostOsData = useGhostOs();
|
|
258208
|
-
const isSystemControlAvailable = (_l = systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.isAvailable) !== null && _l !== void 0 ? _l : ghostOsData.isAvailable;
|
|
258209
|
-
const systemControlState = (_m = systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.state) !== null && _m !== void 0 ? _m : ghostOsData.state;
|
|
258210
|
-
const systemControlStatus = (_o = systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.status) !== null && _o !== void 0 ? _o : ghostOsData.status;
|
|
258211
|
-
const accessibilityPermission = (_p = systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.accessibilityPermission) !== null && _p !== void 0 ? _p : ghostOsData.accessibilityPermission;
|
|
258212
|
-
const installGhostOs = (_q = systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.onInstall) !== null && _q !== void 0 ? _q : ghostOsData.install;
|
|
258213
|
-
const stopGhostOs = (_r = systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.onStop) !== null && _r !== void 0 ? _r : ghostOsData.stop;
|
|
258214
|
-
const checkGhostOsStatus = (_s = systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.onCheckStatus) !== null && _s !== void 0 ? _s : ghostOsData.checkStatus;
|
|
258215
|
-
const resetGhostOsState = (_t = systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.onResetState) !== null && _t !== void 0 ? _t : ghostOsData.resetState;
|
|
258216
|
-
const requestAccessibilityPermission = (_u = systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.onRequestAccessibilityPermission) !== null && _u !== void 0 ? _u : ghostOsData.requestAccessibilityPermission;
|
|
258217
257889
|
// Support controlled modal state
|
|
258218
257890
|
const [internalIsUserProfileOpen, setInternalIsUserProfileOpen] = useState(false);
|
|
258219
257891
|
const isUserProfileOpen = isModalOpen !== null && isModalOpen !== void 0 ? isModalOpen : internalIsUserProfileOpen;
|
|
@@ -258390,23 +258062,6 @@ isModalOpen, onModalOpenChange, defaultActiveTab, onAccountDeleted, enableMemory
|
|
|
258390
258062
|
onResetState: resetState,
|
|
258391
258063
|
onSelectFoundryModel,
|
|
258392
258064
|
},
|
|
258393
|
-
systemControlProps: {
|
|
258394
|
-
isAvailable: isSystemControlAvailable,
|
|
258395
|
-
state: systemControlState,
|
|
258396
|
-
status: systemControlStatus,
|
|
258397
|
-
requiredSizeGb: systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.requiredSizeGb,
|
|
258398
|
-
// Local-model status/memory + downloader, so the "Upgrade" action can
|
|
258399
|
-
// check what's installed, keep the RAM/VRAM check, and pull a model.
|
|
258400
|
-
ollamaStatus,
|
|
258401
|
-
systemMemory,
|
|
258402
|
-
accessibilityPermission,
|
|
258403
|
-
onInstall: installGhostOs,
|
|
258404
|
-
onStop: stopGhostOs,
|
|
258405
|
-
onCheckStatus: checkGhostOsStatus,
|
|
258406
|
-
onResetState: resetGhostOsState,
|
|
258407
|
-
onRequestAccessibilityPermission: requestAccessibilityPermission,
|
|
258408
|
-
onDownloadModel: startDownload,
|
|
258409
|
-
},
|
|
258410
258065
|
onAccountDeleted,
|
|
258411
258066
|
enableMemoryTab,
|
|
258412
258067
|
showBenchmarks,
|