@lobehub/lobehub 2.0.0-next.237 → 2.0.0-next.239

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,64 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [Version 2.0.0-next.239](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.238...v2.0.0-next.239)
6
+
7
+ <sup>Released on **2026-01-08**</sup>
8
+
9
+ #### ✨ Features
10
+
11
+ - **misc**: Add the twitter lobehub skill.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's improved
19
+
20
+ - **misc**: Add the twitter lobehub skill, closes [#11342](https://github.com/lobehub/lobe-chat/issues/11342) ([503acb3](https://github.com/lobehub/lobe-chat/commit/503acb3))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
30
+ ## [Version 2.0.0-next.238](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.237...v2.0.0-next.238)
31
+
32
+ <sup>Released on **2026-01-08**</sup>
33
+
34
+ #### ✨ Features
35
+
36
+ - **misc**: Change the klavis Linear to LobeHub oauth Linear.
37
+
38
+ #### 🐛 Bug Fixes
39
+
40
+ - **misc**: Topic renaming input focus issue in context menu.
41
+
42
+ <br/>
43
+
44
+ <details>
45
+ <summary><kbd>Improvements and Fixes</kbd></summary>
46
+
47
+ #### What's improved
48
+
49
+ - **misc**: Change the klavis Linear to LobeHub oauth Linear, closes [#11339](https://github.com/lobehub/lobe-chat/issues/11339) ([ec8ff26](https://github.com/lobehub/lobe-chat/commit/ec8ff26))
50
+
51
+ #### What's fixed
52
+
53
+ - **misc**: Topic renaming input focus issue in context menu, closes [#11323](https://github.com/lobehub/lobe-chat/issues/11323) ([dd065fc](https://github.com/lobehub/lobe-chat/commit/dd065fc))
54
+
55
+ </details>
56
+
57
+ <div align="right">
58
+
59
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
60
+
61
+ </div>
62
+
5
63
  ## [Version 2.0.0-next.237](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.236...v2.0.0-next.237)
6
64
 
7
65
  <sup>Released on **2026-01-08**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,25 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "features": [
5
+ "Add the twitter lobehub skill."
6
+ ]
7
+ },
8
+ "date": "2026-01-08",
9
+ "version": "2.0.0-next.239"
10
+ },
11
+ {
12
+ "children": {
13
+ "features": [
14
+ "Change the klavis Linear to LobeHub oauth Linear."
15
+ ],
16
+ "fixes": [
17
+ "Topic renaming input focus issue in context menu."
18
+ ]
19
+ },
20
+ "date": "2026-01-08",
21
+ "version": "2.0.0-next.238"
22
+ },
2
23
  {
3
24
  "children": {},
4
25
  "date": "2026-01-08",
@@ -32,5 +32,6 @@
32
32
  "login.title": "Login to {{clientName}}",
33
33
  "login.userWelcome": "Welcome back, ",
34
34
  "success.subTitle": "You have successfully authorized the application to access your account. You may now close this page.",
35
+ "success.subTitleWithCountdown": "Authorization successful. Auto-closing in {{countdown}}s...",
35
36
  "success.title": "Authorization Successful"
36
37
  }
@@ -32,5 +32,6 @@
32
32
  "login.title": "登录 {{clientName}}",
33
33
  "login.userWelcome": "欢迎回来,",
34
34
  "success.subTitle": "应用已获得授权。你可以关闭此页面了",
35
+ "success.subTitleWithCountdown": "应用已获得授权。{{countdown}}秒后自动关闭…",
35
36
  "success.title": "授权完成"
36
37
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/lobehub",
3
- "version": "2.0.0-next.237",
3
+ "version": "2.0.0-next.239",
4
4
  "description": "LobeHub - an open-source,comprehensive AI Agent framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -1,4 +1,4 @@
1
- import { IconType, SiCaldotcom, SiGithub, SiLinear } from '@icons-pack/react-simple-icons';
1
+ import { IconType, SiCaldotcom, SiGithub } from '@icons-pack/react-simple-icons';
2
2
  import { Klavis } from 'klavis';
3
3
 
4
4
  export interface KlavisServerType {
@@ -40,12 +40,6 @@ export const KLAVIS_SERVER_TYPES: KlavisServerType[] = [
40
40
  label: 'Airtable',
41
41
  serverName: Klavis.McpServerName.Airtable,
42
42
  },
43
- {
44
- icon: SiLinear,
45
- identifier: 'linear',
46
- label: 'Linear',
47
- serverName: Klavis.McpServerName.Linear,
48
- },
49
43
  {
50
44
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/googlesheets.svg',
51
45
  identifier: 'google-sheets',
@@ -1,4 +1,4 @@
1
- import { type IconType, SiLinear } from '@icons-pack/react-simple-icons';
1
+ import { type IconType, SiLinear, SiX } from '@icons-pack/react-simple-icons';
2
2
 
3
3
  export interface LobehubSkillProviderType {
4
4
  /**
@@ -40,6 +40,12 @@ export const LOBEHUB_SKILL_PROVIDERS: LobehubSkillProviderType[] = [
40
40
  id: 'microsoft',
41
41
  label: 'Outlook Calendar',
42
42
  },
43
+ {
44
+ defaultVisible: true,
45
+ icon: SiX,
46
+ id: 'twitter',
47
+ label: 'X (Twitter)',
48
+ },
43
49
  ];
44
50
 
45
51
  /**
@@ -2,11 +2,48 @@
2
2
 
3
3
  import { FluentEmoji, Text } from '@lobehub/ui';
4
4
  import { Result } from 'antd';
5
- import React, { memo } from 'react';
5
+ import { useSearchParams } from 'next/navigation';
6
+ import React, { memo, useEffect, useState } from 'react';
6
7
  import { useTranslation } from 'react-i18next';
7
8
 
8
9
  const SuccessPage = memo(() => {
9
10
  const { t } = useTranslation('oauth');
11
+ const searchParams = useSearchParams();
12
+ const [countdown, setCountdown] = useState(3);
13
+
14
+ useEffect(() => {
15
+ // Check if this is a LobeHub Skill OAuth callback
16
+ const provider = searchParams.get('provider');
17
+
18
+ if (provider && window.opener) {
19
+ // Notify parent window about successful OAuth
20
+ window.opener.postMessage(
21
+ {
22
+ provider,
23
+ type: 'LOBEHUB_SKILL_AUTH_SUCCESS',
24
+ },
25
+ window.location.origin,
26
+ );
27
+
28
+ // Start countdown and close window after 3 seconds
29
+ let timeLeft = 3;
30
+ setCountdown(timeLeft);
31
+
32
+ const countdownTimer = setInterval(() => {
33
+ timeLeft -= 1;
34
+ setCountdown(timeLeft);
35
+
36
+ if (timeLeft <= 0) {
37
+ clearInterval(countdownTimer);
38
+ window.close();
39
+ }
40
+ }, 1000);
41
+
42
+ return () => clearInterval(countdownTimer);
43
+ }
44
+ }, [searchParams]);
45
+
46
+ const provider = searchParams.get('provider');
10
47
 
11
48
  return (
12
49
  <Result
@@ -14,7 +51,12 @@ const SuccessPage = memo(() => {
14
51
  status="success"
15
52
  subTitle={
16
53
  <Text fontSize={16} type="secondary">
17
- {t('success.subTitle')}
54
+ {provider
55
+ ? t('success.subTitleWithCountdown', {
56
+ countdown,
57
+ defaultValue: `You may close this page. Auto-closing in ${countdown}s...`,
58
+ })
59
+ : t('success.subTitle')}
18
60
  </Text>
19
61
  }
20
62
  title={
@@ -1,5 +1,6 @@
1
- import { Input, Popover } from '@lobehub/ui';
2
- import { memo, useCallback, useState } from 'react';
1
+ import { Input, type InputProps, Popover } from '@lobehub/ui';
2
+ import type { InputRef } from 'antd';
3
+ import { memo, useCallback, useEffect, useRef, useState } from 'react';
3
4
 
4
5
  import { useChatStore } from '@/store/chat';
5
6
 
@@ -9,6 +10,18 @@ interface EditingProps {
9
10
  toggleEditing: (visible?: boolean) => void;
10
11
  }
11
12
 
13
+ function FocusableInput({ ...props }: InputProps) {
14
+ const ref = useRef<InputRef>(null);
15
+ useEffect(() => {
16
+ queueMicrotask(() => {
17
+ if (ref.current) {
18
+ ref.current.input?.focus();
19
+ }
20
+ });
21
+ }, []);
22
+ return <Input {...props} ref={ref} />;
23
+ }
24
+
12
25
  const Editing = memo<EditingProps>(({ id, title, toggleEditing }) => {
13
26
  const [newTitle, setNewTitle] = useState(title);
14
27
  const [editing, updateTopicTitle] = useChatStore((s) => [
@@ -41,19 +54,14 @@ const Editing = memo<EditingProps>(({ id, title, toggleEditing }) => {
41
54
  );
42
55
  }
43
56
  }
44
- toggleEditing(false);
45
57
  }, [newTitle, title, id, updateTopicTitle, toggleEditing]);
46
58
 
47
59
  return (
48
60
  <Popover
49
61
  content={
50
- <Input
51
- autoFocus
62
+ <FocusableInput
52
63
  defaultValue={title}
53
- onBlur={() => {
54
- handleUpdate();
55
- toggleEditing(false);
56
- }}
64
+ onBlur={handleUpdate}
57
65
  onChange={(e) => setNewTitle(e.target.value)}
58
66
  onClick={(e) => e.stopPropagation()}
59
67
  onPressEnter={() => {
@@ -64,6 +72,7 @@ const Editing = memo<EditingProps>(({ id, title, toggleEditing }) => {
64
72
  }
65
73
  onOpenChange={(open) => {
66
74
  if (!open) handleUpdate();
75
+
67
76
  toggleEditing(open);
68
77
  }}
69
78
  open={editing}
@@ -135,13 +135,52 @@ const LobehubSkillServerItem = memo<LobehubSkillServerItemProps>(({ provider, la
135
135
  s.togglePlugin,
136
136
  ]);
137
137
 
138
+ // Listen for OAuth success message from popup window
139
+ useEffect(() => {
140
+ const handleMessage = async (event: MessageEvent) => {
141
+ // Verify origin for security
142
+ if (event.origin !== window.location.origin) return;
143
+
144
+ if (event.data?.type === 'LOBEHUB_SKILL_AUTH_SUCCESS' && event.data?.provider === provider) {
145
+ console.log('[LobehubSkill] OAuth success message received for provider:', provider);
146
+
147
+ // Cleanup polling/window monitoring
148
+ cleanup();
149
+
150
+ // Refresh status to get the connected state
151
+ await checkStatus(provider);
152
+
153
+ // Auto-enable the plugin after successful OAuth
154
+ // Need to get the latest server state after checkStatus
155
+ const latestServer = useToolStore
156
+ .getState()
157
+ .lobehubSkillServers?.find((s) => s.identifier === provider);
158
+ if (latestServer?.status === LobehubSkillStatus.CONNECTED) {
159
+ const newPluginId = latestServer.identifier;
160
+ const isAlreadyEnabled = agentSelectors
161
+ .currentAgentPlugins(useAgentStore.getState())
162
+ .includes(newPluginId);
163
+ if (!isAlreadyEnabled) {
164
+ console.log('[LobehubSkill] Auto-enabling plugin:', newPluginId);
165
+ togglePlugin(newPluginId);
166
+ }
167
+ }
168
+ }
169
+ };
170
+
171
+ window.addEventListener('message', handleMessage);
172
+ return () => window.removeEventListener('message', handleMessage);
173
+ }, [provider, cleanup, checkStatus, togglePlugin]);
174
+
138
175
  const handleConnect = async () => {
139
176
  // 只有已连接状态才阻止重新连接
140
177
  if (server?.isConnected) return;
141
178
 
142
179
  setIsConnecting(true);
143
180
  try {
144
- const { authorizeUrl } = await getAuthorizeUrl(provider);
181
+ // Use /oauth/callback/success as redirect URI with provider param for auto-enable
182
+ const redirectUri = `${window.location.origin}/oauth/callback/success?provider=${encodeURIComponent(provider)}`;
183
+ const { authorizeUrl } = await getAuthorizeUrl(provider, { redirectUri });
145
184
  openOAuthWindow(authorizeUrl);
146
185
  } catch (error) {
147
186
  console.error('[LobehubSkill] Failed to get authorize URL:', error);
@@ -236,7 +275,8 @@ const LobehubSkillServerItem = memo<LobehubSkillServerItemProps>(({ provider, la
236
275
  onClick={async (e) => {
237
276
  e.stopPropagation();
238
277
  try {
239
- const { authorizeUrl } = await getAuthorizeUrl(provider);
278
+ const redirectUri = `${window.location.origin}/oauth/callback/success?provider=${encodeURIComponent(provider)}`;
279
+ const { authorizeUrl } = await getAuthorizeUrl(provider, { redirectUri });
240
280
  openOAuthWindow(authorizeUrl);
241
281
  } catch (error) {
242
282
  console.error('[LobehubSkill] Failed to get authorize URL:', error);