@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,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zustand
|
|
3
|
+
description: Zustand state management guide. Use when working with store code (src/store/**), implementing actions, managing state, or creating slices. Triggers on Zustand store development, state management questions, or action implementation.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# LobeChat Zustand State Management
|
|
7
|
+
|
|
8
|
+
## Action Type Hierarchy
|
|
9
|
+
|
|
10
|
+
### 1. Public Actions
|
|
11
|
+
Main interfaces for UI components:
|
|
12
|
+
- Naming: Verb form (`createTopic`, `sendMessage`)
|
|
13
|
+
- Responsibilities: Parameter validation, flow orchestration
|
|
14
|
+
|
|
15
|
+
### 2. Internal Actions (`internal_*`)
|
|
16
|
+
Core business logic implementation:
|
|
17
|
+
- Naming: `internal_` prefix (`internal_createTopic`)
|
|
18
|
+
- Responsibilities: Optimistic updates, service calls, error handling
|
|
19
|
+
- Should not be called directly by UI
|
|
20
|
+
|
|
21
|
+
### 3. Dispatch Methods (`internal_dispatch*`)
|
|
22
|
+
State update handlers:
|
|
23
|
+
- Naming: `internal_dispatch` + entity (`internal_dispatchTopic`)
|
|
24
|
+
- Responsibilities: Calling reducers, updating store
|
|
25
|
+
|
|
26
|
+
## When to Use Reducer vs Simple `set`
|
|
27
|
+
|
|
28
|
+
**Use Reducer Pattern:**
|
|
29
|
+
- Managing object lists/maps (`messagesMap`, `topicMaps`)
|
|
30
|
+
- Optimistic updates
|
|
31
|
+
- Complex state transitions
|
|
32
|
+
|
|
33
|
+
**Use Simple `set`:**
|
|
34
|
+
- Toggling booleans
|
|
35
|
+
- Updating simple values
|
|
36
|
+
- Setting single state fields
|
|
37
|
+
|
|
38
|
+
## Optimistic Update Pattern
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
internal_createTopic: async (params) => {
|
|
42
|
+
const tmpId = Date.now().toString();
|
|
43
|
+
|
|
44
|
+
// 1. Immediately update frontend (optimistic)
|
|
45
|
+
get().internal_dispatchTopic(
|
|
46
|
+
{ type: 'addTopic', value: { ...params, id: tmpId } },
|
|
47
|
+
'internal_createTopic'
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
// 2. Call backend service
|
|
51
|
+
const topicId = await topicService.createTopic(params);
|
|
52
|
+
|
|
53
|
+
// 3. Refresh for consistency
|
|
54
|
+
await get().refreshTopic();
|
|
55
|
+
return topicId;
|
|
56
|
+
},
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Delete operations**: Don't use optimistic updates (destructive, complex recovery)
|
|
60
|
+
|
|
61
|
+
## Naming Conventions
|
|
62
|
+
|
|
63
|
+
**Actions:**
|
|
64
|
+
- Public: `createTopic`, `sendMessage`
|
|
65
|
+
- Internal: `internal_createTopic`, `internal_updateMessageContent`
|
|
66
|
+
- Dispatch: `internal_dispatchTopic`
|
|
67
|
+
- Toggle: `internal_toggleMessageLoading`
|
|
68
|
+
|
|
69
|
+
**State:**
|
|
70
|
+
- ID arrays: `messageLoadingIds`, `topicEditingIds`
|
|
71
|
+
- Maps: `topicMaps`, `messagesMap`
|
|
72
|
+
- Active: `activeTopicId`
|
|
73
|
+
- Init flags: `topicsInit`
|
|
74
|
+
|
|
75
|
+
## Detailed Guides
|
|
76
|
+
|
|
77
|
+
- Action patterns: `references/action-patterns.md`
|
|
78
|
+
- Slice organization: `references/slice-organization.md`
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Zustand Action Patterns
|
|
2
|
+
|
|
3
|
+
## Optimistic Update Implementation
|
|
4
|
+
|
|
5
|
+
### Standard Flow
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
internal_updateMessageContent: async (id, content, extra) => {
|
|
9
|
+
const { internal_dispatchMessage, refreshMessages } = get();
|
|
10
|
+
|
|
11
|
+
// 1. Immediately update frontend
|
|
12
|
+
internal_dispatchMessage({
|
|
13
|
+
id,
|
|
14
|
+
type: 'updateMessage',
|
|
15
|
+
value: { content },
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// 2. Call backend
|
|
19
|
+
await messageService.updateMessage(id, { content });
|
|
20
|
+
|
|
21
|
+
// 3. Refresh for consistency
|
|
22
|
+
await refreshMessages();
|
|
23
|
+
},
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Create Operations
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
internal_createMessage: async (message, context) => {
|
|
30
|
+
let tempId = context?.tempMessageId;
|
|
31
|
+
if (!tempId) {
|
|
32
|
+
tempId = internal_createTmpMessage(message);
|
|
33
|
+
internal_toggleMessageLoading(true, tempId);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const id = await messageService.createMessage(message);
|
|
38
|
+
await refreshMessages();
|
|
39
|
+
internal_toggleMessageLoading(false, tempId);
|
|
40
|
+
return id;
|
|
41
|
+
} catch (e) {
|
|
42
|
+
internal_toggleMessageLoading(false, tempId);
|
|
43
|
+
internal_dispatchMessage({
|
|
44
|
+
id: tempId,
|
|
45
|
+
type: 'updateMessage',
|
|
46
|
+
value: { error: { type: ChatErrorType.CreateMessageError } },
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Delete Operations (No Optimistic Update)
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
internal_removeGenerationTopic: async (id: string) => {
|
|
56
|
+
get().internal_updateGenerationTopicLoading(id, true);
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
await generationTopicService.deleteTopic(id);
|
|
60
|
+
await get().refreshGenerationTopics();
|
|
61
|
+
} finally {
|
|
62
|
+
get().internal_updateGenerationTopicLoading(id, false);
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Loading State Management
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
// Define in initialState.ts
|
|
71
|
+
export interface ChatMessageState {
|
|
72
|
+
messageEditingIds: string[];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Manage in action
|
|
76
|
+
toggleMessageEditing: (id, editing) => {
|
|
77
|
+
set(
|
|
78
|
+
{ messageEditingIds: toggleBooleanList(get().messageEditingIds, id, editing) },
|
|
79
|
+
false,
|
|
80
|
+
'toggleMessageEditing'
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## SWR Integration
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
useFetchMessages: (enable, sessionId, activeTopicId) =>
|
|
89
|
+
useClientDataSWR<ChatMessage[]>(
|
|
90
|
+
enable ? [SWR_USE_FETCH_MESSAGES, sessionId, activeTopicId] : null,
|
|
91
|
+
async ([, sessionId, topicId]) => messageService.getMessages(sessionId, topicId),
|
|
92
|
+
{
|
|
93
|
+
onSuccess: (messages) => {
|
|
94
|
+
const nextMap = { ...get().messagesMap, [messageMapKey(sessionId, activeTopicId)]: messages };
|
|
95
|
+
if (get().messagesInit && isEqual(nextMap, get().messagesMap)) return;
|
|
96
|
+
set({ messagesInit: true, messagesMap: nextMap }, false, n('useFetchMessages'));
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
),
|
|
100
|
+
|
|
101
|
+
// Cache invalidation
|
|
102
|
+
refreshMessages: async () => {
|
|
103
|
+
await mutate([SWR_USE_FETCH_MESSAGES, get().activeId, get().activeTopicId]);
|
|
104
|
+
};
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Reducer Pattern
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
export const messagesReducer = (state: ChatMessage[], payload: MessageDispatch): ChatMessage[] => {
|
|
111
|
+
switch (payload.type) {
|
|
112
|
+
case 'updateMessage': {
|
|
113
|
+
return produce(state, (draftState) => {
|
|
114
|
+
const index = draftState.findIndex((i) => i.id === payload.id);
|
|
115
|
+
if (index < 0) return;
|
|
116
|
+
draftState[index] = merge(draftState[index], {
|
|
117
|
+
...payload.value,
|
|
118
|
+
updatedAt: Date.now(),
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
// ...other cases
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
```
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Zustand Slice Organization
|
|
2
|
+
|
|
3
|
+
## Top-Level Store Structure
|
|
4
|
+
|
|
5
|
+
Key aggregation files:
|
|
6
|
+
- `src/store/chat/initialState.ts`: Aggregate all slice initial states
|
|
7
|
+
- `src/store/chat/store.ts`: Define top-level `ChatStore`, combine all slice actions
|
|
8
|
+
- `src/store/chat/selectors.ts`: Export all slice selectors
|
|
9
|
+
- `src/store/chat/helpers.ts`: Chat helper functions
|
|
10
|
+
|
|
11
|
+
## Store Aggregation Pattern
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
// src/store/chat/initialState.ts
|
|
15
|
+
import { ChatTopicState, initialTopicState } from './slices/topic/initialState';
|
|
16
|
+
import { ChatMessageState, initialMessageState } from './slices/message/initialState';
|
|
17
|
+
|
|
18
|
+
export type ChatStoreState = ChatTopicState & ChatMessageState & ...
|
|
19
|
+
|
|
20
|
+
export const initialState: ChatStoreState = {
|
|
21
|
+
...initialMessageState,
|
|
22
|
+
...initialTopicState,
|
|
23
|
+
...
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// src/store/chat/store.ts
|
|
27
|
+
export interface ChatStoreAction
|
|
28
|
+
extends ChatMessageAction, ChatTopicAction, ...
|
|
29
|
+
|
|
30
|
+
const createStore: StateCreator<ChatStore, [['zustand/devtools', never]]> = (...params) => ({
|
|
31
|
+
...initialState,
|
|
32
|
+
...chatMessage(...params),
|
|
33
|
+
...chatTopic(...params),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export const useChatStore = createWithEqualityFn<ChatStore>()(
|
|
37
|
+
subscribeWithSelector(devtools(createStore)),
|
|
38
|
+
shallow
|
|
39
|
+
);
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Single Slice Structure
|
|
43
|
+
|
|
44
|
+
```plaintext
|
|
45
|
+
src/store/chat/slices/
|
|
46
|
+
└── [sliceName]/
|
|
47
|
+
├── action.ts # Define actions (or actions/ directory)
|
|
48
|
+
├── initialState.ts # State structure and initial values
|
|
49
|
+
├── reducer.ts # (Optional) Reducer pattern
|
|
50
|
+
├── selectors.ts # Define selectors
|
|
51
|
+
└── index.ts # (Optional) Re-exports
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### initialState.ts
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
export interface ChatTopicState {
|
|
58
|
+
activeTopicId?: string;
|
|
59
|
+
topicMaps: Record<string, ChatTopic[]>;
|
|
60
|
+
topicsInit: boolean;
|
|
61
|
+
topicLoadingIds: string[];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const initialTopicState: ChatTopicState = {
|
|
65
|
+
activeTopicId: undefined,
|
|
66
|
+
topicMaps: {},
|
|
67
|
+
topicsInit: false,
|
|
68
|
+
topicLoadingIds: [],
|
|
69
|
+
};
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### selectors.ts
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
const currentTopics = (s: ChatStoreState): ChatTopic[] | undefined => s.topicMaps[s.activeId];
|
|
76
|
+
|
|
77
|
+
const getTopicById = (id: string) => (s: ChatStoreState): ChatTopic | undefined =>
|
|
78
|
+
currentTopics(s)?.find((topic) => topic.id === id);
|
|
79
|
+
|
|
80
|
+
// Core pattern: Use xxxSelectors aggregate
|
|
81
|
+
export const topicSelectors = {
|
|
82
|
+
currentTopics,
|
|
83
|
+
getTopicById,
|
|
84
|
+
};
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Complex Actions Sub-directory
|
|
88
|
+
|
|
89
|
+
```plaintext
|
|
90
|
+
src/store/chat/slices/aiChat/
|
|
91
|
+
├── actions/
|
|
92
|
+
│ ├── generateAIChat.ts
|
|
93
|
+
│ ├── rag.ts
|
|
94
|
+
│ ├── memory.ts
|
|
95
|
+
│ └── index.ts
|
|
96
|
+
├── initialState.ts
|
|
97
|
+
└── selectors.ts
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## State Design Patterns
|
|
101
|
+
|
|
102
|
+
### Map Structure for Associated Data
|
|
103
|
+
```typescript
|
|
104
|
+
topicMaps: Record<string, ChatTopic[]>;
|
|
105
|
+
messagesMap: Record<string, ChatMessage[]>;
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Arrays for Loading State
|
|
109
|
+
```typescript
|
|
110
|
+
messageLoadingIds: string[]
|
|
111
|
+
topicLoadingIds: string[]
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Optional Fields for Active Items
|
|
115
|
+
```typescript
|
|
116
|
+
activeId: string
|
|
117
|
+
activeTopicId?: string
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Best Practices
|
|
121
|
+
|
|
122
|
+
1. **Slice division**: By functional domain (message, topic, aiChat)
|
|
123
|
+
2. **File naming**: camelCase for directories, consistent patterns
|
|
124
|
+
3. **State structure**: Flat, avoid deep nesting
|
|
125
|
+
4. **Type safety**: Clear TypeScript interfaces for each slice
|
package/AGENTS.md
CHANGED
|
@@ -4,12 +4,10 @@ This document serves as a comprehensive guide for all team members when developi
|
|
|
4
4
|
|
|
5
5
|
## Project Description
|
|
6
6
|
|
|
7
|
-
You are developing an open-source, modern-design AI Agent Workspace: LobeHub(
|
|
7
|
+
You are developing an open-source, modern-design AI Agent Workspace: LobeHub (previously LobeChat).
|
|
8
8
|
|
|
9
9
|
## Tech Stack
|
|
10
10
|
|
|
11
|
-
Built with modern technologies:
|
|
12
|
-
|
|
13
11
|
- **Frontend**: Next.js 16, React 19, TypeScript
|
|
14
12
|
- **UI Components**: Ant Design, @lobehub/ui, antd-style
|
|
15
13
|
- **State Management**: Zustand, SWR
|
|
@@ -19,24 +17,33 @@ Built with modern technologies:
|
|
|
19
17
|
|
|
20
18
|
## Directory Structure
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
```
|
|
21
|
+
lobe-chat/
|
|
22
|
+
├── apps/desktop/ # Electron desktop app
|
|
23
|
+
├── packages/ # Shared packages (@lobechat/*)
|
|
24
|
+
│ ├── database/ # Database schemas, models, repositories
|
|
25
|
+
│ ├── agent-runtime/ # Agent runtime
|
|
26
|
+
│ └── ...
|
|
27
|
+
├── src/
|
|
28
|
+
│ ├── app/ # Next.js app router
|
|
29
|
+
│ ├── store/ # Zustand stores
|
|
30
|
+
│ ├── services/ # Client services
|
|
31
|
+
│ ├── server/ # Server services and routers
|
|
32
|
+
│ └── ...
|
|
33
|
+
├── .agents/skills/ # AI development skills
|
|
34
|
+
└── e2e/ # E2E tests (Cucumber + Playwright)
|
|
35
|
+
```
|
|
30
36
|
|
|
31
37
|
## Development Workflow
|
|
32
38
|
|
|
33
39
|
### Git Workflow
|
|
34
40
|
|
|
35
|
-
- The current release branch is `next`
|
|
41
|
+
- The current release branch is `next` until v2.0.0 is officially released
|
|
36
42
|
- Use rebase for git pull
|
|
37
43
|
- Git commit messages should prefix with gitmoji
|
|
38
44
|
- Git branch name format: `username/feat/feature-name`
|
|
39
45
|
- Use `.github/PULL_REQUEST_TEMPLATE.md` for PR descriptions
|
|
46
|
+
- PR titles with `✨ feat/` or `🐛 fix` trigger releases
|
|
40
47
|
|
|
41
48
|
### Package Management
|
|
42
49
|
|
|
@@ -52,17 +59,18 @@ The project follows a well-organized monorepo structure:
|
|
|
52
59
|
|
|
53
60
|
### Testing Strategy
|
|
54
61
|
|
|
55
|
-
|
|
62
|
+
```bash
|
|
63
|
+
# Web tests
|
|
64
|
+
bunx vitest run --silent='passed-only' '[file-path-pattern]'
|
|
56
65
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
- Packages: `cd packages/[package-name] && bunx vitest run --silent='passed-only' '[file-path-pattern]'` (each subpackage contains its own vitest.config.mts)
|
|
66
|
+
# Package tests (e.g., database)
|
|
67
|
+
cd packages/[package-name] && bunx vitest run --silent='passed-only' '[file-path-pattern]'
|
|
68
|
+
```
|
|
61
69
|
|
|
62
70
|
**Important Notes**:
|
|
63
71
|
|
|
64
72
|
- Wrap file paths in single quotes to avoid shell expansion
|
|
65
|
-
- Never run `bun run test` - this runs all tests and takes
|
|
73
|
+
- Never run `bun run test` - this runs all tests and takes ~10 minutes
|
|
66
74
|
|
|
67
75
|
### Type Checking
|
|
68
76
|
|
|
@@ -78,40 +86,19 @@ The project follows a well-organized monorepo structure:
|
|
|
78
86
|
|
|
79
87
|
Follow [Linear rules in CLAUDE.md](CLAUDE.md#linear-issue-management-ignore-if-not-installed-linear-mcp) when working with Linear issues.
|
|
80
88
|
|
|
81
|
-
##
|
|
82
|
-
|
|
83
|
-
All
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
- `
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
- `zustand-action-patterns.mdc` – Recommended patterns for organizing Zustand actions
|
|
99
|
-
- `zustand-slice-organization.mdc` – Best practices for structuring Zustand slices
|
|
100
|
-
|
|
101
|
-
### Desktop (Electron)
|
|
102
|
-
|
|
103
|
-
- `desktop-feature-implementation.mdc` – Implementing new Electron desktop features
|
|
104
|
-
- `desktop-controller-tests.mdc` – Desktop controller unit testing guide
|
|
105
|
-
- `desktop-local-tools-implement.mdc` – Workflow to add new desktop local tools
|
|
106
|
-
- `desktop-menu-configuration.mdc` – Desktop menu configuration guide
|
|
107
|
-
- `desktop-window-management.mdc` – Desktop window management guide
|
|
108
|
-
|
|
109
|
-
### Debugging
|
|
110
|
-
|
|
111
|
-
- `debug-usage.mdc` – Using the debug package and namespace conventions
|
|
112
|
-
|
|
113
|
-
### Testing
|
|
114
|
-
|
|
115
|
-
- `testing-guide/testing-guide.mdc` – Comprehensive testing guide for Vitest
|
|
116
|
-
- `testing-guide/electron-ipc-test.mdc` – Electron IPC interface testing strategy
|
|
117
|
-
- `testing-guide/db-model-test.mdc` – Database Model testing guide
|
|
89
|
+
## Skills (Auto-loaded)
|
|
90
|
+
|
|
91
|
+
All AI development skills are available in `.agents/skills/` directory:
|
|
92
|
+
|
|
93
|
+
| Category | Skills |
|
|
94
|
+
|----------|--------|
|
|
95
|
+
| Frontend | `react`, `typescript`, `i18n`, `microcopy` |
|
|
96
|
+
| State | `zustand` |
|
|
97
|
+
| Backend | `drizzle` |
|
|
98
|
+
| Desktop | `desktop` |
|
|
99
|
+
| Testing | `testing` |
|
|
100
|
+
| UI | `modal`, `hotkey`, `recent-data` |
|
|
101
|
+
| Config | `add-provider-doc`, `add-setting-env` |
|
|
102
|
+
| Workflow | `linear`, `debug` |
|
|
103
|
+
| Performance | `vercel-react-best-practices` |
|
|
104
|
+
| Overview | `project-overview` |
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,66 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 2.0.0-next.355](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.354...v2.0.0-next.355)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2026-01-23**</sup>
|
|
8
|
+
|
|
9
|
+
#### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **home**: Use correct CreateGroupModal for session group creation.
|
|
12
|
+
- **misc**: Fix favorite refresh bug and group topic refresh issue.
|
|
13
|
+
|
|
14
|
+
<br/>
|
|
15
|
+
|
|
16
|
+
<details>
|
|
17
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
18
|
+
|
|
19
|
+
#### What's fixed
|
|
20
|
+
|
|
21
|
+
- **home**: Use correct CreateGroupModal for session group creation, closes [#11752](https://github.com/lobehub/lobe-chat/issues/11752) ([36bcc50](https://github.com/lobehub/lobe-chat/commit/36bcc50))
|
|
22
|
+
- **misc**: Fix favorite refresh bug and group topic refresh issue, closes [#11745](https://github.com/lobehub/lobe-chat/issues/11745) ([5d115ef](https://github.com/lobehub/lobe-chat/commit/5d115ef))
|
|
23
|
+
|
|
24
|
+
</details>
|
|
25
|
+
|
|
26
|
+
<div align="right">
|
|
27
|
+
|
|
28
|
+
[](#readme-top)
|
|
29
|
+
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
## [Version 2.0.0-next.354](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.353...v2.0.0-next.354)
|
|
33
|
+
|
|
34
|
+
<sup>Released on **2026-01-23**</sup>
|
|
35
|
+
|
|
36
|
+
#### ♻ Code Refactoring
|
|
37
|
+
|
|
38
|
+
- **misc**: Migrate AI Rules to Claude Code Skills.
|
|
39
|
+
|
|
40
|
+
#### 🐛 Bug Fixes
|
|
41
|
+
|
|
42
|
+
- **pdf**: Ensure worker config before Document render.
|
|
43
|
+
|
|
44
|
+
<br/>
|
|
45
|
+
|
|
46
|
+
<details>
|
|
47
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
48
|
+
|
|
49
|
+
#### Code refactoring
|
|
50
|
+
|
|
51
|
+
- **misc**: Migrate AI Rules to Claude Code Skills, closes [#11737](https://github.com/lobehub/lobe-chat/issues/11737) ([346fc46](https://github.com/lobehub/lobe-chat/commit/346fc46))
|
|
52
|
+
|
|
53
|
+
#### What's fixed
|
|
54
|
+
|
|
55
|
+
- **pdf**: Ensure worker config before Document render, closes [#11746](https://github.com/lobehub/lobe-chat/issues/11746) ([ad34072](https://github.com/lobehub/lobe-chat/commit/ad34072))
|
|
56
|
+
|
|
57
|
+
</details>
|
|
58
|
+
|
|
59
|
+
<div align="right">
|
|
60
|
+
|
|
61
|
+
[](#readme-top)
|
|
62
|
+
|
|
63
|
+
</div>
|
|
64
|
+
|
|
5
65
|
## [Version 2.0.0-next.353](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.352...v2.0.0-next.353)
|
|
6
66
|
|
|
7
67
|
<sup>Released on **2026-01-23**</sup>
|
package/CLAUDE.md
CHANGED
|
@@ -1,72 +1,83 @@
|
|
|
1
1
|
# CLAUDE.md
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Guidelines for using Claude Code in this LobeChat repository.
|
|
4
4
|
|
|
5
5
|
## Tech Stack
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
- Next.js 16 + React 19 + TypeScript
|
|
8
|
+
- SPA inside Next.js with `react-router-dom`
|
|
9
|
+
- `@lobehub/ui`, antd for components; antd-style for CSS-in-JS
|
|
10
|
+
- react-i18next for i18n; zustand for state management
|
|
11
|
+
- SWR for data fetching; TRPC for type-safe backend
|
|
12
|
+
- Drizzle ORM with PostgreSQL; Vitest for testing
|
|
13
|
+
|
|
14
|
+
## Project Structure
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
lobe-chat/
|
|
18
|
+
├── apps/desktop/ # Electron desktop app
|
|
19
|
+
├── packages/ # Shared packages (@lobechat/*)
|
|
20
|
+
│ ├── database/ # Database schemas, models, repositories
|
|
21
|
+
│ ├── agent-runtime/ # Agent runtime
|
|
22
|
+
│ └── ...
|
|
23
|
+
├── src/
|
|
24
|
+
│ ├── app/ # Next.js app router
|
|
25
|
+
│ ├── store/ # Zustand stores
|
|
26
|
+
│ ├── services/ # Client services
|
|
27
|
+
│ ├── server/ # Server services and routers
|
|
28
|
+
│ └── ...
|
|
29
|
+
└── e2e/ # E2E tests (Cucumber + Playwright)
|
|
30
|
+
```
|
|
12
31
|
|
|
13
32
|
## Development
|
|
14
33
|
|
|
15
34
|
### Git Workflow
|
|
16
35
|
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
- PR titles starting with `✨ feat/` or `🐛 fix` will trigger the release workflow upon merge. Only use these prefixes for significant user-facing feature changes or bug fixes
|
|
36
|
+
- Use rebase for `git pull`
|
|
37
|
+
- Commit messages: prefix with gitmoji
|
|
38
|
+
- Branch format: `<type>/<feature-name>`
|
|
39
|
+
- PR titles with `✨ feat/` or `🐛 fix` trigger releases
|
|
22
40
|
|
|
23
41
|
### Package Management
|
|
24
42
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
- Use `bun` to run npm scripts
|
|
29
|
-
- Use `bunx` to run executable npm packages
|
|
30
|
-
|
|
31
|
-
### TypeScript Code Style Guide
|
|
32
|
-
|
|
33
|
-
see @.cursor/rules/typescript.mdc
|
|
34
|
-
|
|
35
|
-
### Code Comments
|
|
36
|
-
|
|
37
|
-
- **Avoid meaningless comments**: Do not write comments that merely restate what the code does. Comments should explain _why_ something is done, not _what_ is being done. The code itself should be self-explanatory.
|
|
43
|
+
- `pnpm` for dependency management
|
|
44
|
+
- `bun` to run npm scripts
|
|
45
|
+
- `bunx` for executable npm packages
|
|
38
46
|
|
|
39
47
|
### Testing
|
|
40
48
|
|
|
41
|
-
|
|
42
|
-
-
|
|
43
|
-
|
|
44
|
-
- packages(eg: database): `cd packages/database && bunx vitest run --silent='passed-only' '[file-path-pattern]'`
|
|
49
|
+
```bash
|
|
50
|
+
# Run specific test (NEVER run `bun run test` - takes ~10 minutes)
|
|
51
|
+
bunx vitest run --silent='passed-only' '[file-path]'
|
|
45
52
|
|
|
46
|
-
|
|
53
|
+
# Database package
|
|
54
|
+
cd packages/database && bunx vitest run --silent='passed-only' '[file]'
|
|
55
|
+
```
|
|
47
56
|
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
- **Prefer `vi.spyOn` over `vi.mock`**: When mocking modules or functions, prefer using `vi.spyOn` to mock specific functions rather than `vi.mock` to mock entire modules. This approach is more targeted, easier to maintain, and allows for better control over mock behavior in individual tests.
|
|
52
|
-
- **Tests must pass type check**: After writing or modifying tests, run `bun run type-check` to ensure there are no type errors. Tests should pass both runtime execution and TypeScript type checking.
|
|
57
|
+
- Prefer `vi.spyOn` over `vi.mock`
|
|
58
|
+
- Tests must pass type check: `bun run type-check`
|
|
59
|
+
- After 2 failed fix attempts, stop and ask for help
|
|
53
60
|
|
|
54
|
-
###
|
|
61
|
+
### i18n
|
|
55
62
|
|
|
56
|
-
-
|
|
63
|
+
- Add keys to `src/locales/default/namespace.ts`
|
|
64
|
+
- For dev preview: translate `locales/zh-CN/` and `locales/en-US/`
|
|
65
|
+
- Don't run `pnpm i18n` - CI handles it
|
|
57
66
|
|
|
58
|
-
|
|
67
|
+
## Linear Issue Management
|
|
68
|
+
|
|
69
|
+
**Trigger conditions** - when ANY of these occur, apply Linear workflow:
|
|
59
70
|
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
71
|
+
- User mentions issue ID like `LOBE-XXX`
|
|
72
|
+
- User says "linear", "link linear", "linear issue"
|
|
73
|
+
- Creating PR that references a Linear issue
|
|
63
74
|
|
|
64
|
-
|
|
75
|
+
**Workflow:**
|
|
65
76
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
77
|
+
1. Use `ToolSearch` to confirm `linear-server` MCP exists (search `linear` or `mcp__linear-server__`)
|
|
78
|
+
2. If found, read `.agents/skills/linear/SKILL.md` and follow the workflow
|
|
79
|
+
3. If not found, skip Linear integration (treat as not installed)
|
|
69
80
|
|
|
70
|
-
##
|
|
81
|
+
## Skills (Auto-loaded by Claude)
|
|
71
82
|
|
|
72
|
-
|
|
83
|
+
Claude Code automatically loads relevant skills from `.agents/skills/`.
|