@lobehub/lobehub 2.0.0-next.344 → 2.0.0-next.346

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.
Files changed (185) hide show
  1. package/.cursor/rules/i18n.mdc +1 -1
  2. package/.cursor/rules/modal-imperative.mdc +162 -0
  3. package/.cursor/rules/rules-index.mdc +1 -0
  4. package/.env.example +0 -14
  5. package/.eslintrc.js +8 -1
  6. package/CHANGELOG.md +66 -0
  7. package/CLAUDE.md +4 -2
  8. package/Dockerfile +3 -13
  9. package/README.md +3 -5
  10. package/README.zh-CN.md +3 -5
  11. package/changelog/v1.json +20 -0
  12. package/docs/self-hosting/advanced/auth/clerk-to-betterauth.mdx +11 -42
  13. package/docs/self-hosting/advanced/auth/clerk-to-betterauth.zh-CN.mdx +10 -41
  14. package/e2e/src/support/webServer.ts +2 -0
  15. package/locales/ar/error.json +0 -4
  16. package/locales/bg-BG/error.json +0 -4
  17. package/locales/de-DE/error.json +0 -4
  18. package/locales/en-US/error.json +0 -4
  19. package/locales/es-ES/error.json +0 -4
  20. package/locales/fa-IR/error.json +0 -4
  21. package/locales/fr-FR/error.json +0 -4
  22. package/locales/it-IT/error.json +0 -4
  23. package/locales/ja-JP/error.json +0 -4
  24. package/locales/ko-KR/error.json +0 -4
  25. package/locales/nl-NL/error.json +0 -4
  26. package/locales/pl-PL/error.json +0 -4
  27. package/locales/pt-BR/error.json +0 -4
  28. package/locales/ru-RU/error.json +0 -4
  29. package/locales/tr-TR/error.json +0 -4
  30. package/locales/vi-VN/error.json +0 -4
  31. package/locales/zh-CN/error.json +0 -4
  32. package/locales/zh-TW/error.json +0 -4
  33. package/package.json +12 -12
  34. package/packages/builtin-agents/package.json +2 -0
  35. package/packages/builtin-agents/src/agents/agent-builder/index.ts +4 -2
  36. package/packages/builtin-agents/src/agents/group-agent-builder/index.ts +4 -2
  37. package/packages/builtin-agents/src/agents/page-agent/index.ts +5 -2
  38. package/packages/context-engine/src/engine/messages/MessagesEngine.ts +9 -9
  39. package/packages/context-engine/src/providers/GroupContextInjector.ts +19 -33
  40. package/packages/context-engine/src/providers/__tests__/GroupContextInjector.test.ts +79 -43
  41. package/packages/context-engine/src/providers/__tests__/__snapshots__/GroupContextInjector.test.ts.snap +5 -15
  42. package/packages/database/src/repositories/userMemory/__tests__/UserMemoryTopicRepository.test.ts +24 -3
  43. package/packages/file-loaders/package.json +1 -1
  44. package/packages/file-loaders/src/loadFile.ts +10 -15
  45. package/packages/file-loaders/src/loaders/index.ts +68 -19
  46. package/packages/file-loaders/src/loaders/pdf/__snapshots__/index.test.ts.snap +1 -1
  47. package/packages/file-loaders/test/__snapshots__/loaders.test.ts.snap +1 -1
  48. package/packages/model-bank/src/modelProviders/comfyui.ts +0 -1
  49. package/packages/model-bank/src/modelProviders/fal.ts +0 -1
  50. package/packages/types/src/fetch.ts +1 -2
  51. package/packages/utils/src/server/__tests__/auth.test.ts +0 -47
  52. package/packages/utils/src/server/auth.ts +1 -9
  53. package/pnpm-workspace.yaml +1 -0
  54. package/scripts/_shared/checkDeprecatedClerkEnv.js +42 -0
  55. package/scripts/changelogWorkflow/buildStaticChangelog.ts +2 -1
  56. package/scripts/clerk-to-betterauth/_internal/types.ts +53 -20
  57. package/scripts/clerk-to-betterauth/export-clerk-users-with-api.ts +43 -36
  58. package/scripts/countEnWord.ts +1 -1
  59. package/scripts/electronWorkflow/modifiers/appCode.mts +2 -131
  60. package/scripts/i18nWorkflow/protectedPatterns.ts +1 -2
  61. package/scripts/prebuild.mts +10 -8
  62. package/scripts/serverLauncher/startServer.js +23 -5
  63. package/src/app/(backend)/middleware/auth/index.test.ts +8 -4
  64. package/src/app/(backend)/middleware/auth/index.ts +0 -15
  65. package/src/app/(backend)/middleware/auth/utils.test.ts +0 -28
  66. package/src/app/(backend)/middleware/auth/utils.ts +2 -17
  67. package/src/app/(backend)/webapi/chat/[provider]/route.test.ts +3 -51
  68. package/src/app/(backend)/webapi/models/[provider]/route.test.ts +8 -4
  69. package/src/app/[variants]/(auth)/next-auth/signin/AuthSignInBox.tsx +7 -6
  70. package/src/app/[variants]/(auth)/signup/[[...signup]]/page.tsx +1 -16
  71. package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/index.tsx +1 -1
  72. package/src/app/[variants]/(main)/home/features/InputArea/SkillInstallBanner.tsx +13 -13
  73. package/src/app/[variants]/(main)/home/features/RecentPage/Item.tsx +2 -2
  74. package/src/app/[variants]/(main)/resource/features/store/action.ts +2 -2
  75. package/src/app/[variants]/(main)/resource/features/store/initialState.ts +2 -2
  76. package/src/app/[variants]/(main)/resource/store/action.ts +2 -2
  77. package/src/app/[variants]/(main)/resource/store/initialState.ts +2 -2
  78. package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +3 -21
  79. package/src/app/[variants]/(main)/settings/profile/features/AvatarRow.tsx +1 -2
  80. package/src/app/[variants]/(main)/settings/security/index.tsx +1 -22
  81. package/src/app/[variants]/(main)/settings/skill/features/KlavisSkillItem.tsx +12 -14
  82. package/src/app/[variants]/(main)/settings/skill/features/LobehubSkillItem.tsx +8 -14
  83. package/src/app/[variants]/(main)/settings/skill/index.tsx +7 -5
  84. package/src/app/[variants]/(mobile)/me/(home)/__tests__/UserBanner.test.tsx +2 -35
  85. package/src/app/[variants]/(mobile)/me/(home)/__tests__/useCategory.test.tsx +0 -20
  86. package/src/app/[variants]/(mobile)/me/(home)/features/UserBanner.tsx +1 -2
  87. package/src/app/[variants]/(mobile)/me/profile/features/Category.tsx +3 -13
  88. package/src/app/[variants]/(mobile)/settings/_layout/Header.tsx +2 -3
  89. package/src/app/[variants]/share/t/[id]/_layout/index.tsx +1 -1
  90. package/src/app/[variants]/share/t/[id]/index.tsx +1 -1
  91. package/src/app/robots.tsx +1 -1
  92. package/src/envs/auth.ts +2 -27
  93. package/src/envs/llm.ts +2 -2
  94. package/src/features/AgentSetting/AgentPlugin/index.tsx +9 -12
  95. package/src/features/ChatInput/ActionBar/Tools/index.tsx +7 -5
  96. package/src/features/ChatMiniMap/utils.ts +1 -1
  97. package/src/features/CommandMenu/SearchResults.tsx +1 -1
  98. package/src/features/Conversation/ChatList/components/AutoScroll/DebugInspector.tsx +166 -0
  99. package/src/features/Conversation/ChatList/components/AutoScroll/index.tsx +86 -0
  100. package/src/features/Conversation/ChatList/components/VirtualizedList.tsx +11 -17
  101. package/src/features/Conversation/Messages/AgentCouncil/components/AutoScrollShadow.tsx +25 -14
  102. package/src/features/Conversation/Messages/AgentCouncil/components/CouncilMember.tsx +1 -1
  103. package/src/features/FileViewer/Renderer/PDF/index.tsx +5 -8
  104. package/src/features/IntegrationDetailModal/IntegrationDetailContent.tsx +305 -0
  105. package/src/features/IntegrationDetailModal/index.tsx +21 -283
  106. package/src/features/MCPPluginDetail/Deployment/index.tsx +1 -1
  107. package/src/features/MCPPluginDetail/Schema/Prompts.tsx +1 -1
  108. package/src/features/MCPPluginDetail/Schema/Tools.tsx +1 -1
  109. package/src/features/ProfileEditor/AgentTool.tsx +14 -20
  110. package/src/features/ResourceManager/components/Explorer/ListView/ListItem/index.tsx +0 -8
  111. package/src/features/ResourceManager/components/Explorer/MasonryView/MasonryFileItem/NoteFileItem.tsx +1 -1
  112. package/src/features/ResourceManager/index.tsx +1 -1
  113. package/src/features/ShareModal/SharePdf/PdfPreview.tsx +4 -4
  114. package/src/features/SkillStore/LobeHubList/index.tsx +50 -87
  115. package/src/features/SkillStore/Search/index.tsx +1 -1
  116. package/src/features/SkillStore/{Content.tsx → SkillStoreContent.tsx} +3 -8
  117. package/src/features/SkillStore/index.tsx +15 -33
  118. package/src/features/User/UserPanel/PanelContent.tsx +0 -8
  119. package/src/features/User/__tests__/PanelContent.test.tsx +1 -35
  120. package/src/features/User/__tests__/UserAvatar.test.tsx +30 -57
  121. package/src/features/User/__tests__/useMenu.test.tsx +2 -43
  122. package/src/layout/AuthProvider/index.tsx +0 -5
  123. package/src/libs/next/config/define-config.ts +20 -15
  124. package/src/libs/next/proxy/createRouteMatcher.test.ts +121 -0
  125. package/src/libs/next/proxy/createRouteMatcher.ts +18 -0
  126. package/src/libs/next/proxy/define-config.ts +4 -53
  127. package/src/libs/next-auth/adapter/index.ts +1 -2
  128. package/src/libs/oidc-provider/provider.test.ts +5 -316
  129. package/src/libs/pdfjs/pdf.worker.ts +1 -0
  130. package/src/libs/pdfjs/worker.ts +12 -0
  131. package/src/libs/trpc/lambda/context.test.ts +0 -13
  132. package/src/libs/trpc/lambda/context.ts +3 -22
  133. package/src/libs/trpc/middleware/userAuth.ts +2 -4
  134. package/src/libs/trusted-client/getSessionUser.ts +2 -17
  135. package/src/locales/default/error.ts +0 -6
  136. package/src/locales/default/index.ts +0 -2
  137. package/src/proxy.ts +0 -1
  138. package/src/server/routers/lambda/__tests__/user.test.ts +0 -71
  139. package/src/server/routers/lambda/user.ts +6 -63
  140. package/src/server/services/changelog/index.test.ts +3 -2
  141. package/src/server/services/changelog/index.ts +1 -1
  142. package/src/server/services/user/index.ts +0 -83
  143. package/src/services/chat/index.ts +1 -2
  144. package/src/services/chat/mecha/agentConfigResolver.test.ts +43 -0
  145. package/src/services/chat/mecha/agentConfigResolver.ts +3 -1
  146. package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +58 -14
  147. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +10 -2
  148. package/src/store/user/slices/auth/action.test.ts +1 -81
  149. package/src/store/user/slices/auth/action.ts +3 -28
  150. package/src/store/user/slices/auth/initialState.ts +1 -18
  151. package/src/store/user/slices/auth/selectors.test.ts +2 -127
  152. package/src/store/user/slices/auth/selectors.ts +1 -21
  153. package/src/utils/errorResponse.ts +1 -4
  154. package/src/utils/markdownToTxt.ts +20 -0
  155. package/locales/ar/clerk.json +0 -545
  156. package/locales/bg-BG/clerk.json +0 -545
  157. package/locales/de-DE/clerk.json +0 -545
  158. package/locales/en-US/clerk.json +0 -545
  159. package/locales/es-ES/clerk.json +0 -545
  160. package/locales/fa-IR/clerk.json +0 -545
  161. package/locales/fr-FR/clerk.json +0 -545
  162. package/locales/it-IT/clerk.json +0 -545
  163. package/locales/ja-JP/clerk.json +0 -545
  164. package/locales/ko-KR/clerk.json +0 -545
  165. package/locales/nl-NL/clerk.json +0 -545
  166. package/locales/pl-PL/clerk.json +0 -545
  167. package/locales/pt-BR/clerk.json +0 -545
  168. package/locales/ru-RU/clerk.json +0 -545
  169. package/locales/tr-TR/clerk.json +0 -545
  170. package/locales/vi-VN/clerk.json +0 -545
  171. package/locales/zh-CN/clerk.json +0 -545
  172. package/locales/zh-TW/clerk.json +0 -545
  173. package/src/app/(backend)/api/webhooks/clerk/__tests__/fixtures/createUser.json +0 -73
  174. package/src/app/(backend)/api/webhooks/clerk/route.ts +0 -95
  175. package/src/app/(backend)/api/webhooks/clerk/validateRequest.ts +0 -22
  176. package/src/app/[variants]/(auth)/login/[[...login]]/page.tsx +0 -27
  177. package/src/app/[variants]/(main)/settings/security/features/ClerkProfile.tsx +0 -67
  178. package/src/features/Conversation/ChatList/components/AutoScroll.tsx +0 -25
  179. package/src/layout/AuthProvider/Clerk/UserUpdater.tsx +0 -40
  180. package/src/layout/AuthProvider/Clerk/index.tsx +0 -54
  181. package/src/layout/AuthProvider/Clerk/useAppearance.ts +0 -133
  182. package/src/libs/clerk-auth/index.test.ts +0 -216
  183. package/src/libs/clerk-auth/index.ts +0 -80
  184. package/src/locales/default/clerk.ts +0 -677
  185. package/src/server/services/user/index.test.ts +0 -220
@@ -2,30 +2,32 @@
2
2
 
3
3
  import { Button, Icon } from '@lobehub/ui';
4
4
  import { Store } from 'lucide-react';
5
- import { useState } from 'react';
5
+ import { useCallback } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
 
8
8
  import SettingHeader from '@/app/[variants]/(main)/settings/features/SettingHeader';
9
- import SkillStore from '@/features/SkillStore';
9
+ import { createSkillStoreModal } from '@/features/SkillStore';
10
10
 
11
11
  import SkillList from './features/SkillList';
12
12
 
13
13
  const Page = () => {
14
14
  const { t } = useTranslation('setting');
15
- const [open, setOpen] = useState(false);
15
+
16
+ const handleOpenStore = useCallback(() => {
17
+ createSkillStoreModal();
18
+ }, []);
16
19
 
17
20
  return (
18
21
  <>
19
22
  <SettingHeader
20
23
  extra={
21
- <Button icon={<Icon icon={Store} />} onClick={() => setOpen(true)}>
24
+ <Button icon={<Icon icon={Store} />} onClick={handleOpenStore}>
22
25
  {t('skillStore.button')}
23
26
  </Button>
24
27
  }
25
28
  title={t('tab.skill')}
26
29
  />
27
30
  <SkillList />
28
- <SkillStore open={open} setOpen={setOpen} />
29
31
  </>
30
32
  );
31
33
  };
@@ -31,48 +31,16 @@ vi.mock('@/const/version', () => ({
31
31
  isDesktop: false,
32
32
  }));
33
33
 
34
- // Use vi.hoisted to ensure variables exist before vi.mock factory executes
35
- const { enableAuth, enableClerk } = vi.hoisted(() => ({
36
- enableAuth: { value: true },
37
- enableClerk: { value: false },
38
- }));
39
-
40
- vi.mock('@/envs/auth', () => ({
41
- get enableAuth() {
42
- return enableAuth.value;
43
- },
44
- get enableClerk() {
45
- return enableClerk.value;
46
- },
47
- }));
48
-
49
34
  afterEach(() => {
50
- enableAuth.value = true;
51
- enableClerk.value = false;
52
35
  mockNavigate.mockReset();
53
36
  });
54
37
 
55
38
  describe('UserBanner', () => {
56
- it('should render UserInfo and DataStatistics when auth is disabled', () => {
57
- act(() => {
58
- useUserStore.setState({ isSignedIn: false });
59
- });
60
- enableAuth.value = false;
61
-
62
- render(<UserBanner />);
63
-
64
- expect(screen.getByText('Mocked UserInfo')).toBeInTheDocument();
65
- expect(screen.getByText('Mocked DataStatistics')).toBeInTheDocument();
66
- expect(screen.queryByText('Mocked UserLoginOrSignup')).not.toBeInTheDocument();
67
- });
68
-
69
- it('should render UserInfo and DataStatistics when user is logged in with auth enabled', () => {
39
+ it('should render UserInfo and DataStatistics when user is logged in', () => {
70
40
  act(() => {
71
41
  useUserStore.setState({ isSignedIn: true });
72
42
  });
73
43
 
74
- enableClerk.value = true;
75
-
76
44
  render(<UserBanner />);
77
45
 
78
46
  expect(screen.getByText('Mocked UserInfo')).toBeInTheDocument();
@@ -80,11 +48,10 @@ describe('UserBanner', () => {
80
48
  expect(screen.queryByText('Mocked UserLoginOrSignup')).not.toBeInTheDocument();
81
49
  });
82
50
 
83
- it('should render UserLoginOrSignup when user is not logged in with auth enabled', () => {
51
+ it('should render UserLoginOrSignup when user is not logged in', () => {
84
52
  act(() => {
85
53
  useUserStore.setState({ isSignedIn: false });
86
54
  });
87
- enableClerk.value = true;
88
55
 
89
56
  render(<UserBanner />);
90
57
 
@@ -22,21 +22,6 @@ vi.mock('react-i18next', () => ({
22
22
  })),
23
23
  }));
24
24
 
25
- // Use vi.hoisted to ensure variables exist before vi.mock factory executes
26
- const { enableAuth, enableClerk } = vi.hoisted(() => ({
27
- enableAuth: { value: true },
28
- enableClerk: { value: true },
29
- }));
30
-
31
- vi.mock('@/envs/auth', () => ({
32
- get enableAuth() {
33
- return enableAuth.value;
34
- },
35
- get enableClerk() {
36
- return enableClerk.value;
37
- },
38
- }));
39
-
40
25
  // Mock version constants
41
26
  vi.mock('@/const/version', async (importOriginal) => {
42
27
  const actual = await importOriginal<typeof import('@/const/version')>();
@@ -47,8 +32,6 @@ vi.mock('@/const/version', async (importOriginal) => {
47
32
  });
48
33
 
49
34
  afterEach(() => {
50
- enableAuth.value = true;
51
- enableClerk.value = true;
52
35
  mockNavigate.mockReset();
53
36
  });
54
37
 
@@ -57,8 +40,6 @@ describe('useCategory', () => {
57
40
  act(() => {
58
41
  useUserStore.setState({ isSignedIn: true });
59
42
  });
60
- enableAuth.value = true;
61
- enableClerk.value = false;
62
43
 
63
44
  const mockOpenChangelogModal = vi.fn();
64
45
  const { result } = renderHook(() => useCategory(mockOpenChangelogModal), { wrapper });
@@ -77,7 +58,6 @@ describe('useCategory', () => {
77
58
  act(() => {
78
59
  useUserStore.setState({ isSignedIn: false });
79
60
  });
80
- enableAuth.value = true;
81
61
 
82
62
  const mockOpenChangelogModal = vi.fn();
83
63
  const { result } = renderHook(() => useCategory(mockOpenChangelogModal), { wrapper });
@@ -4,7 +4,6 @@ import { Flexbox } from '@lobehub/ui';
4
4
  import { memo } from 'react';
5
5
  import { Link } from 'react-router-dom';
6
6
 
7
- import { enableAuth } from '@/envs/auth';
8
7
  import DataStatistics from '@/features/User/DataStatistics';
9
8
  import UserInfo from '@/features/User/UserInfo';
10
9
  import UserLoginOrSignup from '@/features/User/UserLoginOrSignup/Community';
@@ -17,7 +16,7 @@ const UserBanner = memo(() => {
17
16
 
18
17
  return (
19
18
  <Flexbox gap={12} paddingBlock={8}>
20
- {!enableAuth || (enableAuth && isLoginWithAuth) ? (
19
+ {isLoginWithAuth ? (
21
20
  <>
22
21
  <Link style={{ color: 'inherit' }} to="/settings/profile">
23
22
  <UserInfo />
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { ChartColumnBigIcon, LogOut, ShieldCheck, UserCircle } from 'lucide-react';
3
+ import { ChartColumnBigIcon, LogOut, UserCircle } from 'lucide-react';
4
4
  import { memo } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
  import { useNavigate } from 'react-router-dom';
@@ -11,11 +11,7 @@ import { useUserStore } from '@/store/user';
11
11
  import { authSelectors } from '@/store/user/selectors';
12
12
 
13
13
  const Category = memo(() => {
14
- const [isLogin, isLoginWithClerk, signOut] = useUserStore((s) => [
15
- authSelectors.isLogin(s),
16
- authSelectors.isLoginWithClerk(s),
17
- s.logout,
18
- ]);
14
+ const [isLogin, signOut] = useUserStore((s) => [authSelectors.isLogin(s), s.logout]);
19
15
  const navigate = useNavigate();
20
16
  const { t } = useTranslation('auth');
21
17
  const items: CellProps[] = [
@@ -25,12 +21,6 @@ const Category = memo(() => {
25
21
  label: t('tab.profile'),
26
22
  onClick: () => navigate('/settings/profile'),
27
23
  },
28
- isLoginWithClerk && {
29
- icon: ShieldCheck,
30
- key: ProfileTabs.Security,
31
- label: t('tab.security'),
32
- onClick: () => navigate('/settings/security'),
33
- },
34
24
  {
35
25
  icon: ChartColumnBigIcon,
36
26
  key: ProfileTabs.Stats,
@@ -46,7 +36,7 @@ const Category = memo(() => {
46
36
  label: t('signout', { ns: 'auth' }),
47
37
  onClick: () => {
48
38
  signOut();
49
- navigate('/login');
39
+ navigate('/signin');
50
40
  },
51
41
  },
52
42
  ].filter(Boolean) as CellProps[];
@@ -6,7 +6,6 @@ import { memo } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
  import { useNavigate, useParams } from 'react-router-dom';
8
8
 
9
- import { enableAuth } from '@/envs/auth';
10
9
  import { useShowMobileWorkspace } from '@/hooks/useShowMobileWorkspace';
11
10
  import { type SettingsTabs } from '@/store/global/initialState';
12
11
  import { useSessionStore } from '@/store/session';
@@ -16,7 +15,7 @@ const Header = memo(() => {
16
15
  const { t } = useTranslation('setting');
17
16
  const showMobileWorkspace = useShowMobileWorkspace();
18
17
  const navigate = useNavigate();
19
- const params = useParams<{ providerId?: string, tab?: string; }>();
18
+ const params = useParams<{ providerId?: string; tab?: string }>();
20
19
 
21
20
  const isSessionActive = useSessionStore((s) => !!s.activeId);
22
21
  const isProvider = params.providerId && params.providerId !== 'all';
@@ -27,7 +26,7 @@ const Header = memo(() => {
27
26
  } else if (isProvider) {
28
27
  navigate('/settings/provider/all');
29
28
  } else {
30
- navigate(enableAuth ? '/me/settings' : '/me');
29
+ navigate('/me/settings');
31
30
  }
32
31
  };
33
32
 
@@ -65,7 +65,7 @@ const ShareTopicLayout = memo<PropsWithChildren>(({ children }) => {
65
65
  <UserAvatar size={32} />
66
66
  </Link>
67
67
  ) : (
68
- <NextLink href="/login">
68
+ <NextLink href="/signin">
69
69
  <ProductLogo size={32} />
70
70
  </NextLink>
71
71
  )}
@@ -56,7 +56,7 @@ const ShareTopicPage = memo(() => {
56
56
  <NotFound
57
57
  desc={t('sharePage.error.unauthorized.subtitle')}
58
58
  extra={
59
- <Button href="/login" type="primary">
59
+ <Button href="/signin" type="primary">
60
60
  {t('sharePage.error.unauthorized.action')}
61
61
  </Button>
62
62
  }
@@ -26,7 +26,7 @@ const robots = (): MetadataRoute.Robots => {
26
26
  },
27
27
  {
28
28
  allow: ['/'],
29
- disallow: ['/api/*', '/login', '/signup', '/knowledge/*', '/share/*'],
29
+ disallow: ['/api/*', '/signin', '/signup', '/knowledge/*', '/share/*'],
30
30
  userAgent: '*',
31
31
  },
32
32
  ],
package/src/envs/auth.ts CHANGED
@@ -6,11 +6,6 @@ declare global {
6
6
  // eslint-disable-next-line @typescript-eslint/no-namespace
7
7
  namespace NodeJS {
8
8
  interface ProcessEnv {
9
- // ===== Clerk ===== //
10
- NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY?: string;
11
- CLERK_SECRET_KEY?: string;
12
- CLERK_WEBHOOK_SECRET?: string;
13
-
14
9
  // ===== Auth (shared by Better Auth / Next Auth) ===== //
15
10
  AUTH_SECRET?: string;
16
11
  AUTH_EMAIL_VERIFICATION?: string;
@@ -136,10 +131,6 @@ declare global {
136
131
  export const getAuthConfig = () => {
137
132
  return createEnv({
138
133
  client: {
139
- // ---------------------------------- clerk ----------------------------------
140
- NEXT_PUBLIC_ENABLE_CLERK_AUTH: z.boolean().optional().default(false),
141
- NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().optional(),
142
-
143
134
  // ---------------------------------- better auth ----------------------------------
144
135
  NEXT_PUBLIC_ENABLE_BETTER_AUTH: z.boolean().optional(),
145
136
 
@@ -147,10 +138,6 @@ export const getAuthConfig = () => {
147
138
  NEXT_PUBLIC_ENABLE_NEXT_AUTH: z.boolean().optional(),
148
139
  },
149
140
  server: {
150
- // ---------------------------------- clerk ----------------------------------
151
- CLERK_SECRET_KEY: z.string().optional(),
152
- CLERK_WEBHOOK_SECRET: z.string().optional(),
153
-
154
141
  // ---------------------------------- better auth ----------------------------------
155
142
  AUTH_SECRET: z.string().optional(),
156
143
  AUTH_SSO_PROVIDERS: z.string().optional().default(''),
@@ -261,14 +248,6 @@ export const getAuthConfig = () => {
261
248
  },
262
249
 
263
250
  runtimeEnv: {
264
- // Clerk
265
- NEXT_PUBLIC_ENABLE_CLERK_AUTH:
266
- process.env.NEXT_PUBLIC_ENABLE_CLERK_AUTH === '1' ||
267
- !!process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
268
- NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
269
- CLERK_SECRET_KEY: process.env.CLERK_SECRET_KEY,
270
- CLERK_WEBHOOK_SECRET: process.env.CLERK_WEBHOOK_SECRET,
271
-
272
251
  // ---------------------------------- better auth ----------------------------------
273
252
  NEXT_PUBLIC_ENABLE_BETTER_AUTH: process.env.NEXT_PUBLIC_ENABLE_BETTER_AUTH === '1',
274
253
  // Fallback to NEXT_PUBLIC_* for seamless migration
@@ -396,13 +375,9 @@ export const getAuthConfig = () => {
396
375
  export const authEnv = getAuthConfig();
397
376
 
398
377
  // Auth flags - use process.env directly for build-time dead code elimination
399
- export const enableClerk =
400
- process.env.NEXT_PUBLIC_ENABLE_CLERK_AUTH === '1'
401
- ? true
402
- : !!process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY;
403
- export const enableBetterAuth = process.env.NEXT_PUBLIC_ENABLE_BETTER_AUTH === '1';
378
+ // Better Auth is the default auth solution when NextAuth is not explicitly enabled
404
379
  export const enableNextAuth = process.env.NEXT_PUBLIC_ENABLE_NEXT_AUTH === '1';
405
- export const enableAuth = enableClerk || enableBetterAuth || enableNextAuth || false;
380
+ export const enableBetterAuth = !enableNextAuth;
406
381
 
407
382
  // Auth headers and constants
408
383
  export const LOBE_CHAT_AUTH_HEADER = 'X-lobe-chat-auth';
package/src/envs/llm.ts CHANGED
@@ -241,7 +241,7 @@ export const getLLMConfig = () => {
241
241
  ENABLED_DEEPSEEK: !!process.env.DEEPSEEK_API_KEY,
242
242
  DEEPSEEK_API_KEY: process.env.DEEPSEEK_API_KEY,
243
243
 
244
- ENABLED_GOOGLE: !!process.env.GOOGLE_API_KEY,
244
+ ENABLED_GOOGLE: process.env.ENABLED_GOOGLE !== '0',
245
245
  GOOGLE_API_KEY: process.env.GOOGLE_API_KEY,
246
246
 
247
247
  ENABLED_VERTEXAI: !!process.env.VERTEXAI_CREDENTIALS,
@@ -252,7 +252,7 @@ export const getLLMConfig = () => {
252
252
  ENABLED_PERPLEXITY: !!process.env.PERPLEXITY_API_KEY,
253
253
  PERPLEXITY_API_KEY: process.env.PERPLEXITY_API_KEY,
254
254
 
255
- ENABLED_ANTHROPIC: !!process.env.ANTHROPIC_API_KEY,
255
+ ENABLED_ANTHROPIC: process.env.ENABLED_ANTHROPIC !== '0',
256
256
  ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY,
257
257
 
258
258
  ENABLED_MINIMAX: !!process.env.MINIMAX_API_KEY,
@@ -5,14 +5,14 @@ import { Center, Flexbox } from '@lobehub/ui';
5
5
  import { Space, Switch } from 'antd';
6
6
  import isEqual from 'fast-deep-equal';
7
7
  import { LucideTrash2, Plug2, Store } from 'lucide-react';
8
- import { memo, useState } from 'react';
8
+ import { memo, useCallback } from 'react';
9
9
  import { Trans, useTranslation } from 'react-i18next';
10
10
  import { Link, useNavigate } from 'react-router-dom';
11
11
 
12
12
  import PluginAvatar from '@/components/Plugins/PluginAvatar';
13
13
  import PluginTag from '@/components/Plugins/PluginTag';
14
14
  import { FORM_STYLE } from '@/const/layoutTokens';
15
- import SkillStore from '@/features/SkillStore';
15
+ import { createSkillStoreModal } from '@/features/SkillStore';
16
16
  import { useFetchInstalledPlugins } from '@/hooks/useFetchInstalledPlugins';
17
17
  import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
18
18
  import { pluginHelpers, useToolStore } from '@/store/tool';
@@ -27,10 +27,12 @@ import PluginAction from './PluginAction';
27
27
  const AgentPlugin = memo(() => {
28
28
  const { t } = useTranslation('setting');
29
29
 
30
- const [showStore, setShowStore] = useState(false);
31
-
32
30
  const navigate = useNavigate();
33
31
 
32
+ const handleOpenStore = useCallback(() => {
33
+ createSkillStoreModal();
34
+ }, []);
35
+
34
36
  const [userEnabledPlugins, toggleAgentPlugin] = useStore((s) => [
35
37
  s.config.plugins || [],
36
38
  s.toggleAgentPlugin,
@@ -120,7 +122,7 @@ const AgentPlugin = memo(() => {
120
122
  icon={Store}
121
123
  onClick={(e) => {
122
124
  e.stopPropagation();
123
- setShowStore(true);
125
+ handleOpenStore();
124
126
  }}
125
127
  size={'small'}
126
128
  />
@@ -139,7 +141,7 @@ const AgentPlugin = memo(() => {
139
141
  onClick={(e) => {
140
142
  e.stopPropagation();
141
143
  e.preventDefault();
142
- setShowStore(true);
144
+ handleOpenStore();
143
145
  navigate('/community/mcp');
144
146
  }}
145
147
  to={'/community/mcp'}
@@ -168,12 +170,7 @@ const AgentPlugin = memo(() => {
168
170
  title: t('settingPlugin.title'),
169
171
  };
170
172
 
171
- return (
172
- <>
173
- <SkillStore open={showStore} setOpen={setShowStore} />
174
- <Form items={[plugin]} itemsType={'group'} variant={'borderless'} {...FORM_STYLE} />
175
- </>
176
- );
173
+ return <Form items={[plugin]} itemsType={'group'} variant={'borderless'} {...FORM_STYLE} />;
177
174
  });
178
175
 
179
176
  export default AgentPlugin;
@@ -1,8 +1,8 @@
1
1
  import { Blocks } from 'lucide-react';
2
- import { Suspense, memo, useState } from 'react';
2
+ import { Suspense, memo, useCallback, useState } from 'react';
3
3
  import { useTranslation } from 'react-i18next';
4
4
 
5
- import SkillStore from '@/features/SkillStore';
5
+ import { createSkillStoreModal } from '@/features/SkillStore';
6
6
  import { useModelSupportToolUse } from '@/hooks/useModelSupportToolUse';
7
7
  import { useAgentStore } from '@/store/agent';
8
8
  import { agentByIdSelectors } from '@/store/agent/selectors';
@@ -15,7 +15,6 @@ import { useControls } from './useControls';
15
15
 
16
16
  const Tools = memo(() => {
17
17
  const { t } = useTranslation('setting');
18
- const [modalOpen, setModalOpen] = useState(false);
19
18
  const [updating, setUpdating] = useState(false);
20
19
  const { marketItems } = useControls({
21
20
  setUpdating,
@@ -29,6 +28,10 @@ const Tools = memo(() => {
29
28
 
30
29
  const enableFC = useModelSupportToolUse(model, provider);
31
30
 
31
+ const handleOpenStore = useCallback(() => {
32
+ createSkillStoreModal();
33
+ }, []);
34
+
32
35
  if (!enableFC)
33
36
  return <Action disabled icon={Blocks} showTooltip={true} title={t('tools.disabled')} />;
34
37
 
@@ -42,7 +45,7 @@ const Tools = memo(() => {
42
45
  <PopoverContent
43
46
  enableKlavis={enableKlavis}
44
47
  items={marketItems}
45
- onOpenStore={() => setModalOpen(true)}
48
+ onOpenStore={handleOpenStore}
46
49
  />
47
50
  ),
48
51
  maxWidth: 320,
@@ -56,7 +59,6 @@ const Tools = memo(() => {
56
59
  showTooltip={false}
57
60
  title={t('tools.title')}
58
61
  />
59
- <SkillStore open={modalOpen} setOpen={setModalOpen} />
60
62
  </Suspense>
61
63
  );
62
64
  });
@@ -1,4 +1,4 @@
1
- import { markdownToTxt } from 'markdown-to-txt';
1
+ import { markdownToTxt } from '@/utils/markdownToTxt';
2
2
 
3
3
  const MIN_WIDTH = 12;
4
4
  const MAX_WIDTH = 24;
@@ -11,12 +11,12 @@ import {
11
11
  Puzzle,
12
12
  Sparkles,
13
13
  } from 'lucide-react';
14
- import { markdownToTxt } from 'markdown-to-txt';
15
14
  import { memo } from 'react';
16
15
  import { useTranslation } from 'react-i18next';
17
16
  import { useNavigate } from 'react-router-dom';
18
17
 
19
18
  import type { SearchResult } from '@/database/repositories/search';
19
+ import { markdownToTxt } from '@/utils/markdownToTxt';
20
20
 
21
21
  import { CommandItem } from './components';
22
22
  import { styles } from './styles';
@@ -0,0 +1,166 @@
1
+ 'use client';
2
+
3
+ import { memo } from 'react';
4
+ import { createPortal } from 'react-dom';
5
+
6
+ import { messageStateSelectors, useConversationStore, virtuaListSelectors } from '../../../store';
7
+
8
+ /**
9
+ * 判断是否在底部的阈值(单位:px)
10
+ * 当距离底部小于等于此值时,认为在底部
11
+ */
12
+ export const AT_BOTTOM_THRESHOLD = 300;
13
+
14
+ /**
15
+ * 是否开启调试面板
16
+ * 设为 true 可以显示滚动位置调试信息
17
+ */
18
+ export const OPEN_DEV_INSPECTOR = false;
19
+
20
+ const DebugInspector = memo(() => {
21
+ const atBottom = useConversationStore(virtuaListSelectors.atBottom);
22
+ const isScrolling = useConversationStore(virtuaListSelectors.isScrolling);
23
+ const isGenerating = useConversationStore(messageStateSelectors.isAIGenerating);
24
+ const virtuaScrollMethods = useConversationStore((s) => s.virtuaScrollMethods);
25
+
26
+ const shouldAutoScroll = atBottom && isGenerating && !isScrolling;
27
+ const scrollOffset = virtuaScrollMethods?.getScrollOffset?.() ?? 0;
28
+ const scrollSize = virtuaScrollMethods?.getScrollSize?.() ?? 0;
29
+ const viewportSize = virtuaScrollMethods?.getViewportSize?.() ?? 0;
30
+ const distanceToBottom = scrollSize - scrollOffset - viewportSize;
31
+ // 可视化计算
32
+ const visualHeight = 120;
33
+ const scale = scrollSize > 0 ? visualHeight / scrollSize : 0;
34
+ const viewportVisualHeight = Math.max(viewportSize * scale, 10);
35
+ const scrollVisualOffset = scrollOffset * scale;
36
+ const thresholdVisualHeight = Math.min(AT_BOTTOM_THRESHOLD * scale, visualHeight * 0.3);
37
+
38
+ const panel = (
39
+ <div
40
+ style={{
41
+ background: 'rgba(0,0,0,0.9)',
42
+ borderRadius: 8,
43
+ bottom: 80,
44
+ display: 'flex',
45
+ fontFamily: 'monospace',
46
+ fontSize: 11,
47
+ gap: 16,
48
+ left: 12,
49
+ padding: '10px 14px',
50
+ position: 'fixed',
51
+ zIndex: 9999,
52
+ }}
53
+ >
54
+ {/* 滚动条可视化 */}
55
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
56
+ <div style={{ color: '#9ca3af', fontSize: 10 }}>Scroll Position</div>
57
+ <div
58
+ style={{
59
+ background: '#374151',
60
+ borderRadius: 3,
61
+ height: visualHeight,
62
+ position: 'relative',
63
+ width: 24,
64
+ }}
65
+ >
66
+ {/* threshold 区域 (底部 200px) */}
67
+ <div
68
+ style={{
69
+ background: atBottom ? 'rgba(34, 197, 94, 0.3)' : 'rgba(239, 68, 68, 0.3)',
70
+ borderRadius: '0 0 3px 3px',
71
+ bottom: 0,
72
+ height: thresholdVisualHeight,
73
+ left: 0,
74
+ position: 'absolute',
75
+ right: 0,
76
+ }}
77
+ />
78
+ {/* 当前视口位置 */}
79
+ <div
80
+ style={{
81
+ background: atBottom ? '#22c55e' : '#3b82f6',
82
+ borderRadius: 2,
83
+ height: viewportVisualHeight,
84
+ left: 2,
85
+ position: 'absolute',
86
+ right: 2,
87
+ top: scrollVisualOffset,
88
+ transition: 'top 0.1s',
89
+ }}
90
+ />
91
+ {/* threshold 线 */}
92
+ <div
93
+ style={{
94
+ background: '#f59e0b',
95
+ bottom: thresholdVisualHeight,
96
+ height: 1,
97
+ left: 0,
98
+ position: 'absolute',
99
+ right: 0,
100
+ }}
101
+ />
102
+ </div>
103
+ <div style={{ color: '#f59e0b', fontSize: 9, textAlign: 'center' }}>
104
+ {AT_BOTTOM_THRESHOLD}px
105
+ </div>
106
+ </div>
107
+
108
+ {/* 数值信息 */}
109
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
110
+ <div style={{ color: '#9ca3af', fontSize: 10 }}>
111
+ scrollSize: <span style={{ color: 'white' }}>{Math.round(scrollSize)}px</span>
112
+ </div>
113
+ <div style={{ color: '#9ca3af', fontSize: 10 }}>
114
+ viewport: <span style={{ color: 'white' }}>{Math.round(viewportSize)}px</span>
115
+ </div>
116
+ <div style={{ color: '#9ca3af', fontSize: 10 }}>
117
+ offset: <span style={{ color: 'white' }}>{Math.round(scrollOffset)}px</span>
118
+ </div>
119
+ <div
120
+ style={{
121
+ color: atBottom ? '#22c55e' : '#ef4444',
122
+ fontSize: 10,
123
+ fontWeight: 'bold',
124
+ }}
125
+ >
126
+ toBottom: {Math.round(distanceToBottom)}px
127
+ {distanceToBottom <= AT_BOTTOM_THRESHOLD ? ' ≤' : ' >'} {AT_BOTTOM_THRESHOLD}
128
+ </div>
129
+
130
+ <div style={{ borderTop: '1px solid #374151', marginTop: 4, paddingTop: 4 }}>
131
+ <div style={{ color: atBottom ? '#22c55e' : '#ef4444', fontSize: 10 }}>
132
+ atBottom: {atBottom ? 'YES' : 'NO'}
133
+ </div>
134
+ <div style={{ color: isGenerating ? '#3b82f6' : '#6b7280', fontSize: 10 }}>
135
+ generating: {isGenerating ? 'YES' : 'NO'}
136
+ </div>
137
+ <div style={{ color: isScrolling ? '#f59e0b' : '#6b7280', fontSize: 10 }}>
138
+ scrolling: {isScrolling ? 'YES' : 'NO'}
139
+ </div>
140
+ </div>
141
+
142
+ <div
143
+ style={{
144
+ background: shouldAutoScroll ? '#22c55e' : '#ef4444',
145
+ borderRadius: 3,
146
+ color: 'white',
147
+ fontSize: 10,
148
+ marginTop: 4,
149
+ padding: '2px 6px',
150
+ textAlign: 'center',
151
+ }}
152
+ >
153
+ autoScroll: {shouldAutoScroll ? 'YES' : 'NO'}
154
+ </div>
155
+ </div>
156
+ </div>
157
+ );
158
+
159
+ if (typeof document === 'undefined') return null;
160
+
161
+ return createPortal(panel, document.body);
162
+ });
163
+
164
+ DebugInspector.displayName = 'DebugInspector';
165
+
166
+ export default DebugInspector;