@lobehub/lobehub 2.0.0-next.353 → 2.0.0-next.355
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/.agents/skills/add-provider-doc/SKILL.md +90 -0
- package/.agents/skills/add-setting-env/SKILL.md +106 -0
- package/.agents/skills/debug/SKILL.md +66 -0
- package/.agents/skills/desktop/SKILL.md +78 -0
- package/.agents/skills/desktop/references/feature-implementation.md +99 -0
- package/.agents/skills/desktop/references/local-tools.md +133 -0
- package/.agents/skills/desktop/references/menu-config.md +103 -0
- package/.agents/skills/desktop/references/window-management.md +143 -0
- package/.agents/skills/drizzle/SKILL.md +129 -0
- package/.agents/skills/drizzle/references/db-migrations.md +50 -0
- package/.agents/skills/hotkey/SKILL.md +90 -0
- package/{.cursor/rules/i18n.mdc → .agents/skills/i18n/SKILL.md} +14 -23
- package/.agents/skills/linear/SKILL.md +51 -0
- package/.agents/skills/microcopy/SKILL.md +83 -0
- package/.agents/skills/modal/SKILL.md +102 -0
- package/{.cursor/rules/project-structure.mdc → .agents/skills/project-overview/SKILL.md} +65 -37
- package/.agents/skills/react/SKILL.md +73 -0
- package/.agents/skills/react/references/layout-kit.md +100 -0
- package/.agents/skills/recent-data/SKILL.md +108 -0
- package/.agents/skills/testing/SKILL.md +89 -0
- package/.agents/skills/testing/references/agent-runtime-e2e.md +126 -0
- package/.agents/skills/testing/references/db-model-test.md +124 -0
- package/.agents/skills/testing/references/desktop-controller-test.md +124 -0
- package/.agents/skills/testing/references/electron-ipc-test.md +63 -0
- package/.agents/skills/testing/references/zustand-store-action-test.md +150 -0
- package/.agents/skills/typescript/SKILL.md +52 -0
- package/.agents/skills/zustand/SKILL.md +78 -0
- package/.agents/skills/zustand/references/action-patterns.md +125 -0
- package/.agents/skills/zustand/references/slice-organization.md +125 -0
- package/AGENTS.md +42 -55
- package/CHANGELOG.md +60 -0
- package/CLAUDE.md +57 -46
- package/GEMINI.md +47 -39
- package/changelog/v1.json +18 -0
- package/locales/en-US/plugin.json +3 -0
- package/locales/zh-CN/plugin.json +3 -0
- package/package.json +1 -1
- package/packages/builtin-tool-memory/src/client/Render/SearchUserMemory/index.tsx +3 -11
- package/packages/context-engine/src/engine/messages/MessagesEngine.ts +0 -13
- package/packages/context-engine/src/engine/messages/__tests__/MessagesEngine.test.ts +0 -25
- package/packages/database/src/models/__tests__/topics/topic.create.test.ts +3 -3
- package/src/app/[variants]/(main)/agent/_layout/Sidebar/Topic/List/Item/index.tsx +1 -0
- package/src/app/[variants]/(main)/agent/features/Conversation/ConversationArea.tsx +4 -0
- package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/List/Item/index.tsx +1 -0
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/AgentItem/index.tsx +1 -1
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/InboxItem.tsx +19 -29
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/List.tsx +1 -1
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/ModalProvider.tsx +1 -1
- package/src/features/FileViewer/Renderer/PDF/index.tsx +2 -3
- package/src/features/ShareModal/SharePdf/PdfPreview.tsx +1 -2
- package/src/libs/pdfjs/index.tsx +25 -0
- package/src/locales/default/plugin.ts +3 -0
- package/src/server/modules/Mecha/ContextEngineering/__tests__/serverMessagesEngine.test.ts +0 -25
- package/src/services/chat/chat.test.ts +19 -19
- package/src/services/chat/index.ts +8 -3
- package/src/services/chat/mecha/agentConfigResolver.test.ts +72 -55
- package/src/services/chat/mecha/agentConfigResolver.ts +28 -4
- package/src/services/chat/mecha/contextEngineering.test.ts +21 -14
- package/src/services/chat/mecha/contextEngineering.ts +12 -0
- package/src/services/chat/types.ts +7 -1
- package/src/store/chat/agents/createAgentExecutors.ts +15 -4
- package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +1 -0
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +6 -2
- package/src/store/test-coverage.md +5 -5
- package/.cursor/rules/add-provider-doc.mdc +0 -183
- package/.cursor/rules/add-setting-env.mdc +0 -175
- package/.cursor/rules/cursor-rules.mdc +0 -28
- package/.cursor/rules/db-migrations.mdc +0 -46
- package/.cursor/rules/debug-usage.mdc +0 -86
- package/.cursor/rules/desktop-controller-tests.mdc +0 -189
- package/.cursor/rules/desktop-feature-implementation.mdc +0 -155
- package/.cursor/rules/desktop-local-tools-implement.mdc +0 -81
- package/.cursor/rules/desktop-menu-configuration.mdc +0 -209
- package/.cursor/rules/desktop-window-management.mdc +0 -301
- package/.cursor/rules/drizzle-schema-style-guide.mdc +0 -218
- package/.cursor/rules/hotkey.mdc +0 -162
- package/.cursor/rules/linear.mdc +0 -53
- package/.cursor/rules/microcopy-cn.mdc +0 -158
- package/.cursor/rules/microcopy-en.mdc +0 -148
- package/.cursor/rules/modal-imperative.mdc +0 -162
- package/.cursor/rules/packages/react-layout-kit.mdc +0 -122
- package/.cursor/rules/project-introduce.mdc +0 -36
- package/.cursor/rules/react.mdc +0 -169
- package/.cursor/rules/recent-data-usage.mdc +0 -139
- package/.cursor/rules/rules-index.mdc +0 -44
- package/.cursor/rules/testing-guide/agent-runtime-e2e.mdc +0 -285
- package/.cursor/rules/testing-guide/db-model-test.mdc +0 -455
- package/.cursor/rules/testing-guide/electron-ipc-test.mdc +0 -80
- package/.cursor/rules/testing-guide/testing-guide.mdc +0 -534
- package/.cursor/rules/testing-guide/zustand-store-action-test.mdc +0 -574
- package/.cursor/rules/typescript.mdc +0 -55
- package/.cursor/rules/zustand-action-patterns.mdc +0 -328
- package/.cursor/rules/zustand-slice-organization.mdc +0 -308
- package/src/libs/pdfjs/pdf.worker.ts +0 -1
- package/src/libs/pdfjs/worker.ts +0 -12
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/AGENTS.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/SKILL.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/advanced-event-handler-refs.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/advanced-use-latest.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/async-api-routes.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/async-defer-await.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/async-dependencies.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/async-parallel.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/async-suspense-boundaries.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/bundle-barrel-imports.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/bundle-conditional.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/bundle-defer-third-party.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/bundle-dynamic-imports.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/bundle-preload.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/client-event-listeners.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/client-localstorage-schema.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/client-passive-event-listeners.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/client-swr-dedup.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-batch-dom-css.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-cache-function-results.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-cache-property-access.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-cache-storage.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-combine-iterations.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-early-exit.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-hoist-regexp.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-index-maps.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-length-check-first.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-min-max-loop.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-set-map-lookups.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-tosorted-immutable.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-activity.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-animate-svg-wrapper.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-conditional-render.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-content-visibility.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-hoist-jsx.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-hydration-no-flicker.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-svg-precision.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-defer-reads.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-dependencies.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-derived-state.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-functional-setstate.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-lazy-state-init.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-memo.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-transitions.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/server-after-nonblocking.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/server-cache-lru.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/server-cache-react.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/server-parallel-fetching.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/server-serialization.md +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: add-provider-doc
|
|
3
|
+
description: Guide for adding new AI provider documentation. Use when adding documentation for a new AI provider (like OpenAI, Anthropic, etc.), including usage docs, environment variables, Docker config, and image resources. Triggers on provider documentation tasks.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Adding New AI Provider Documentation
|
|
7
|
+
|
|
8
|
+
Complete workflow for adding documentation for a new AI provider.
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
1. Create usage documentation (EN + CN)
|
|
13
|
+
2. Add environment variable documentation (EN + CN)
|
|
14
|
+
3. Update Docker configuration files
|
|
15
|
+
4. Update .env.example
|
|
16
|
+
5. Prepare image resources
|
|
17
|
+
|
|
18
|
+
## Step 1: Create Provider Usage Documentation
|
|
19
|
+
|
|
20
|
+
### Required Files
|
|
21
|
+
|
|
22
|
+
- `docs/usage/providers/{provider-name}.mdx` (English)
|
|
23
|
+
- `docs/usage/providers/{provider-name}.zh-CN.mdx` (Chinese)
|
|
24
|
+
|
|
25
|
+
### Key Requirements
|
|
26
|
+
|
|
27
|
+
- 5-6 screenshots showing the process
|
|
28
|
+
- Cover image for the provider
|
|
29
|
+
- Real registration and dashboard URLs
|
|
30
|
+
- Pricing information callout
|
|
31
|
+
- **Never include real API keys** - use placeholders
|
|
32
|
+
|
|
33
|
+
Reference: `docs/usage/providers/fal.mdx`
|
|
34
|
+
|
|
35
|
+
## Step 2: Update Environment Variables Documentation
|
|
36
|
+
|
|
37
|
+
### Files to Update
|
|
38
|
+
|
|
39
|
+
- `docs/self-hosting/environment-variables/model-provider.mdx` (EN)
|
|
40
|
+
- `docs/self-hosting/environment-variables/model-provider.zh-CN.mdx` (CN)
|
|
41
|
+
|
|
42
|
+
### Content Format
|
|
43
|
+
|
|
44
|
+
```markdown
|
|
45
|
+
### `{PROVIDER}_API_KEY`
|
|
46
|
+
- Type: Required
|
|
47
|
+
- Description: API key from {Provider Name}
|
|
48
|
+
- Example: `{api-key-format}`
|
|
49
|
+
|
|
50
|
+
### `{PROVIDER}_MODEL_LIST`
|
|
51
|
+
- Type: Optional
|
|
52
|
+
- Description: Control model list. Use `+` to add, `-` to hide
|
|
53
|
+
- Example: `-all,+model-1,+model-2=Display Name`
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Step 3: Update Docker Files
|
|
57
|
+
|
|
58
|
+
Update all Dockerfiles at the **end** of ENV section:
|
|
59
|
+
|
|
60
|
+
- `Dockerfile`
|
|
61
|
+
- `Dockerfile.database`
|
|
62
|
+
- `Dockerfile.pglite`
|
|
63
|
+
|
|
64
|
+
```dockerfile
|
|
65
|
+
# {New Provider}
|
|
66
|
+
{PROVIDER}_API_KEY="" {PROVIDER}_MODEL_LIST=""
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Step 4: Update .env.example
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
### {Provider Name} ###
|
|
73
|
+
# {PROVIDER}_API_KEY={prefix}-xxxxxxxx
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Step 5: Image Resources
|
|
77
|
+
|
|
78
|
+
- Cover image
|
|
79
|
+
- 3-4 API dashboard screenshots
|
|
80
|
+
- 2-3 LobeChat configuration screenshots
|
|
81
|
+
- Host on LobeHub CDN: `hub-apac-1.lobeobjects.space`
|
|
82
|
+
|
|
83
|
+
## Checklist
|
|
84
|
+
|
|
85
|
+
- [ ] EN + CN usage docs
|
|
86
|
+
- [ ] EN + CN env var docs
|
|
87
|
+
- [ ] All 3 Dockerfiles updated
|
|
88
|
+
- [ ] .env.example updated
|
|
89
|
+
- [ ] All images prepared
|
|
90
|
+
- [ ] No real API keys in docs
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: add-setting-env
|
|
3
|
+
description: Guide for adding environment variables to configure user settings. Use when implementing server-side environment variables that control default values for user settings. Triggers on env var configuration or setting default value tasks.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Adding Environment Variable for User Settings
|
|
7
|
+
|
|
8
|
+
Add server-side environment variables to configure default values for user settings.
|
|
9
|
+
|
|
10
|
+
**Priority**: User Custom > Server Env Var > Hardcoded Default
|
|
11
|
+
|
|
12
|
+
## Steps
|
|
13
|
+
|
|
14
|
+
### 1. Define Environment Variable
|
|
15
|
+
|
|
16
|
+
Create `src/envs/<domain>.ts`:
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { createEnv } from '@t3-oss/env-nextjs';
|
|
20
|
+
import { z } from 'zod';
|
|
21
|
+
|
|
22
|
+
export const get<Domain>Config = () => {
|
|
23
|
+
return createEnv({
|
|
24
|
+
server: {
|
|
25
|
+
YOUR_ENV_VAR: z.coerce.number().min(MIN).max(MAX).optional(),
|
|
26
|
+
},
|
|
27
|
+
runtimeEnv: {
|
|
28
|
+
YOUR_ENV_VAR: process.env.YOUR_ENV_VAR,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const <domain>Env = get<Domain>Config();
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 2. Update Type (if new domain)
|
|
37
|
+
|
|
38
|
+
Add to `packages/types/src/serverConfig.ts`:
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { User<Domain>Config } from './user/settings';
|
|
42
|
+
|
|
43
|
+
export interface GlobalServerConfig {
|
|
44
|
+
<domain>?: PartialDeep<User<Domain>Config>;
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Prefer reusing existing types** from `packages/types/src/user/settings`.
|
|
49
|
+
|
|
50
|
+
### 3. Assemble Server Config (if new domain)
|
|
51
|
+
|
|
52
|
+
In `src/server/globalConfig/index.ts`:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { <domain>Env } from '@/envs/<domain>';
|
|
56
|
+
|
|
57
|
+
export const getServerGlobalConfig = async () => {
|
|
58
|
+
const config: GlobalServerConfig = {
|
|
59
|
+
<domain>: cleanObject({
|
|
60
|
+
<settingName>: <domain>Env.YOUR_ENV_VAR,
|
|
61
|
+
}),
|
|
62
|
+
};
|
|
63
|
+
return config;
|
|
64
|
+
};
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 4. Merge to User Store (if new domain)
|
|
68
|
+
|
|
69
|
+
In `src/store/user/slices/common/action.ts`:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
const serverSettings: PartialDeep<UserSettings> = {
|
|
73
|
+
<domain>: serverConfig.<domain>,
|
|
74
|
+
};
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 5. Update .env.example
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# <Description> (range/options, default: X)
|
|
81
|
+
# YOUR_ENV_VAR=<example>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 6. Update Documentation
|
|
85
|
+
|
|
86
|
+
- `docs/self-hosting/environment-variables/basic.mdx` (EN)
|
|
87
|
+
- `docs/self-hosting/environment-variables/basic.zh-CN.mdx` (CN)
|
|
88
|
+
|
|
89
|
+
## Example: AI_IMAGE_DEFAULT_IMAGE_NUM
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
// src/envs/image.ts
|
|
93
|
+
AI_IMAGE_DEFAULT_IMAGE_NUM: z.coerce.number().min(1).max(20).optional(),
|
|
94
|
+
|
|
95
|
+
// packages/types/src/serverConfig.ts
|
|
96
|
+
image?: PartialDeep<UserImageConfig>;
|
|
97
|
+
|
|
98
|
+
// src/server/globalConfig/index.ts
|
|
99
|
+
image: cleanObject({ defaultImageNum: imageEnv.AI_IMAGE_DEFAULT_IMAGE_NUM }),
|
|
100
|
+
|
|
101
|
+
// src/store/user/slices/common/action.ts
|
|
102
|
+
image: serverConfig.image,
|
|
103
|
+
|
|
104
|
+
// .env.example
|
|
105
|
+
# AI_IMAGE_DEFAULT_IMAGE_NUM=4
|
|
106
|
+
```
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: debug
|
|
3
|
+
description: Debug package usage guide. Use when adding debug logging, understanding log namespaces, or implementing debugging features. Triggers on debug logging requests or logging implementation.
|
|
4
|
+
user-invocable: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Debug Package Usage Guide
|
|
8
|
+
|
|
9
|
+
## Basic Usage
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import debug from 'debug';
|
|
13
|
+
|
|
14
|
+
// Format: lobe-[module]:[submodule]
|
|
15
|
+
const log = debug('lobe-server:market');
|
|
16
|
+
|
|
17
|
+
log('Simple message');
|
|
18
|
+
log('With variable: %O', object);
|
|
19
|
+
log('Formatted number: %d', number);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Namespace Conventions
|
|
23
|
+
|
|
24
|
+
- Desktop: `lobe-desktop:[module]`
|
|
25
|
+
- Server: `lobe-server:[module]`
|
|
26
|
+
- Client: `lobe-client:[module]`
|
|
27
|
+
- Router: `lobe-[type]-router:[module]`
|
|
28
|
+
|
|
29
|
+
## Format Specifiers
|
|
30
|
+
|
|
31
|
+
- `%O` - Object expanded (recommended for complex objects)
|
|
32
|
+
- `%o` - Object
|
|
33
|
+
- `%s` - String
|
|
34
|
+
- `%d` - Number
|
|
35
|
+
|
|
36
|
+
## Enable Debug Output
|
|
37
|
+
|
|
38
|
+
### Browser
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
localStorage.debug = 'lobe-*';
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Node.js
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
DEBUG=lobe-* npm run dev
|
|
48
|
+
DEBUG=lobe-* pnpm dev
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Electron
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
process.env.DEBUG = 'lobe-*';
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Example
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
// src/server/routers/edge/market/index.ts
|
|
61
|
+
import debug from 'debug';
|
|
62
|
+
|
|
63
|
+
const log = debug('lobe-edge-router:market');
|
|
64
|
+
|
|
65
|
+
log('getAgent input: %O', input);
|
|
66
|
+
```
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: desktop
|
|
3
|
+
description: Electron desktop development guide. Use when implementing desktop features, IPC handlers, controllers, preload scripts, window management, menu configuration, or Electron-specific functionality. Triggers on desktop app development, Electron IPC, or desktop local tools implementation.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Desktop Development Guide
|
|
8
|
+
|
|
9
|
+
## Architecture Overview
|
|
10
|
+
|
|
11
|
+
LobeChat desktop is built on Electron with main-renderer architecture:
|
|
12
|
+
|
|
13
|
+
1. **Main Process** (`apps/desktop/src/main`): App lifecycle, system APIs, window management
|
|
14
|
+
2. **Renderer Process**: Reuses web code from `src/`
|
|
15
|
+
3. **Preload Scripts** (`apps/desktop/src/preload`): Securely expose main process to renderer
|
|
16
|
+
|
|
17
|
+
## Adding New Desktop Features
|
|
18
|
+
|
|
19
|
+
### 1. Create Controller
|
|
20
|
+
Location: `apps/desktop/src/main/controllers/`
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { ControllerModule, IpcMethod } from '@/controllers';
|
|
24
|
+
|
|
25
|
+
export default class NewFeatureCtr extends ControllerModule {
|
|
26
|
+
static override readonly groupName = 'newFeature';
|
|
27
|
+
|
|
28
|
+
@IpcMethod()
|
|
29
|
+
async doSomething(params: SomeParams): Promise<SomeResult> {
|
|
30
|
+
// Implementation
|
|
31
|
+
return { success: true };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Register in `apps/desktop/src/main/controllers/registry.ts`.
|
|
37
|
+
|
|
38
|
+
### 2. Define IPC Types
|
|
39
|
+
Location: `packages/electron-client-ipc/src/types.ts`
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
export interface SomeParams { /* ... */ }
|
|
43
|
+
export interface SomeResult { success: boolean; error?: string }
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 3. Create Renderer Service
|
|
47
|
+
Location: `src/services/electron/`
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { ensureElectronIpc } from '@/utils/electron/ipc';
|
|
51
|
+
|
|
52
|
+
const ipc = ensureElectronIpc();
|
|
53
|
+
|
|
54
|
+
export const newFeatureService = async (params: SomeParams) => {
|
|
55
|
+
return ipc.newFeature.doSomething(params);
|
|
56
|
+
};
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 4. Implement Store Action
|
|
60
|
+
Location: `src/store/`
|
|
61
|
+
|
|
62
|
+
### 5. Add Tests
|
|
63
|
+
Location: `apps/desktop/src/main/controllers/__tests__/`
|
|
64
|
+
|
|
65
|
+
## Detailed Guides
|
|
66
|
+
|
|
67
|
+
See `references/` for specific topics:
|
|
68
|
+
- **Feature implementation**: `references/feature-implementation.md`
|
|
69
|
+
- **Local tools workflow**: `references/local-tools.md`
|
|
70
|
+
- **Menu configuration**: `references/menu-config.md`
|
|
71
|
+
- **Window management**: `references/window-management.md`
|
|
72
|
+
|
|
73
|
+
## Best Practices
|
|
74
|
+
|
|
75
|
+
1. **Security**: Validate inputs, limit exposed APIs
|
|
76
|
+
2. **Performance**: Use async methods, batch data transfers
|
|
77
|
+
3. **UX**: Add progress indicators, provide error feedback
|
|
78
|
+
4. **Code organization**: Follow existing patterns, add documentation
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Desktop Feature Implementation Guide
|
|
2
|
+
|
|
3
|
+
## Architecture Overview
|
|
4
|
+
|
|
5
|
+
```plaintext
|
|
6
|
+
Main Process Renderer Process
|
|
7
|
+
┌──────────────────┐ ┌──────────────────┐
|
|
8
|
+
│ Controller │◄──IPC───►│ Service Layer │
|
|
9
|
+
│ (IPC Handler) │ │ │
|
|
10
|
+
└──────────────────┘ └──────────────────┘
|
|
11
|
+
│ │
|
|
12
|
+
▼ ▼
|
|
13
|
+
┌──────────────────┐ ┌──────────────────┐
|
|
14
|
+
│ System APIs │ │ Store Actions │
|
|
15
|
+
│ (fs, network) │ │ (UI State) │
|
|
16
|
+
└──────────────────┘ └──────────────────┘
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Step-by-Step Implementation
|
|
20
|
+
|
|
21
|
+
### 1. Create Controller
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// apps/desktop/src/main/controllers/NotificationCtr.ts
|
|
25
|
+
import type { ShowDesktopNotificationParams, DesktopNotificationResult } from '@lobechat/electron-client-ipc';
|
|
26
|
+
import { Notification } from 'electron';
|
|
27
|
+
import { ControllerModule, IpcMethod } from '@/controllers';
|
|
28
|
+
|
|
29
|
+
export default class NotificationCtr extends ControllerModule {
|
|
30
|
+
static override readonly groupName = 'notification';
|
|
31
|
+
|
|
32
|
+
@IpcMethod()
|
|
33
|
+
async showDesktopNotification(params: ShowDesktopNotificationParams): Promise<DesktopNotificationResult> {
|
|
34
|
+
if (!Notification.isSupported()) {
|
|
35
|
+
return { error: 'Notifications not supported', success: false };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const notification = new Notification({ body: params.body, title: params.title });
|
|
40
|
+
notification.show();
|
|
41
|
+
return { success: true };
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error('[NotificationCtr] Failed:', error);
|
|
44
|
+
return { error: error instanceof Error ? error.message : 'Unknown error', success: false };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 2. Define IPC Types
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
// packages/electron-client-ipc/src/types.ts
|
|
54
|
+
export interface ShowDesktopNotificationParams {
|
|
55
|
+
title: string;
|
|
56
|
+
body: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface DesktopNotificationResult {
|
|
60
|
+
success: boolean;
|
|
61
|
+
error?: string;
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 3. Create Service Layer
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// src/services/electron/notificationService.ts
|
|
69
|
+
import type { ShowDesktopNotificationParams } from '@lobechat/electron-client-ipc';
|
|
70
|
+
import { ensureElectronIpc } from '@/utils/electron/ipc';
|
|
71
|
+
|
|
72
|
+
const ipc = ensureElectronIpc();
|
|
73
|
+
|
|
74
|
+
export const notificationService = {
|
|
75
|
+
show: (params: ShowDesktopNotificationParams) =>
|
|
76
|
+
ipc.notification.showDesktopNotification(params),
|
|
77
|
+
};
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 4. Implement Store Action
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
// src/store/.../actions.ts
|
|
84
|
+
showNotification: async (title: string, body: string) => {
|
|
85
|
+
if (!isElectron) return;
|
|
86
|
+
|
|
87
|
+
const result = await notificationService.show({ title, body });
|
|
88
|
+
if (!result.success) {
|
|
89
|
+
console.error('Notification failed:', result.error);
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Best Practices
|
|
95
|
+
|
|
96
|
+
1. **Security**: Validate inputs, limit exposed APIs
|
|
97
|
+
2. **Performance**: Use async methods for heavy operations
|
|
98
|
+
3. **Error handling**: Always return structured results
|
|
99
|
+
4. **UX**: Provide loading states and error feedback
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Desktop Local Tools Implementation
|
|
2
|
+
|
|
3
|
+
## Workflow Overview
|
|
4
|
+
|
|
5
|
+
1. Define tool interface (Manifest)
|
|
6
|
+
2. Define related types
|
|
7
|
+
3. Implement Store Action
|
|
8
|
+
4. Implement Service Layer
|
|
9
|
+
5. Implement Controller (IPC Handler)
|
|
10
|
+
6. Update Agent documentation
|
|
11
|
+
|
|
12
|
+
## Step 1: Define Tool Interface (Manifest)
|
|
13
|
+
|
|
14
|
+
Location: `src/tools/[tool_category]/index.ts`
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
// src/tools/local-files/index.ts
|
|
18
|
+
export const LocalFilesApiName = {
|
|
19
|
+
RenameFile: 'renameFile',
|
|
20
|
+
MoveFile: 'moveFile',
|
|
21
|
+
} as const;
|
|
22
|
+
|
|
23
|
+
export const LocalFilesManifest = {
|
|
24
|
+
api: [
|
|
25
|
+
{
|
|
26
|
+
name: LocalFilesApiName.RenameFile,
|
|
27
|
+
description: 'Rename a local file',
|
|
28
|
+
parameters: {
|
|
29
|
+
type: 'object',
|
|
30
|
+
properties: {
|
|
31
|
+
oldPath: { type: 'string', description: 'Current file path' },
|
|
32
|
+
newName: { type: 'string', description: 'New file name' },
|
|
33
|
+
},
|
|
34
|
+
required: ['oldPath', 'newName'],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
};
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Step 2: Define Types
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
// packages/electron-client-ipc/src/types.ts
|
|
45
|
+
export interface RenameLocalFileParams {
|
|
46
|
+
oldPath: string;
|
|
47
|
+
newName: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// src/tools/local-files/type.ts
|
|
51
|
+
export interface LocalRenameFileState {
|
|
52
|
+
success: boolean;
|
|
53
|
+
error?: string;
|
|
54
|
+
oldPath: string;
|
|
55
|
+
newPath: string;
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Step 3: Implement Store Action
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// src/store/chat/slices/builtinTool/actions/localFile.ts
|
|
63
|
+
renameLocalFile: async (id: string, params: RenameLocalFileParams) => {
|
|
64
|
+
const { toggleLocalFileLoading, updatePluginState, internal_updateMessageContent } = get();
|
|
65
|
+
|
|
66
|
+
toggleLocalFileLoading(id, true);
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const result = await localFileService.renameFile(params);
|
|
70
|
+
|
|
71
|
+
if (result.success) {
|
|
72
|
+
updatePluginState(id, { success: true, ...result });
|
|
73
|
+
internal_updateMessageContent(id, JSON.stringify({ success: true }));
|
|
74
|
+
} else {
|
|
75
|
+
updatePluginState(id, { success: false, error: result.error });
|
|
76
|
+
internal_updateMessageContent(id, JSON.stringify({ error: result.error }));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return result.success;
|
|
80
|
+
} catch (e) {
|
|
81
|
+
console.error(e);
|
|
82
|
+
updatePluginState(id, { success: false, error: e.message });
|
|
83
|
+
return false;
|
|
84
|
+
} finally {
|
|
85
|
+
toggleLocalFileLoading(id, false);
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Step 4: Implement Service Layer
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
// src/services/electron/localFileService.ts
|
|
94
|
+
import { ensureElectronIpc } from '@/utils/electron/ipc';
|
|
95
|
+
|
|
96
|
+
const ipc = ensureElectronIpc();
|
|
97
|
+
|
|
98
|
+
export const localFileService = {
|
|
99
|
+
renameFile: (params: RenameLocalFileParams) => ipc.localFiles.renameFile(params),
|
|
100
|
+
};
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Step 5: Implement Controller
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
// apps/desktop/src/main/controllers/LocalFileCtr.ts
|
|
107
|
+
import * as fs from 'fs/promises';
|
|
108
|
+
import * as path from 'path';
|
|
109
|
+
import { ControllerModule, IpcMethod } from '@/controllers';
|
|
110
|
+
|
|
111
|
+
export default class LocalFileCtr extends ControllerModule {
|
|
112
|
+
static override readonly groupName = 'localFiles';
|
|
113
|
+
|
|
114
|
+
@IpcMethod()
|
|
115
|
+
async renameFile(params: RenameLocalFileParams) {
|
|
116
|
+
const { oldPath, newName } = params;
|
|
117
|
+
const newPath = path.join(path.dirname(oldPath), newName);
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
await fs.rename(oldPath, newPath);
|
|
121
|
+
return { success: true, newPath };
|
|
122
|
+
} catch (error) {
|
|
123
|
+
return { success: false, error: error.message };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Step 6: Update Agent Documentation
|
|
130
|
+
|
|
131
|
+
Location: `src/tools/[tool_category]/systemRole.ts`
|
|
132
|
+
|
|
133
|
+
Add tool description to `<core_capabilities>` and usage guidelines to `<tool_usage_guidelines>`.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Desktop Menu Configuration Guide
|
|
2
|
+
|
|
3
|
+
## Menu Types
|
|
4
|
+
|
|
5
|
+
1. **App Menu**: Top of window (macOS) or title bar (Windows/Linux)
|
|
6
|
+
2. **Context Menu**: Right-click menus
|
|
7
|
+
3. **Tray Menu**: System tray icon menus
|
|
8
|
+
|
|
9
|
+
## File Structure
|
|
10
|
+
|
|
11
|
+
```plaintext
|
|
12
|
+
apps/desktop/src/main/
|
|
13
|
+
├── menus/
|
|
14
|
+
│ ├── appMenu.ts # App menu config
|
|
15
|
+
│ ├── contextMenu.ts # Context menu config
|
|
16
|
+
│ └── factory.ts # Menu factory functions
|
|
17
|
+
├── controllers/
|
|
18
|
+
│ ├── MenuCtr.ts # Menu controller
|
|
19
|
+
│ └── TrayMenuCtr.ts # Tray menu controller
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## App Menu Configuration
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// apps/desktop/src/main/menus/appMenu.ts
|
|
26
|
+
import { BrowserWindow, Menu, MenuItemConstructorOptions } from 'electron';
|
|
27
|
+
|
|
28
|
+
export const createAppMenu = (win: BrowserWindow) => {
|
|
29
|
+
const template: MenuItemConstructorOptions[] = [
|
|
30
|
+
{
|
|
31
|
+
label: 'File',
|
|
32
|
+
submenu: [
|
|
33
|
+
{ label: 'New', accelerator: 'CmdOrCtrl+N', click: () => { /* ... */ } },
|
|
34
|
+
{ type: 'separator' },
|
|
35
|
+
{ role: 'quit' },
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
// ...
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
return Menu.buildFromTemplate(template);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Register in MenuCtr.ts
|
|
45
|
+
Menu.setApplicationMenu(menu);
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Context Menu
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
export const createContextMenu = () => {
|
|
52
|
+
const template = [
|
|
53
|
+
{ label: 'Copy', role: 'copy' },
|
|
54
|
+
{ label: 'Paste', role: 'paste' },
|
|
55
|
+
];
|
|
56
|
+
return Menu.buildFromTemplate(template);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// Show on right-click
|
|
60
|
+
const menu = createContextMenu();
|
|
61
|
+
menu.popup();
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Tray Menu
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
// TrayMenuCtr.ts
|
|
68
|
+
this.tray = new Tray(trayIconPath);
|
|
69
|
+
const contextMenu = Menu.buildFromTemplate([
|
|
70
|
+
{ label: 'Show Window', click: this.showMainWindow },
|
|
71
|
+
{ type: 'separator' },
|
|
72
|
+
{ label: 'Quit', click: () => app.quit() },
|
|
73
|
+
]);
|
|
74
|
+
this.tray.setContextMenu(contextMenu);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## i18n Support
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { i18n } from '../locales';
|
|
81
|
+
|
|
82
|
+
const template = [
|
|
83
|
+
{
|
|
84
|
+
label: i18n.t('menu.file'),
|
|
85
|
+
submenu: [
|
|
86
|
+
{ label: i18n.t('menu.new'), click: createNew },
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Best Practices
|
|
93
|
+
|
|
94
|
+
1. Use standard roles (`role: 'copy'`) for native behavior
|
|
95
|
+
2. Use `CmdOrCtrl` for cross-platform shortcuts
|
|
96
|
+
3. Use `{ type: 'separator' }` to group related items
|
|
97
|
+
4. Handle platform differences with `process.platform`
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
if (process.platform === 'darwin') {
|
|
101
|
+
template.unshift({ role: 'appMenu' });
|
|
102
|
+
}
|
|
103
|
+
```
|