@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,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: modal
|
|
3
|
+
description: Modal imperative API guide. Use when creating modal dialogs using createModal from @lobehub/ui. Triggers on modal component implementation or dialog creation tasks.
|
|
4
|
+
user-invocable: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Modal Imperative API Guide
|
|
8
|
+
|
|
9
|
+
Use `createModal` from `@lobehub/ui` for imperative modal dialogs.
|
|
10
|
+
|
|
11
|
+
## Why Imperative?
|
|
12
|
+
|
|
13
|
+
| Mode | Characteristics | Recommended |
|
|
14
|
+
|------|-----------------|-------------|
|
|
15
|
+
| Declarative | Need `open` state, render `<Modal />` | ❌ |
|
|
16
|
+
| Imperative | Call function directly, no state | ✅ |
|
|
17
|
+
|
|
18
|
+
## File Structure
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
features/
|
|
22
|
+
└── MyFeatureModal/
|
|
23
|
+
├── index.tsx # Export createXxxModal
|
|
24
|
+
└── MyFeatureContent.tsx # Modal content
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Implementation
|
|
28
|
+
|
|
29
|
+
### 1. Content Component (`MyFeatureContent.tsx`)
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
'use client';
|
|
33
|
+
|
|
34
|
+
import { useModalContext } from '@lobehub/ui';
|
|
35
|
+
import { useTranslation } from 'react-i18next';
|
|
36
|
+
|
|
37
|
+
export const MyFeatureContent = () => {
|
|
38
|
+
const { t } = useTranslation('namespace');
|
|
39
|
+
const { close } = useModalContext(); // Optional: get close method
|
|
40
|
+
|
|
41
|
+
return <div>{/* Modal content */}</div>;
|
|
42
|
+
};
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 2. Export createModal (`index.tsx`)
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
'use client';
|
|
49
|
+
|
|
50
|
+
import { createModal } from '@lobehub/ui';
|
|
51
|
+
import { t } from 'i18next'; // Note: use i18next, not react-i18next
|
|
52
|
+
|
|
53
|
+
import { MyFeatureContent } from './MyFeatureContent';
|
|
54
|
+
|
|
55
|
+
export const createMyFeatureModal = () =>
|
|
56
|
+
createModal({
|
|
57
|
+
allowFullscreen: true,
|
|
58
|
+
children: <MyFeatureContent />,
|
|
59
|
+
destroyOnHidden: false,
|
|
60
|
+
footer: null,
|
|
61
|
+
styles: { body: { overflow: 'hidden', padding: 0 } },
|
|
62
|
+
title: t('myFeature.title', { ns: 'setting' }),
|
|
63
|
+
width: 'min(80%, 800px)',
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 3. Usage
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
import { createMyFeatureModal } from '@/features/MyFeatureModal';
|
|
71
|
+
|
|
72
|
+
const handleOpen = useCallback(() => {
|
|
73
|
+
createMyFeatureModal();
|
|
74
|
+
}, []);
|
|
75
|
+
|
|
76
|
+
return <Button onClick={handleOpen}>Open</Button>;
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## i18n Handling
|
|
80
|
+
|
|
81
|
+
- **Content component**: `useTranslation` hook (React context)
|
|
82
|
+
- **createModal params**: `import { t } from 'i18next'` (non-hook, imperative)
|
|
83
|
+
|
|
84
|
+
## useModalContext Hook
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
const { close, setCanDismissByClickOutside } = useModalContext();
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Common Config
|
|
91
|
+
|
|
92
|
+
| Property | Type | Description |
|
|
93
|
+
|----------|------|-------------|
|
|
94
|
+
| `allowFullscreen` | `boolean` | Allow fullscreen mode |
|
|
95
|
+
| `destroyOnHidden` | `boolean` | Destroy content on close |
|
|
96
|
+
| `footer` | `ReactNode \| null` | Footer content |
|
|
97
|
+
| `width` | `string \| number` | Modal width |
|
|
98
|
+
|
|
99
|
+
## Examples
|
|
100
|
+
|
|
101
|
+
- `src/features/SkillStore/index.tsx`
|
|
102
|
+
- `src/features/LibraryModal/CreateNew/index.tsx`
|
|
@@ -1,19 +1,50 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
2
|
+
name: project-overview
|
|
3
|
+
description: Complete project architecture and structure guide. Use when exploring the codebase, understanding project organization, finding files, or needing comprehensive architectural context. Triggers on architecture questions, directory navigation, or project overview needs.
|
|
3
4
|
---
|
|
4
5
|
|
|
5
|
-
# LobeChat Project
|
|
6
|
+
# LobeChat Project Overview
|
|
6
7
|
|
|
7
|
-
##
|
|
8
|
+
## Project Description
|
|
9
|
+
|
|
10
|
+
Open-source, modern-design AI Agent Workspace: **LobeHub** (previously LobeChat).
|
|
11
|
+
|
|
12
|
+
**Supported platforms:**
|
|
13
|
+
- Web desktop/mobile
|
|
14
|
+
- Desktop (Electron)
|
|
15
|
+
- Mobile app (React Native) - coming soon
|
|
16
|
+
|
|
17
|
+
**Logo emoji:** 🤯
|
|
18
|
+
|
|
19
|
+
## Complete Tech Stack
|
|
8
20
|
|
|
9
|
-
|
|
21
|
+
| Category | Technology |
|
|
22
|
+
|----------|------------|
|
|
23
|
+
| Framework | Next.js 16 + React 19 |
|
|
24
|
+
| Routing | SPA inside Next.js with `react-router-dom` |
|
|
25
|
+
| Language | TypeScript |
|
|
26
|
+
| UI Components | `@lobehub/ui`, antd |
|
|
27
|
+
| CSS-in-JS | antd-style |
|
|
28
|
+
| Icons | lucide-react, `@ant-design/icons` |
|
|
29
|
+
| i18n | react-i18next |
|
|
30
|
+
| State | zustand |
|
|
31
|
+
| URL Params | nuqs |
|
|
32
|
+
| Data Fetching | SWR |
|
|
33
|
+
| React Hooks | aHooks |
|
|
34
|
+
| Date/Time | dayjs |
|
|
35
|
+
| Utilities | es-toolkit |
|
|
36
|
+
| API | TRPC (type-safe) |
|
|
37
|
+
| Database | Neon PostgreSQL + Drizzle ORM |
|
|
38
|
+
| Testing | Vitest |
|
|
10
39
|
|
|
11
|
-
|
|
40
|
+
## Complete Project Structure
|
|
41
|
+
|
|
42
|
+
Monorepo using `@lobechat/` namespace for workspace packages.
|
|
12
43
|
|
|
13
|
-
```
|
|
44
|
+
```
|
|
14
45
|
lobe-chat/
|
|
15
46
|
├── apps/
|
|
16
|
-
│ └── desktop/
|
|
47
|
+
│ └── desktop/ # Electron desktop app
|
|
17
48
|
├── docs/
|
|
18
49
|
│ ├── changelog/
|
|
19
50
|
│ ├── development/
|
|
@@ -23,10 +54,10 @@ lobe-chat/
|
|
|
23
54
|
│ ├── en-US/
|
|
24
55
|
│ └── zh-CN/
|
|
25
56
|
├── packages/
|
|
26
|
-
│ ├── agent-runtime/
|
|
57
|
+
│ ├── agent-runtime/ # Agent runtime
|
|
27
58
|
│ ├── builtin-agents/
|
|
28
|
-
│ ├── builtin-tool-*/
|
|
29
|
-
│ ├── business/
|
|
59
|
+
│ ├── builtin-tool-*/ # Builtin tool packages
|
|
60
|
+
│ ├── business/ # Cloud-only business logic
|
|
30
61
|
│ │ ├── config/
|
|
31
62
|
│ │ ├── const/
|
|
32
63
|
│ │ └── model-runtime/
|
|
@@ -59,8 +90,6 @@ lobe-chat/
|
|
|
59
90
|
│ ├── types/
|
|
60
91
|
│ ├── utils/
|
|
61
92
|
│ └── web-crawler/
|
|
62
|
-
├── public/
|
|
63
|
-
├── scripts/
|
|
64
93
|
├── src/
|
|
65
94
|
│ ├── app/
|
|
66
95
|
│ │ ├── (backend)/
|
|
@@ -78,7 +107,7 @@ lobe-chat/
|
|
|
78
107
|
│ │ │ ├── onboarding/
|
|
79
108
|
│ │ │ └── router/
|
|
80
109
|
│ │ └── desktop/
|
|
81
|
-
│ ├── business/
|
|
110
|
+
│ ├── business/ # Cloud-only (client/server)
|
|
82
111
|
│ │ ├── client/
|
|
83
112
|
│ │ ├── locales/
|
|
84
113
|
│ │ └── server/
|
|
@@ -117,33 +146,32 @@ lobe-chat/
|
|
|
117
146
|
│ ├── tools/
|
|
118
147
|
│ ├── types/
|
|
119
148
|
│ └── utils/
|
|
120
|
-
└──
|
|
149
|
+
└── e2e/ # E2E tests (Cucumber + Playwright)
|
|
121
150
|
```
|
|
122
151
|
|
|
123
152
|
## Architecture Map
|
|
124
153
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
-
|
|
143
|
-
- Business (cloud-only): Code specific to LobeHub cloud service, only expose empty interfaces for opens-source version.
|
|
144
|
-
- `src/business/*`
|
|
145
|
-
- `packages/business/*`
|
|
154
|
+
| Layer | Location |
|
|
155
|
+
|-------|----------|
|
|
156
|
+
| UI Components | `src/components`, `src/features` |
|
|
157
|
+
| Global Providers | `src/layout` |
|
|
158
|
+
| Zustand Stores | `src/store` |
|
|
159
|
+
| Client Services | `src/services/` |
|
|
160
|
+
| REST API | `src/app/(backend)/webapi` |
|
|
161
|
+
| tRPC Routers | `src/server/routers/{async\|lambda\|mobile\|tools}` |
|
|
162
|
+
| Server Services | `src/server/services` (can access DB) |
|
|
163
|
+
| Server Modules | `src/server/modules` (no DB access) |
|
|
164
|
+
| Feature Flags | `src/server/featureFlags` |
|
|
165
|
+
| Global Config | `src/server/globalConfig` |
|
|
166
|
+
| DB Schema | `packages/database/src/schemas` |
|
|
167
|
+
| DB Model | `packages/database/src/models` |
|
|
168
|
+
| DB Repository | `packages/database/src/repositories` |
|
|
169
|
+
| Third-party | `src/libs` (analytics, oidc, etc.) |
|
|
170
|
+
| Builtin Tools | `src/tools`, `packages/builtin-tool-*` |
|
|
171
|
+
| Cloud-only | `src/business/*`, `packages/business/*` |
|
|
146
172
|
|
|
147
|
-
## Data Flow
|
|
173
|
+
## Data Flow
|
|
148
174
|
|
|
149
|
-
|
|
175
|
+
```
|
|
176
|
+
React UI → Store Actions → Client Service → TRPC Lambda → Server Services → DB Model → PostgreSQL
|
|
177
|
+
```
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: react
|
|
3
|
+
description: React component development guide. Use when working with React components (.tsx files), creating UI, using @lobehub/ui components, implementing routing, or building frontend features. Triggers on React component creation, modification, layout implementation, or navigation tasks.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# React Component Writing Guide
|
|
7
|
+
|
|
8
|
+
- Use antd-style for complex styles; for simple cases, use inline `style` attribute
|
|
9
|
+
- Use `Flexbox` and `Center` from `@lobehub/ui` for layouts (see `references/layout-kit.md`)
|
|
10
|
+
- Component priority: `src/components` > installed packages > `@lobehub/ui` > antd
|
|
11
|
+
- Use selectors to access zustand store data
|
|
12
|
+
|
|
13
|
+
## @lobehub/ui Components
|
|
14
|
+
|
|
15
|
+
If unsure about component usage, search existing code in this project. Most components extend antd with additional props.
|
|
16
|
+
|
|
17
|
+
Reference: `node_modules/@lobehub/ui/es/index.mjs` for all available components.
|
|
18
|
+
|
|
19
|
+
**Common Components:**
|
|
20
|
+
- General: ActionIcon, ActionIconGroup, Block, Button, Icon
|
|
21
|
+
- Data Display: Avatar, Collapse, Empty, Highlighter, Markdown, Tag, Tooltip
|
|
22
|
+
- Data Entry: CodeEditor, CopyButton, EditableText, Form, FormModal, Input, SearchBar, Select
|
|
23
|
+
- Feedback: Alert, Drawer, Modal
|
|
24
|
+
- Layout: Center, DraggablePanel, Flexbox, Grid, Header, MaskShadow
|
|
25
|
+
- Navigation: Burger, Dropdown, Menu, SideNav, Tabs
|
|
26
|
+
|
|
27
|
+
## Routing Architecture
|
|
28
|
+
|
|
29
|
+
Hybrid routing: Next.js App Router (static pages) + React Router DOM (main SPA).
|
|
30
|
+
|
|
31
|
+
| Route Type | Use Case | Implementation |
|
|
32
|
+
|------------|----------|----------------|
|
|
33
|
+
| Next.js App Router | Auth pages (login, signup, oauth) | `src/app/[variants]/(auth)/` |
|
|
34
|
+
| React Router DOM | Main SPA (chat, settings) | `desktopRouter.config.tsx` |
|
|
35
|
+
|
|
36
|
+
### Key Files
|
|
37
|
+
- Entry: `src/app/[variants]/page.tsx`
|
|
38
|
+
- Desktop router: `src/app/[variants]/router/desktopRouter.config.tsx`
|
|
39
|
+
- Mobile router: `src/app/[variants]/(mobile)/router/mobileRouter.config.tsx`
|
|
40
|
+
- Router utilities: `src/utils/router.tsx`
|
|
41
|
+
|
|
42
|
+
### Router Utilities
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { dynamicElement, redirectElement, ErrorBoundary } from '@/utils/router';
|
|
46
|
+
|
|
47
|
+
element: dynamicElement(() => import('./chat'), 'Desktop > Chat');
|
|
48
|
+
element: redirectElement('/settings/profile');
|
|
49
|
+
errorElement: <ErrorBoundary resetPath="/chat" />;
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Navigation
|
|
53
|
+
|
|
54
|
+
**Important**: For SPA pages, use `Link` from `react-router-dom`, NOT `next/link`.
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
// ❌ Wrong
|
|
58
|
+
import Link from 'next/link';
|
|
59
|
+
<Link href="/">Home</Link>
|
|
60
|
+
|
|
61
|
+
// ✅ Correct
|
|
62
|
+
import { Link } from 'react-router-dom';
|
|
63
|
+
<Link to="/">Home</Link>
|
|
64
|
+
|
|
65
|
+
// In components
|
|
66
|
+
import { useNavigate } from 'react-router-dom';
|
|
67
|
+
const navigate = useNavigate();
|
|
68
|
+
navigate('/chat');
|
|
69
|
+
|
|
70
|
+
// From stores
|
|
71
|
+
const navigate = useGlobalStore.getState().navigate;
|
|
72
|
+
navigate?.('/settings');
|
|
73
|
+
```
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Flexbox Layout Components Guide
|
|
2
|
+
|
|
3
|
+
`@lobehub/ui` provides `Flexbox` and `Center` components for creating flexible layouts.
|
|
4
|
+
|
|
5
|
+
## Flexbox Component
|
|
6
|
+
|
|
7
|
+
Flexbox is the most commonly used layout component, similar to CSS `display: flex`.
|
|
8
|
+
|
|
9
|
+
### Basic Usage
|
|
10
|
+
|
|
11
|
+
```jsx
|
|
12
|
+
import { Flexbox } from '@lobehub/ui';
|
|
13
|
+
|
|
14
|
+
// Default vertical layout
|
|
15
|
+
<Flexbox>
|
|
16
|
+
<div>Child 1</div>
|
|
17
|
+
<div>Child 2</div>
|
|
18
|
+
</Flexbox>
|
|
19
|
+
|
|
20
|
+
// Horizontal layout
|
|
21
|
+
<Flexbox horizontal>
|
|
22
|
+
<div>Left</div>
|
|
23
|
+
<div>Right</div>
|
|
24
|
+
</Flexbox>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Common Props
|
|
28
|
+
|
|
29
|
+
- `horizontal`: Boolean, set horizontal direction layout
|
|
30
|
+
- `flex`: Number or string, controls flex property
|
|
31
|
+
- `gap`: Number, spacing between children
|
|
32
|
+
- `align`: Alignment like 'center', 'flex-start', etc.
|
|
33
|
+
- `justify`: Main axis alignment like 'space-between', 'center', etc.
|
|
34
|
+
- `padding`: Padding value
|
|
35
|
+
- `paddingInline`: Horizontal padding
|
|
36
|
+
- `paddingBlock`: Vertical padding
|
|
37
|
+
- `width/height`: Set dimensions, typically '100%' or specific pixels
|
|
38
|
+
- `style`: Custom style object
|
|
39
|
+
|
|
40
|
+
### Layout Example
|
|
41
|
+
|
|
42
|
+
```jsx
|
|
43
|
+
// Classic three-column layout
|
|
44
|
+
<Flexbox horizontal height={'100%'} width={'100%'}>
|
|
45
|
+
{/* Left sidebar */}
|
|
46
|
+
<Flexbox
|
|
47
|
+
width={260}
|
|
48
|
+
style={{
|
|
49
|
+
borderRight: `1px solid ${theme.colorBorderSecondary}`,
|
|
50
|
+
height: '100%',
|
|
51
|
+
overflowY: 'auto',
|
|
52
|
+
}}
|
|
53
|
+
>
|
|
54
|
+
<SidebarContent />
|
|
55
|
+
</Flexbox>
|
|
56
|
+
|
|
57
|
+
{/* Center content */}
|
|
58
|
+
<Flexbox flex={1} style={{ height: '100%' }}>
|
|
59
|
+
<Flexbox flex={1} padding={24} style={{ overflowY: 'auto' }}>
|
|
60
|
+
<MainContent />
|
|
61
|
+
</Flexbox>
|
|
62
|
+
|
|
63
|
+
{/* Footer */}
|
|
64
|
+
<Flexbox
|
|
65
|
+
style={{
|
|
66
|
+
borderTop: `1px solid ${theme.colorBorderSecondary}`,
|
|
67
|
+
padding: '16px 24px',
|
|
68
|
+
}}
|
|
69
|
+
>
|
|
70
|
+
<Footer />
|
|
71
|
+
</Flexbox>
|
|
72
|
+
</Flexbox>
|
|
73
|
+
</Flexbox>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Center Component
|
|
77
|
+
|
|
78
|
+
Center wraps Flexbox with horizontal and vertical centering.
|
|
79
|
+
|
|
80
|
+
```jsx
|
|
81
|
+
import { Center } from '@lobehub/ui';
|
|
82
|
+
|
|
83
|
+
<Center width={'100%'} height={'100%'}>
|
|
84
|
+
<Content />
|
|
85
|
+
</Center>
|
|
86
|
+
|
|
87
|
+
// Icon centered
|
|
88
|
+
<Center className={styles.icon} flex={'none'} height={40} width={40}>
|
|
89
|
+
<Icon icon={icon} size={24} />
|
|
90
|
+
</Center>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Best Practices
|
|
94
|
+
|
|
95
|
+
- Use `flex={1}` to fill available space
|
|
96
|
+
- Use `gap` instead of margin for spacing
|
|
97
|
+
- Nest Flexbox for complex layouts
|
|
98
|
+
- Set `overflow: 'auto'` for scrollable content
|
|
99
|
+
- Use `horizontal` for horizontal layout (default is vertical)
|
|
100
|
+
- Combine with `useTheme` hook for theme-responsive layouts
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: recent-data
|
|
3
|
+
description: Guide for using Recent Data (topics, resources, pages). Use when working with recently accessed items, implementing recent lists, or accessing session store recent data. Triggers on recent data usage or implementation tasks.
|
|
4
|
+
user-invocable: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Recent Data Usage Guide
|
|
8
|
+
|
|
9
|
+
Recent data (recentTopics, recentResources, recentPages) is stored in session store.
|
|
10
|
+
|
|
11
|
+
## Initialization
|
|
12
|
+
|
|
13
|
+
In app top-level (e.g., `RecentHydration.tsx`):
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { useInitRecentTopic } from '@/hooks/useInitRecentTopic';
|
|
17
|
+
import { useInitRecentResource } from '@/hooks/useInitRecentResource';
|
|
18
|
+
import { useInitRecentPage } from '@/hooks/useInitRecentPage';
|
|
19
|
+
|
|
20
|
+
const App = () => {
|
|
21
|
+
useInitRecentTopic();
|
|
22
|
+
useInitRecentResource();
|
|
23
|
+
useInitRecentPage();
|
|
24
|
+
return <YourComponents />;
|
|
25
|
+
};
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
### Method 1: Read from Store (Recommended)
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { useSessionStore } from '@/store/session';
|
|
34
|
+
import { recentSelectors } from '@/store/session/selectors';
|
|
35
|
+
|
|
36
|
+
const Component = () => {
|
|
37
|
+
const recentTopics = useSessionStore(recentSelectors.recentTopics);
|
|
38
|
+
const isInit = useSessionStore(recentSelectors.isRecentTopicsInit);
|
|
39
|
+
|
|
40
|
+
if (!isInit) return <div>Loading...</div>;
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div>
|
|
44
|
+
{recentTopics.map((topic) => (
|
|
45
|
+
<div key={topic.id}>{topic.title}</div>
|
|
46
|
+
))}
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Method 2: Use Hook Return (Single component)
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
const { data: recentTopics, isLoading } = useInitRecentTopic();
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Available Selectors
|
|
59
|
+
|
|
60
|
+
### Recent Topics
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
const recentTopics = useSessionStore(recentSelectors.recentTopics);
|
|
64
|
+
// Type: RecentTopic[]
|
|
65
|
+
|
|
66
|
+
const isInit = useSessionStore(recentSelectors.isRecentTopicsInit);
|
|
67
|
+
// Type: boolean
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**RecentTopic type:**
|
|
71
|
+
```typescript
|
|
72
|
+
interface RecentTopic {
|
|
73
|
+
agent: { avatar: string | null; backgroundColor: string | null; id: string; title: string | null } | null;
|
|
74
|
+
id: string;
|
|
75
|
+
title: string | null;
|
|
76
|
+
updatedAt: Date;
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Recent Resources
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
const recentResources = useSessionStore(recentSelectors.recentResources);
|
|
84
|
+
// Type: FileListItem[]
|
|
85
|
+
|
|
86
|
+
const isInit = useSessionStore(recentSelectors.isRecentResourcesInit);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Recent Pages
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
const recentPages = useSessionStore(recentSelectors.recentPages);
|
|
93
|
+
const isInit = useSessionStore(recentSelectors.isRecentPagesInit);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Features
|
|
97
|
+
|
|
98
|
+
1. **Auto login detection**: Only loads when user is logged in
|
|
99
|
+
2. **Data caching**: Stored in store, no repeated loading
|
|
100
|
+
3. **Auto refresh**: SWR refreshes on focus (5-minute interval)
|
|
101
|
+
4. **Type safe**: Full TypeScript types
|
|
102
|
+
|
|
103
|
+
## Best Practices
|
|
104
|
+
|
|
105
|
+
1. Initialize all recent data at app top-level
|
|
106
|
+
2. Use selectors to read from store
|
|
107
|
+
3. For multi-component use, prefer Method 1
|
|
108
|
+
4. Use selectors for render optimization
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testing
|
|
3
|
+
description: Testing guide using Vitest. Use when writing tests (.test.ts, .test.tsx), fixing failing tests, improving test coverage, or debugging test issues. Triggers on test creation, test debugging, mock setup, or test-related questions.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# LobeChat Testing Guide
|
|
7
|
+
|
|
8
|
+
## Quick Reference
|
|
9
|
+
|
|
10
|
+
**Commands:**
|
|
11
|
+
```bash
|
|
12
|
+
# Run specific test file
|
|
13
|
+
bunx vitest run --silent='passed-only' '[file-path]'
|
|
14
|
+
|
|
15
|
+
# Database package (client)
|
|
16
|
+
cd packages/database && bunx vitest run --silent='passed-only' '[file]'
|
|
17
|
+
|
|
18
|
+
# Database package (server)
|
|
19
|
+
cd packages/database && TEST_SERVER_DB=1 bunx vitest run --silent='passed-only' '[file]'
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Never run** `bun run test` - it runs all 3000+ tests (~10 minutes).
|
|
23
|
+
|
|
24
|
+
## Test Categories
|
|
25
|
+
|
|
26
|
+
| Category | Location | Config |
|
|
27
|
+
|----------|----------|--------|
|
|
28
|
+
| Webapp | `src/**/*.test.ts(x)` | `vitest.config.ts` |
|
|
29
|
+
| Packages | `packages/*/**/*.test.ts` | `packages/*/vitest.config.ts` |
|
|
30
|
+
| Desktop | `apps/desktop/**/*.test.ts` | `apps/desktop/vitest.config.ts` |
|
|
31
|
+
|
|
32
|
+
## Core Principles
|
|
33
|
+
|
|
34
|
+
1. **Prefer `vi.spyOn` over `vi.mock`** - More targeted, easier to maintain
|
|
35
|
+
2. **Tests must pass type check** - Run `bun run type-check` after writing tests
|
|
36
|
+
3. **After 1-2 failed fix attempts, stop and ask for help**
|
|
37
|
+
4. **Test behavior, not implementation details**
|
|
38
|
+
|
|
39
|
+
## Basic Test Structure
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
43
|
+
|
|
44
|
+
beforeEach(() => {
|
|
45
|
+
vi.clearAllMocks();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
afterEach(() => {
|
|
49
|
+
vi.restoreAllMocks();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe('ModuleName', () => {
|
|
53
|
+
describe('functionName', () => {
|
|
54
|
+
it('should handle normal case', () => {
|
|
55
|
+
// Arrange → Act → Assert
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Mock Patterns
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
// ✅ Spy on direct dependencies
|
|
65
|
+
vi.spyOn(messageService, 'createMessage').mockResolvedValue('id');
|
|
66
|
+
|
|
67
|
+
// ✅ Use vi.stubGlobal for browser APIs
|
|
68
|
+
vi.stubGlobal('Image', mockImage);
|
|
69
|
+
vi.spyOn(URL, 'createObjectURL').mockReturnValue('blob:mock');
|
|
70
|
+
|
|
71
|
+
// ❌ Avoid mocking entire modules globally
|
|
72
|
+
vi.mock('@/services/chat'); // Too broad
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Detailed Guides
|
|
76
|
+
|
|
77
|
+
See `references/` for specific testing scenarios:
|
|
78
|
+
- **Database Model testing**: `references/db-model-test.md`
|
|
79
|
+
- **Electron IPC testing**: `references/electron-ipc-test.md`
|
|
80
|
+
- **Zustand Store Action testing**: `references/zustand-store-action-test.md`
|
|
81
|
+
- **Agent Runtime E2E testing**: `references/agent-runtime-e2e.md`
|
|
82
|
+
- **Desktop Controller testing**: `references/desktop-controller-test.md`
|
|
83
|
+
|
|
84
|
+
## Common Issues
|
|
85
|
+
|
|
86
|
+
1. **Module pollution**: Use `vi.resetModules()` when tests fail mysteriously
|
|
87
|
+
2. **Mock not working**: Check setup position and use `vi.clearAllMocks()` in beforeEach
|
|
88
|
+
3. **Test data pollution**: Clean database state in beforeEach/afterEach
|
|
89
|
+
4. **Async issues**: Wrap state changes in `act()` for React hooks
|