@lobehub/chat 1.82.9 → 1.83.0

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 (196) hide show
  1. package/.env.desktop +1 -2
  2. package/.github/workflows/{release-desktop.yml → desktop-pr-build.yml} +59 -137
  3. package/.github/workflows/release-desktop-beta.yml +196 -0
  4. package/CHANGELOG.md +50 -0
  5. package/apps/desktop/.i18nrc.js +31 -0
  6. package/apps/desktop/Development.md +47 -0
  7. package/apps/desktop/README.md +6 -0
  8. package/apps/desktop/build/Icon-beta.icns +0 -0
  9. package/apps/desktop/build/Icon-nightly.icns +0 -0
  10. package/apps/desktop/build/Icon.icns +0 -0
  11. package/apps/desktop/build/entitlements.mac.plist +12 -0
  12. package/apps/desktop/build/favicon.ico +0 -0
  13. package/apps/desktop/build/icon-beta.png +0 -0
  14. package/apps/desktop/build/icon-dev.png +0 -0
  15. package/apps/desktop/build/icon-nightly.ico +0 -0
  16. package/apps/desktop/build/icon-nightly.png +0 -0
  17. package/apps/desktop/build/icon.ico +0 -0
  18. package/apps/desktop/build/icon.png +0 -0
  19. package/apps/desktop/dev-app-update.yml +6 -0
  20. package/apps/desktop/electron-builder.js +92 -0
  21. package/apps/desktop/electron.vite.config.ts +40 -0
  22. package/apps/desktop/package.json +72 -0
  23. package/apps/desktop/pnpm-workspace.yaml +5 -0
  24. package/apps/desktop/resources/error.html +136 -0
  25. package/apps/desktop/resources/locales/ar/common.json +32 -0
  26. package/apps/desktop/resources/locales/ar/dialog.json +31 -0
  27. package/apps/desktop/resources/locales/ar/menu.json +70 -0
  28. package/apps/desktop/resources/locales/bg-BG/common.json +32 -0
  29. package/apps/desktop/resources/locales/bg-BG/dialog.json +31 -0
  30. package/apps/desktop/resources/locales/bg-BG/menu.json +70 -0
  31. package/apps/desktop/resources/locales/de-DE/common.json +32 -0
  32. package/apps/desktop/resources/locales/de-DE/dialog.json +31 -0
  33. package/apps/desktop/resources/locales/de-DE/menu.json +70 -0
  34. package/apps/desktop/resources/locales/en-US/common.json +32 -0
  35. package/apps/desktop/resources/locales/en-US/dialog.json +31 -0
  36. package/apps/desktop/resources/locales/en-US/menu.json +70 -0
  37. package/apps/desktop/resources/locales/es-ES/common.json +32 -0
  38. package/apps/desktop/resources/locales/es-ES/dialog.json +31 -0
  39. package/apps/desktop/resources/locales/es-ES/menu.json +70 -0
  40. package/apps/desktop/resources/locales/fa-IR/common.json +32 -0
  41. package/apps/desktop/resources/locales/fa-IR/dialog.json +31 -0
  42. package/apps/desktop/resources/locales/fa-IR/menu.json +70 -0
  43. package/apps/desktop/resources/locales/fr-FR/common.json +32 -0
  44. package/apps/desktop/resources/locales/fr-FR/dialog.json +31 -0
  45. package/apps/desktop/resources/locales/fr-FR/menu.json +70 -0
  46. package/apps/desktop/resources/locales/it-IT/common.json +32 -0
  47. package/apps/desktop/resources/locales/it-IT/dialog.json +31 -0
  48. package/apps/desktop/resources/locales/it-IT/menu.json +70 -0
  49. package/apps/desktop/resources/locales/ja-JP/common.json +32 -0
  50. package/apps/desktop/resources/locales/ja-JP/dialog.json +31 -0
  51. package/apps/desktop/resources/locales/ja-JP/menu.json +70 -0
  52. package/apps/desktop/resources/locales/ko-KR/common.json +32 -0
  53. package/apps/desktop/resources/locales/ko-KR/dialog.json +31 -0
  54. package/apps/desktop/resources/locales/ko-KR/menu.json +70 -0
  55. package/apps/desktop/resources/locales/nl-NL/common.json +32 -0
  56. package/apps/desktop/resources/locales/nl-NL/dialog.json +31 -0
  57. package/apps/desktop/resources/locales/nl-NL/menu.json +70 -0
  58. package/apps/desktop/resources/locales/pl-PL/common.json +32 -0
  59. package/apps/desktop/resources/locales/pl-PL/dialog.json +31 -0
  60. package/apps/desktop/resources/locales/pl-PL/menu.json +70 -0
  61. package/apps/desktop/resources/locales/pt-BR/common.json +32 -0
  62. package/apps/desktop/resources/locales/pt-BR/dialog.json +31 -0
  63. package/apps/desktop/resources/locales/pt-BR/menu.json +70 -0
  64. package/apps/desktop/resources/locales/ru-RU/common.json +32 -0
  65. package/apps/desktop/resources/locales/ru-RU/dialog.json +31 -0
  66. package/apps/desktop/resources/locales/ru-RU/menu.json +70 -0
  67. package/apps/desktop/resources/locales/tr-TR/common.json +32 -0
  68. package/apps/desktop/resources/locales/tr-TR/dialog.json +31 -0
  69. package/apps/desktop/resources/locales/tr-TR/menu.json +70 -0
  70. package/apps/desktop/resources/locales/vi-VN/common.json +32 -0
  71. package/apps/desktop/resources/locales/vi-VN/dialog.json +31 -0
  72. package/apps/desktop/resources/locales/vi-VN/menu.json +70 -0
  73. package/apps/desktop/resources/locales/zh-CN/common.json +32 -0
  74. package/apps/desktop/resources/locales/zh-CN/dialog.json +31 -0
  75. package/apps/desktop/resources/locales/zh-CN/menu.json +70 -0
  76. package/apps/desktop/resources/locales/zh-TW/common.json +32 -0
  77. package/apps/desktop/resources/locales/zh-TW/dialog.json +31 -0
  78. package/apps/desktop/resources/locales/zh-TW/menu.json +70 -0
  79. package/apps/desktop/resources/splash.html +88 -0
  80. package/apps/desktop/scripts/i18nWorkflow/const.ts +18 -0
  81. package/apps/desktop/scripts/i18nWorkflow/genDefaultLocale.ts +35 -0
  82. package/apps/desktop/scripts/i18nWorkflow/genDiff.ts +57 -0
  83. package/apps/desktop/scripts/i18nWorkflow/index.ts +35 -0
  84. package/apps/desktop/scripts/i18nWorkflow/utils.ts +54 -0
  85. package/apps/desktop/scripts/pglite-server.ts +14 -0
  86. package/apps/desktop/src/common/routes.ts +78 -0
  87. package/apps/desktop/src/main/appBrowsers.ts +47 -0
  88. package/apps/desktop/src/main/const/dir.ts +29 -0
  89. package/apps/desktop/src/main/const/env.ts +3 -0
  90. package/apps/desktop/src/main/const/store.ts +22 -0
  91. package/apps/desktop/src/main/controllers/AuthCtr.ts +390 -0
  92. package/apps/desktop/src/main/controllers/BrowserWindowsCtr.ts +95 -0
  93. package/apps/desktop/src/main/controllers/DevtoolsCtr.ts +9 -0
  94. package/apps/desktop/src/main/controllers/LocalFileCtr.ts +380 -0
  95. package/apps/desktop/src/main/controllers/MenuCtr.ts +29 -0
  96. package/apps/desktop/src/main/controllers/RemoteServerConfigCtr.ts +335 -0
  97. package/apps/desktop/src/main/controllers/RemoteServerSyncCtr.ts +321 -0
  98. package/apps/desktop/src/main/controllers/ShortcutCtr.ts +19 -0
  99. package/apps/desktop/src/main/controllers/SystemCtr.ts +93 -0
  100. package/apps/desktop/src/main/controllers/UpdaterCtr.ts +43 -0
  101. package/apps/desktop/src/main/controllers/UploadFileCtr.ts +34 -0
  102. package/apps/desktop/src/main/controllers/_template.ts +9 -0
  103. package/apps/desktop/src/main/controllers/index.ts +58 -0
  104. package/apps/desktop/src/main/core/App.ts +370 -0
  105. package/apps/desktop/src/main/core/Browser.ts +345 -0
  106. package/apps/desktop/src/main/core/BrowserManager.ts +154 -0
  107. package/apps/desktop/src/main/core/I18nManager.ts +185 -0
  108. package/apps/desktop/src/main/core/IoCContainer.ts +12 -0
  109. package/apps/desktop/src/main/core/MenuManager.ts +64 -0
  110. package/apps/desktop/src/main/core/ShortcutManager.ts +173 -0
  111. package/apps/desktop/src/main/core/StoreManager.ts +89 -0
  112. package/apps/desktop/src/main/core/UpdaterManager.ts +321 -0
  113. package/apps/desktop/src/main/index.ts +5 -0
  114. package/apps/desktop/src/main/locales/default/common.ts +34 -0
  115. package/apps/desktop/src/main/locales/default/dialog.ts +33 -0
  116. package/apps/desktop/src/main/locales/default/index.ts +11 -0
  117. package/apps/desktop/src/main/locales/default/menu.ts +72 -0
  118. package/apps/desktop/src/main/locales/resources.ts +35 -0
  119. package/apps/desktop/src/main/menus/impls/BaseMenuPlatform.ts +10 -0
  120. package/apps/desktop/src/main/menus/impls/linux.ts +243 -0
  121. package/apps/desktop/src/main/menus/impls/macOS.ts +360 -0
  122. package/apps/desktop/src/main/menus/impls/windows.ts +226 -0
  123. package/apps/desktop/src/main/menus/index.ts +34 -0
  124. package/apps/desktop/src/main/menus/types.ts +28 -0
  125. package/apps/desktop/src/main/modules/fileSearch/impl/macOS.ts +577 -0
  126. package/apps/desktop/src/main/modules/fileSearch/index.ts +23 -0
  127. package/apps/desktop/src/main/modules/fileSearch/type.ts +27 -0
  128. package/apps/desktop/src/main/modules/updater/configs.ts +22 -0
  129. package/apps/desktop/src/main/modules/updater/utils.ts +33 -0
  130. package/apps/desktop/src/main/services/fileSearchSrv.ts +35 -0
  131. package/apps/desktop/src/main/services/fileSrv.ts +255 -0
  132. package/apps/desktop/src/main/services/index.ts +9 -0
  133. package/apps/desktop/src/main/shortcuts/config.ts +18 -0
  134. package/apps/desktop/src/main/shortcuts/index.ts +1 -0
  135. package/apps/desktop/src/main/types/fileSearch.ts +51 -0
  136. package/apps/desktop/src/main/types/store.ts +14 -0
  137. package/apps/desktop/src/main/utils/file-system.ts +15 -0
  138. package/apps/desktop/src/main/utils/logger.ts +44 -0
  139. package/apps/desktop/src/main/utils/next-electron-rsc.ts +383 -0
  140. package/apps/desktop/src/preload/electronApi.ts +18 -0
  141. package/apps/desktop/src/preload/index.ts +14 -0
  142. package/apps/desktop/src/preload/invoke.ts +10 -0
  143. package/apps/desktop/src/preload/routeInterceptor.ts +162 -0
  144. package/apps/desktop/tsconfig.json +21 -0
  145. package/changelog/v1.json +18 -0
  146. package/package.json +1 -1
  147. package/packages/electron-client-ipc/src/events/remoteServer.ts +11 -4
  148. package/packages/electron-client-ipc/src/types/dataSync.ts +15 -0
  149. package/packages/electron-client-ipc/src/types/index.ts +2 -1
  150. package/packages/electron-client-ipc/src/types/proxyTRPCRequest.ts +21 -0
  151. package/packages/electron-server-ipc/src/const.ts +3 -3
  152. package/packages/electron-server-ipc/src/ipcClient.test.ts +7 -6
  153. package/packages/electron-server-ipc/src/ipcClient.ts +17 -8
  154. package/packages/electron-server-ipc/src/ipcServer.ts +7 -3
  155. package/scripts/electronWorkflow/setDesktopVersion.ts +60 -43
  156. package/src/app/[variants]/(main)/_layout/Desktop/index.tsx +1 -1
  157. package/src/components/Analytics/Desktop.tsx +19 -0
  158. package/src/components/Analytics/index.tsx +3 -0
  159. package/src/config/aiModels/wenxin.ts +95 -8
  160. package/src/database/core/db-adaptor.ts +4 -1
  161. package/src/database/core/electron.ts +317 -0
  162. package/src/{app/[variants]/(main)/_layout/Desktop/ElectronTitlebar/Connection/Mode.tsx → features/ElectronTitlebar/Connection/ConnectionMode.tsx} +24 -21
  163. package/src/{app/[variants]/(main)/_layout/Desktop → features}/ElectronTitlebar/Connection/Option.tsx +3 -5
  164. package/src/{app/[variants]/(main)/_layout/Desktop/ElectronTitlebar/Connection/Sync.tsx → features/ElectronTitlebar/Connection/RemoteStatus.tsx} +10 -7
  165. package/src/{app/[variants]/(main)/_layout/Desktop → features}/ElectronTitlebar/Connection/index.tsx +4 -4
  166. package/src/{app/[variants]/(main)/_layout/Desktop → features}/ElectronTitlebar/UpdateModal.tsx +2 -1
  167. package/src/libs/trpc/client/async.ts +6 -0
  168. package/src/libs/trpc/client/edge.ts +6 -0
  169. package/src/libs/trpc/client/helpers/desktopRemoteRPCFetch.ts +72 -0
  170. package/src/libs/trpc/client/index.ts +1 -0
  171. package/src/libs/trpc/client/lambda.ts +10 -1
  172. package/src/libs/trpc/client/tools.ts +6 -0
  173. package/src/server/globalConfig/index.ts +0 -3
  174. package/src/server/modules/ElectronIPCClient/index.ts +3 -1
  175. package/src/server/routers/desktop/index.ts +2 -0
  176. package/src/server/routers/desktop/mcp.ts +47 -0
  177. package/src/server/routers/lambda/user.ts +38 -23
  178. package/src/server/routers/tools/mcp.ts +0 -6
  179. package/src/services/electron/remoteServer.ts +4 -4
  180. package/src/services/mcp.ts +17 -7
  181. package/src/services/upload.ts +9 -0
  182. package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +11 -2
  183. package/src/store/chat/slices/builtinTool/actions/localFile.ts +110 -53
  184. package/src/store/electron/actions/sync.ts +20 -19
  185. package/src/store/electron/initialState.ts +3 -3
  186. package/src/store/electron/selectors/sync.ts +6 -3
  187. package/src/store/electron/store.ts +2 -0
  188. package/src/store/file/slices/upload/action.ts +11 -3
  189. package/src/store/tool/selectors/tool.ts +10 -1
  190. package/src/utils/fetch/headers.ts +27 -0
  191. package/src/utils/fetch/index.ts +2 -0
  192. package/src/utils/fetch/request.ts +28 -0
  193. package/packages/electron-client-ipc/src/types/remoteServer.ts +0 -8
  194. /package/src/{app/[variants]/(main)/_layout/Desktop → features}/ElectronTitlebar/Connection/Waiting.tsx +0 -0
  195. /package/src/{app/[variants]/(main)/_layout/Desktop → features}/ElectronTitlebar/UpdateNotification.tsx +0 -0
  196. /package/src/{app/[variants]/(main)/_layout/Desktop → features}/ElectronTitlebar/index.tsx +0 -0
@@ -1,6 +1,7 @@
1
+ export * from './dataSync';
1
2
  export * from './dispatch';
2
3
  export * from './localFile';
3
- export * from './remoteServer';
4
+ export * from './proxyTRPCRequest';
4
5
  export * from './route';
5
6
  export * from './shortcut';
6
7
  export * from './system';
@@ -0,0 +1,21 @@
1
+ export type ProxyTRPCRequestParams = {
2
+ /** Request body (can be string, ArrayBuffer, or null/undefined) */
3
+ body?: string | ArrayBuffer;
4
+ /** Request headers */
5
+ headers: Record<string, string>;
6
+ /** The HTTP method (e.g., 'GET', 'POST') */
7
+ method: string;
8
+ /** The path and query string of the request (e.g., '/trpc/lambda/...') */
9
+ urlPath: string;
10
+ };
11
+
12
+ export interface ProxyTRPCRequestResult {
13
+ /** Response body (likely as ArrayBuffer or string) */
14
+ body: ArrayBuffer | string;
15
+ /** Response headers */
16
+ headers: Record<string, string>;
17
+ /** Response status code */
18
+ status: number;
19
+ /** Response status text */
20
+ statusText: string;
21
+ }
@@ -1,5 +1,5 @@
1
- export const SOCK_FILE = 'lobehub-electron-ipc.sock';
1
+ export const SOCK_FILE = (id: string) => `${id}-electron-ipc.sock`;
2
2
 
3
- export const SOCK_INFO_FILE = 'lobehub-electron-ipc-info.json';
3
+ export const SOCK_INFO_FILE = (id: string) => `${id}-electron-ipc-info.json`;
4
4
 
5
- export const WINDOW_PIPE_FILE = '\\\\.\\pipe\\lobehub-electron-ipc';
5
+ export const WINDOW_PIPE_FILE = (id: string) => `\\\\.\\pipe\\${id}-electron-ipc`;
@@ -12,6 +12,7 @@ vi.mock('node:net');
12
12
  vi.mock('node:os');
13
13
  vi.mock('node:path');
14
14
 
15
+ const appId = 'lobehub';
15
16
  describe('ElectronIpcClient', () => {
16
17
  // Mock data
17
18
  const mockTempDir = '/mock/temp/dir';
@@ -54,7 +55,7 @@ describe('ElectronIpcClient', () => {
54
55
  vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify(mockSocketInfo));
55
56
 
56
57
  // Execute
57
- new ElectronIpcClient();
58
+ new ElectronIpcClient(appId);
58
59
 
59
60
  // Verify
60
61
  expect(fs.existsSync).toHaveBeenCalledWith(mockSocketInfoPath);
@@ -66,7 +67,7 @@ describe('ElectronIpcClient', () => {
66
67
  vi.mocked(fs.existsSync).mockReturnValue(false);
67
68
 
68
69
  // Execute
69
- new ElectronIpcClient();
70
+ new ElectronIpcClient(appId);
70
71
 
71
72
  // Verify
72
73
  expect(fs.existsSync).toHaveBeenCalledWith(mockSocketInfoPath);
@@ -75,7 +76,7 @@ describe('ElectronIpcClient', () => {
75
76
  // Test platform-specific behavior
76
77
  const originalPlatform = process.platform;
77
78
  Object.defineProperty(process, 'platform', { value: 'win32' });
78
- new ElectronIpcClient();
79
+ new ElectronIpcClient(appId);
79
80
  Object.defineProperty(process, 'platform', { value: originalPlatform });
80
81
  });
81
82
 
@@ -86,7 +87,7 @@ describe('ElectronIpcClient', () => {
86
87
  });
87
88
 
88
89
  // Execute
89
- new ElectronIpcClient();
90
+ new ElectronIpcClient(appId);
90
91
 
91
92
  // Verify
92
93
  expect(console.error).toHaveBeenCalledWith(
@@ -103,7 +104,7 @@ describe('ElectronIpcClient', () => {
103
104
  // Setup a client with a known socket path
104
105
  vi.mocked(fs.existsSync).mockReturnValue(true);
105
106
  vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify(mockSocketInfo));
106
- client = new ElectronIpcClient();
107
+ client = new ElectronIpcClient(appId);
107
108
 
108
109
  // Reset socket mocks for each test
109
110
  mockSocket.on.mockReset();
@@ -170,7 +171,7 @@ describe('ElectronIpcClient', () => {
170
171
  // Setup a client with a known socket path
171
172
  vi.mocked(fs.existsSync).mockReturnValue(true);
172
173
  vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify(mockSocketInfo));
173
- client = new ElectronIpcClient();
174
+ client = new ElectronIpcClient(appId);
174
175
 
175
176
  // Setup socket.on
176
177
  mockSocket.on.mockImplementation((event, callback) => {
@@ -20,18 +20,28 @@ export class ElectronIpcClient {
20
20
  private connectionAttempts: number = 0;
21
21
  private maxConnectionAttempts: number = 5;
22
22
  private dataBuffer: string = '';
23
+ private readonly appId: string;
23
24
 
24
- constructor() {
25
- log('Initializing client');
25
+ constructor(appId: string) {
26
+ log('Initializing client', appId);
27
+ this.appId = appId;
26
28
  this.initialize();
27
29
  }
28
30
 
29
31
  // 初始化客户端
30
32
  private initialize() {
31
33
  try {
32
- // 从临时文件读取套接字路径
33
34
  const tempDir = os.tmpdir();
34
- const socketInfoPath = path.join(tempDir, SOCK_INFO_FILE);
35
+
36
+ // Windows 平台强制使用命名管道
37
+ if (process.platform === 'win32') {
38
+ this.socketPath = WINDOW_PIPE_FILE(this.appId);
39
+ log('Using named pipe for Windows: %s', this.socketPath);
40
+ return;
41
+ }
42
+
43
+ // 其他平台尝试读取 sock info 文件
44
+ const socketInfoPath = path.join(tempDir, SOCK_INFO_FILE(this.appId));
35
45
 
36
46
  log('Looking for socket info at: %s', socketInfoPath);
37
47
  if (fs.existsSync(socketInfoPath)) {
@@ -39,10 +49,9 @@ export class ElectronIpcClient {
39
49
  this.socketPath = socketInfo.socketPath;
40
50
  log('Found socket path: %s', this.socketPath);
41
51
  } else {
42
- // 如果找不到套接字信息,使用默认路径
43
- this.socketPath =
44
- process.platform === 'win32' ? WINDOW_PIPE_FILE : path.join(os.tmpdir(), SOCK_FILE);
45
- log('Socket info not found, using default path: %s', this.socketPath);
52
+ // 如果找不到套接字信息,使用默认 sock 文件路径
53
+ this.socketPath = path.join(tempDir, SOCK_FILE(this.appId));
54
+ log('Socket info not found, using default sock path: %s', this.socketPath);
46
55
  }
47
56
  } catch (err) {
48
57
  console.error('Failed to initialize IPC client:', err);
@@ -13,12 +13,16 @@ const log = debug('electron-server-ipc:server');
13
13
  export class ElectronIPCServer {
14
14
  private server: net.Server;
15
15
  private socketPath: string;
16
+ private appId: string;
16
17
  private eventHandler: ElectronIPCEventHandler;
17
18
 
18
- constructor(eventHandler: ElectronIPCEventHandler) {
19
+ constructor(appId: string, eventHandler: ElectronIPCEventHandler) {
20
+ this.appId = appId;
19
21
  const isWindows = process.platform === 'win32';
20
22
  // 创建唯一的套接字路径,避免冲突
21
- this.socketPath = isWindows ? WINDOW_PIPE_FILE : path.join(os.tmpdir(), SOCK_FILE);
23
+ this.socketPath = isWindows
24
+ ? WINDOW_PIPE_FILE(appId)
25
+ : path.join(os.tmpdir(), SOCK_FILE(appId));
22
26
 
23
27
  // 如果是 Unix 套接字,确保文件不存在
24
28
  if (!isWindows && fs.existsSync(this.socketPath)) {
@@ -47,7 +51,7 @@ export class ElectronIPCServer {
47
51
 
48
52
  // 将套接字路径写入临时文件,供 Next.js 服务端读取
49
53
  const tempDir = os.tmpdir();
50
- const socketInfoPath = path.join(tempDir, SOCK_INFO_FILE);
54
+ const socketInfoPath = path.join(tempDir, SOCK_INFO_FILE(this.appId));
51
55
  log('Writing socket info to: %s', socketInfoPath);
52
56
  fs.writeFileSync(socketInfoPath, JSON.stringify({ socketPath: this.socketPath }), 'utf8');
53
57
 
@@ -2,12 +2,24 @@
2
2
  import fs from 'fs-extra';
3
3
  import path from 'node:path';
4
4
 
5
+ type ReleaseType = 'stable' | 'beta' | 'nightly';
6
+
5
7
  // 获取脚本的命令行参数
6
8
  const version = process.argv[2];
7
- const isPr = process.argv[3] === 'true';
9
+ const releaseType = process.argv[3] as ReleaseType;
10
+
11
+ // 验证参数
12
+ if (!version || !releaseType) {
13
+ console.error(
14
+ 'Missing parameters. Usage: bun run setDesktopVersion.ts <version> <stable|beta|nightly>',
15
+ );
16
+ process.exit(1);
17
+ }
8
18
 
9
- if (!version) {
10
- console.error('Missing version parameter, usage: bun run setDesktopVersion.ts <version> [isPr]');
19
+ if (!['stable', 'beta', 'nightly'].includes(releaseType)) {
20
+ console.error(
21
+ `Invalid release type: ${releaseType}. Must be one of 'stable', 'beta', 'nightly'.`,
22
+ );
11
23
  process.exit(1);
12
24
  }
13
25
 
@@ -16,81 +28,86 @@ const rootDir = path.resolve(__dirname, '../..');
16
28
 
17
29
  // 桌面应用 package.json 的路径
18
30
  const desktopPackageJsonPath = path.join(rootDir, 'apps/desktop/package.json');
31
+ const buildDir = path.join(rootDir, 'apps/desktop/build');
19
32
 
20
33
  // 更新应用图标
21
- function updateAppIcon() {
34
+ function updateAppIcon(type: 'beta' | 'nightly') {
35
+ console.log(`📦 Updating app icon for ${type} version...`);
22
36
  try {
23
- const buildDir = path.join(rootDir, 'apps/desktop/build');
24
-
25
- // 定义需要处理的图标映射,考虑到大小写敏感性
37
+ const iconSuffix = type === 'beta' ? 'beta' : 'nightly';
26
38
  const iconMappings = [
27
- // { ext: '.ico', nightly: 'icon-nightly.ico', normal: 'icon.ico' },
28
- { ext: '.png', nightly: 'icon-nightly.png', normal: 'icon.png' },
29
- { ext: '.icns', nightly: 'Icon-nightly.icns', normal: 'Icon.icns' },
39
+ { ext: '.png', source: `icon-${iconSuffix}.png`, target: 'icon.png' },
40
+ { ext: '.icns', source: `Icon-${iconSuffix}.icns`, target: 'Icon.icns' },
41
+ { ext: '.ico', source: `icon-${iconSuffix}.ico`, target: 'icon.ico' },
30
42
  ];
31
43
 
32
- // 处理每种图标格式
33
44
  for (const mapping of iconMappings) {
34
- const sourceFile = path.join(buildDir, mapping.nightly);
35
- const targetFile = path.join(buildDir, mapping.normal);
45
+ const sourceFile = path.join(buildDir, mapping.source);
46
+ const targetFile = path.join(buildDir, mapping.target);
36
47
 
37
- // 检查源文件是否存在
38
48
  if (fs.existsSync(sourceFile)) {
39
- // 只有当源文件和目标文件不同,才进行复制
40
49
  if (sourceFile !== targetFile) {
41
50
  fs.copyFileSync(sourceFile, targetFile);
42
- console.log(`Updated app icon: ${targetFile}`);
51
+ console.log(` Copied ${mapping.source} to ${mapping.target}`);
43
52
  }
44
53
  } else {
45
- console.warn(`Warning: Source icon not found: ${sourceFile}`);
54
+ console.warn(` ⚠️ Warning: Source icon not found: ${sourceFile}`);
46
55
  }
47
56
  }
48
57
  } catch (error) {
49
- console.error('Error updating icons:', error);
50
- // 继续处理,不终止程序
58
+ console.error('Error updating icons:', error);
59
+ // 不终止程序,继续处理 package.json
51
60
  }
52
61
  }
53
62
 
54
- function updateVersion() {
63
+ function updatePackageJson() {
64
+ console.log(`⚙️ Updating ${desktopPackageJsonPath} for ${releaseType} version ${version}...`);
55
65
  try {
56
- // 确保文件存在
57
66
  if (!fs.existsSync(desktopPackageJsonPath)) {
58
- console.error(`Error: File not found ${desktopPackageJsonPath}`);
67
+ console.error(`❌ Error: File not found ${desktopPackageJsonPath}`);
59
68
  process.exit(1);
60
69
  }
61
70
 
62
- // 读取 package.json 文件
63
71
  const packageJson = fs.readJSONSync(desktopPackageJsonPath);
64
72
 
65
- // 更新版本号
73
+ // 始终更新版本号
66
74
  packageJson.version = version;
67
- packageJson.productName = 'LobeHub';
68
- packageJson.name = 'lobehub-desktop';
69
-
70
- // 如果是 PR 构建,设置为 Nightly 版本
71
- if (isPr) {
72
- // 修改包名,添加 -nightly 后缀
73
- if (!packageJson.name.endsWith('-nightly')) {
74
- packageJson.name = `${packageJson.name}-nightly`;
75
- }
76
75
 
77
- // 修改产品名称为 LobeHub Nightly
78
- packageJson.productName = 'LobeHub-Nightly';
79
-
80
- console.log('🌙 Setting as Nightly version with modified package name and productName');
81
-
82
- // 使用 nightly 图标替换常规图标
83
- updateAppIcon();
76
+ // 根据 releaseType 修改其他字段
77
+ switch (releaseType) {
78
+ case 'stable': {
79
+ packageJson.productName = 'LobeHub';
80
+ packageJson.name = 'lobehub-desktop';
81
+ console.log('🌟 Setting as Stable version.');
82
+ break;
83
+ }
84
+ case 'beta': {
85
+ packageJson.productName = 'LobeHub-Beta'; // Or 'LobeHub-Beta' if preferred
86
+ packageJson.name = 'lobehub-desktop-beta'; // Or 'lobehub-desktop' if preferred
87
+ console.log('🧪 Setting as Beta version.');
88
+ updateAppIcon('beta');
89
+ break;
90
+ }
91
+ case 'nightly': {
92
+ packageJson.productName = 'LobeHub-Nightly'; // Or 'LobeHub-Nightly'
93
+ packageJson.name = 'lobehub-desktop-nightly'; // Or 'lobehub-desktop-nightly'
94
+ console.log('🌙 Setting as Nightly version.');
95
+ updateAppIcon('nightly');
96
+ break;
97
+ }
84
98
  }
85
99
 
86
100
  // 写回文件
87
101
  fs.writeJsonSync(desktopPackageJsonPath, packageJson, { spaces: 2 });
88
102
 
89
- console.log(`Desktop app version updated to: ${version}, isPr: ${isPr}`);
103
+ console.log(
104
+ `✅ Desktop app package.json updated successfully for ${releaseType} version ${version}.`,
105
+ );
90
106
  } catch (error) {
91
- console.error('Error updating version:', error);
107
+ console.error('Error updating package.json:', error);
92
108
  process.exit(1);
93
109
  }
94
110
  }
95
111
 
96
- updateVersion();
112
+ // 执行更新
113
+ updatePackageJson();
@@ -9,12 +9,12 @@ import { Flexbox } from 'react-layout-kit';
9
9
 
10
10
  import { isDesktop } from '@/const/version';
11
11
  import { BANNER_HEIGHT } from '@/features/AlertBanner/CloudBanner';
12
+ import TitleBar, { TITLE_BAR_HEIGHT } from '@/features/ElectronTitlebar';
12
13
  import HotkeyHelperPanel from '@/features/HotkeyHelperPanel';
13
14
  import { usePlatform } from '@/hooks/usePlatform';
14
15
  import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
15
16
  import { HotkeyScopeEnum } from '@/types/hotkey';
16
17
 
17
- import TitleBar, { TITLE_BAR_HEIGHT } from './ElectronTitlebar';
18
18
  import RegisterHotkeys from './RegisterHotkeys';
19
19
  import SideBar from './SideBar';
20
20
 
@@ -0,0 +1,19 @@
1
+ 'use client';
2
+
3
+ import Script from 'next/script';
4
+ import { memo } from 'react';
5
+ import urlJoin from 'url-join';
6
+
7
+ const DesktopAnalytics = memo(
8
+ () =>
9
+ process.env.NEXT_PUBLIC_DESKTOP_PROJECT_ID &&
10
+ process.env.NEXT_PUBLIC_DESKTOP_UMAMI_BASE_URL && (
11
+ <Script
12
+ data-website-id={process.env.NEXT_PUBLIC_DESKTOP_PROJECT_ID}
13
+ defer
14
+ src={urlJoin(process.env.NEXT_PUBLIC_DESKTOP_UMAMI_BASE_URL, 'script.js')}
15
+ />
16
+ ),
17
+ );
18
+
19
+ export default DesktopAnalytics;
@@ -1,7 +1,9 @@
1
1
  import dynamic from 'next/dynamic';
2
2
 
3
3
  import { analyticsEnv } from '@/config/analytics';
4
+ import { isDesktop } from '@/const/version';
4
5
 
6
+ import Desktop from './Desktop';
5
7
  import Google from './Google';
6
8
  import Vercel from './Vercel';
7
9
 
@@ -41,6 +43,7 @@ const Analytics = () => {
41
43
  {!!analyticsEnv.REACT_SCAN_MONITOR_API_KEY && (
42
44
  <ReactScan apiKey={analyticsEnv.REACT_SCAN_MONITOR_API_KEY} />
43
45
  )}
46
+ {isDesktop && <Desktop />}
44
47
  </>
45
48
  );
46
49
  };
@@ -1,6 +1,41 @@
1
1
  import { AIChatModelCard } from '@/types/aiModel';
2
2
 
3
3
  const wenxinChatModels: AIChatModelCard[] = [
4
+ {
5
+ abilities: {
6
+ reasoning: true,
7
+ },
8
+ contextWindowTokens: 32_768,
9
+ description:
10
+ '与ERNIE-X1-32K相比,模型效果和性能更好。',
11
+ displayName: 'ERNIE X1 Turbo 32K',
12
+ enabled: true,
13
+ id: 'ernie-x1-turbo-32k',
14
+ pricing: {
15
+ currency: 'CNY',
16
+ input: 1,
17
+ output: 4,
18
+ },
19
+ releasedAt: '2025-04-24',
20
+ type: 'chat',
21
+ },
22
+ {
23
+ abilities: {
24
+ reasoning: true,
25
+ },
26
+ contextWindowTokens: 32_768,
27
+ description:
28
+ '具备更强的理解、规划、反思、进化能力。作为能力更全面的深度思考模型,文心X1兼备准确、创意和文采,在中文知识问答、文学创作、文稿写作、日常对话、逻辑推理、复杂计算及工具调用等方面表现尤为出色。',
29
+ displayName: 'ERNIE X1 32K',
30
+ id: 'ernie-x1-32k',
31
+ pricing: {
32
+ currency: 'CNY',
33
+ input: 2,
34
+ output: 8,
35
+ },
36
+ releasedAt: '2025-04-15',
37
+ type: 'chat',
38
+ },
4
39
  {
5
40
  abilities: {
6
41
  reasoning: true,
@@ -9,7 +44,6 @@ const wenxinChatModels: AIChatModelCard[] = [
9
44
  description:
10
45
  '文心大模型X1具备更强的理解、规划、反思、进化能力。作为能力更全面的深度思考模型,文心X1兼备准确、创意和文采,在中文知识问答、文学创作、文稿写作、日常对话、逻辑推理、复杂计算及工具调用等方面表现尤为出色。',
11
46
  displayName: 'ERNIE X1 32K Preview',
12
- enabled: true,
13
47
  id: 'ernie-x1-32k-preview',
14
48
  pricing: {
15
49
  currency: 'CNY',
@@ -21,14 +55,73 @@ const wenxinChatModels: AIChatModelCard[] = [
21
55
  },
22
56
  {
23
57
  abilities: {
58
+ functionCall: true,
59
+ search: true,
60
+ },
61
+ contextWindowTokens: 131_072,
62
+ description:
63
+ '文心4.5 Turbo在去幻觉、逻辑推理和代码能力等方面也有着明显增强。对比文心4.5,速度更快、价格更低。模型能力全面提升,更好满足多轮长历史对话处理、长文档理解问答任务。',
64
+ displayName: 'ERNIE 4.5 Turbo 128K',
65
+ enabled: true,
66
+ id: 'ernie-4.5-turbo-128k',
67
+ pricing: {
68
+ currency: 'CNY',
69
+ input: 0.8,
70
+ output: 3.2,
71
+ },
72
+ releasedAt: '2025-04-24',
73
+ settings: {
74
+ searchImpl: 'params',
75
+ },
76
+ type: 'chat',
77
+ },
78
+ {
79
+ abilities: {
80
+ functionCall: true,
24
81
  search: true,
82
+ },
83
+ contextWindowTokens: 32_768,
84
+ description:
85
+ '文心4.5 Turbo在去幻觉、逻辑推理和代码能力等方面也有着明显增强。对比文心4.5,速度更快、价格更低。文本创作、知识问答等能力提升显著。输出长度及整句时延相较ERNIE 4.5有所增加。',
86
+ displayName: 'ERNIE 4.5 Turbo 32K',
87
+ id: 'ernie-4.5-turbo-32k',
88
+ pricing: {
89
+ currency: 'CNY',
90
+ input: 0.8,
91
+ output: 3.2,
92
+ },
93
+ releasedAt: '2025-04-24',
94
+ settings: {
95
+ searchImpl: 'params',
96
+ },
97
+ type: 'chat',
98
+ },
99
+ {
100
+ abilities: {
101
+ vision: true,
102
+ },
103
+ contextWindowTokens: 32_768,
104
+ description:
105
+ '文心一言大模型全新版本,图片理解、创作、翻译、代码等能力显著提升,首次支持32K上下文长度,首Token时延显著降低。',
106
+ displayName: 'ERNIE 4.5 Turbo VL 32K',
107
+ enabled: true,
108
+ id: 'ernie-4.5-turbo-vl-32k',
109
+ pricing: {
110
+ currency: 'CNY',
111
+ input: 3,
112
+ output: 9,
113
+ },
114
+ releasedAt: '2025-04-24',
115
+ type: 'chat',
116
+ },
117
+ {
118
+ abilities: {
25
119
  vision: true,
26
120
  },
27
121
  contextWindowTokens: 8192,
28
122
  description:
29
123
  '文心大模型4.5是百度自主研发的新一代原生多模态基础大模型,通过多个模态联合建模实现协同优化,多模态理解能力优秀;具备更精进的语言能力,理解、生成、逻辑、记忆能力全面提升,去幻觉、逻辑推理、代码能力显著提升。',
30
124
  displayName: 'ERNIE 4.5 8K Preview',
31
- enabled: true,
32
125
  id: 'ernie-4.5-8k-preview',
33
126
  pricing: {
34
127
  currency: 'CNY',
@@ -36,9 +129,6 @@ const wenxinChatModels: AIChatModelCard[] = [
36
129
  output: 16,
37
130
  },
38
131
  releasedAt: '2025-03-16',
39
- settings: {
40
- searchImpl: 'params',
41
- },
42
132
  type: 'chat',
43
133
  },
44
134
  {
@@ -50,7 +140,6 @@ const wenxinChatModels: AIChatModelCard[] = [
50
140
  description:
51
141
  '百度自研的旗舰级超大规模⼤语⾔模型,相较ERNIE 3.5实现了模型能力全面升级,广泛适用于各领域复杂任务场景;支持自动对接百度搜索插件,保障问答信息时效。',
52
142
  displayName: 'ERNIE 4.0 8K',
53
- enabled: true,
54
143
  id: 'ernie-4.0-8k-latest',
55
144
  pricing: {
56
145
  currency: 'CNY',
@@ -91,7 +180,6 @@ const wenxinChatModels: AIChatModelCard[] = [
91
180
  description:
92
181
  '百度自研的旗舰级超大规模⼤语⾔模型,综合效果表现出色,广泛适用于各领域复杂任务场景;支持自动对接百度搜索插件,保障问答信息时效。相较于ERNIE 4.0在性能表现上更优秀',
93
182
  displayName: 'ERNIE 4.0 Turbo 8K',
94
- enabled: true,
95
183
  id: 'ernie-4.0-turbo-8k-latest',
96
184
  pricing: {
97
185
  currency: 'CNY',
@@ -112,7 +200,6 @@ const wenxinChatModels: AIChatModelCard[] = [
112
200
  description:
113
201
  '百度自研的旗舰级超大规模⼤语⾔模型,综合效果表现出色,广泛适用于各领域复杂任务场景;支持自动对接百度搜索插件,保障问答信息时效。相较于ERNIE 4.0在性能表现上更优秀',
114
202
  displayName: 'ERNIE 4.0 Turbo 128K',
115
- enabled: true,
116
203
  id: 'ernie-4.0-turbo-128k',
117
204
  pricing: {
118
205
  currency: 'CNY',
@@ -1,6 +1,9 @@
1
+ import { isDesktop } from '@/const/version';
1
2
  import { getDBInstance } from '@/database/core/web-server';
2
3
  import { LobeChatDatabase } from '@/database/type';
3
4
 
5
+ import { getPgliteInstance } from './electron';
6
+
4
7
  /**
5
8
  * 懒加载数据库实例
6
9
  * 避免每次模块导入时都初始化数据库
@@ -13,7 +16,7 @@ export const getServerDB = async (): Promise<LobeChatDatabase> => {
13
16
 
14
17
  try {
15
18
  // 根据环境选择合适的数据库实例
16
- cachedDB = getDBInstance();
19
+ cachedDB = isDesktop ? await getPgliteInstance() : getDBInstance();
17
20
  return cachedDB;
18
21
  } catch (error) {
19
22
  console.error('❌ Failed to initialize database:', error);