@lobehub/lobehub 2.0.0-next.276 → 2.0.0-next.278
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/db-migrations.mdc +1 -1
- package/.cursor/rules/debug-usage.mdc +7 -5
- package/.cursor/rules/desktop-controller-tests.mdc +2 -1
- package/.cursor/rules/desktop-feature-implementation.mdc +9 -5
- package/.cursor/rules/desktop-local-tools-implement.mdc +67 -66
- package/.cursor/rules/desktop-menu-configuration.mdc +21 -9
- package/.cursor/rules/desktop-window-management.mdc +17 -2
- package/.cursor/rules/drizzle-schema-style-guide.mdc +6 -6
- package/.cursor/rules/hotkey.mdc +1 -0
- package/.cursor/rules/i18n.mdc +1 -0
- package/.cursor/rules/project-structure.mdc +16 -3
- package/.cursor/rules/react.mdc +17 -5
- package/.cursor/rules/recent-data-usage.mdc +2 -1
- package/.cursor/rules/testing-guide/testing-guide.mdc +262 -238
- package/.cursor/rules/testing-guide/zustand-store-action-test.mdc +1 -1
- package/.cursor/rules/zustand-action-patterns.mdc +1 -1
- package/.cursor/rules/zustand-slice-organization.mdc +4 -4
- package/CHANGELOG.md +51 -0
- package/CLAUDE.md +1 -1
- package/GEMINI.md +1 -1
- package/changelog/v1.json +14 -0
- package/docs/development/database-schema.dbml +16 -0
- package/locales/en-US/chat.json +24 -0
- package/locales/en-US/setting.json +11 -0
- package/locales/zh-CN/chat.json +24 -0
- package/locales/zh-CN/setting.json +11 -0
- package/package.json +1 -1
- package/packages/builtin-tool-group-agent-builder/src/client/Inspector/BatchCreateAgents/index.tsx +2 -2
- package/packages/builtin-tool-group-agent-builder/src/client/Inspector/UpdateGroup/index.tsx +56 -56
- package/packages/builtin-tool-group-agent-builder/src/client/Render/BatchCreateAgents.tsx +3 -2
- package/packages/builtin-tool-group-agent-builder/src/executor.ts +2 -1
- package/packages/business/const/src/index.ts +3 -0
- package/packages/database/migrations/0069_add_topic_shares_table.sql +22 -0
- package/packages/database/migrations/meta/0069_snapshot.json +9704 -0
- package/packages/database/migrations/meta/_journal.json +7 -0
- package/packages/database/src/models/__tests__/topicShare.test.ts +318 -0
- package/packages/database/src/models/topicShare.ts +177 -0
- package/packages/database/src/schemas/topic.ts +44 -2
- package/packages/types/src/agentCronJob/index.ts +19 -23
- package/packages/types/src/conversation.ts +5 -0
- package/packages/types/src/serverConfig.ts +1 -0
- package/packages/types/src/topic/topic.ts +46 -0
- package/src/app/[variants]/(main)/agent/_layout/Sidebar/Cron/Actions.tsx +31 -0
- package/src/app/[variants]/(main)/agent/_layout/Sidebar/Cron/CronTopicGroup.tsx +10 -6
- package/src/app/[variants]/(main)/agent/_layout/Sidebar/Cron/index.tsx +7 -11
- package/src/app/[variants]/(main)/agent/_layout/Sidebar/Cron/useDropdownMenu.tsx +102 -0
- package/src/app/[variants]/(main)/agent/cron/[cronId]/CronConfig.ts +179 -0
- package/src/app/[variants]/(main)/agent/cron/[cronId]/features/CronJobContentEditor.tsx +111 -0
- package/src/app/[variants]/(main)/agent/cron/[cronId]/features/CronJobHeader.tsx +45 -0
- package/src/app/[variants]/(main)/agent/cron/[cronId]/features/CronJobSaveButton.tsx +31 -0
- package/src/app/[variants]/(main)/agent/cron/[cronId]/features/CronJobScheduleConfig.tsx +213 -0
- package/src/app/[variants]/(main)/agent/cron/[cronId]/index.tsx +186 -344
- package/src/app/[variants]/(main)/agent/features/Conversation/Header/ShareButton/index.tsx +24 -9
- package/src/app/[variants]/(main)/agent/profile/features/AgentCronJobs/index.tsx +42 -97
- package/src/app/[variants]/(main)/agent/profile/features/ProfileEditor/index.tsx +4 -20
- package/src/app/[variants]/(main)/community/features/UserAvatar/index.tsx +15 -5
- package/src/app/[variants]/(main)/group/_layout/Sidebar/GroupConfig/AgentProfilePopup.tsx +1 -6
- package/src/app/[variants]/(main)/group/features/Conversation/Header/ShareButton/index.tsx +26 -9
- package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/AspectRatioSelect/index.tsx +1 -2
- package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/ImageNum.tsx +54 -173
- package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/ResolutionSelect.tsx +22 -67
- package/src/app/[variants]/(mobile)/router/mobileRouter.config.tsx +18 -0
- package/src/app/[variants]/router/desktopRouter.config.tsx +18 -0
- package/src/app/[variants]/share/t/[id]/SharedMessageList.tsx +54 -0
- package/src/app/[variants]/share/t/[id]/_layout/index.tsx +170 -0
- package/src/app/[variants]/share/t/[id]/features/Portal/index.tsx +66 -0
- package/src/app/[variants]/share/t/[id]/index.tsx +112 -0
- package/src/app/robots.tsx +1 -1
- package/src/business/client/BusinessMobileRoutes.tsx +1 -1
- package/src/features/Conversation/ChatList/index.tsx +12 -5
- package/src/features/Conversation/Messages/AssistantGroup/Tool/Render/index.tsx +8 -4
- package/src/features/Conversation/Messages/AssistantGroup/Tool/index.tsx +15 -10
- package/src/features/Conversation/Messages/AssistantGroup/Tools.tsx +3 -1
- package/src/features/Conversation/Messages/AssistantGroup/components/ContentBlock.tsx +3 -2
- package/src/features/Conversation/Messages/AssistantGroup/components/GroupItem.tsx +2 -2
- package/src/features/Conversation/Messages/Supervisor/components/ContentBlock.tsx +25 -26
- package/src/features/Conversation/Messages/Supervisor/components/Group.tsx +4 -2
- package/src/features/Conversation/Messages/Tool/Tool/index.tsx +16 -12
- package/src/features/Conversation/Messages/Tool/index.tsx +20 -11
- package/src/features/Conversation/Messages/index.tsx +1 -1
- package/src/features/Conversation/store/slices/data/action.ts +2 -1
- package/src/features/SharePopover/index.tsx +215 -0
- package/src/features/SharePopover/style.ts +10 -0
- package/src/libs/next/proxy/define-config.ts +4 -1
- package/src/locales/default/chat.ts +26 -0
- package/src/proxy.ts +1 -0
- package/src/server/globalConfig/index.ts +1 -0
- package/src/server/routers/lambda/__tests__/message.test.ts +152 -0
- package/src/server/routers/lambda/__tests__/share.test.ts +227 -0
- package/src/server/routers/lambda/__tests__/topic.test.ts +174 -0
- package/src/server/routers/lambda/index.ts +2 -0
- package/src/server/routers/lambda/message.ts +37 -4
- package/src/server/routers/lambda/share.ts +55 -0
- package/src/server/routers/lambda/topic.ts +45 -0
- package/src/services/chatGroup/index.ts +1 -4
- package/src/services/message/index.ts +1 -0
- package/src/services/topic/index.ts +16 -0
- package/src/store/serverConfig/selectors.ts +1 -0
|
@@ -43,4 +43,4 @@ DROP TABLE "old_table";
|
|
|
43
43
|
CREATE INDEX "users_email_idx" ON "users" ("email");
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
**Important**: After modifying migration SQL (e.g., adding `IF NOT EXISTS` clauses), run `bun run db:generate
|
|
46
|
+
**Important**: After modifying migration SQL (e.g., adding `IF NOT EXISTS` clauses), run `bun run db:generate:client` to update the hash in `packages/database/src/core/migrations.json`.
|
|
@@ -3,9 +3,10 @@ description: 包含添加 console.log 日志请求时
|
|
|
3
3
|
globs:
|
|
4
4
|
alwaysApply: false
|
|
5
5
|
---
|
|
6
|
+
|
|
6
7
|
# Debug 包使用指南
|
|
7
8
|
|
|
8
|
-
本项目使用
|
|
9
|
+
本项目使用 `debug` 包进行调试日志记录。使用此规则来确保团队成员统一调试日志格式。
|
|
9
10
|
|
|
10
11
|
## 基本用法
|
|
11
12
|
|
|
@@ -15,14 +16,14 @@ alwaysApply: false
|
|
|
15
16
|
import debug from 'debug';
|
|
16
17
|
```
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
1. 创建一个命名空间的日志记录器:
|
|
19
20
|
|
|
20
21
|
```typescript
|
|
21
22
|
// 格式: lobe:[模块]:[子模块]
|
|
22
23
|
const log = debug('lobe-[模块名]:[子模块名]');
|
|
23
24
|
```
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
1. 使用日志记录器:
|
|
26
27
|
|
|
27
28
|
```typescript
|
|
28
29
|
log('简单消息');
|
|
@@ -46,7 +47,7 @@ log('格式化数字: %d', number);
|
|
|
46
47
|
|
|
47
48
|
## 示例
|
|
48
49
|
|
|
49
|
-
查看
|
|
50
|
+
查看 `src/server/routers/edge/market/index.ts` 中的使用示例:
|
|
50
51
|
|
|
51
52
|
```typescript
|
|
52
53
|
import debug from 'debug';
|
|
@@ -63,8 +64,9 @@ log('getAgent input: %O', input);
|
|
|
63
64
|
### 在浏览器中
|
|
64
65
|
|
|
65
66
|
在控制台执行:
|
|
67
|
+
|
|
66
68
|
```javascript
|
|
67
|
-
localStorage.debug = 'lobe-*'
|
|
69
|
+
localStorage.debug = 'lobe-*';
|
|
68
70
|
```
|
|
69
71
|
|
|
70
72
|
### 在 Node.js 环境中
|
|
@@ -3,13 +3,14 @@ description: 桌面端测试
|
|
|
3
3
|
globs:
|
|
4
4
|
alwaysApply: false
|
|
5
5
|
---
|
|
6
|
+
|
|
6
7
|
# 桌面端控制器单元测试指南
|
|
7
8
|
|
|
8
9
|
## 测试框架与目录结构
|
|
9
10
|
|
|
10
11
|
LobeChat 桌面端使用 Vitest 作为测试框架。控制器的单元测试应放置在对应控制器文件同级的 `__tests__` 目录下,并以原控制器文件名加 `.test.ts` 作为文件名。
|
|
11
12
|
|
|
12
|
-
```
|
|
13
|
+
```plaintext
|
|
13
14
|
apps/desktop/src/main/controllers/
|
|
14
15
|
├── __tests__/
|
|
15
16
|
│ ├── index.test.ts
|
|
@@ -3,7 +3,8 @@ description: 当要做 electron 相关工作时
|
|
|
3
3
|
globs:
|
|
4
4
|
alwaysApply: false
|
|
5
5
|
---
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
# 桌面端新功能实现指南
|
|
7
8
|
|
|
8
9
|
## 桌面端应用架构概述
|
|
9
10
|
|
|
@@ -26,6 +27,7 @@ LobeChat 桌面端基于 Electron 框架构建,采用主进程-渲染进程架
|
|
|
26
27
|
### 1. 确定功能需求与设计
|
|
27
28
|
|
|
28
29
|
首先确定新功能的需求和设计,包括:
|
|
30
|
+
|
|
29
31
|
- 功能描述和用例
|
|
30
32
|
- 是否需要系统级API(如文件系统、网络等)
|
|
31
33
|
- UI/UX设计(如必要)
|
|
@@ -64,9 +66,10 @@ LobeChat 桌面端基于 Electron 框架构建,采用主进程-渲染进程架
|
|
|
64
66
|
|
|
65
67
|
```typescript
|
|
66
68
|
// src/services/electron/newFeatureService.ts
|
|
67
|
-
import { ensureElectronIpc } from '@/utils/electron/ipc';
|
|
68
69
|
import type { NewFeatureParams } from '@lobechat/electron-client-ipc';
|
|
69
70
|
|
|
71
|
+
import { ensureElectronIpc } from '@/utils/electron/ipc';
|
|
72
|
+
|
|
70
73
|
const ipc = ensureElectronIpc();
|
|
71
74
|
|
|
72
75
|
export const newFeatureService = async (params: NewFeatureParams) => {
|
|
@@ -84,7 +87,7 @@ LobeChat 桌面端基于 Electron 框架构建,采用主进程-渲染进程架
|
|
|
84
87
|
|
|
85
88
|
### 5. 如果是新增内置工具,遵循工具实现流程
|
|
86
89
|
|
|
87
|
-
参考
|
|
90
|
+
参考 `desktop-local-tools-implement.mdc` 了解更多关于添加内置工具的详细步骤。
|
|
88
91
|
|
|
89
92
|
### 6. 添加测试
|
|
90
93
|
|
|
@@ -120,12 +123,13 @@ LobeChat 桌面端基于 Electron 框架构建,采用主进程-渲染进程架
|
|
|
120
123
|
|
|
121
124
|
```typescript
|
|
122
125
|
// apps/desktop/src/main/controllers/NotificationCtr.ts
|
|
123
|
-
import { Notification } from 'electron';
|
|
124
|
-
import { ControllerModule, IpcMethod } from '@/controllers';
|
|
125
126
|
import type {
|
|
126
127
|
DesktopNotificationResult,
|
|
127
128
|
ShowDesktopNotificationParams,
|
|
128
129
|
} from '@lobechat/electron-client-ipc';
|
|
130
|
+
import { Notification } from 'electron';
|
|
131
|
+
|
|
132
|
+
import { ControllerModule, IpcMethod } from '@/controllers';
|
|
129
133
|
|
|
130
134
|
export default class NotificationCtr extends ControllerModule {
|
|
131
135
|
static override readonly groupName = 'notification';
|
|
@@ -3,78 +3,79 @@ description:
|
|
|
3
3
|
globs:
|
|
4
4
|
alwaysApply: false
|
|
5
5
|
---
|
|
6
|
+
|
|
6
7
|
**新增桌面端工具流程:**
|
|
7
8
|
|
|
8
|
-
1.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
1. **定义工具接口 (Manifest):**
|
|
10
|
+
- **文件:** `src/tools/[tool_category]/index.ts` (例如: `src/tools/local-files/index.ts`)
|
|
11
|
+
- **操作:**
|
|
12
|
+
- 在 `ApiName` 对象(例如 `LocalFilesApiName`)中添加一个新的、唯一的 API 名称。
|
|
13
|
+
- 在 `Manifest` 对象(例如 `LocalFilesManifest`)的 `api` 数组中,新增一个对象来定义新工具的接口。
|
|
14
|
+
- **关键字段:**
|
|
15
|
+
- `name`: 使用上一步定义的 API 名称。
|
|
16
|
+
- `description`: 清晰描述工具的功能,供 Agent 理解和向用户展示。
|
|
17
|
+
- `parameters`: 使用 JSON Schema 定义工具所需的输入参数。
|
|
18
|
+
- `type`: 通常是 'object'。
|
|
19
|
+
- `properties`: 定义每个参数的名称、`description`、`type` (string, number, boolean, array, etc.),使用英文。
|
|
20
|
+
- `required`: 一个字符串数组,列出必须提供的参数名称。
|
|
20
21
|
|
|
21
|
-
2.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
2. **定义相关类型:**
|
|
23
|
+
- **文件 1:** `packages/electron-client-ipc/src/types.ts` (或类似的共享 IPC 类型文件)
|
|
24
|
+
- **操作:** 定义传递给 IPC 事件的参数类型接口 (例如: `RenameLocalFileParams`, `MoveLocalFileParams`)。确保与 Manifest 中定义的 `parameters` 一致。
|
|
25
|
+
- **文件 2:** `src/tools/[tool_category]/type.ts` (例如: `src/tools/local-files/type.ts`)
|
|
26
|
+
- **操作:** 定义此工具执行后,存储在前端 Zustand Store 中的状态类型接口 (例如: `LocalRenameFileState`, `LocalMoveFileState`)。这通常包含操作结果(成功/失败)、错误信息以及相关数据(如旧路径、新路径等)。
|
|
26
27
|
|
|
27
|
-
3.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
28
|
+
3. **实现前端状态管理 (Store Action):**
|
|
29
|
+
- **文件:** `src/store/chat/slices/builtinTool/actions/[tool_category].ts` (例如: `src/store/chat/slices/builtinTool/actions/localFile.ts`)
|
|
30
|
+
- **操作:**
|
|
31
|
+
- 导入在步骤 2 中定义的 IPC 参数类型和状态类型。
|
|
32
|
+
- 在 Action 接口 (例如: `LocalFileAction`) 中添加新 Action 的方法签名,使用对应的 IPC 参数类型。
|
|
33
|
+
- 在 `createSlice` (例如: `localFileSlice`) 中实现该 Action 方法:
|
|
34
|
+
- 接收 `id` (消息 ID) 和 `params` (符合 IPC 参数类型)。
|
|
35
|
+
- 设置加载状态 (`toggleLocalFileLoading(id, true)`)。
|
|
36
|
+
- 调用对应的 `Service` 层方法 (见步骤 4),传递 `params`。
|
|
37
|
+
- 使用 `try...catch` 处理 `Service` 调用可能发生的错误。
|
|
38
|
+
- **成功时:**
|
|
39
|
+
- 调用 `updatePluginState(id, {...})` 更新插件状态,使用步骤 2 中定义的状态类型。
|
|
40
|
+
- 调用 `internal_updateMessageContent(id, JSON.stringify({...}))` 更新消息内容,通常包含成功确认信息。
|
|
41
|
+
- **失败时:**
|
|
42
|
+
- 记录错误 (`console.error`)。
|
|
43
|
+
- 调用 `updatePluginState(id, {...})` 更新插件状态,包含错误信息。
|
|
44
|
+
- 调用 `internal_updateMessagePluginError(id, {...})` 设置消息的错误状态。
|
|
45
|
+
- 调用 `internal_updateMessageContent(id, JSON.stringify({...}))` 更新消息内容,包含错误信息。
|
|
46
|
+
- 在 `finally` 块中取消加载状态 (`toggleLocalFileLoading(id, false)`)。
|
|
47
|
+
- 返回操作是否成功 (`boolean`)。
|
|
47
48
|
|
|
48
|
-
4.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
49
|
+
4. **实现 Service 层 (调用 IPC):**
|
|
50
|
+
- **文件:** `src/services/electron/[tool_category]Service.ts` (例如: `src/services/electron/localFileService.ts`)
|
|
51
|
+
- **操作:**
|
|
52
|
+
- 导入在步骤 2 中定义的 IPC 参数类型。
|
|
53
|
+
- 添加一个新的 `async` 方法,方法名通常与 Action 名称对应 (例如: `renameLocalFile`)。
|
|
54
|
+
- 方法接收 `params` (符合 IPC 参数类型)。
|
|
55
|
+
- 通过 `ensureElectronIpc()` 获取 IPC 代理 (`const ipc = ensureElectronIpc();`),调用与 Manifest 中 `name` 字段匹配的链式方法,并将 `params` 传递过去。
|
|
56
|
+
- 定义方法的返回类型,通常是 `Promise<{ success: boolean; error?: string }>`,与后端 Controller 返回的结构一致。
|
|
56
57
|
|
|
57
|
-
5.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
58
|
+
5. **实现后端逻辑 (Controller / IPC Handler):**
|
|
59
|
+
- **文件:** `apps/desktop/src/main/controllers/[ToolName]Ctr.ts` (例如: `apps/desktop/src/main/controllers/LocalFileCtr.ts`)
|
|
60
|
+
- **操作:**
|
|
61
|
+
- 导入 Node.js 相关模块 (`fs`, `path` 等) 和 IPC 相关依赖 (`ControllerModule`, `IpcMethod`、参数类型等)。
|
|
62
|
+
- 添加一个新的 `async` 方法,方法名通常以 `handle` 开头 (例如: `handleRenameFile`)。
|
|
63
|
+
- 使用 `@IpcMethod()` 装饰器将此方法注册为对应 IPC 事件的处理器,确保方法名与 Manifest 中的 `name` 以及 Service 层的链式调用一致。
|
|
64
|
+
- 方法的参数应解构自 Service 层传递过来的对象,类型与步骤 2 中定义的 IPC 参数类型匹配。
|
|
65
|
+
- 实现核心业务逻辑:
|
|
66
|
+
- 进行必要的输入验证。
|
|
67
|
+
- 执行文件系统操作或其他后端任务 (例如: `fs.promises.rename`)。
|
|
68
|
+
- 使用 `try...catch` 捕获执行过程中的错误。
|
|
69
|
+
- 处理特定错误码 (`error.code`) 以提供更友好的错误消息。
|
|
70
|
+
- 返回一个包含 `success` (boolean) 和可选 `error` (string) 字段的对象。
|
|
70
71
|
|
|
71
|
-
6.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
6. **更新 Agent 文档 (System Role):**
|
|
73
|
+
- **文件:** `src/tools/[tool_category]/systemRole.ts` (例如: `src/tools/local-files/systemRole.ts`)
|
|
74
|
+
- **操作:**
|
|
75
|
+
- 在 `<core_capabilities>` 部分添加新工具的简要描述。
|
|
76
|
+
- 如果需要,更新 `<workflow>`。
|
|
77
|
+
- 在 `<tool_usage_guidelines>` 部分为新工具添加详细的使用说明,解释其参数、用途和预期行为。
|
|
78
|
+
- 如有必要,更新 `<security_considerations>`。
|
|
79
|
+
- 如有必要(例如工具返回了新的数据结构或路径),更新 `<response_format>` 中的示例。
|
|
79
80
|
|
|
80
81
|
通过遵循这些步骤,可以系统地将新的桌面端工具集成到 LobeChat 的插件系统中。
|
|
@@ -3,7 +3,8 @@ description:
|
|
|
3
3
|
globs:
|
|
4
4
|
alwaysApply: false
|
|
5
5
|
---
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
# 桌面端菜单配置指南
|
|
7
8
|
|
|
8
9
|
## 菜单系统概述
|
|
9
10
|
|
|
@@ -15,7 +16,7 @@ LobeChat 桌面应用有三种主要的菜单类型:
|
|
|
15
16
|
|
|
16
17
|
## 菜单相关文件结构
|
|
17
18
|
|
|
18
|
-
```
|
|
19
|
+
```plaintext
|
|
19
20
|
apps/desktop/src/main/
|
|
20
21
|
├── menus/ # 菜单定义
|
|
21
22
|
│ ├── appMenu.ts # 应用菜单配置
|
|
@@ -33,8 +34,9 @@ apps/desktop/src/main/
|
|
|
33
34
|
应用菜单在 `apps/desktop/src/main/menus/appMenu.ts` 中定义:
|
|
34
35
|
|
|
35
36
|
1. **导入依赖**
|
|
37
|
+
|
|
36
38
|
```typescript
|
|
37
|
-
import {
|
|
39
|
+
import { BrowserWindow, Menu, MenuItem, MenuItemConstructorOptions, app } from 'electron';
|
|
38
40
|
import { is } from 'electron-util';
|
|
39
41
|
```
|
|
40
42
|
|
|
@@ -43,6 +45,7 @@ apps/desktop/src/main/
|
|
|
43
45
|
- 每个菜单项可以包含:label, accelerator (快捷键), role, submenu, click 等属性
|
|
44
46
|
|
|
45
47
|
3. **创建菜单工厂函数**
|
|
48
|
+
|
|
46
49
|
```typescript
|
|
47
50
|
export const createAppMenu = (win: BrowserWindow) => {
|
|
48
51
|
const template = [
|
|
@@ -61,6 +64,7 @@ apps/desktop/src/main/
|
|
|
61
64
|
上下文菜单通常在特定元素上右键点击时显示:
|
|
62
65
|
|
|
63
66
|
1. **在主进程中定义菜单模板**
|
|
67
|
+
|
|
64
68
|
```typescript
|
|
65
69
|
// apps/desktop/src/main/menus/contextMenu.ts
|
|
66
70
|
export const createContextMenu = () => {
|
|
@@ -73,6 +77,7 @@ apps/desktop/src/main/
|
|
|
73
77
|
```
|
|
74
78
|
|
|
75
79
|
2. **在适当的事件处理器中显示菜单**
|
|
80
|
+
|
|
76
81
|
```typescript
|
|
77
82
|
const menu = createContextMenu();
|
|
78
83
|
menu.popup();
|
|
@@ -83,11 +88,13 @@ apps/desktop/src/main/
|
|
|
83
88
|
托盘菜单在 `TrayMenuCtr.ts` 中配置:
|
|
84
89
|
|
|
85
90
|
1. **创建托盘图标**
|
|
91
|
+
|
|
86
92
|
```typescript
|
|
87
93
|
this.tray = new Tray(trayIconPath);
|
|
88
94
|
```
|
|
89
95
|
|
|
90
96
|
2. **定义托盘菜单**
|
|
97
|
+
|
|
91
98
|
```typescript
|
|
92
99
|
const contextMenu = Menu.buildFromTemplate([
|
|
93
100
|
{ label: '显示主窗口', click: this.showMainWindow },
|
|
@@ -97,6 +104,7 @@ apps/desktop/src/main/
|
|
|
97
104
|
```
|
|
98
105
|
|
|
99
106
|
3. **设置托盘菜单**
|
|
107
|
+
|
|
100
108
|
```typescript
|
|
101
109
|
this.tray.setContextMenu(contextMenu);
|
|
102
110
|
```
|
|
@@ -106,11 +114,13 @@ apps/desktop/src/main/
|
|
|
106
114
|
为菜单添加多语言支持:
|
|
107
115
|
|
|
108
116
|
1. **导入本地化工具**
|
|
117
|
+
|
|
109
118
|
```typescript
|
|
110
119
|
import { i18n } from '../locales';
|
|
111
120
|
```
|
|
112
121
|
|
|
113
122
|
2. **使用翻译函数**
|
|
123
|
+
|
|
114
124
|
```typescript
|
|
115
125
|
const template = [
|
|
116
126
|
{
|
|
@@ -118,14 +128,13 @@ apps/desktop/src/main/
|
|
|
118
128
|
submenu: [
|
|
119
129
|
{ label: i18n.t('menu.new'), click: createNew },
|
|
120
130
|
// ...
|
|
121
|
-
]
|
|
131
|
+
],
|
|
122
132
|
},
|
|
123
133
|
// ...
|
|
124
134
|
];
|
|
125
135
|
```
|
|
126
136
|
|
|
127
|
-
3. **在语言切换时更新菜单**
|
|
128
|
-
在 `MenuCtr.ts` 中监听语言变化事件并重新创建菜单
|
|
137
|
+
3. **在语言切换时更新菜单** 在 `MenuCtr.ts` 中监听语言变化事件并重新创建菜单
|
|
129
138
|
|
|
130
139
|
## 添加新菜单项流程
|
|
131
140
|
|
|
@@ -134,6 +143,7 @@ apps/desktop/src/main/
|
|
|
134
143
|
- 确定在菜单中的位置(主菜单项或子菜单项)
|
|
135
144
|
|
|
136
145
|
2. **定义菜单项**
|
|
146
|
+
|
|
137
147
|
```typescript
|
|
138
148
|
const newMenuItem: MenuItemConstructorOptions = {
|
|
139
149
|
label: '新功能',
|
|
@@ -141,12 +151,11 @@ apps/desktop/src/main/
|
|
|
141
151
|
click: (_, window) => {
|
|
142
152
|
// 处理点击事件
|
|
143
153
|
if (window) window.webContents.send('trigger-new-feature');
|
|
144
|
-
}
|
|
154
|
+
},
|
|
145
155
|
};
|
|
146
156
|
```
|
|
147
157
|
|
|
148
|
-
3. **添加到菜单模板**
|
|
149
|
-
将新菜单项添加到相应的菜单模板中
|
|
158
|
+
3. **添加到菜单模板** 将新菜单项添加到相应的菜单模板中
|
|
150
159
|
|
|
151
160
|
4. **对于与渲染进程交互的功能**
|
|
152
161
|
- 使用 `window.webContents.send()` 发送 IPC 消息到渲染进程
|
|
@@ -157,6 +166,7 @@ apps/desktop/src/main/
|
|
|
157
166
|
动态控制菜单项状态:
|
|
158
167
|
|
|
159
168
|
1. **保存对菜单项的引用**
|
|
169
|
+
|
|
160
170
|
```typescript
|
|
161
171
|
this.menuItems = {};
|
|
162
172
|
const menu = Menu.buildFromTemplate(template);
|
|
@@ -164,6 +174,7 @@ apps/desktop/src/main/
|
|
|
164
174
|
```
|
|
165
175
|
|
|
166
176
|
2. **根据条件更新状态**
|
|
177
|
+
|
|
167
178
|
```typescript
|
|
168
179
|
updateMenuState(state) {
|
|
169
180
|
if (this.menuItems.newFeature) {
|
|
@@ -179,6 +190,7 @@ apps/desktop/src/main/
|
|
|
179
190
|
|
|
180
191
|
2. **平台特定菜单**
|
|
181
192
|
- 使用 `process.platform` 检查为不同平台提供不同菜单
|
|
193
|
+
|
|
182
194
|
```typescript
|
|
183
195
|
if (process.platform === 'darwin') {
|
|
184
196
|
template.unshift({ role: 'appMenu' });
|
|
@@ -3,7 +3,8 @@ description:
|
|
|
3
3
|
globs:
|
|
4
4
|
alwaysApply: false
|
|
5
5
|
---
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
# 桌面端窗口管理指南
|
|
7
8
|
|
|
8
9
|
## 窗口管理概述
|
|
9
10
|
|
|
@@ -16,7 +17,7 @@ LobeChat 桌面应用使用 Electron 的 `BrowserWindow` 管理应用窗口。
|
|
|
16
17
|
|
|
17
18
|
## 相关文件结构
|
|
18
19
|
|
|
19
|
-
```
|
|
20
|
+
```plaintext
|
|
20
21
|
apps/desktop/src/main/
|
|
21
22
|
├── appBrowsers.ts # 窗口管理的核心文件
|
|
22
23
|
├── controllers/
|
|
@@ -63,6 +64,7 @@ export const createMainWindow = () => {
|
|
|
63
64
|
实现窗口状态持久化保存和恢复:
|
|
64
65
|
|
|
65
66
|
1. **保存窗口状态**
|
|
67
|
+
|
|
66
68
|
```typescript
|
|
67
69
|
const saveWindowState = (window: BrowserWindow) => {
|
|
68
70
|
if (!window.isMinimized() && !window.isMaximized()) {
|
|
@@ -80,6 +82,7 @@ export const createMainWindow = () => {
|
|
|
80
82
|
```
|
|
81
83
|
|
|
82
84
|
2. **恢复窗口状态**
|
|
85
|
+
|
|
83
86
|
```typescript
|
|
84
87
|
const restoreWindowState = (window: BrowserWindow) => {
|
|
85
88
|
const savedState = settings.get('windowState');
|
|
@@ -96,6 +99,7 @@ export const createMainWindow = () => {
|
|
|
96
99
|
```
|
|
97
100
|
|
|
98
101
|
3. **监听窗口事件**
|
|
102
|
+
|
|
99
103
|
```typescript
|
|
100
104
|
window.on('close', () => saveWindowState(window));
|
|
101
105
|
window.on('moved', () => saveWindowState(window));
|
|
@@ -107,6 +111,7 @@ export const createMainWindow = () => {
|
|
|
107
111
|
对于需要多窗口支持的功能:
|
|
108
112
|
|
|
109
113
|
1. **跟踪窗口**
|
|
114
|
+
|
|
110
115
|
```typescript
|
|
111
116
|
export class WindowManager {
|
|
112
117
|
private windows: Map<string, BrowserWindow> = new Map();
|
|
@@ -133,6 +138,7 @@ export const createMainWindow = () => {
|
|
|
133
138
|
```
|
|
134
139
|
|
|
135
140
|
2. **窗口间通信**
|
|
141
|
+
|
|
136
142
|
```typescript
|
|
137
143
|
// 从一个窗口向另一个窗口发送消息
|
|
138
144
|
sendMessageToWindow(targetWindowId, channel, data) {
|
|
@@ -148,9 +154,11 @@ export const createMainWindow = () => {
|
|
|
148
154
|
通过 IPC 实现窗口操作:
|
|
149
155
|
|
|
150
156
|
1. **在主进程中注册 IPC 处理器**
|
|
157
|
+
|
|
151
158
|
```typescript
|
|
152
159
|
// apps/desktop/src/main/controllers/BrowserWindowsCtr.ts
|
|
153
160
|
import { BrowserWindow } from 'electron';
|
|
161
|
+
|
|
154
162
|
import { ControllerModule, IpcMethod } from '@/controllers';
|
|
155
163
|
|
|
156
164
|
export default class BrowserWindowsCtr extends ControllerModule {
|
|
@@ -178,10 +186,12 @@ export const createMainWindow = () => {
|
|
|
178
186
|
}
|
|
179
187
|
}
|
|
180
188
|
```
|
|
189
|
+
|
|
181
190
|
- `@IpcMethod()` 根据控制器的 `groupName` 自动将方法映射为 `windows.minimizeWindow` 形式的通道名称。
|
|
182
191
|
- 控制器需继承 `ControllerModule`,并在 `controllers/registry.ts` 中通过 `controllerIpcConstructors` 注册,便于类型生成。
|
|
183
192
|
|
|
184
193
|
2. **在渲染进程中调用**
|
|
194
|
+
|
|
185
195
|
```typescript
|
|
186
196
|
// src/services/electron/windowService.ts
|
|
187
197
|
import { ensureElectronIpc } from '@/utils/electron/ipc';
|
|
@@ -194,6 +204,7 @@ export const createMainWindow = () => {
|
|
|
194
204
|
close: () => ipc.windows.closeWindow(),
|
|
195
205
|
};
|
|
196
206
|
```
|
|
207
|
+
|
|
197
208
|
- `ensureElectronIpc()` 会基于 `DesktopIpcServices` 运行时生成 Proxy,并通过 `window.electronAPI.invoke` 与主进程通信;不再直接使用 `dispatch`。
|
|
198
209
|
|
|
199
210
|
### 5. 自定义窗口控制 (无边框窗口)
|
|
@@ -201,6 +212,7 @@ export const createMainWindow = () => {
|
|
|
201
212
|
对于自定义窗口标题栏:
|
|
202
213
|
|
|
203
214
|
1. **创建无边框窗口**
|
|
215
|
+
|
|
204
216
|
```typescript
|
|
205
217
|
const window = new BrowserWindow({
|
|
206
218
|
frame: false,
|
|
@@ -210,6 +222,7 @@ export const createMainWindow = () => {
|
|
|
210
222
|
```
|
|
211
223
|
|
|
212
224
|
2. **在渲染进程中实现拖拽区域**
|
|
225
|
+
|
|
213
226
|
```css
|
|
214
227
|
/* CSS */
|
|
215
228
|
.titlebar {
|
|
@@ -229,6 +242,7 @@ export const createMainWindow = () => {
|
|
|
229
242
|
|
|
230
243
|
2. **安全性**
|
|
231
244
|
- 始终设置适当的 `webPreferences` 确保安全
|
|
245
|
+
|
|
232
246
|
```typescript
|
|
233
247
|
webPreferences: {
|
|
234
248
|
preload: path.join(__dirname, '../preload/index.js'),
|
|
@@ -255,6 +269,7 @@ export const createMainWindow = () => {
|
|
|
255
269
|
```typescript
|
|
256
270
|
// apps/desktop/src/main/controllers/BrowserWindowsCtr.ts
|
|
257
271
|
import type { OpenSettingsWindowOptions } from '@lobechat/electron-client-ipc';
|
|
272
|
+
|
|
258
273
|
import { ControllerModule, IpcMethod } from '@/controllers';
|
|
259
274
|
|
|
260
275
|
export default class BrowserWindowsCtr extends ControllerModule {
|
|
@@ -10,14 +10,14 @@ This document outlines the conventions and best practices for defining PostgreSQ
|
|
|
10
10
|
|
|
11
11
|
## Configuration
|
|
12
12
|
|
|
13
|
-
- Drizzle configuration is managed in
|
|
13
|
+
- Drizzle configuration is managed in `drizzle.config.ts`
|
|
14
14
|
- Schema files are located in the src/database/schemas/ directory
|
|
15
15
|
- Migration files are output to `src/database/migrations/`
|
|
16
16
|
- The project uses `postgresql` dialect with `strict: true`
|
|
17
17
|
|
|
18
18
|
## Helper Functions
|
|
19
19
|
|
|
20
|
-
Commonly used column definitions, especially for timestamps, are centralized in
|
|
20
|
+
Commonly used column definitions, especially for timestamps, are centralized in `src/database/schemas/_helpers.ts`:
|
|
21
21
|
|
|
22
22
|
- `timestamptz(name: string)`: Creates a timestamp column with timezone
|
|
23
23
|
- `createdAt()`, `updatedAt()`, `accessedAt()`: Helper functions for standard timestamp columns
|
|
@@ -46,7 +46,7 @@ Commonly used column definitions, especially for timestamps, are centralized in
|
|
|
46
46
|
|
|
47
47
|
### Timestamps
|
|
48
48
|
|
|
49
|
-
- Consistently use the `...timestamps` spread from
|
|
49
|
+
- Consistently use the `...timestamps` spread from `_helpers.ts` for `created_at`, `updated_at`, and `accessed_at` columns
|
|
50
50
|
|
|
51
51
|
### Default Values
|
|
52
52
|
|
|
@@ -74,12 +74,12 @@ Commonly used column definitions, especially for timestamps, are centralized in
|
|
|
74
74
|
|
|
75
75
|
## Relations
|
|
76
76
|
|
|
77
|
-
- Table relationships are defined centrally in
|
|
77
|
+
- Table relationships are defined centrally in `src/database/schemas/relations.ts` using the `relations()` utility from `drizzle-orm`
|
|
78
78
|
|
|
79
79
|
## Code Style & Structure
|
|
80
80
|
|
|
81
|
-
- **File Organization**: Each main database entity typically has its own schema file (e.g.,
|
|
82
|
-
- All schemas are re-exported from
|
|
81
|
+
- **File Organization**: Each main database entity typically has its own schema file (e.g., `user.ts`, `agent.ts`)
|
|
82
|
+
- All schemas are re-exported from `src/database/schemas/index.ts`
|
|
83
83
|
- **ESLint**: Files often start with `/* eslint-disable sort-keys-fix/sort-keys-fix */`
|
|
84
84
|
- **Comments**: Use JSDoc-style comments to explain the purpose of tables and complex columns, fields that are self-explanatory do not require jsdoc explanations, such as id, user_id, etc.
|
|
85
85
|
|
package/.cursor/rules/hotkey.mdc
CHANGED
package/.cursor/rules/i18n.mdc
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
alwaysApply: false
|
|
2
|
+
alwaysApply: true
|
|
4
3
|
---
|
|
5
4
|
|
|
6
5
|
# LobeChat Project Structure
|
|
@@ -27,6 +26,11 @@ lobe-chat/
|
|
|
27
26
|
│ ├── agent-runtime/
|
|
28
27
|
│ ├── builtin-agents/
|
|
29
28
|
│ ├── builtin-tool-*/ # builtin tool packages
|
|
29
|
+
│ ├── business/ # cloud-only business logic packages
|
|
30
|
+
│ │ ├── config/
|
|
31
|
+
│ │ ├── const/
|
|
32
|
+
│ │ └── model-runtime/
|
|
33
|
+
│ ├── config/
|
|
30
34
|
│ ├── const/
|
|
31
35
|
│ ├── context-engine/
|
|
32
36
|
│ ├── conversation-flow/
|
|
@@ -36,6 +40,8 @@ lobe-chat/
|
|
|
36
40
|
│ │ ├── schemas/
|
|
37
41
|
│ │ └── repositories/
|
|
38
42
|
│ ├── desktop-bridge/
|
|
43
|
+
│ ├── edge-config/
|
|
44
|
+
│ ├── editor-runtime/
|
|
39
45
|
│ ├── electron-client-ipc/
|
|
40
46
|
│ ├── electron-server-ipc/
|
|
41
47
|
│ ├── fetch-sse/
|
|
@@ -46,7 +52,7 @@ lobe-chat/
|
|
|
46
52
|
│ │ └── src/
|
|
47
53
|
│ │ ├── core/
|
|
48
54
|
│ │ └── providers/
|
|
49
|
-
│ ├──
|
|
55
|
+
│ ├── observability-otel/
|
|
50
56
|
│ ├── prompts/
|
|
51
57
|
│ ├── python-interpreter/
|
|
52
58
|
│ ├── ssrf-safe-fetch/
|
|
@@ -72,6 +78,10 @@ lobe-chat/
|
|
|
72
78
|
│ │ │ ├── onboarding/
|
|
73
79
|
│ │ │ └── router/
|
|
74
80
|
│ │ └── desktop/
|
|
81
|
+
│ ├── business/ # cloud-only business logic (client/server)
|
|
82
|
+
│ │ ├── client/
|
|
83
|
+
│ │ ├── locales/
|
|
84
|
+
│ │ └── server/
|
|
75
85
|
│ ├── components/
|
|
76
86
|
│ ├── config/
|
|
77
87
|
│ ├── const/
|
|
@@ -130,6 +140,9 @@ lobe-chat/
|
|
|
130
140
|
- Repository (bff-queries): `packages/database/src/repositories`
|
|
131
141
|
- Third-party Integrations: `src/libs` — analytics, oidc etc.
|
|
132
142
|
- Builtin Tools: `src/tools`, `packages/builtin-tool-*`
|
|
143
|
+
- Business (cloud-only): Code specific to LobeHub cloud service, only expose empty interfaces for opens-source version.
|
|
144
|
+
- `src/business/*`
|
|
145
|
+
- `packages/business/*`
|
|
133
146
|
|
|
134
147
|
## Data Flow Architecture
|
|
135
148
|
|