@lobehub/lobehub 2.0.0-next.302 → 2.0.0-next.304

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 (42) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/apps/desktop/src/common/routes.ts +8 -8
  3. package/apps/desktop/src/main/const/dir.ts +2 -2
  4. package/apps/desktop/src/main/const/env.ts +4 -4
  5. package/apps/desktop/src/main/const/store.ts +3 -3
  6. package/apps/desktop/src/main/controllers/AuthCtr.ts +1 -1
  7. package/apps/desktop/src/main/controllers/McpInstallCtr.ts +8 -8
  8. package/apps/desktop/src/main/controllers/NetworkProxyCtr.ts +9 -9
  9. package/apps/desktop/src/main/controllers/RemoteServerSyncCtr.ts +8 -8
  10. package/apps/desktop/src/main/core/App.ts +9 -9
  11. package/apps/desktop/src/main/core/infrastructure/StaticFileServerManager.ts +2 -2
  12. package/apps/desktop/src/main/core/ui/ShortcutManager.ts +10 -10
  13. package/apps/desktop/src/main/core/ui/TrayManager.ts +12 -12
  14. package/apps/desktop/src/main/locales/resources.ts +4 -4
  15. package/apps/desktop/src/main/menus/impls/macOS.ts +1 -1
  16. package/apps/desktop/src/main/menus/types.ts +5 -5
  17. package/apps/desktop/src/main/modules/updater/configs.ts +10 -10
  18. package/apps/desktop/src/main/modules/updater/utils.ts +9 -9
  19. package/apps/desktop/src/main/services/fileSrv.ts +62 -62
  20. package/apps/desktop/src/main/shortcuts/config.ts +3 -3
  21. package/apps/desktop/src/main/types/protocol.ts +12 -12
  22. package/apps/desktop/src/main/utils/file-system.ts +2 -2
  23. package/apps/desktop/src/main/utils/logger.ts +5 -5
  24. package/apps/desktop/src/main/utils/protocol.ts +32 -32
  25. package/changelog/v1.json +18 -0
  26. package/locales/en-US/plugin.json +1 -0
  27. package/locales/zh-CN/discover.json +4 -4
  28. package/locales/zh-CN/plugin.json +1 -0
  29. package/package.json +1 -1
  30. package/packages/builtin-tool-group-management/src/client/Inspector/ExecuteAgentTask/index.tsx +78 -0
  31. package/packages/builtin-tool-group-management/src/client/Inspector/{ExecuteTasks → ExecuteAgentTasks}/index.tsx +1 -5
  32. package/packages/builtin-tool-group-management/src/client/Inspector/index.ts +4 -2
  33. package/packages/database/src/schemas/relations.ts +4 -4
  34. package/src/features/Conversation/ChatList/components/AutoScroll.tsx +3 -9
  35. package/src/features/Conversation/ChatList/components/VirtualizedList.tsx +2 -6
  36. package/src/features/Conversation/Messages/Assistant/index.tsx +1 -1
  37. package/src/features/Conversation/Messages/AssistantGroup/components/MessageContent.tsx +3 -3
  38. package/src/features/Conversation/Messages/Supervisor/components/MessageContent.tsx +2 -2
  39. package/src/features/Conversation/Messages/components/ContentLoading.tsx +5 -3
  40. package/src/locales/default/plugin.ts +1 -0
  41. package/src/store/chat/slices/operation/__tests__/selectors.test.ts +165 -0
  42. package/src/store/chat/slices/operation/selectors.ts +23 -0
@@ -1,34 +1,34 @@
1
1
  import { isDev } from '@/const/env';
2
2
  import { getDesktopEnv } from '@/env';
3
3
 
4
- // 更新频道(stable, beta, alpha 等)
4
+ // Update channel (stable, beta, alpha, etc.)
5
5
  export const UPDATE_CHANNEL = getDesktopEnv().UPDATE_CHANNEL || 'stable';
6
6
 
7
- // 判断是否为 stable 频道
7
+ // Determine if stable channel
8
8
  export const isStableChannel = UPDATE_CHANNEL === 'stable' || !UPDATE_CHANNEL;
9
9
 
10
- // 自定义更新服务器 URL (用于 stable 频道)
10
+ // Custom update server URL (for stable channel)
11
11
  // e.g., https://releases.lobehub.com/stable
12
12
  export const UPDATE_SERVER_URL = getDesktopEnv().UPDATE_SERVER_URL;
13
13
 
14
- // GitHub 配置 (用于 beta/nightly 频道,或作为 fallback)
14
+ // GitHub configuration (for beta/nightly channels, or as fallback)
15
15
  export const githubConfig = {
16
16
  owner: 'lobehub',
17
17
  repo: 'lobe-chat',
18
18
  };
19
19
 
20
20
  export const updaterConfig = {
21
- // 应用更新配置
21
+ // 应用Update configuration
22
22
  app: {
23
- // 是否自动检查更新
23
+ // Whether to auto-check for updates
24
24
  autoCheckUpdate: true,
25
- // 是否自动下载更新
25
+ // Whether to auto-download updates
26
26
  autoDownloadUpdate: true,
27
- // 检查更新的时间间隔(毫秒)
28
- checkUpdateInterval: 60 * 60 * 1000, // 1小时
27
+ // Update check interval (milliseconds)
28
+ checkUpdateInterval: 60 * 60 * 1000, // 1 hour
29
29
  },
30
30
 
31
- // 是否启用应用更新
31
+ // Whether to enable application updates
32
32
  enableAppUpdate: !isDev,
33
33
 
34
34
  // 是否启用渲染层热更新
@@ -1,33 +1,33 @@
1
1
  import semver from 'semver';
2
2
 
3
3
  /**
4
- * 判断是否需要应用更新而非仅渲染层更新
5
- * @param currentVersion 当前版本
6
- * @param nextVersion 新版本
7
- * @returns 是否需要应用更新
4
+ * Determine if application update is needed rather than just renderer update
5
+ * @param currentVersion Current version
6
+ * @param nextVersion New version
7
+ * @returns Whether application update is needed
8
8
  */
9
9
  export const shouldUpdateApp = (currentVersion: string, nextVersion: string): boolean => {
10
- // 如果版本号包含 .app 后缀,强制进行应用更新
10
+ // If version contains .app suffix, force application update
11
11
  if (nextVersion.includes('.app')) {
12
12
  return true;
13
13
  }
14
14
 
15
15
  try {
16
- // 解析版本号
16
+ // Parse version number
17
17
  const current = semver.parse(currentVersion);
18
18
  const next = semver.parse(nextVersion);
19
19
 
20
20
  if (!current || !next) return true;
21
21
 
22
- // 主版本号或次版本号变更时,需要进行应用更新
22
+ // Application update needed when major or minor version changes
23
23
  if (current.major !== next.major || current.minor !== next.minor) {
24
24
  return true;
25
25
  }
26
26
 
27
- // 仅修订版本号变更,优先进行渲染层热更新
27
+ // For patch version changes only, prioritize renderer hot update
28
28
  return false;
29
29
  } catch {
30
- // 解析失败时,默认进行应用更新
30
+ // Default to application update when parsing fails
31
31
  return true;
32
32
  }
33
33
  };
@@ -11,7 +11,7 @@ import { createLogger } from '@/utils/logger';
11
11
  import { ServiceModule } from './index';
12
12
 
13
13
  /**
14
- * 文件未找到错误类
14
+ * File not found error class
15
15
  */
16
16
  export class FileNotFoundError extends Error {
17
17
  constructor(
@@ -46,8 +46,8 @@ export interface FileMetadata {
46
46
 
47
47
  export default class FileService extends ServiceModule {
48
48
  /**
49
- * 获取旧版上传目录路径
50
- * @deprecated 仅用于向后兼容旧版文件访问,新文件应存储在 FILE_STORAGE_DIR 的自定义路径下
49
+ * Get legacy upload directory path
50
+ * @deprecated Only for backward compatibility with legacy file access, new files should be stored under custom paths in FILE_STORAGE_DIR
51
51
  */
52
52
  get UPLOADS_DIR() {
53
53
  return join(this.app.appStoragePath, FILE_STORAGE_DIR, 'uploads');
@@ -58,7 +58,7 @@ export default class FileService extends ServiceModule {
58
58
  }
59
59
 
60
60
  /**
61
- * 上传文件到本地存储
61
+ * Upload file to local storage
62
62
  */
63
63
  async uploadFile({
64
64
  content,
@@ -69,15 +69,15 @@ export default class FileService extends ServiceModule {
69
69
  }: UploadFileParams): Promise<{ metadata: FileMetadata; success: boolean }> {
70
70
  logger.info(`Starting to upload file: ${filename}, hash: ${hash}, path: ${filePath}`);
71
71
  try {
72
- // 获取当前时间戳,避免重复调用 Date.now()
72
+ // Get current timestamp, avoid repeated Date.now() calls
73
73
  const now = Date.now();
74
74
  const date = (now / 1000 / 60 / 60).toFixed(0);
75
75
 
76
- // 使用传入的 filePath 作为文件的存储路径
76
+ // Use provided filePath as the file storage path
77
77
  const fullStoragePath = join(this.app.appStoragePath, FILE_STORAGE_DIR, filePath);
78
78
  logger.debug(`Target file storage path: ${fullStoragePath}`);
79
79
 
80
- // 确保目标目录存在
80
+ // Ensure target directory exists
81
81
  const targetDir = path.dirname(fullStoragePath);
82
82
  logger.debug(`Ensuring target directory exists: ${targetDir}`);
83
83
  makeSureDirExist(targetDir);
@@ -85,23 +85,23 @@ export default class FileService extends ServiceModule {
85
85
  const savedPath = fullStoragePath;
86
86
  logger.debug(`Final file save path: ${savedPath}`);
87
87
 
88
- // 根据 content 类型创建 Buffer
88
+ // Create Buffer based on content type
89
89
  let buffer: Buffer;
90
90
  if (typeof content === 'string') {
91
- // 来自服务端的 Base64 字符串
91
+ // Base64 string from server
92
92
  buffer = Buffer.from(content, 'base64');
93
93
  logger.debug(`Creating buffer from Base64 string, size: ${buffer.length} bytes`);
94
94
  } else {
95
- // 来自浏览器端的 ArrayBuffer
95
+ // ArrayBuffer from browser
96
96
  buffer = Buffer.from(content);
97
97
  logger.debug(`Creating buffer from ArrayBuffer, size: ${buffer.length} bytes`);
98
98
  }
99
99
  await writeFile(savedPath, buffer);
100
100
 
101
- // 写入元数据文件
101
+ // Write metadata file
102
102
  const metaFilePath = `${savedPath}.meta`;
103
103
  const metadata = {
104
- createdAt: now, // 使用统一的时间戳
104
+ createdAt: now, // Use unified timestamp
105
105
  filename,
106
106
  hash,
107
107
  size: buffer.length,
@@ -110,18 +110,18 @@ export default class FileService extends ServiceModule {
110
110
  logger.debug(`Writing metadata file: ${metaFilePath}`);
111
111
  await writeFile(metaFilePath, JSON.stringify(metadata, null, 2));
112
112
 
113
- // 返回与S3兼容的元数据格式
113
+ // Return S3-compatible metadata format
114
114
  const desktopPath = `desktop://${filePath}`;
115
115
  logger.info(`File upload successful: ${desktopPath}`);
116
116
 
117
- // 从路径中提取文件名和目录信息
117
+ // Extract filename and directory information from path
118
118
  const parsedPath = path.parse(filePath);
119
119
  const dirname = parsedPath.dir || '';
120
120
  const savedFilename = parsedPath.base;
121
121
 
122
122
  return {
123
123
  metadata: {
124
- date, // 保持时间戳格式,用于兼容性和时间追踪
124
+ date, // Keep timestamp format for compatibility and time tracking
125
125
  dirname,
126
126
  filename: savedFilename,
127
127
  path: desktopPath,
@@ -135,25 +135,25 @@ export default class FileService extends ServiceModule {
135
135
  }
136
136
 
137
137
  /**
138
- * 判断路径是否为旧版格式(时间戳目录)
138
+ * Check if path is in legacy format (timestamp directory)
139
139
  *
140
- * 旧版路径格式: {timestamp}/{hash}.{ext} (例如: 1234567890/abc123.png)
141
- * 新版路径格式: 任意自定义路径 (例如: user_uploads/images/photo.png, ai_generations/image.jpg)
140
+ * Legacy path format: {timestamp}/{hash}.{ext} (e.g., 1234567890/abc123.png)
141
+ * New path format: arbitrary custom paths (e.g., user_uploads/images/photo.png, ai_generations/image.jpg)
142
142
  *
143
- * @param path - 相对路径,不包含 desktop:// 前缀
144
- * @returns true 如果是旧版格式,false 如果是新版格式
143
+ * @param path - Relative path, without desktop:// prefix
144
+ * @returns true if legacy format, false if new format
145
145
  */
146
146
  private isLegacyPath(path: string): boolean {
147
147
  const parts = path.split('/');
148
148
  if (parts.length < 2) return false;
149
149
 
150
- // 如果第一部分是纯数字(时间戳),则认为是旧版格式
151
- // 时间戳格式:精确到小时的 Unix 时间戳,通常是 10 位数字
150
+ // If the first part is purely numeric (timestamp), consider it legacy format
151
+ // Timestamp format: Unix timestamp accurate to the hour, typically 10 digits
152
152
  return /^\d+$/.test(parts[0]);
153
153
  }
154
154
 
155
155
  /**
156
- * 获取文件内容
156
+ * Get file content
157
157
  */
158
158
  async getFile(path: string): Promise<{ content: ArrayBuffer; mimeType: string }> {
159
159
  logger.info(`Getting file content: ${path}`);
@@ -164,30 +164,30 @@ export default class FileService extends ServiceModule {
164
164
  throw new Error(`Invalid desktop file path: ${path}`);
165
165
  }
166
166
 
167
- // 标准化路径格式
168
- // 可能收到的格式: desktop:/12345/file.png desktop://12345/file.png
167
+ // Normalize path format
168
+ // Possible formats received: desktop:/12345/file.png or desktop://12345/file.png
169
169
  const normalizedPath = path.replace(/^desktop:\/+/, 'desktop://');
170
170
  logger.debug(`Normalized path: ${normalizedPath}`);
171
171
 
172
- // 解析路径
172
+ // Parse path
173
173
  const relativePath = normalizedPath.replace('desktop://', '');
174
174
 
175
- // 智能路由:根据路径格式决定从哪个目录读取文件
175
+ // Smart routing: decide which directory to read file from based on path format
176
176
  let filePath: string;
177
177
  let isLegacyAttempt = false;
178
178
 
179
179
  if (this.isLegacyPath(relativePath)) {
180
- // 旧版路径:从 uploads 目录读取(向后兼容)
180
+ // Legacy path: read from uploads directory (backward compatibility)
181
181
  filePath = join(this.UPLOADS_DIR, relativePath);
182
182
  isLegacyAttempt = true;
183
183
  logger.debug(`Legacy path detected, reading from uploads directory: ${filePath}`);
184
184
  } else {
185
- // 新版路径:从 FILE_STORAGE_DIR 根目录读取
185
+ // New path: read from FILE_STORAGE_DIR root directory
186
186
  filePath = join(this.app.appStoragePath, FILE_STORAGE_DIR, relativePath);
187
187
  logger.debug(`New path format, reading from storage root: ${filePath}`);
188
188
  }
189
189
 
190
- // 读取文件内容,如果第一次尝试失败且是 legacy 路径,则尝试新路径
190
+ // Read file content, if first attempt fails and is legacy path, try new path
191
191
  logger.debug(`Starting to read file content`);
192
192
  let content: Buffer;
193
193
  try {
@@ -195,14 +195,14 @@ export default class FileService extends ServiceModule {
195
195
  logger.debug(`File content read complete, size: ${content.length} bytes`);
196
196
  } catch (firstError) {
197
197
  if (isLegacyAttempt) {
198
- // 如果是 legacy 路径读取失败,尝试从新路径读取
198
+ // If legacy path read fails, try reading from new path
199
199
  const fallbackPath = join(this.app.appStoragePath, FILE_STORAGE_DIR, relativePath);
200
200
  logger.debug(
201
201
  `Legacy path read failed, attempting fallback to storage root: ${fallbackPath}`,
202
202
  );
203
203
  try {
204
204
  content = await readFilePromise(fallbackPath);
205
- filePath = fallbackPath; // 更新 filePath 用于后续的元数据读取
205
+ filePath = fallbackPath; // Update filePath for subsequent metadata reading
206
206
  logger.debug(`Fallback read successful, size: ${content.length} bytes`);
207
207
  } catch (fallbackError) {
208
208
  logger.error(
@@ -215,9 +215,9 @@ export default class FileService extends ServiceModule {
215
215
  }
216
216
  }
217
217
 
218
- // 读取元数据获取MIME类型
218
+ // Read metadata to get MIME type
219
219
  const metaFilePath = `${filePath}.meta`;
220
- let mimeType = 'application/octet-stream'; // 默认MIME类型
220
+ let mimeType = 'application/octet-stream'; // Default MIME type
221
221
  logger.debug(`Attempting to read metadata file: ${metaFilePath}`);
222
222
 
223
223
  try {
@@ -229,7 +229,7 @@ export default class FileService extends ServiceModule {
229
229
  logger.warn(
230
230
  `Failed to read metadata file: ${(metaError as Error).message}, using default MIME type`,
231
231
  );
232
- // 如果元数据文件不存在,尝试从文件扩展名猜测MIME类型
232
+ // If metadata file doesn't exist, try to guess MIME type from file extension
233
233
  const ext = path.split('.').pop()?.toLowerCase();
234
234
  if (ext) {
235
235
  if (['jpg', 'jpeg'].includes(ext)) mimeType = 'image/jpeg';
@@ -271,7 +271,7 @@ export default class FileService extends ServiceModule {
271
271
  } catch (error) {
272
272
  logger.error(`File retrieval failed:`, error);
273
273
 
274
- // 如果是文件不存在错误,抛出自定义的 FileNotFoundError
274
+ // If file not found error, throw custom FileNotFoundError
275
275
  if (error instanceof Error && error.message.includes('ENOENT')) {
276
276
  throw new FileNotFoundError(`File not found: ${path}`, path);
277
277
  }
@@ -281,7 +281,7 @@ export default class FileService extends ServiceModule {
281
281
  }
282
282
 
283
283
  /**
284
- * 删除文件
284
+ * Delete file
285
285
  */
286
286
  async deleteFile(path: string): Promise<{ success: boolean }> {
287
287
  logger.info(`Deleting file: ${path}`);
@@ -292,42 +292,42 @@ export default class FileService extends ServiceModule {
292
292
  throw new Error(`Invalid desktop file path: ${path}`);
293
293
  }
294
294
 
295
- // 标准化路径格式
295
+ // Normalize path format
296
296
  const normalizedPath = path.replace(/^desktop:\/+/, 'desktop://');
297
297
 
298
- // 解析路径
298
+ // Parse path
299
299
  const relativePath = normalizedPath.replace('desktop://', '');
300
300
 
301
- // 智能路由:根据路径格式决定从哪个目录删除文件
301
+ // Smart routing: decide which directory to delete file from based on path format
302
302
  let filePath: string;
303
303
  let isLegacyAttempt = false;
304
304
 
305
305
  if (this.isLegacyPath(relativePath)) {
306
- // 旧版路径:从 uploads 目录删除(向后兼容)
306
+ // Legacy path: delete from uploads directory (backward compatibility)
307
307
  filePath = join(this.UPLOADS_DIR, relativePath);
308
308
  isLegacyAttempt = true;
309
309
  logger.debug(`Legacy path detected, deleting from uploads directory: ${filePath}`);
310
310
  } else {
311
- // 新版路径:从 FILE_STORAGE_DIR 根目录删除
311
+ // New path: delete from FILE_STORAGE_DIR root directory
312
312
  filePath = join(this.app.appStoragePath, FILE_STORAGE_DIR, relativePath);
313
313
  logger.debug(`New path format, deleting from storage root: ${filePath}`);
314
314
  }
315
315
 
316
- // 删除文件及其元数据,如果第一次尝试失败且是 legacy 路径,则尝试新路径
316
+ // Delete file and its metadata, if first attempt fails and is legacy path, try new path
317
317
  logger.debug(`Starting file deletion`);
318
318
  try {
319
319
  await unlinkPromise(filePath);
320
320
  logger.debug(`File deletion successful`);
321
321
  } catch (firstError) {
322
322
  if (isLegacyAttempt) {
323
- // 如果是 legacy 路径删除失败,尝试从新路径删除
323
+ // If legacy path deletion fails, try deleting from new path
324
324
  const fallbackPath = join(this.app.appStoragePath, FILE_STORAGE_DIR, relativePath);
325
325
  logger.debug(
326
326
  `Legacy path deletion failed, attempting fallback to storage root: ${fallbackPath}`,
327
327
  );
328
328
  try {
329
329
  await unlinkPromise(fallbackPath);
330
- filePath = fallbackPath; // 更新 filePath 用于后续的元数据删除
330
+ filePath = fallbackPath; // Update filePath for subsequent metadata deletion
331
331
  logger.debug(`Fallback deletion successful`);
332
332
  } catch (fallbackError) {
333
333
  logger.error(
@@ -340,7 +340,7 @@ export default class FileService extends ServiceModule {
340
340
  }
341
341
  }
342
342
 
343
- // 尝试删除元数据文件,但不强制要求存在
343
+ // Try to delete metadata file, but don't require it to exist
344
344
  try {
345
345
  logger.debug(`Attempting to delete metadata file`);
346
346
  await unlinkPromise(`${filePath}.meta`);
@@ -358,13 +358,13 @@ export default class FileService extends ServiceModule {
358
358
  }
359
359
 
360
360
  /**
361
- * 批量删除文件
361
+ * Batch delete files
362
362
  */
363
363
  async deleteFiles(paths: string[]): Promise<DeleteFilesResponse> {
364
364
  logger.info(`Batch deleting files, count: ${paths.length}`);
365
365
  const errors: { message: string; path: string }[] = [];
366
366
 
367
- // 并行处理所有删除请求
367
+ // Process all deletion requests in parallel
368
368
  logger.debug(`Starting parallel deletion requests`);
369
369
  const results = await Promise.allSettled(
370
370
  paths.map(async (path) => {
@@ -382,7 +382,7 @@ export default class FileService extends ServiceModule {
382
382
  }),
383
383
  );
384
384
 
385
- // 处理结果
385
+ // Process results
386
386
  logger.debug(`Processing batch deletion results`);
387
387
  results.forEach((result) => {
388
388
  if (result.status === 'rejected') {
@@ -411,31 +411,31 @@ export default class FileService extends ServiceModule {
411
411
 
412
412
  async getFilePath(path: string): Promise<string> {
413
413
  logger.debug(`Getting filesystem path: ${path}`);
414
- // 处理desktop://路径
414
+ // Handle desktop:// paths
415
415
  if (!path.startsWith('desktop://')) {
416
416
  logger.error(`Invalid desktop file path: ${path}`);
417
417
  throw new Error(`Invalid desktop file path: ${path}`);
418
418
  }
419
419
 
420
- // 标准化路径格式
420
+ // Normalize path format
421
421
  const normalizedPath = path.replace(/^desktop:\/+/, 'desktop://');
422
422
 
423
- // 解析路径
423
+ // Parse path
424
424
  const relativePath = normalizedPath.replace('desktop://', '');
425
425
 
426
- // 智能路由:根据路径格式决定从哪个目录获取文件路径
426
+ // Smart routing: decide which directory to get file path from based on path format
427
427
  let fullPath: string;
428
428
  if (this.isLegacyPath(relativePath)) {
429
- // 旧版路径:从 uploads 目录获取(向后兼容)
429
+ // Legacy path: get from uploads directory (backward compatibility)
430
430
  fullPath = join(this.UPLOADS_DIR, relativePath);
431
431
  logger.debug(`Legacy path detected, resolved to uploads directory: ${fullPath}`);
432
432
 
433
- // 检查文件是否存在,如果不存在则尝试新路径
433
+ // Check if file exists, if not try new path
434
434
  try {
435
435
  await fs.promises.access(fullPath, fs.constants.F_OK);
436
436
  logger.debug(`Legacy path file exists: ${fullPath}`);
437
437
  } catch {
438
- // 如果 legacy 路径文件不存在,尝试新路径
438
+ // If legacy path file doesn't exist, try new path
439
439
  const fallbackPath = join(this.app.appStoragePath, FILE_STORAGE_DIR, relativePath);
440
440
  logger.debug(`Legacy path file not found, trying fallback path: ${fallbackPath}`);
441
441
  try {
@@ -443,14 +443,14 @@ export default class FileService extends ServiceModule {
443
443
  fullPath = fallbackPath;
444
444
  logger.debug(`Fallback path file exists: ${fullPath}`);
445
445
  } catch {
446
- // 两个路径都不存在,返回原始的 legacy 路径(保持原有行为)
446
+ // Neither path exists, return original legacy path (maintain existing behavior)
447
447
  logger.debug(
448
448
  `Neither legacy nor fallback path exists, returning legacy path: ${fullPath}`,
449
449
  );
450
450
  }
451
451
  }
452
452
  } else {
453
- // 新版路径:从 FILE_STORAGE_DIR 根目录获取
453
+ // New path: get from FILE_STORAGE_DIR root directory
454
454
  fullPath = join(this.app.appStoragePath, FILE_STORAGE_DIR, relativePath);
455
455
  logger.debug(`New path format, resolved to storage root: ${fullPath}`);
456
456
  }
@@ -460,19 +460,19 @@ export default class FileService extends ServiceModule {
460
460
 
461
461
  async getFileHTTPURL(path: string): Promise<string> {
462
462
  logger.debug(`Getting file HTTP URL: ${path}`);
463
- // 处理desktop://路径
463
+ // Handle desktop:// paths
464
464
  if (!path.startsWith('desktop://')) {
465
465
  logger.error(`Invalid desktop file path: ${path}`);
466
466
  throw new Error(`Invalid desktop file path: ${path}`);
467
467
  }
468
468
 
469
- // 标准化路径格式
469
+ // Normalize path format
470
470
  const normalizedPath = path.replace(/^desktop:\/+/, 'desktop://');
471
471
 
472
- // 解析路径:从 desktop://path/to/file.png 中提取 path/to/file.png
472
+ // Parse path: extract path/to/file.png from desktop://path/to/file.png
473
473
  const relativePath = normalizedPath.replace('desktop://', '');
474
474
 
475
- // 使用 StaticFileServerManager 获取文件服务器域名,然后构建完整 URL
475
+ // Use StaticFileServerManager to get file server domain, then construct full URL
476
476
  const serverDomain = this.app.staticFileServerManager.getFileServerDomain();
477
477
  const httpURL = `${serverDomain}${LOCAL_STORAGE_URL_PREFIX}/${relativePath}`;
478
478
  logger.debug(`Generated HTTP URL: ${httpURL}`);
@@ -1,10 +1,10 @@
1
1
  /**
2
- * 快捷键操作类型枚举
2
+ * Shortcut action type enum
3
3
  */
4
4
  export const ShortcutActionEnum = {
5
5
  openSettings: 'openSettings',
6
6
  /**
7
- * 显示/隐藏主窗口
7
+ * Show/hide main window
8
8
  */
9
9
  showApp: 'showApp',
10
10
  } as const;
@@ -12,7 +12,7 @@ export const ShortcutActionEnum = {
12
12
  export type ShortcutActionType = (typeof ShortcutActionEnum)[keyof typeof ShortcutActionEnum];
13
13
 
14
14
  /**
15
- * 默认快捷键配置
15
+ * Default shortcut configuration
16
16
  */
17
17
  export const DEFAULT_SHORTCUTS_CONFIG: Record<ShortcutActionType, string> = {
18
18
  [ShortcutActionEnum.showApp]: 'Control+E',
@@ -1,5 +1,5 @@
1
1
  /**
2
- * MCP Schema - stdio 配置类型
2
+ * MCP Schema - stdio configuration type
3
3
  */
4
4
  export interface McpStdioConfig {
5
5
  args?: string[];
@@ -9,7 +9,7 @@ export interface McpStdioConfig {
9
9
  }
10
10
 
11
11
  /**
12
- * MCP Schema - http 配置类型
12
+ * MCP Schema - http configuration type
13
13
  */
14
14
  export interface McpHttpConfig {
15
15
  headers?: Record<string, string>;
@@ -18,26 +18,26 @@ export interface McpHttpConfig {
18
18
  }
19
19
 
20
20
  /**
21
- * MCP Schema 配置类型
21
+ * MCP Schema configuration type
22
22
  */
23
23
  export type McpConfig = McpStdioConfig | McpHttpConfig;
24
24
 
25
25
  /**
26
- * MCP Schema 对象
27
- * 符合 RFC 0001 定义
26
+ * MCP Schema object
27
+ * Conforms to RFC 0001 definition
28
28
  */
29
29
  export interface McpSchema {
30
- /** 插件作者 */
30
+ /** Plugin author */
31
31
  author: string;
32
- /** 插件配置 */
32
+ /** Plugin configuration */
33
33
  config: McpConfig;
34
- /** 插件描述 */
34
+ /** Plugin description */
35
35
  description: string;
36
- /** 插件主页 */
36
+ /** Plugin homepage */
37
37
  homepage?: string;
38
- /** 插件图标 */
38
+ /** Plugin icon */
39
39
  icon?: string;
40
- /** 插件唯一标识符,必须与URL中的id参数匹配 */
40
+ /** Plugin unique identifier,必须与URL中的id参数匹配 */
41
41
  identifier: string;
42
42
  /** 插件名称 */
43
43
  name: string;
@@ -49,7 +49,7 @@ export interface McpSchema {
49
49
  * 协议URL解析结果
50
50
  */
51
51
  export interface ProtocolUrlParsed {
52
- /** 操作类型 (如: 'install') */
52
+ /** Action type (e.g., 'install') */
53
53
  action: string;
54
54
  /** 原始URL */
55
55
  originalUrl: string;
@@ -4,11 +4,11 @@ export const makeSureDirExist = (dir: string) => {
4
4
  try {
5
5
  statSync(dir);
6
6
  } catch {
7
- // 使用 recursive: true,如果目录已存在则此操作无效果,如果不存在则创建
7
+ // Use recursive: true, no effect if directory exists, create if it doesn't
8
8
  try {
9
9
  mkdirSync(dir, { recursive: true });
10
10
  } catch (mkdirError: any) {
11
- // 如果创建目录失败(例如权限问题),则抛出错误
11
+ // Throw error if directory creation fails (e.g., permission issues)
12
12
  throw new Error(`Could not create target directory: ${dir}. Error: ${mkdirError.message}`);
13
13
  }
14
14
  }
@@ -3,14 +3,14 @@ import electronLog from 'electron-log';
3
3
 
4
4
  import { getDesktopEnv } from '@/env';
5
5
 
6
- // 配置 electron-log
7
- electronLog.transports.file.level = 'info'; // 生产环境记录 info 及以上级别
6
+ // Configure electron-log
7
+ electronLog.transports.file.level = 'info'; // Log info level and above in production
8
8
  electronLog.transports.console.level =
9
9
  getDesktopEnv().NODE_ENV === 'development'
10
- ? 'debug' // 开发环境显示更多日志
11
- : 'warn'; // 生产环境只显示警告和错误
10
+ ? 'debug' // Show more logs in development
11
+ : 'warn'; // Only show warnings and errors in production
12
12
 
13
- // 创建命名空间调试器
13
+ // Create namespaced debugger
14
14
  export const createLogger = (namespace: string) => {
15
15
  const debugLogger = debug(namespace);
16
16