@becrafter/prompt-manager 0.1.21 → 0.1.31

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 (114) hide show
  1. package/package.json +23 -23
  2. package/packages/resources/tools/agent-browser/README.md +640 -0
  3. package/packages/resources/tools/agent-browser/agent-browser.tool.js +1388 -0
  4. package/packages/resources/tools/thinking/README.md +324 -0
  5. package/packages/resources/tools/thinking/thinking.tool.js +911 -0
  6. package/packages/server/README.md +3 -4
  7. package/packages/server/api/admin.routes.js +668 -664
  8. package/packages/server/api/open.routes.js +68 -67
  9. package/packages/server/api/surge.routes.js +5 -6
  10. package/packages/server/api/tool.routes.js +70 -71
  11. package/packages/server/app.js +70 -73
  12. package/packages/server/configs/authors.json +40 -0
  13. package/packages/server/configs/models/built-in/bigmodel.yaml +6 -6
  14. package/packages/server/configs/models/providers.yaml +4 -4
  15. package/packages/server/configs/templates/built-in/general-iteration.yaml +1 -1
  16. package/packages/server/configs/templates/built-in/general-optimize.yaml +1 -1
  17. package/packages/server/configs/templates/built-in/output-format-optimize.yaml +1 -1
  18. package/packages/server/index.js +3 -9
  19. package/packages/server/mcp/heartbeat-patch.js +1 -3
  20. package/packages/server/mcp/mcp.server.js +64 -134
  21. package/packages/server/mcp/prompt.handler.js +101 -95
  22. package/packages/server/middlewares/auth.middleware.js +31 -31
  23. package/packages/server/server.js +60 -45
  24. package/packages/server/services/TerminalService.js +156 -70
  25. package/packages/server/services/WebSocketService.js +35 -34
  26. package/packages/server/services/author-config.service.js +199 -0
  27. package/packages/server/services/manager.js +66 -60
  28. package/packages/server/services/model.service.js +5 -9
  29. package/packages/server/services/optimization.service.js +25 -22
  30. package/packages/server/services/template.service.js +3 -8
  31. package/packages/server/toolm/author-sync.service.js +97 -0
  32. package/packages/server/toolm/index.js +1 -2
  33. package/packages/server/toolm/package-installer.service.js +47 -50
  34. package/packages/server/toolm/tool-context.service.js +64 -62
  35. package/packages/server/toolm/tool-dependency.service.js +28 -30
  36. package/packages/server/toolm/tool-description-generator-optimized.service.js +55 -55
  37. package/packages/server/toolm/tool-description-generator.service.js +20 -23
  38. package/packages/server/toolm/tool-environment.service.js +45 -44
  39. package/packages/server/toolm/tool-execution.service.js +49 -48
  40. package/packages/server/toolm/tool-loader.service.js +13 -18
  41. package/packages/server/toolm/tool-logger.service.js +33 -39
  42. package/packages/server/toolm/tool-manager.handler.js +17 -15
  43. package/packages/server/toolm/tool-manual-generator.service.js +107 -87
  44. package/packages/server/toolm/tool-mode-handlers.service.js +52 -59
  45. package/packages/server/toolm/tool-storage.service.js +11 -12
  46. package/packages/server/toolm/tool-sync.service.js +36 -39
  47. package/packages/server/toolm/tool-utils.js +0 -1
  48. package/packages/server/toolm/tool-yaml-parser.service.js +12 -11
  49. package/packages/server/toolm/validate-system.js +56 -84
  50. package/packages/server/utils/config.js +98 -13
  51. package/packages/server/utils/logger.js +1 -1
  52. package/packages/server/utils/port-checker.js +8 -8
  53. package/packages/server/utils/util.js +470 -467
  54. package/packages/resources/tools/cognitive-thinking/README.md +0 -284
  55. package/packages/resources/tools/cognitive-thinking/cognitive-thinking.tool.js +0 -837
  56. package/packages/server/mcp/sequential-thinking.handler.js +0 -318
  57. package/packages/server/mcp/think-plan.handler.js +0 -274
  58. package/packages/server/mcp/thinking-toolkit.handler.js +0 -380
  59. package/packages/web/0.d1c5a72339dfc32ad86a.js +0 -1
  60. package/packages/web/112.8807b976372b2b0541a8.js +0 -1
  61. package/packages/web/130.584c7e365da413f5d9be.js +0 -1
  62. package/packages/web/142.72c985bc29720f975cca.js +0 -1
  63. package/packages/web/165.a05fc53bf84d18db36b8.js +0 -2
  64. package/packages/web/165.a05fc53bf84d18db36b8.js.LICENSE.txt +0 -9
  65. package/packages/web/203.724ab9f717b80554c397.js +0 -1
  66. package/packages/web/241.bf941d4f02866795f64a.js +0 -1
  67. package/packages/web/249.54cfb224af63f5f5ec55.js +0 -1
  68. package/packages/web/291.6df35042f8f296fca7cd.js +0 -1
  69. package/packages/web/319.2fab900a31b29873f666.js +0 -1
  70. package/packages/web/32.c78d866281995ec33a7b.js +0 -1
  71. package/packages/web/325.9ca297d0f73f38468ce9.js +0 -1
  72. package/packages/web/366.2f9b48fdbf8eee039e57.js +0 -1
  73. package/packages/web/378.6be08c612cd5a3ef97dc.js +0 -1
  74. package/packages/web/393.7a2f817515c5e90623d7.js +0 -1
  75. package/packages/web/412.062df5f732d5ba203415.js +0 -1
  76. package/packages/web/426.08656fef4918b3fb19ad.js +0 -1
  77. package/packages/web/465.2be8018327130a3bd798.js +0 -1
  78. package/packages/web/48.8ca96fc93667a715e67a.js +0 -1
  79. package/packages/web/480.44c1f1a2927486ac3d4f.js +0 -1
  80. package/packages/web/489.e041a8d0db15dc96d607.js +0 -1
  81. package/packages/web/490.9ffb26c907de020d671b.js +0 -1
  82. package/packages/web/492.58781369e348d91fc06a.js +0 -1
  83. package/packages/web/495.ed63e99791a87167c6b3.js +0 -1
  84. package/packages/web/510.4cc07ab7d30d5c1cd17f.js +0 -1
  85. package/packages/web/543.3af155ed4fa237664308.js +0 -1
  86. package/packages/web/567.f04ab60f8e2c2fb0745a.js +0 -1
  87. package/packages/web/592.f3ad085fa9c1849daa06.js +0 -1
  88. package/packages/web/616.b03fb801b3433b17750f.js +0 -1
  89. package/packages/web/617.d88def54921d2c4dc44c.js +0 -1
  90. package/packages/web/641.d30787d674f548928261.js +0 -1
  91. package/packages/web/672.5269c8399fa42a5af95d.js +0 -1
  92. package/packages/web/731.97cab92b71811c502bda.js +0 -1
  93. package/packages/web/746.3947c6f0235407e420fb.js +0 -1
  94. package/packages/web/756.a53233b3f3913900d5ac.js +0 -1
  95. package/packages/web/77.68801af593a28a631fbf.js +0 -1
  96. package/packages/web/802.53b2bff3cf2a69f7b80c.js +0 -1
  97. package/packages/web/815.b6dfab82265f56c7e046.js +0 -1
  98. package/packages/web/821.f5a13e5c735aac244eb9.js +0 -1
  99. package/packages/web/846.b9bf97d5f559270675ce.js +0 -1
  100. package/packages/web/869.7c10403f500e6201407f.js +0 -1
  101. package/packages/web/885.135050364f99e6924fb5.js +0 -1
  102. package/packages/web/901.fd5aeb9df630609a2b43.js +0 -1
  103. package/packages/web/928.f67e590de3caa4daa3ae.js +0 -1
  104. package/packages/web/955.d833403521ba4dd567ee.js +0 -1
  105. package/packages/web/981.a45cb745cf424044c8c8.js +0 -1
  106. package/packages/web/992.645320b60c74c8787482.js +0 -1
  107. package/packages/web/996.ed9a963dc9e7439eca9a.js +0 -1
  108. package/packages/web/css/codemirror-theme_xq-light.css +0 -43
  109. package/packages/web/css/codemirror.css +0 -344
  110. package/packages/web/css/main.196f434e6a88cd448158.css +0 -7278
  111. package/packages/web/css/terminal-fix.css +0 -571
  112. package/packages/web/index.html +0 -3
  113. package/packages/web/main.dceff50c7307dda04873.js +0 -2
  114. package/packages/web/main.dceff50c7307dda04873.js.LICENSE.txt +0 -3
@@ -0,0 +1,199 @@
1
+ /**
2
+ * 作者配置加载服务
3
+ *
4
+ * 职责:
5
+ * - 从配置文件加载作者信息
6
+ * - 构建别名映射
7
+ * - 提供作者查询接口
8
+ *
9
+ * 注意:此服务只负责读取配置,不允许在程序中设置作者信息
10
+ */
11
+
12
+ import fs from 'fs-extra';
13
+ import { logger } from '../utils/logger.js';
14
+ import { util } from '../utils/util.js';
15
+
16
+ class AuthorConfigService {
17
+ constructor() {
18
+ this.config = null;
19
+ this.aliasMap = new Map();
20
+ this.cacheTTL = 24 * 60 * 60 * 1000;
21
+ this.lastLoadTime = 0;
22
+ }
23
+
24
+ async loadConfig() {
25
+ const now = Date.now();
26
+
27
+ if (this.config && now - this.lastLoadTime < this.cacheTTL) {
28
+ return this.config;
29
+ }
30
+
31
+ const configPath = util.getDefaultUserConfigPath();
32
+ logger.debug('Loading author config from path', { configPath });
33
+
34
+ try {
35
+ const configData = await fs.readJson(configPath);
36
+
37
+ if (!configData.authors) {
38
+ throw new Error('配置文件格式错误:缺少 authors 字段');
39
+ }
40
+
41
+ this.config = configData;
42
+ this.lastLoadTime = now;
43
+
44
+ this.buildAliasMap();
45
+
46
+ logger.info('Author config loaded successfully', {
47
+ authorCount: Object.keys(configData.authors).length
48
+ });
49
+
50
+ return this.config;
51
+ } catch (error) {
52
+ if (error.code === 'ENOENT') {
53
+ logger.warn('作者配置文件不存在,将使用默认配置', { path: configPath });
54
+ return this.getDefaultConfig();
55
+ } else {
56
+ logger.error('加载作者配置失败:', error);
57
+ return this.getDefaultConfig();
58
+ }
59
+ }
60
+ }
61
+
62
+ buildAliasMap() {
63
+ this.aliasMap.clear();
64
+
65
+ if (!this.config || !this.config.authors) {
66
+ return;
67
+ }
68
+
69
+ for (const [authorId, author] of Object.entries(this.config.authors)) {
70
+ this.aliasMap.set(authorId.toLowerCase(), authorId);
71
+
72
+ if (author.name) {
73
+ this.aliasMap.set(author.name.toLowerCase(), authorId);
74
+ }
75
+
76
+ if (author.aliases && Array.isArray(author.aliases)) {
77
+ for (const alias of author.aliases) {
78
+ this.aliasMap.set(alias.toLowerCase(), authorId);
79
+ }
80
+ }
81
+ }
82
+ }
83
+
84
+ async resolveAuthor(authorInput) {
85
+ await this.loadConfig();
86
+
87
+ if (!this.config || !this.config.settings) {
88
+ logger.debug('Using default author info (config not loaded)');
89
+ return this.getDefaultAuthorInfo();
90
+ }
91
+
92
+ if (!authorInput) {
93
+ const defaultAuthorId = this.config.settings.default_author;
94
+ return this.getAuthorInfo(defaultAuthorId);
95
+ }
96
+
97
+ const normalized = authorInput.toString().trim().toLowerCase();
98
+
99
+ if (this.aliasMap.has(normalized)) {
100
+ const authorId = this.aliasMap.get(normalized);
101
+ logger.debug('Author resolved via alias map', { alias: authorInput, authorId });
102
+ return this.getAuthorInfo(authorId);
103
+ }
104
+
105
+ logger.warn(`未知作者 "${authorInput}",将使用默认作者`);
106
+ const defaultAuthorId = this.config.settings.default_author;
107
+ return this.getAuthorInfo(defaultAuthorId);
108
+ }
109
+
110
+ getGitHubAvatarUrl(githubUrl) {
111
+ if (!githubUrl) return null;
112
+
113
+ /*eslint no-useless-escape: "off"*/
114
+ const match = githubUrl.match(/github\.com\/([^\/]+)/i);
115
+ if (!match) return null;
116
+ return `https://github.com/${match[1]}.png`;
117
+ }
118
+
119
+ getAuthorInfo(authorId) {
120
+ if (!this.config || !this.config.authors) {
121
+ return this.getDefaultAuthorInfo();
122
+ }
123
+
124
+ const author = this.config.authors[authorId];
125
+
126
+ if (!author) {
127
+ logger.warn(`作者 "${authorId}" 不存在于配置中`);
128
+ return this.getDefaultAuthorInfo();
129
+ }
130
+
131
+ return {
132
+ id: authorId,
133
+ name: author.name || authorId,
134
+ github: author.github || null,
135
+ homepage: author.homepage || null,
136
+ bio: author.bio || '开发者',
137
+ featured: author.featured || false,
138
+ sort_order: author.sort_order || 999,
139
+ aliases: author.aliases || [],
140
+ avatar_url: author.github ? this.getGitHubAvatarUrl(author.github) : null
141
+ };
142
+ }
143
+
144
+ async getAllAuthors() {
145
+ await this.loadConfig();
146
+
147
+ if (!this.config || !this.config.authors) {
148
+ return [];
149
+ }
150
+
151
+ const authors = Object.entries(this.config.authors)
152
+ .map(([id, author]) => ({
153
+ id,
154
+ name: author.name || id,
155
+ github: author.github || null,
156
+ homepage: author.homepage || null,
157
+ bio: author.bio || '开发者',
158
+ featured: author.featured || false,
159
+ sort_order: author.sort_order || 999,
160
+ aliases: author.aliases || []
161
+ }))
162
+ .sort((a, b) => a.sort_order - b.sort_order);
163
+
164
+ return authors;
165
+ }
166
+
167
+ getDefaultAuthorInfo() {
168
+ return {
169
+ id: 'default',
170
+ name: 'Unknown',
171
+ github: null,
172
+ homepage: null,
173
+ bio: '开发者',
174
+ featured: false,
175
+ sort_order: 999,
176
+ aliases: []
177
+ };
178
+ }
179
+
180
+ getDefaultConfig() {
181
+ return {
182
+ version: '1.0.0',
183
+ last_updated: new Date().toISOString(),
184
+ authors: {},
185
+ settings: {
186
+ default_author: 'default',
187
+ cache_avatar_hours: 24
188
+ }
189
+ };
190
+ }
191
+
192
+ async reload() {
193
+ this.lastLoadTime = 0;
194
+ this.aliasMap.clear();
195
+ return await this.loadConfig();
196
+ }
197
+ }
198
+
199
+ export const authorConfigService = new AuthorConfigService();
@@ -13,18 +13,27 @@ import { GROUP_META_FILENAME } from '../utils/util.js';
13
13
  const PromptSchema = z.object({
14
14
  name: z.string().min(1, 'Prompt名称不能为空'),
15
15
  description: z.string().optional(),
16
- messages: z.array(z.object({
17
- role: z.enum(['user', 'assistant', 'system']),
18
- content: z.object({
19
- text: z.string()
20
- })
21
- })).optional(),
22
- arguments: z.array(z.object({
23
- name: z.string().min(1, '参数名不能为空'),
24
- description: z.string().optional(),
25
- type: z.enum(['string', 'number', 'boolean']).optional().default('string'),
26
- required: z.boolean().optional().default(true)
27
- })).optional().default([]),
16
+ messages: z
17
+ .array(
18
+ z.object({
19
+ role: z.enum(['user', 'assistant', 'system']),
20
+ content: z.object({
21
+ text: z.string()
22
+ })
23
+ })
24
+ )
25
+ .optional(),
26
+ arguments: z
27
+ .array(
28
+ z.object({
29
+ name: z.string().min(1, '参数名不能为空'),
30
+ description: z.string().optional(),
31
+ type: z.enum(['string', 'number', 'boolean']).optional().default('string'),
32
+ required: z.boolean().optional().default(true)
33
+ })
34
+ )
35
+ .optional()
36
+ .default([]),
28
37
  // 元数据字段(可选,用于远程服务)
29
38
  uniqueId: z.string().optional(),
30
39
  filePath: z.string().optional(),
@@ -53,11 +62,11 @@ class PromptManager {
53
62
  const hash = crypto.createHash('sha256');
54
63
  hash.update(relativePath);
55
64
  const hashHex = hash.digest('hex');
56
-
65
+
57
66
  // 取前8位作为ID,保证长度一致
58
67
  // 8位十六进制可以表示 16^8 = 4,294,967,296 种不同的值,足够保证唯一性
59
68
  const shortId = hashHex.substring(0, 8);
60
-
69
+
61
70
  return shortId;
62
71
  }
63
72
 
@@ -71,10 +80,10 @@ class PromptManager {
71
80
  const hash = crypto.createHash('sha256');
72
81
  hash.update(relativePath);
73
82
  const hashHex = hash.digest('hex');
74
-
83
+
75
84
  // 取指定长度的字符作为ID
76
85
  const shortId = hashHex.substring(0, length);
77
-
86
+
78
87
  return shortId;
79
88
  }
80
89
 
@@ -88,7 +97,7 @@ class PromptManager {
88
97
  }
89
98
 
90
99
  /**
91
- * 读取组元数据的函数
100
+ * 读取组元数据的函数
92
101
  * @param {string} dir - 目录路径
93
102
  * @returns {Object} 组元数据
94
103
  */
@@ -131,13 +140,13 @@ class PromptManager {
131
140
  };
132
141
 
133
142
  const response = await fetch(config.remoteUrl, { headers });
134
-
143
+
135
144
  if (!response.ok) {
136
145
  throw new Error(`远程服务器返回错误: ${response.status} ${response.statusText}`);
137
146
  }
138
147
 
139
148
  const data = await response.json();
140
-
149
+
141
150
  // 清空之前的加载结果
142
151
  this.loadedPrompts.clear();
143
152
  this.loadErrors.clear();
@@ -149,20 +158,20 @@ class PromptManager {
149
158
  for (const promptData of data) {
150
159
  try {
151
160
  const validatedPrompt = PromptSchema.parse(promptData);
152
-
161
+
153
162
  // 检查远程服务是否提供了uniqueId
154
163
  if (promptData.uniqueId) {
155
164
  // 远程服务提供了uniqueId,直接使用
156
165
  validatedPrompt.uniqueId = promptData.uniqueId;
157
-
166
+
158
167
  // 可选:如果提供了其他元数据字段就使用,没提供就设置默认值
159
168
  validatedPrompt.filePath = promptData.filePath || `remote://${validatedPrompt.name}`;
160
169
  validatedPrompt.fileName = promptData.fileName || `${validatedPrompt.name}.yaml`;
161
170
  validatedPrompt.relativePath = promptData.relativePath || `${validatedPrompt.name}.yaml`;
162
-
171
+
163
172
  // 注册ID到路径的映射
164
173
  this.registerIdPathMapping(promptData.uniqueId, validatedPrompt.relativePath);
165
-
174
+
166
175
  // 使用唯一ID作为存储键
167
176
  this.loadedPrompts.set(promptData.uniqueId, validatedPrompt);
168
177
  logger.debug(`使用远程服务提供的uniqueId: ${validatedPrompt.name} -> ID: ${promptData.uniqueId}`);
@@ -174,28 +183,28 @@ class PromptManager {
174
183
  validatedPrompt.filePath = `remote://${validatedPrompt.name}`;
175
184
  validatedPrompt.fileName = `${validatedPrompt.name}.yaml`;
176
185
  validatedPrompt.relativePath = virtualPath;
177
-
186
+
178
187
  // 注册ID到路径的映射
179
188
  this.registerIdPathMapping(uniqueId, virtualPath);
180
-
189
+
181
190
  // 使用唯一ID作为存储键
182
191
  this.loadedPrompts.set(uniqueId, validatedPrompt);
183
192
  logger.debug(`使用兼容模式加载远程prompt: ${validatedPrompt.name} -> ID: ${uniqueId}`);
184
193
  }
185
-
194
+
186
195
  successCount++;
187
196
  } catch (error) {
188
197
  errorCount++;
189
198
  this.loadErrors.set(promptData.name || 'unknown', error.message);
190
- logger.error(`验证远程prompt失败:`, error.message);
199
+ logger.error('验证远程prompt失败:', error.message);
191
200
  }
192
201
  }
193
202
 
194
203
  logger.info(`远程Prompt加载完成: 成功 ${successCount} 个, 失败 ${errorCount} 个`);
195
-
204
+
196
205
  return {
197
206
  success: successCount,
198
- errorCount: errorCount,
207
+ errorCount,
199
208
  prompts: Array.from(this.loadedPrompts.values()),
200
209
  loadErrors: Object.fromEntries(this.loadErrors)
201
210
  };
@@ -207,7 +216,7 @@ class PromptManager {
207
216
 
208
217
  /**
209
218
  * 递归扫描目录,获取所有prompt文件
210
- *
219
+ *
211
220
  * @param {string} currentPath - 当前目录路径
212
221
  * @param {string} relativePath - 相对于当前目录的路径
213
222
  * @param {boolean} inheritedEnabled - 从父目录继承的启用状态
@@ -220,20 +229,20 @@ class PromptManager {
220
229
  if (relativePath) {
221
230
  // console.log('读取组元数据:', "{relativePath:", relativePath, ", currentPath:", currentPath, "}");
222
231
  const meta = this.readGroupMeta(path.join(currentPath, relativePath));
223
- currentEnabled = currentEnabled && (meta.enabled !== false);
232
+ currentEnabled = currentEnabled && meta.enabled !== false;
224
233
  }
225
234
 
226
235
  // 如果当前目录被禁用,直接返回空数组
227
236
  if (!currentEnabled) {
228
237
  return [];
229
238
  }
230
-
239
+
231
240
  try {
232
241
  const items = await fs.readdir(currentPath, { withFileTypes: true });
233
242
  // console.log('扫描目录:', "{currentPath:", currentPath, ", items:", items, "}");
234
-
243
+
235
244
  for (const item of items) {
236
- const itemPath = path.join(currentPath, item.name); // 文件的绝对路径,相对于当前目录,如:/home/work/prompt-manager/prompts/xxx/xxx.yaml
245
+ const itemPath = path.join(currentPath, item.name); // 文件的绝对路径,相对于当前目录,如:/home/work/prompt-manager/prompts/xxx/xxx.yaml
237
246
  const itemRelativePath = relativePath ? path.join(relativePath, item.name) : item.name; // 文件的相对路径,相对于当前目录,如:xxx/xxx.yaml
238
247
 
239
248
  if (item.isDirectory()) {
@@ -255,7 +264,7 @@ class PromptManager {
255
264
  } catch (error) {
256
265
  logger.warn(`扫描目录 ${currentPath} 时发生错误:`, error.message);
257
266
  }
258
-
267
+
259
268
  return promptFiles;
260
269
  }
261
270
 
@@ -270,10 +279,10 @@ class PromptManager {
270
279
 
271
280
  try {
272
281
  logger.info(`开始从 ${this.promptsDir} 加载prompts`);
273
-
282
+
274
283
  // 确保目录存在
275
284
  await fs.ensureDir(this.promptsDir);
276
-
285
+
277
286
  // 根据配置决定是否递归扫描
278
287
  let promptFiles;
279
288
  if (config.recursiveScan) {
@@ -292,7 +301,7 @@ class PromptManager {
292
301
  relativePath: file
293
302
  }));
294
303
  }
295
-
304
+
296
305
  logger.debug(`找到 ${promptFiles.length} 个prompt文件`);
297
306
 
298
307
  // 清空之前的加载结果
@@ -304,18 +313,16 @@ class PromptManager {
304
313
  const results = await Promise.allSettled(loadPromises);
305
314
 
306
315
  // 统计加载结果
307
- let successCount = 0;
308
316
  let errorCount = 0;
309
317
 
310
- let loadedCount = 0;
318
+ let loadedCount = 0;
311
319
  let disabledCount = 0;
312
320
 
313
321
  results.forEach((result, index) => {
314
322
  if (result.status === 'fulfilled') {
315
- successCount++;
316
323
  if (result.value !== null) {
317
324
  loadedCount++;
318
- }else{
325
+ } else {
319
326
  disabledCount++;
320
327
  }
321
328
  } else {
@@ -328,10 +335,10 @@ class PromptManager {
328
335
  });
329
336
 
330
337
  logger.info(`本地Prompt加载完成: 启用 ${loadedCount} 个, 禁用 ${disabledCount} 个, 失败 ${errorCount} 个\n`);
331
-
338
+
332
339
  return {
333
340
  success: loadedCount,
334
- errorCount: errorCount,
341
+ errorCount,
335
342
  prompts: Array.from(this.loadedPrompts.values()),
336
343
  loadErrors: Object.fromEntries(this.loadErrors)
337
344
  };
@@ -349,7 +356,7 @@ class PromptManager {
349
356
  const fileName = typeof fileInfo === 'string' ? fileInfo : fileInfo.fileName;
350
357
  const filePath = typeof fileInfo === 'string' ? path.join(this.promptsDir, fileInfo) : fileInfo.filePath;
351
358
  const relativePath = typeof fileInfo === 'string' ? fileInfo : fileInfo.relativePath;
352
-
359
+
353
360
  if (fileName === GROUP_META_FILENAME) {
354
361
  // 跳过组元数据文件
355
362
  return null;
@@ -358,7 +365,7 @@ class PromptManager {
358
365
  try {
359
366
  const content = await fs.readFile(filePath, 'utf8');
360
367
  const ext = path.extname(fileName).toLowerCase();
361
-
368
+
362
369
  let promptData;
363
370
  if (ext === '.json') {
364
371
  promptData = JSON.parse(content);
@@ -373,47 +380,46 @@ class PromptManager {
373
380
  }
374
381
 
375
382
  // 检查目录启用状态
376
- const fileDir = path.dirname(filePath);
377
383
  const relativeDir = path.dirname(relativePath);
378
384
  if (relativeDir && relativeDir !== '.') {
379
385
  // 检查从根目录到当前文件路径的所有目录的启用状态
380
386
  const dirParts = relativeDir.split(path.sep);
381
387
  let currentPath = this.promptsDir;
382
388
  let inheritedEnabled = true;
383
-
389
+
384
390
  for (const dirPart of dirParts) {
385
391
  currentPath = path.join(currentPath, dirPart);
386
392
  const meta = this.readGroupMeta(currentPath);
387
- inheritedEnabled = inheritedEnabled && (meta.enabled !== false);
388
-
393
+ inheritedEnabled = inheritedEnabled && meta.enabled !== false;
394
+
389
395
  if (!inheritedEnabled) {
390
396
  logger.debug(`skipped loading prompt: ${promptData.name} -> parent directory disabled`);
391
397
  return null;
392
398
  }
393
399
  }
394
400
  }
395
-
401
+
396
402
  logger.debug(`loaded prompt: ${promptData.name} -> ${filePath}`);
397
403
 
398
404
  // 验证prompt数据结构
399
405
  const validatedPrompt = PromptSchema.parse(promptData);
400
-
406
+
401
407
  // 添加文件路径信息
402
408
  validatedPrompt.filePath = filePath;
403
409
  validatedPrompt.fileName = fileName;
404
410
  validatedPrompt.relativePath = relativePath;
405
-
411
+
406
412
  // 生成基于文件路径的唯一ID
407
413
  const uniqueId = this.generateUniqueId(relativePath);
408
414
  validatedPrompt.uniqueId = uniqueId;
409
-
415
+
410
416
  // 注册ID到路径的映射
411
417
  this.registerIdPathMapping(uniqueId, relativePath);
412
-
418
+
413
419
  // 使用唯一ID作为存储键
414
420
  this.loadedPrompts.set(uniqueId, validatedPrompt);
415
421
  logger.debug(`成功加载prompt: ${validatedPrompt.name} -> ID: ${uniqueId} (${relativePath})`);
416
-
422
+
417
423
  return validatedPrompt;
418
424
  } catch (error) {
419
425
  if (error instanceof z.ZodError) {
@@ -440,14 +446,14 @@ class PromptManager {
440
446
  if (this.loadedPrompts.has(id)) {
441
447
  return this.loadedPrompts.get(id);
442
448
  }
443
-
449
+
444
450
  // 如果直接匹配失败,尝试匹配原始名称(向后兼容)
445
- for (const [key, prompt] of this.loadedPrompts.entries()) {
451
+ for (const prompt of this.loadedPrompts.values()) {
446
452
  if (prompt.name === id || prompt.relativePath === id) {
447
453
  return prompt;
448
454
  }
449
455
  }
450
-
456
+
451
457
  return null;
452
458
  }
453
459
 
@@ -509,4 +515,4 @@ class PromptManager {
509
515
  export const promptManager = new PromptManager(config.getPromptsDir());
510
516
 
511
517
  // 导出PromptManager类供测试使用
512
- export { PromptManager };
518
+ export { PromptManager };
@@ -1,15 +1,11 @@
1
1
  import fs from 'fs-extra';
2
2
  import path from 'path';
3
- import { fileURLToPath } from 'url';
4
3
  import YAML from 'yaml';
5
4
  import { z } from 'zod';
6
5
  import crypto from 'crypto';
7
- import os from 'os';
8
6
  import { logger } from '../utils/logger.js';
9
7
  import { util } from '../utils/util.js';
10
-
11
- const __filename = fileURLToPath(import.meta.url);
12
- const __dirname = path.dirname(__filename);
8
+ import { config } from '../utils/config.js';
13
9
 
14
10
  /**
15
11
  * 模型数据结构验证schema
@@ -39,7 +35,7 @@ const ALGORITHM = 'aes-256-cbc';
39
35
  class ModelManager {
40
36
  constructor() {
41
37
  this.builtInDir = path.join(util.getBuiltInConfigsDir(), 'models/built-in');
42
- this.customDir = path.join(os.homedir(), '.prompt-manager/configs/models');
38
+ this.customDir = config.getModelsDir();
43
39
  this.loadedModels = new Map();
44
40
  this.idToPathMap = new Map();
45
41
  this.providersConfig = null;
@@ -93,7 +89,7 @@ class ModelManager {
93
89
  return this.providersConfig;
94
90
  }
95
91
  } catch (error) {
96
- logger.warn(`加载提供商配置失败:`, error.message);
92
+ logger.warn('加载提供商配置失败:', error.message);
97
93
  }
98
94
 
99
95
  this.providersConfig = { providers: {} };
@@ -149,7 +145,7 @@ class ModelManager {
149
145
  let encrypted = cipher.update(text, 'utf8', 'hex');
150
146
  encrypted += cipher.final('hex');
151
147
 
152
- return iv.toString('hex') + ':' + encrypted;
148
+ return `${iv.toString('hex')}:${encrypted}`;
153
149
  } catch (error) {
154
150
  logger.error('加密失败:', error);
155
151
  throw error;
@@ -470,4 +466,4 @@ class ModelManager {
470
466
  export const modelManager = new ModelManager();
471
467
 
472
468
  // 导出ModelManager类供测试使用
473
- export { ModelManager };
469
+ export { ModelManager };