@lobehub/chat 1.82.10 → 1.83.1

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 (195) 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 +194 -0
  4. package/CHANGELOG.md +42 -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 +14 -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/database/core/db-adaptor.ts +4 -1
  160. package/src/database/core/electron.ts +317 -0
  161. package/src/{app/[variants]/(main)/_layout/Desktop/ElectronTitlebar/Connection/Mode.tsx → features/ElectronTitlebar/Connection/ConnectionMode.tsx} +24 -21
  162. package/src/{app/[variants]/(main)/_layout/Desktop → features}/ElectronTitlebar/Connection/Option.tsx +3 -5
  163. package/src/{app/[variants]/(main)/_layout/Desktop/ElectronTitlebar/Connection/Sync.tsx → features/ElectronTitlebar/Connection/RemoteStatus.tsx} +10 -7
  164. package/src/{app/[variants]/(main)/_layout/Desktop → features}/ElectronTitlebar/Connection/index.tsx +4 -4
  165. package/src/{app/[variants]/(main)/_layout/Desktop → features}/ElectronTitlebar/UpdateModal.tsx +2 -1
  166. package/src/libs/trpc/client/async.ts +6 -0
  167. package/src/libs/trpc/client/edge.ts +6 -0
  168. package/src/libs/trpc/client/helpers/desktopRemoteRPCFetch.ts +72 -0
  169. package/src/libs/trpc/client/index.ts +1 -0
  170. package/src/libs/trpc/client/lambda.ts +10 -1
  171. package/src/libs/trpc/client/tools.ts +6 -0
  172. package/src/server/globalConfig/index.ts +0 -3
  173. package/src/server/modules/ElectronIPCClient/index.ts +3 -1
  174. package/src/server/routers/desktop/index.ts +2 -0
  175. package/src/server/routers/desktop/mcp.ts +47 -0
  176. package/src/server/routers/lambda/user.ts +38 -23
  177. package/src/server/routers/tools/mcp.ts +0 -6
  178. package/src/services/electron/remoteServer.ts +4 -4
  179. package/src/services/mcp.ts +17 -7
  180. package/src/services/upload.ts +9 -0
  181. package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +11 -2
  182. package/src/store/chat/slices/builtinTool/actions/localFile.ts +110 -53
  183. package/src/store/electron/actions/sync.ts +20 -19
  184. package/src/store/electron/initialState.ts +3 -3
  185. package/src/store/electron/selectors/sync.ts +6 -3
  186. package/src/store/electron/store.ts +2 -0
  187. package/src/store/file/slices/upload/action.ts +11 -3
  188. package/src/store/tool/selectors/tool.ts +10 -1
  189. package/src/utils/fetch/headers.ts +27 -0
  190. package/src/utils/fetch/index.ts +2 -0
  191. package/src/utils/fetch/request.ts +28 -0
  192. package/packages/electron-client-ipc/src/types/remoteServer.ts +0 -8
  193. /package/src/{app/[variants]/(main)/_layout/Desktop → features}/ElectronTitlebar/Connection/Waiting.tsx +0 -0
  194. /package/src/{app/[variants]/(main)/_layout/Desktop → features}/ElectronTitlebar/UpdateNotification.tsx +0 -0
  195. /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,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);