@lobehub/lobehub 2.0.0-next.241 → 2.0.0-next.243
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/.cursor/rules/desktop-feature-implementation.mdc +2 -2
- package/.cursor/rules/desktop-local-tools-implement.mdc +2 -2
- package/.github/workflows/test.yml +13 -5
- package/CHANGELOG.md +52 -0
- package/apps/desktop/Development.md +1 -6
- package/apps/desktop/README.md +2 -17
- package/apps/desktop/README.zh-CN.md +1 -15
- package/apps/desktop/build/Icon-beta.Assets.car +0 -0
- package/apps/desktop/build/Icon-beta.icns +0 -0
- package/apps/desktop/build/icon-beta.ico +0 -0
- package/apps/desktop/build/icon-beta.png +0 -0
- package/apps/desktop/src/main/controllers/index.ts +1 -1
- package/apps/desktop/src/main/controllers/registry.ts +0 -9
- package/apps/desktop/src/main/core/App.ts +1 -11
- package/apps/desktop/src/main/core/browser/Browser.ts +278 -457
- package/apps/desktop/src/main/core/browser/WindowStateManager.ts +180 -0
- package/apps/desktop/src/main/core/browser/WindowThemeManager.ts +167 -0
- package/apps/desktop/src/main/core/browser/__tests__/WindowStateManager.test.ts +237 -0
- package/apps/desktop/src/main/core/browser/__tests__/WindowThemeManager.test.ts +240 -0
- package/apps/desktop/src/main/exports.d.ts +1 -1
- package/apps/desktop/src/main/exports.ts +1 -1
- package/apps/desktop/src/main/utils/__tests__/http-headers.test.ts +131 -0
- package/apps/desktop/src/main/utils/http-headers.ts +61 -0
- package/apps/desktop/src/main/utils/ipc/__tests__/base.test.ts +1 -22
- package/apps/desktop/src/main/utils/ipc/base.ts +0 -20
- package/apps/desktop/src/main/utils/ipc/index.ts +1 -9
- package/changelog/v1.json +10 -0
- package/locales/ar/models.json +48 -7
- package/locales/ar/plugin.json +9 -0
- package/locales/ar/providers.json +1 -0
- package/locales/bg-BG/models.json +35 -7
- package/locales/bg-BG/plugin.json +9 -0
- package/locales/bg-BG/providers.json +1 -0
- package/locales/de-DE/models.json +26 -6
- package/locales/de-DE/plugin.json +9 -0
- package/locales/de-DE/providers.json +1 -0
- package/locales/en-US/models.json +10 -10
- package/locales/en-US/oauth.json +0 -1
- package/locales/en-US/providers.json +1 -0
- package/locales/en-US/subscription.json +2 -2
- package/locales/es-ES/models.json +42 -7
- package/locales/es-ES/plugin.json +9 -0
- package/locales/es-ES/providers.json +1 -0
- package/locales/fa-IR/models.json +52 -10
- package/locales/fa-IR/plugin.json +9 -0
- package/locales/fa-IR/providers.json +1 -0
- package/locales/fr-FR/models.json +36 -7
- package/locales/fr-FR/plugin.json +9 -0
- package/locales/fr-FR/providers.json +1 -0
- package/locales/it-IT/models.json +42 -7
- package/locales/it-IT/plugin.json +9 -0
- package/locales/it-IT/providers.json +1 -0
- package/locales/ja-JP/models.json +35 -6
- package/locales/ja-JP/plugin.json +9 -0
- package/locales/ja-JP/providers.json +1 -0
- package/locales/ko-KR/models.json +28 -7
- package/locales/ko-KR/plugin.json +9 -0
- package/locales/ko-KR/providers.json +1 -0
- package/locales/nl-NL/models.json +35 -6
- package/locales/nl-NL/plugin.json +9 -0
- package/locales/nl-NL/providers.json +1 -0
- package/locales/pl-PL/models.json +36 -7
- package/locales/pl-PL/plugin.json +9 -0
- package/locales/pl-PL/providers.json +1 -0
- package/locales/pt-BR/models.json +35 -6
- package/locales/pt-BR/plugin.json +9 -0
- package/locales/pt-BR/providers.json +1 -0
- package/locales/ru-RU/models.json +35 -7
- package/locales/ru-RU/plugin.json +9 -0
- package/locales/ru-RU/providers.json +1 -0
- package/locales/tr-TR/models.json +5 -7
- package/locales/tr-TR/plugin.json +9 -0
- package/locales/tr-TR/providers.json +1 -0
- package/locales/vi-VN/models.json +5 -5
- package/locales/vi-VN/plugin.json +9 -0
- package/locales/vi-VN/providers.json +1 -0
- package/locales/zh-CN/models.json +48 -6
- package/locales/zh-CN/oauth.json +0 -1
- package/locales/zh-CN/providers.json +1 -0
- package/locales/zh-CN/subscription.json +1 -1
- package/locales/zh-TW/models.json +10 -10
- package/locales/zh-TW/plugin.json +9 -0
- package/locales/zh-TW/providers.json +1 -0
- package/package.json +1 -1
- package/src/features/ChatInput/InputEditor/Placeholder.tsx +4 -1
- package/src/locales/default/subscription.ts +2 -3
- package/src/server/services/memory/userMemory/extract.ts +46 -6
- package/apps/desktop/src/main/controllers/UploadFileServerCtr.ts +0 -33
- package/apps/desktop/src/main/controllers/__tests__/UploadFileServerCtr.test.ts +0 -55
- package/src/server/modules/ElectronIPCClient/index.ts +0 -92
|
@@ -37,10 +37,10 @@ LobeChat 桌面端基于 Electron 框架构建,采用主进程-渲染进程架
|
|
|
37
37
|
- 位置:`apps/desktop/src/main/controllers/`
|
|
38
38
|
- 示例:创建 `NewFeatureCtr.ts`
|
|
39
39
|
- 需继承 `ControllerModule`,并设置 `static readonly groupName`(例如 `static override readonly groupName = 'newFeature';`)
|
|
40
|
-
- 按 `_template.ts` 模板格式实现,并在 `apps/desktop/src/main/controllers/registry.ts` 的 `controllerIpcConstructors
|
|
40
|
+
- 按 `_template.ts` 模板格式实现,并在 `apps/desktop/src/main/controllers/registry.ts` 的 `controllerIpcConstructors` 中注册,保证类型推导与自动装配
|
|
41
41
|
|
|
42
42
|
2. **定义 IPC 事件处理器**
|
|
43
|
-
- 使用 `@IpcMethod()`
|
|
43
|
+
- 使用 `@IpcMethod()` 装饰器暴露渲染进程可访问的通道
|
|
44
44
|
- 通道名称基于 `groupName.methodName` 自动生成,不再手动拼接字符串
|
|
45
45
|
- 处理函数可通过 `getIpcContext()` 获取 `sender`、`event` 等上下文信息,并按照需要返回结构化结果
|
|
46
46
|
|
|
@@ -57,9 +57,9 @@ alwaysApply: false
|
|
|
57
57
|
5. **实现后端逻辑 (Controller / IPC Handler):**
|
|
58
58
|
* **文件:** `apps/desktop/src/main/controllers/[ToolName]Ctr.ts` (例如: `apps/desktop/src/main/controllers/LocalFileCtr.ts`)
|
|
59
59
|
* **操作:**
|
|
60
|
-
* 导入 Node.js 相关模块 (`fs`, `path` 等) 和 IPC 相关依赖 (`ControllerModule`, `IpcMethod
|
|
60
|
+
* 导入 Node.js 相关模块 (`fs`, `path` 等) 和 IPC 相关依赖 (`ControllerModule`, `IpcMethod`、参数类型等)。
|
|
61
61
|
* 添加一个新的 `async` 方法,方法名通常以 `handle` 开头 (例如: `handleRenameFile`)。
|
|
62
|
-
* 使用 `@IpcMethod()`
|
|
62
|
+
* 使用 `@IpcMethod()` 装饰器将此方法注册为对应 IPC 事件的处理器,确保方法名与 Manifest 中的 `name` 以及 Service 层的链式调用一致。
|
|
63
63
|
* 方法的参数应解构自 Service 层传递过来的对象,类型与步骤 2 中定义的 IPC 参数类型匹配。
|
|
64
64
|
* 实现核心业务逻辑:
|
|
65
65
|
* 进行必要的输入验证。
|
|
@@ -64,15 +64,23 @@ jobs:
|
|
|
64
64
|
run: |
|
|
65
65
|
curl -Os https://cli.codecov.io/latest/linux/codecov
|
|
66
66
|
chmod +x codecov
|
|
67
|
+
TOKEN="${{ secrets.CODECOV_TOKEN }}"
|
|
67
68
|
for package in $PACKAGES; do
|
|
68
69
|
dir="${package#@lobechat/}"
|
|
69
70
|
if [ -f "./packages/$dir/coverage/lcov.info" ]; then
|
|
70
71
|
echo "Uploading coverage for $dir..."
|
|
71
|
-
|
|
72
|
-
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
if [ -n "$TOKEN" ]; then
|
|
73
|
+
./codecov upload-process \
|
|
74
|
+
-t "$TOKEN" \
|
|
75
|
+
-f ./packages/$dir/coverage/lcov.info \
|
|
76
|
+
-F packages/$dir \
|
|
77
|
+
--disable-search
|
|
78
|
+
else
|
|
79
|
+
./codecov upload-process \
|
|
80
|
+
-f ./packages/$dir/coverage/lcov.info \
|
|
81
|
+
-F packages/$dir \
|
|
82
|
+
--disable-search
|
|
83
|
+
fi
|
|
76
84
|
fi
|
|
77
85
|
done
|
|
78
86
|
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,58 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 2.0.0-next.243](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.242...v2.0.0-next.243)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2026-01-08**</sup>
|
|
8
|
+
|
|
9
|
+
#### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **desktop**: Prevent duplicate CORS headers in response.
|
|
12
|
+
- **InputEditor**: Ensure lexical placeholder reactively updates on locale change.
|
|
13
|
+
|
|
14
|
+
<br/>
|
|
15
|
+
|
|
16
|
+
<details>
|
|
17
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
18
|
+
|
|
19
|
+
#### What's fixed
|
|
20
|
+
|
|
21
|
+
- **desktop**: Prevent duplicate CORS headers in response, closes [#11350](https://github.com/lobehub/lobe-chat/issues/11350) ([57e725c](https://github.com/lobehub/lobe-chat/commit/57e725c))
|
|
22
|
+
- **InputEditor**: Ensure lexical placeholder reactively updates on locale change, closes [#11352](https://github.com/lobehub/lobe-chat/issues/11352) ([72e796b](https://github.com/lobehub/lobe-chat/commit/72e796b))
|
|
23
|
+
|
|
24
|
+
</details>
|
|
25
|
+
|
|
26
|
+
<div align="right">
|
|
27
|
+
|
|
28
|
+
[](#readme-top)
|
|
29
|
+
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
## [Version 2.0.0-next.242](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.241...v2.0.0-next.242)
|
|
33
|
+
|
|
34
|
+
<sup>Released on **2026-01-08**</sup>
|
|
35
|
+
|
|
36
|
+
#### 🐛 Bug Fixes
|
|
37
|
+
|
|
38
|
+
- **desktop**: Update macOS beta icon size for macOS 26.
|
|
39
|
+
|
|
40
|
+
<br/>
|
|
41
|
+
|
|
42
|
+
<details>
|
|
43
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
44
|
+
|
|
45
|
+
#### What's fixed
|
|
46
|
+
|
|
47
|
+
- **desktop**: Update macOS beta icon size for macOS 26, closes [#11348](https://github.com/lobehub/lobe-chat/issues/11348) ([0d1eedf](https://github.com/lobehub/lobe-chat/commit/0d1eedf))
|
|
48
|
+
|
|
49
|
+
</details>
|
|
50
|
+
|
|
51
|
+
<div align="right">
|
|
52
|
+
|
|
53
|
+
[](#readme-top)
|
|
54
|
+
|
|
55
|
+
</div>
|
|
56
|
+
|
|
5
57
|
## [Version 2.0.0-next.241](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.240...v2.0.0-next.241)
|
|
6
58
|
|
|
7
59
|
<sup>Released on **2026-01-08**</sup>
|
|
@@ -269,7 +269,7 @@ export class ShortcutManager {
|
|
|
269
269
|
- 注入 App 实例
|
|
270
270
|
|
|
271
271
|
```typescript
|
|
272
|
-
import { ControllerModule, IpcMethod
|
|
272
|
+
import { ControllerModule, IpcMethod } from '@/controllers'
|
|
273
273
|
|
|
274
274
|
export class ControllerModule implements IControllerModule {
|
|
275
275
|
constructor(public app: App) {
|
|
@@ -284,11 +284,6 @@ export class BrowserWindowsCtr extends ControllerModule {
|
|
|
284
284
|
openSettingsWindow(params?: OpenSettingsWindowOptions) {
|
|
285
285
|
// ...
|
|
286
286
|
}
|
|
287
|
-
|
|
288
|
-
@IpcServerMethod()
|
|
289
|
-
handleServerCommand(payload: any) {
|
|
290
|
-
// ...
|
|
291
|
-
}
|
|
292
287
|
}
|
|
293
288
|
```
|
|
294
289
|
|
package/apps/desktop/README.md
CHANGED
|
@@ -183,16 +183,15 @@ The `App.ts` class orchestrates the entire application lifecycle through key pha
|
|
|
183
183
|
#### 🔌 Dependency Injection & Event System
|
|
184
184
|
|
|
185
185
|
- **IoC Container** - WeakMap-based container for decorated controller methods
|
|
186
|
-
- **Typed IPC Decorators** - `@IpcMethod`
|
|
186
|
+
- **Typed IPC Decorators** - `@IpcMethod` wires controller methods into type-safe channels
|
|
187
187
|
- **Automatic Event Mapping** - Events registered during controller loading
|
|
188
188
|
- **Service Locator** - Type-safe service and controller retrieval
|
|
189
189
|
|
|
190
190
|
##### 🧠 Type-Safe IPC Flow
|
|
191
191
|
|
|
192
192
|
- **Async Context Propagation** - `src/main/utils/ipc/base.ts` captures the `IpcContext` with `AsyncLocalStorage`, so controller logic can call `getIpcContext()` anywhere inside an IPC handler without explicitly threading arguments.
|
|
193
|
-
- **Service Constructors Registry** - `src/main/controllers/registry.ts` exports `controllerIpcConstructors
|
|
193
|
+
- **Service Constructors Registry** - `src/main/controllers/registry.ts` exports `controllerIpcConstructors` and `DesktopIpcServices`, enabling automatic typing of renderer IPC proxies.
|
|
194
194
|
- **Renderer Proxy Helper** - `src/utils/electron/ipc.ts` exposes `ensureElectronIpc()` which lazily builds a proxy on top of `window.electronAPI.invoke`, giving React/Next.js code a type-safe API surface without exposing raw proxies in preload.
|
|
195
|
-
- **Server Proxy Helper** - `src/server/modules/ElectronIPCClient/index.ts` mirrors the same typing strategy for the Next.js server runtime, providing a dedicated proxy for `@IpcServerMethod` handlers.
|
|
196
195
|
- **Shared Typings Package** - `apps/desktop/src/main/exports.d.ts` augments `@lobechat/electron-client-ipc` so every package can consume `DesktopIpcServices` without importing desktop business code directly.
|
|
197
196
|
|
|
198
197
|
#### 🪟 Window Management
|
|
@@ -278,20 +277,6 @@ await ipc.windows.openSettingsWindow({ tab: 'provider' });
|
|
|
278
277
|
|
|
279
278
|
The helper internally builds a proxy on top of `window.electronAPI.invoke`, so no proxy objects need to be cloned across the preload boundary.
|
|
280
279
|
|
|
281
|
-
##### 🖥️ Server IPC Helper
|
|
282
|
-
|
|
283
|
-
Next.js (Node) modules use the same proxy pattern via `ensureElectronServerIpc` from `src/server/modules/ElectronIPCClient`. It lazily wraps the socket-based `ElectronIpcClient` so server code can call controllers with full type safety:
|
|
284
|
-
|
|
285
|
-
```ts
|
|
286
|
-
import { ensureElectronServerIpc } from '@/server/modules/ElectronIPCClient';
|
|
287
|
-
|
|
288
|
-
const ipc = ensureElectronServerIpc();
|
|
289
|
-
const dbPath = await ipc.system.getDatabasePath();
|
|
290
|
-
await ipc.upload.deleteFiles(['foo.txt']);
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
All server methods are declared via `@IpcServerMethod` and live in dedicated controller classes, keeping renderer typings clean.
|
|
294
|
-
|
|
295
280
|
#### 🛡️ Security Features
|
|
296
281
|
|
|
297
282
|
- **OAuth 2.0 + PKCE** - Secure authentication with state parameter validation
|
|
@@ -183,7 +183,7 @@ src/main/core/
|
|
|
183
183
|
#### 🔌 依赖注入和事件系统
|
|
184
184
|
|
|
185
185
|
- **IoC 容器** - 基于 WeakMap 的装饰控制器方法容器
|
|
186
|
-
- **装饰器注册** - `@IpcMethod`
|
|
186
|
+
- **装饰器注册** - `@IpcMethod` 装饰器
|
|
187
187
|
- **自动事件映射** - 控制器加载期间注册的事件
|
|
188
188
|
- **服务定位器** - 类型安全的服务和控制器检索
|
|
189
189
|
|
|
@@ -267,20 +267,6 @@ const ipc = ensureElectronIpc();
|
|
|
267
267
|
await ipc.windows.openSettingsWindow({ tab: 'provider' });
|
|
268
268
|
```
|
|
269
269
|
|
|
270
|
-
##### 🖥️ Server IPC 助手
|
|
271
|
-
|
|
272
|
-
Next.js 服务端模块可通过 `ensureElectronServerIpc`(位于 `src/server/modules/ElectronIPCClient`)获得同样的类型安全代理,并复用 socket IPC 通道:
|
|
273
|
-
|
|
274
|
-
```ts
|
|
275
|
-
import { ensureElectronServerIpc } from '@/server/modules/ElectronIPCClient';
|
|
276
|
-
|
|
277
|
-
const ipc = ensureElectronServerIpc();
|
|
278
|
-
const path = await ipc.system.getDatabasePath();
|
|
279
|
-
await ipc.upload.deleteFiles(['foo.txt']);
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
所有 `@IpcServerMethod` 方法都放在独立的控制器中,这样渲染端的类型推导不会包含这些仅供服务器调用的通道。
|
|
283
|
-
|
|
284
270
|
#### 🛡️ 安全功能
|
|
285
271
|
|
|
286
272
|
- **OAuth 2.0 + PKCE** - 具有状态参数验证的安全认证
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -17,7 +17,6 @@ import SystemController from './SystemCtr';
|
|
|
17
17
|
import TrayMenuCtr from './TrayMenuCtr';
|
|
18
18
|
import UpdaterCtr from './UpdaterCtr';
|
|
19
19
|
import UploadFileCtr from './UploadFileCtr';
|
|
20
|
-
import UploadFileServerCtr from './UploadFileServerCtr';
|
|
21
20
|
|
|
22
21
|
export const controllerIpcConstructors = [
|
|
23
22
|
AuthCtr,
|
|
@@ -42,11 +41,3 @@ export const controllerIpcConstructors = [
|
|
|
42
41
|
type DesktopControllerIpcConstructors = typeof controllerIpcConstructors;
|
|
43
42
|
type DesktopControllerServices = CreateServicesResult<DesktopControllerIpcConstructors>;
|
|
44
43
|
export type DesktopIpcServices = MergeIpcService<DesktopControllerServices>;
|
|
45
|
-
|
|
46
|
-
export const controllerServerIpcConstructors = [
|
|
47
|
-
UploadFileServerCtr,
|
|
48
|
-
] as const satisfies readonly IpcServiceConstructor[];
|
|
49
|
-
|
|
50
|
-
type DesktopControllerServerConstructors = typeof controllerServerIpcConstructors;
|
|
51
|
-
type DesktopServerControllerServices = CreateServicesResult<DesktopControllerServerConstructors>;
|
|
52
|
-
export type DesktopServerIpcServices = MergeIpcService<DesktopServerControllerServices>;
|
|
@@ -11,7 +11,6 @@ import { isDev } from '@/const/env';
|
|
|
11
11
|
import { ELECTRON_BE_PROTOCOL_SCHEME } from '@/const/protocol';
|
|
12
12
|
import { IControlModule } from '@/controllers';
|
|
13
13
|
import { IServiceModule } from '@/services';
|
|
14
|
-
import { getServerMethodMetadata } from '@/utils/ipc';
|
|
15
14
|
import { createLogger } from '@/utils/logger';
|
|
16
15
|
|
|
17
16
|
import { BrowserManager } from './browser/BrowserManager';
|
|
@@ -330,15 +329,6 @@ export class App {
|
|
|
330
329
|
const controller = new ControllerClass(this);
|
|
331
330
|
this.controllers.set(ControllerClass, controller);
|
|
332
331
|
|
|
333
|
-
const serverMethods = getServerMethodMetadata(ControllerClass);
|
|
334
|
-
serverMethods?.forEach((methodName, propertyKey) => {
|
|
335
|
-
const channel = `${ControllerClass.groupName}.${methodName}`;
|
|
336
|
-
this.ipcServerEventMap.set(channel, {
|
|
337
|
-
controller,
|
|
338
|
-
methodName: propertyKey,
|
|
339
|
-
});
|
|
340
|
-
});
|
|
341
|
-
|
|
342
332
|
IoCContainer.shortcuts.get(ControllerClass)?.forEach((shortcut) => {
|
|
343
333
|
this.shortcutMethodMap.set(shortcut.name, async () => {
|
|
344
334
|
controller[shortcut.methodName]();
|
|
@@ -408,4 +398,4 @@ export class App {
|
|
|
408
398
|
// 执行清理操作
|
|
409
399
|
this.staticFileServerManager.destroy();
|
|
410
400
|
};
|
|
411
|
-
}
|
|
401
|
+
}
|