@becrafter/prompt-manager 0.0.18 → 0.1.1

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 (108) hide show
  1. package/IFLOW.md +175 -0
  2. package/README.md +145 -234
  3. package/app/desktop/assets/app.1.png +0 -0
  4. package/app/desktop/assets/app.png +0 -0
  5. package/app/desktop/assets/icons/icon.icns +0 -0
  6. package/app/desktop/assets/icons/icon.ico +0 -0
  7. package/app/desktop/assets/icons/icon.png +0 -0
  8. package/app/desktop/assets/icons/tray.png +0 -0
  9. package/app/desktop/assets/templates/about.html +147 -0
  10. package/app/desktop/assets/tray.png +0 -0
  11. package/app/desktop/main.js +187 -732
  12. package/app/desktop/package-lock.json +723 -522
  13. package/app/desktop/package.json +54 -25
  14. package/app/desktop/preload.js +7 -0
  15. package/app/desktop/src/core/error-handler.js +108 -0
  16. package/app/desktop/src/core/event-emitter.js +84 -0
  17. package/app/desktop/src/core/logger.js +108 -0
  18. package/app/desktop/src/core/state-manager.js +125 -0
  19. package/app/desktop/src/services/module-loader.js +214 -0
  20. package/app/desktop/src/services/runtime-manager.js +301 -0
  21. package/app/desktop/src/services/service-manager.js +169 -0
  22. package/app/desktop/src/services/update-manager.js +268 -0
  23. package/app/desktop/src/ui/about-dialog-manager.js +208 -0
  24. package/app/desktop/src/ui/admin-window-manager.js +757 -0
  25. package/app/desktop/src/ui/splash-manager.js +253 -0
  26. package/app/desktop/src/ui/tray-manager.js +186 -0
  27. package/app/desktop/src/utils/icon-manager.js +133 -0
  28. package/app/desktop/src/utils/path-utils.js +58 -0
  29. package/app/desktop/src/utils/resource-paths.js +49 -0
  30. package/app/desktop/src/utils/resource-sync.js +260 -0
  31. package/app/desktop/src/utils/runtime-sync.js +241 -0
  32. package/app/desktop/src/utils/template-renderer.js +284 -0
  33. package/app/desktop/src/utils/version-utils.js +59 -0
  34. package/examples/prompts/engineer/engineer-professional.yaml +92 -0
  35. package/examples/prompts/engineer/laowang-engineer.yaml +132 -0
  36. package/examples/prompts/engineer/nekomata-engineer.yaml +123 -0
  37. package/examples/prompts/engineer/ojousama-engineer.yaml +124 -0
  38. package/examples/prompts/recommend/human_3-0_growth_diagnostic_coach_prompt.yaml +105 -0
  39. package/examples/prompts/workflow/sixstep-workflow.yaml +192 -0
  40. package/package.json +18 -9
  41. package/packages/admin-ui/.babelrc +3 -0
  42. package/packages/admin-ui/admin.html +237 -4784
  43. package/packages/admin-ui/css/main.css +2592 -0
  44. package/packages/admin-ui/css/recommended-prompts.css +610 -0
  45. package/packages/admin-ui/package-lock.json +6981 -0
  46. package/packages/admin-ui/package.json +36 -0
  47. package/packages/admin-ui/src/codemirror.js +53 -0
  48. package/packages/admin-ui/src/index.js +3188 -0
  49. package/packages/admin-ui/webpack.config.js +76 -0
  50. package/packages/resources/tools/chrome-devtools/README.md +310 -0
  51. package/packages/resources/tools/chrome-devtools/chrome-devtools.tool.js +1703 -0
  52. package/packages/resources/tools/file-reader/README.md +289 -0
  53. package/packages/resources/tools/file-reader/file-reader.tool.js +1545 -0
  54. package/packages/resources/tools/filesystem/README.md +359 -0
  55. package/packages/resources/tools/filesystem/filesystem.tool.js +538 -0
  56. package/packages/resources/tools/ollama-remote/README.md +192 -0
  57. package/packages/resources/tools/ollama-remote/ollama-remote.tool.js +421 -0
  58. package/packages/resources/tools/pdf-reader/README.md +236 -0
  59. package/packages/resources/tools/pdf-reader/pdf-reader.tool.js +565 -0
  60. package/packages/resources/tools/playwright/README.md +306 -0
  61. package/packages/resources/tools/playwright/playwright.tool.js +1186 -0
  62. package/packages/resources/tools/todolist/README.md +394 -0
  63. package/packages/resources/tools/todolist/todolist.tool.js +1312 -0
  64. package/packages/server/README.md +142 -0
  65. package/packages/server/api/admin.routes.js +42 -11
  66. package/packages/server/api/surge.routes.js +43 -0
  67. package/packages/server/app.js +119 -14
  68. package/packages/server/index.js +39 -0
  69. package/packages/server/mcp/mcp.server.js +346 -28
  70. package/packages/server/mcp/{mcp.handler.js → prompt.handler.js} +108 -9
  71. package/packages/server/mcp/sequential-thinking.handler.js +318 -0
  72. package/packages/server/mcp/think-plan.handler.js +274 -0
  73. package/packages/server/middlewares/auth.middleware.js +6 -0
  74. package/packages/server/package.json +51 -0
  75. package/packages/server/server.js +37 -1
  76. package/packages/server/toolm/index.js +9 -0
  77. package/packages/server/toolm/package-installer.service.js +267 -0
  78. package/packages/server/toolm/test-tools.js +264 -0
  79. package/packages/server/toolm/tool-context.service.js +334 -0
  80. package/packages/server/toolm/tool-dependency.service.js +168 -0
  81. package/packages/server/toolm/tool-description-generator-optimized.service.js +375 -0
  82. package/packages/server/toolm/tool-description-generator.service.js +312 -0
  83. package/packages/server/toolm/tool-environment.service.js +200 -0
  84. package/packages/server/toolm/tool-execution.service.js +277 -0
  85. package/packages/server/toolm/tool-loader.service.js +219 -0
  86. package/packages/server/toolm/tool-logger.service.js +223 -0
  87. package/packages/server/toolm/tool-manager.handler.js +65 -0
  88. package/packages/server/toolm/tool-manual-generator.service.js +389 -0
  89. package/packages/server/toolm/tool-mode-handlers.service.js +224 -0
  90. package/packages/server/toolm/tool-storage.service.js +111 -0
  91. package/packages/server/toolm/tool-sync.service.js +138 -0
  92. package/packages/server/toolm/tool-utils.js +20 -0
  93. package/packages/server/toolm/tool-yaml-parser.service.js +81 -0
  94. package/packages/server/toolm/validate-system.js +421 -0
  95. package/packages/server/utils/config.js +49 -5
  96. package/packages/server/utils/util.js +65 -10
  97. package/scripts/build-icons.js +135 -0
  98. package/scripts/build.sh +57 -0
  99. package/scripts/surge/CNAME +1 -0
  100. package/scripts/surge/README.md +47 -0
  101. package/scripts/surge/package-lock.json +34 -0
  102. package/scripts/surge/package.json +20 -0
  103. package/scripts/surge/sync-to-surge.js +151 -0
  104. package/packages/admin-ui/js/closebrackets.min.js +0 -8
  105. package/packages/admin-ui/js/codemirror.min.js +0 -8
  106. package/packages/admin-ui/js/js-yaml.min.js +0 -2
  107. package/packages/admin-ui/js/markdown.min.js +0 -8
  108. /package/app/desktop/assets/{icon.png → tray.1.png} +0 -0
@@ -0,0 +1,538 @@
1
+ /**
2
+ * Filesystem Tool - Prompt Manager 体系的文件系统基础设施
3
+ *
4
+ * 战略意义:
5
+ *
6
+ * 1. 架构隔离性
7
+ * 专为 Prompt Manager 体系设计,通过沙箱隔离确保文件操作不会影响
8
+ * Prompt Manager 核心功能。即使 AI Agent 出错,也不会破坏系统稳定性。
9
+ *
10
+ * 2. 平台独立性
11
+ * 虽然很多 AI 平台自带文件工具,但 Prompt Manager 需要自己的实现来保证:
12
+ * - 在无本地工具的 Web Agent 平台上也能工作
13
+ * - 统一的操作语义,不依赖特定 AI 平台
14
+ * - 可移植到任何支持 MCP 协议的环境
15
+ *
16
+ * 3. 生态自主性
17
+ * 作为 Prompt Manager 工具生态的基础组件,filesystem 确保了:
18
+ * - 其他工具可以依赖稳定的文件操作接口
19
+ * - 用户数据始终在 Prompt Manager 控制范围内
20
+ * - 未来可扩展更多存储后端(云存储、分布式等)
21
+ *
22
+ * 这不仅是一个文件操作工具,更是 Prompt Manager 实现平台独立、
23
+ * 生态自主的关键基础设施。
24
+ */
25
+
26
+ import path from 'path';
27
+ import os from 'os';
28
+
29
+ export default {
30
+ /**
31
+ * 获取工具依赖
32
+ * 使用 Node.js 内置模块,无需额外依赖
33
+ */
34
+ getDependencies() {
35
+ return {
36
+ // 使用 Node.js 内置 fs、path 等模块,无需额外依赖
37
+ };
38
+ },
39
+
40
+ /**
41
+ * 获取工具元信息
42
+ */
43
+ getMetadata() {
44
+ return {
45
+ id: 'filesystem',
46
+ name: 'filesystem',
47
+ description: '基于MCP标准的文件系统操作工具,提供读写、搜索、编辑等功能',
48
+ version: '2.0.0',
49
+ category: 'system',
50
+ author: 'Prompt Manager',
51
+ tags: ['file', 'system', 'io', 'mcp'],
52
+ scenarios: [
53
+ '文件读写操作',
54
+ '目录管理和遍历',
55
+ '文件搜索和批量处理',
56
+ 'Prompt Manager资源文件管理',
57
+ '项目文件结构分析'
58
+ ],
59
+ limitations: [
60
+ '默认只能访问 ~/.prompt-manager 目录',
61
+ '可通过环境变量配置额外允许的目录',
62
+ '不支持符号链接操作',
63
+ '单文件大小建议不超过10MB'
64
+ ]
65
+ };
66
+ },
67
+
68
+ /**
69
+ * 获取参数Schema
70
+ */
71
+ getSchema() {
72
+ return {
73
+ parameters: {
74
+ type: 'object',
75
+ properties: {
76
+ method: {
77
+ type: 'string',
78
+ description: 'MCP方法名',
79
+ enum: [
80
+ 'read_text_file',
81
+ 'read_media_file',
82
+ 'read_multiple_files',
83
+ 'write_file',
84
+ 'edit_file',
85
+ 'create_directory',
86
+ 'list_directory',
87
+ 'list_directory_with_sizes',
88
+ 'directory_tree',
89
+ 'move_file',
90
+ 'search_files',
91
+ 'get_file_info',
92
+ 'list_allowed_directories'
93
+ ]
94
+ },
95
+ // 通用参数,根据method动态使用
96
+ path: { type: 'string', description: '文件或目录路径' },
97
+ paths: { type: 'array', items: { type: 'string' }, description: '多个文件路径' },
98
+ content: { type: 'string', description: '文件内容' },
99
+ head: { type: 'number', description: '读取前N行' },
100
+ tail: { type: 'number', description: '读取后N行' },
101
+ edits: {
102
+ type: 'array',
103
+ description: '编辑操作列表,每个元素为对象: {oldText: "要替换的文本", newText: "新文本"}',
104
+ items: {
105
+ type: 'object',
106
+ properties: {
107
+ oldText: {
108
+ type: 'string',
109
+ description: '要替换的原始文本(必须完全匹配)'
110
+ },
111
+ newText: {
112
+ type: 'string',
113
+ description: '替换后的新文本'
114
+ }
115
+ },
116
+ required: ['oldText', 'newText']
117
+ }
118
+ },
119
+ dryRun: { type: 'boolean', description: '仅预览不执行' },
120
+ source: { type: 'string', description: '源路径' },
121
+ destination: { type: 'string', description: '目标路径' },
122
+ pattern: { type: 'string', description: '搜索模式' },
123
+ excludePatterns: { type: 'array', items: { type: 'string' }, description: '排除模式' },
124
+ sortBy: { type: 'string', enum: ['name', 'size'], description: '排序方式' }
125
+ },
126
+ required: ['method']
127
+ },
128
+ environment: {
129
+ type: 'object',
130
+ properties: {
131
+ ALLOWED_DIRECTORIES: {
132
+ type: 'string',
133
+ description: '允许访问的目录列表(JSON数组格式),默认为 ["~/.prompt-manager"]',
134
+ default: '["~/.prompt-manager"]'
135
+ }
136
+ },
137
+ required: []
138
+ }
139
+ };
140
+ },
141
+
142
+ /**
143
+ * 获取业务错误定义
144
+ */
145
+ getBusinessErrors() {
146
+ return [
147
+ {
148
+ code: 'PATH_OUTSIDE_SCOPE',
149
+ description: '路径越权访问',
150
+ match: /路径越权/,
151
+ solution: '确保路径在允许的目录范围内',
152
+ retryable: false
153
+ },
154
+ {
155
+ code: 'FILE_NOT_FOUND',
156
+ description: '文件或目录不存在',
157
+ match: /ENOENT|no such file|cannot find/i,
158
+ solution: '检查文件路径是否正确',
159
+ retryable: false
160
+ },
161
+ {
162
+ code: 'PERMISSION_DENIED',
163
+ description: '权限不足',
164
+ match: /EACCES|permission denied/i,
165
+ solution: '检查文件或目录的访问权限',
166
+ retryable: false
167
+ },
168
+ {
169
+ code: 'FILE_TOO_LARGE',
170
+ description: '文件过大',
171
+ match: /File too large|ENOBUFS|too big/i,
172
+ solution: '文件大小不应超过10MB',
173
+ retryable: false
174
+ },
175
+ {
176
+ code: 'DIRECTORY_NOT_EMPTY',
177
+ description: '目录非空',
178
+ match: /ENOTEMPTY|directory not empty/i,
179
+ solution: '清空目录后再试',
180
+ retryable: false
181
+ },
182
+ {
183
+ code: 'INVALID_PATH',
184
+ description: '无效路径',
185
+ match: /invalid path|illegal characters/i,
186
+ solution: '检查路径格式是否正确',
187
+ retryable: false
188
+ }
189
+ ];
190
+ },
191
+
192
+ /**
193
+ * 执行工具 - 包装MCP实现
194
+ *
195
+ * 注意:文件系统基础能力(getAllowedDirectories、initializeFilesystem、resolvePromptManagerPath)
196
+ * 已由框架层提供,工具可直接通过 this 调用这些方法
197
+ */
198
+ async execute(params) {
199
+ const { api } = this;
200
+
201
+ // 记录执行开始
202
+ api?.logger?.info('Executing filesystem operation', {
203
+ method: params.method,
204
+ path: params.path || params.paths || params.source
205
+ });
206
+
207
+ // 参数验证由 ToolValidator 根据 getSchema() 自动处理
208
+ // 这里进行 method 相关的业务验证
209
+ const methodRequirements = {
210
+ 'read_text_file': ['path'],
211
+ 'read_media_file': ['path'],
212
+ 'read_multiple_files': ['paths'],
213
+ 'write_file': ['path', 'content'],
214
+ 'edit_file': ['path', 'edits'],
215
+ 'create_directory': ['path'],
216
+ 'list_directory': ['path'],
217
+ 'list_directory_with_sizes': ['path'],
218
+ 'directory_tree': ['path'],
219
+ 'move_file': ['source', 'destination'],
220
+ 'search_files': ['path', 'pattern'],
221
+ 'get_file_info': ['path'],
222
+ 'list_allowed_directories': []
223
+ };
224
+
225
+ const required = methodRequirements[params.method];
226
+ if (!required) {
227
+ throw new Error(`不支持的方法: ${params.method}`);
228
+ }
229
+
230
+ const missing = required.filter(field => !params[field]);
231
+ if (missing.length > 0) {
232
+ throw new Error(`方法 ${params.method} 缺少必需参数: ${missing.join(', ')}`);
233
+ }
234
+
235
+ try {
236
+ // 初始化文件系统
237
+ await this.initializeFilesystem();
238
+
239
+ // 导入 fs 模块
240
+ const fs = await import('fs');
241
+ const fsPromises = fs.promises;
242
+
243
+ // 特殊处理list_allowed_directories
244
+ if (params.method === 'list_allowed_directories') {
245
+ // 使用已初始化的目录列表,如果未初始化则获取
246
+ const dirs = this._allowedDirectories ?? this.getAllowedDirectories();
247
+ api?.logger?.info('Returning allowed directories', { directories: dirs });
248
+ return dirs;
249
+ }
250
+
251
+ // 准备MCP调用参数
252
+ let mcpParams = { ...params };
253
+
254
+ // 路径参数转换
255
+ if (params.path) {
256
+ mcpParams.path = this.resolvePromptManagerPath(params.path);
257
+ }
258
+
259
+ if (params.paths) {
260
+ mcpParams.paths = params.paths.map(p => this.resolvePromptManagerPath(p));
261
+ }
262
+
263
+ if (params.source) {
264
+ mcpParams.source = this.resolvePromptManagerPath(params.source);
265
+ }
266
+
267
+ if (params.destination) {
268
+ mcpParams.destination = this.resolvePromptManagerPath(params.destination);
269
+ }
270
+
271
+ // 执行对应的文件系统操作
272
+ let result;
273
+ switch (params.method) {
274
+ case 'read_text_file': {
275
+ const content = await fsPromises.readFile(mcpParams.path, 'utf-8');
276
+
277
+ if (params.head) {
278
+ // 返回前 N 行
279
+ const lines = content.split('\n');
280
+ result = lines.slice(0, params.head).join('\n');
281
+ } else if (params.tail) {
282
+ // 返回后 N 行
283
+ const lines = content.split('\n');
284
+ result = lines.slice(-params.tail).join('\n');
285
+ } else {
286
+ result = content;
287
+ }
288
+ break;
289
+ }
290
+
291
+ case 'read_media_file': {
292
+ // 读取二进制文件并转base64
293
+ const buffer = await fsPromises.readFile(mcpParams.path);
294
+ const base64 = buffer.toString('base64');
295
+ const ext = path.extname(mcpParams.path).toLowerCase();
296
+ const mimeTypes = {
297
+ '.png': 'image/png',
298
+ '.jpg': 'image/jpeg',
299
+ '.jpeg': 'image/jpeg',
300
+ '.gif': 'image/gif',
301
+ '.webp': 'image/webp',
302
+ '.svg': 'image/svg+xml',
303
+ '.mp3': 'audio/mpeg',
304
+ '.wav': 'audio/wav'
305
+ };
306
+ result = {
307
+ base64: base64,
308
+ mimeType: mimeTypes[ext] || 'application/octet-stream'
309
+ };
310
+ break;
311
+ }
312
+
313
+ case 'read_multiple_files':
314
+ result = await Promise.all(
315
+ mcpParams.paths.map(async (filePath, index) => {
316
+ try {
317
+ const content = await fsPromises.readFile(filePath, 'utf-8');
318
+ return {
319
+ path: params.paths[index], // 返回原始相对路径
320
+ content: content,
321
+ success: true
322
+ };
323
+ } catch (error) {
324
+ return {
325
+ path: params.paths[index],
326
+ error: error.message,
327
+ success: false
328
+ };
329
+ }
330
+ })
331
+ );
332
+ break;
333
+
334
+ case 'write_file': {
335
+ // 自动创建父目录
336
+ const dirPath = path.dirname(mcpParams.path);
337
+
338
+ try {
339
+ // 检查目录是否存在,不存在则创建
340
+ await fsPromises.access(dirPath);
341
+ } catch {
342
+ // 目录不存在,创建它
343
+ await fsPromises.mkdir(dirPath, { recursive: true });
344
+ api?.logger?.info('Auto-created directory for write_file', { directory: dirPath });
345
+ }
346
+
347
+ await fsPromises.writeFile(mcpParams.path, params.content, 'utf-8');
348
+ result = {
349
+ bytesWritten: Buffer.byteLength(params.content, 'utf-8'),
350
+ path: params.path
351
+ };
352
+ break;
353
+ }
354
+
355
+ case 'edit_file': {
356
+ // 读取文件内容
357
+ let content = await fsPromises.readFile(mcpParams.path, 'utf-8');
358
+
359
+ // 应用编辑
360
+ for (const edit of params.edits) {
361
+ content = content.replace(edit.oldText, edit.newText);
362
+ }
363
+
364
+ if (params.dryRun) {
365
+ // 预览模式,返回修改后的内容
366
+ result = content;
367
+ } else {
368
+ // 写回文件
369
+ await fsPromises.writeFile(mcpParams.path, content, 'utf-8');
370
+ result = {
371
+ editsApplied: params.edits.length,
372
+ path: params.path
373
+ };
374
+ }
375
+ break;
376
+ }
377
+
378
+ case 'create_directory': {
379
+ await fsPromises.mkdir(mcpParams.path, { recursive: true });
380
+ result = { created: mcpParams.path };
381
+ break;
382
+ }
383
+
384
+ case 'list_directory':
385
+ case 'list_directory_with_sizes': {
386
+ const entries = await fsPromises.readdir(mcpParams.path, { withFileTypes: true });
387
+
388
+ if (params.method === 'list_directory') {
389
+ result = entries.map(entry => ({
390
+ name: entry.name,
391
+ type: entry.isDirectory() ? 'directory' : 'file'
392
+ }));
393
+ } else {
394
+ result = await Promise.all(
395
+ entries.map(async (entry) => {
396
+ const entryPath = path.join(mcpParams.path, entry.name);
397
+ const stats = await fsPromises.stat(entryPath);
398
+ return {
399
+ name: entry.name,
400
+ type: entry.isDirectory() ? 'directory' : 'file',
401
+ size: stats.size,
402
+ modified: stats.mtime
403
+ };
404
+ })
405
+ );
406
+
407
+ if (params.sortBy === 'size') {
408
+ result.sort((a, b) => b.size - a.size);
409
+ } else {
410
+ result.sort((a, b) => a.name.localeCompare(b.name));
411
+ }
412
+ }
413
+ break;
414
+ }
415
+
416
+ case 'directory_tree': {
417
+ // 构建目录树
418
+ const buildTree = async (currentPath) => {
419
+ const entries = await fsPromises.readdir(currentPath, { withFileTypes: true });
420
+ const tree = [];
421
+
422
+ for (const entry of entries) {
423
+ const entryPath = path.join(currentPath, entry.name);
424
+ const node = {
425
+ name: entry.name,
426
+ type: entry.isDirectory() ? 'directory' : 'file'
427
+ };
428
+
429
+ if (entry.isDirectory()) {
430
+ try {
431
+ node.children = await buildTree(entryPath);
432
+ } catch (error) {
433
+ node.children = [];
434
+ node.error = error.message;
435
+ }
436
+ }
437
+
438
+ tree.push(node);
439
+ }
440
+
441
+ return tree;
442
+ };
443
+
444
+ result = await buildTree(mcpParams.path);
445
+ break;
446
+ }
447
+
448
+ case 'move_file': {
449
+ await fsPromises.rename(mcpParams.source, mcpParams.destination);
450
+ result = {
451
+ from: params.source,
452
+ to: params.destination
453
+ };
454
+ break;
455
+ }
456
+
457
+ case 'search_files': {
458
+ // 递归搜索文件(使用内置fs,不依赖glob)
459
+ const searchFiles = async (dir, pattern) => {
460
+ const results = [];
461
+ const entries = await fsPromises.readdir(dir, { withFileTypes: true });
462
+
463
+ for (const entry of entries) {
464
+ const fullPath = path.join(dir, entry.name);
465
+
466
+ // 检查排除模式
467
+ if (params.excludePatterns) {
468
+ const shouldExclude = params.excludePatterns.some(excludePattern => {
469
+ return entry.name.match(new RegExp(excludePattern.replace(/\*/g, '.*')));
470
+ });
471
+ if (shouldExclude) continue;
472
+ }
473
+
474
+ if (entry.isDirectory()) {
475
+ // 递归搜索子目录
476
+ try {
477
+ const subResults = await searchFiles(fullPath, pattern);
478
+ results.push(...subResults);
479
+ } catch (error) {
480
+ // 忽略无权访问的目录
481
+ }
482
+ } else {
483
+ // 检查文件名是否匹配模式
484
+ const regex = new RegExp(pattern.replace(/\*/g, '.*').replace(/\?/g, '.'));
485
+ if (regex.test(entry.name)) {
486
+ results.push(fullPath);
487
+ }
488
+ }
489
+ }
490
+
491
+ return results;
492
+ };
493
+
494
+ const foundFiles = await searchFiles(mcpParams.path, params.pattern);
495
+
496
+ // 转换为相对路径(相对于第一个允许的目录)
497
+ const allowedDirs = this._allowedDirectories ?? this.getAllowedDirectories();
498
+ const baseDir = allowedDirs[0];
499
+ result = foundFiles.map(file => path.relative(baseDir, file));
500
+ break;
501
+ }
502
+
503
+ case 'get_file_info': {
504
+ const stats = await fsPromises.stat(mcpParams.path);
505
+ result = {
506
+ size: stats.size,
507
+ created: stats.birthtime,
508
+ modified: stats.mtime,
509
+ accessed: stats.atime,
510
+ isDirectory: stats.isDirectory(),
511
+ isFile: stats.isFile(),
512
+ permissions: stats.mode
513
+ };
514
+ break;
515
+ }
516
+
517
+ default:
518
+ throw new Error(`不支持的方法: ${params.method}`);
519
+ }
520
+
521
+ // 记录执行成功
522
+ api?.logger?.info('Filesystem operation completed', {
523
+ method: params.method,
524
+ success: true
525
+ });
526
+
527
+ return result;
528
+
529
+ } catch (error) {
530
+ // 记录错误
531
+ api?.logger?.error('Filesystem operation failed', {
532
+ method: params.method,
533
+ error: error.message
534
+ });
535
+ throw error;
536
+ }
537
+ }
538
+ };