@lobehub/lobehub 2.0.0-next.353 → 2.0.0-next.354

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.
Files changed (119) hide show
  1. package/.agents/skills/add-provider-doc/SKILL.md +90 -0
  2. package/.agents/skills/add-setting-env/SKILL.md +106 -0
  3. package/.agents/skills/debug/SKILL.md +66 -0
  4. package/.agents/skills/desktop/SKILL.md +78 -0
  5. package/.agents/skills/desktop/references/feature-implementation.md +99 -0
  6. package/.agents/skills/desktop/references/local-tools.md +133 -0
  7. package/.agents/skills/desktop/references/menu-config.md +103 -0
  8. package/.agents/skills/desktop/references/window-management.md +143 -0
  9. package/.agents/skills/drizzle/SKILL.md +129 -0
  10. package/.agents/skills/drizzle/references/db-migrations.md +50 -0
  11. package/.agents/skills/hotkey/SKILL.md +90 -0
  12. package/{.cursor/rules/i18n.mdc → .agents/skills/i18n/SKILL.md} +14 -23
  13. package/.agents/skills/linear/SKILL.md +51 -0
  14. package/.agents/skills/microcopy/SKILL.md +83 -0
  15. package/.agents/skills/modal/SKILL.md +102 -0
  16. package/{.cursor/rules/project-structure.mdc → .agents/skills/project-overview/SKILL.md} +65 -37
  17. package/.agents/skills/react/SKILL.md +73 -0
  18. package/.agents/skills/react/references/layout-kit.md +100 -0
  19. package/.agents/skills/recent-data/SKILL.md +108 -0
  20. package/.agents/skills/testing/SKILL.md +89 -0
  21. package/.agents/skills/testing/references/agent-runtime-e2e.md +126 -0
  22. package/.agents/skills/testing/references/db-model-test.md +124 -0
  23. package/.agents/skills/testing/references/desktop-controller-test.md +124 -0
  24. package/.agents/skills/testing/references/electron-ipc-test.md +63 -0
  25. package/.agents/skills/testing/references/zustand-store-action-test.md +150 -0
  26. package/.agents/skills/typescript/SKILL.md +52 -0
  27. package/.agents/skills/zustand/SKILL.md +78 -0
  28. package/.agents/skills/zustand/references/action-patterns.md +125 -0
  29. package/.agents/skills/zustand/references/slice-organization.md +125 -0
  30. package/AGENTS.md +42 -55
  31. package/CHANGELOG.md +33 -0
  32. package/CLAUDE.md +57 -46
  33. package/GEMINI.md +47 -39
  34. package/changelog/v1.json +9 -0
  35. package/package.json +1 -1
  36. package/src/features/FileViewer/Renderer/PDF/index.tsx +2 -3
  37. package/src/features/ShareModal/SharePdf/PdfPreview.tsx +1 -2
  38. package/src/libs/pdfjs/index.tsx +25 -0
  39. package/src/store/test-coverage.md +5 -5
  40. package/.cursor/rules/add-provider-doc.mdc +0 -183
  41. package/.cursor/rules/add-setting-env.mdc +0 -175
  42. package/.cursor/rules/cursor-rules.mdc +0 -28
  43. package/.cursor/rules/db-migrations.mdc +0 -46
  44. package/.cursor/rules/debug-usage.mdc +0 -86
  45. package/.cursor/rules/desktop-controller-tests.mdc +0 -189
  46. package/.cursor/rules/desktop-feature-implementation.mdc +0 -155
  47. package/.cursor/rules/desktop-local-tools-implement.mdc +0 -81
  48. package/.cursor/rules/desktop-menu-configuration.mdc +0 -209
  49. package/.cursor/rules/desktop-window-management.mdc +0 -301
  50. package/.cursor/rules/drizzle-schema-style-guide.mdc +0 -218
  51. package/.cursor/rules/hotkey.mdc +0 -162
  52. package/.cursor/rules/linear.mdc +0 -53
  53. package/.cursor/rules/microcopy-cn.mdc +0 -158
  54. package/.cursor/rules/microcopy-en.mdc +0 -148
  55. package/.cursor/rules/modal-imperative.mdc +0 -162
  56. package/.cursor/rules/packages/react-layout-kit.mdc +0 -122
  57. package/.cursor/rules/project-introduce.mdc +0 -36
  58. package/.cursor/rules/react.mdc +0 -169
  59. package/.cursor/rules/recent-data-usage.mdc +0 -139
  60. package/.cursor/rules/rules-index.mdc +0 -44
  61. package/.cursor/rules/testing-guide/agent-runtime-e2e.mdc +0 -285
  62. package/.cursor/rules/testing-guide/db-model-test.mdc +0 -455
  63. package/.cursor/rules/testing-guide/electron-ipc-test.mdc +0 -80
  64. package/.cursor/rules/testing-guide/testing-guide.mdc +0 -534
  65. package/.cursor/rules/testing-guide/zustand-store-action-test.mdc +0 -574
  66. package/.cursor/rules/typescript.mdc +0 -55
  67. package/.cursor/rules/zustand-action-patterns.mdc +0 -328
  68. package/.cursor/rules/zustand-slice-organization.mdc +0 -308
  69. package/src/libs/pdfjs/pdf.worker.ts +0 -1
  70. package/src/libs/pdfjs/worker.ts +0 -12
  71. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/AGENTS.md +0 -0
  72. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/SKILL.md +0 -0
  73. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/advanced-event-handler-refs.md +0 -0
  74. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/advanced-use-latest.md +0 -0
  75. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/async-api-routes.md +0 -0
  76. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/async-defer-await.md +0 -0
  77. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/async-dependencies.md +0 -0
  78. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/async-parallel.md +0 -0
  79. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/async-suspense-boundaries.md +0 -0
  80. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/bundle-barrel-imports.md +0 -0
  81. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/bundle-conditional.md +0 -0
  82. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/bundle-defer-third-party.md +0 -0
  83. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/bundle-dynamic-imports.md +0 -0
  84. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/bundle-preload.md +0 -0
  85. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/client-event-listeners.md +0 -0
  86. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/client-localstorage-schema.md +0 -0
  87. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/client-passive-event-listeners.md +0 -0
  88. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/client-swr-dedup.md +0 -0
  89. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-batch-dom-css.md +0 -0
  90. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-cache-function-results.md +0 -0
  91. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-cache-property-access.md +0 -0
  92. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-cache-storage.md +0 -0
  93. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-combine-iterations.md +0 -0
  94. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-early-exit.md +0 -0
  95. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-hoist-regexp.md +0 -0
  96. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-index-maps.md +0 -0
  97. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-length-check-first.md +0 -0
  98. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-min-max-loop.md +0 -0
  99. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-set-map-lookups.md +0 -0
  100. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-tosorted-immutable.md +0 -0
  101. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-activity.md +0 -0
  102. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-animate-svg-wrapper.md +0 -0
  103. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-conditional-render.md +0 -0
  104. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-content-visibility.md +0 -0
  105. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-hoist-jsx.md +0 -0
  106. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-hydration-no-flicker.md +0 -0
  107. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-svg-precision.md +0 -0
  108. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-defer-reads.md +0 -0
  109. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-dependencies.md +0 -0
  110. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-derived-state.md +0 -0
  111. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-functional-setstate.md +0 -0
  112. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-lazy-state-init.md +0 -0
  113. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-memo.md +0 -0
  114. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-transitions.md +0 -0
  115. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/server-after-nonblocking.md +0 -0
  116. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/server-cache-lru.md +0 -0
  117. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/server-cache-react.md +0 -0
  118. /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/server-parallel-fetching.md +0 -0
  119. /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
+ ```