@becrafter/prompt-manager 0.1.22 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +31 -24
- package/packages/resources/tools/agent-browser/README.md +640 -0
- package/packages/resources/tools/agent-browser/agent-browser.tool.js +1389 -0
- package/packages/resources/tools/thinking/README.md +324 -0
- package/packages/resources/tools/thinking/thinking.tool.js +911 -0
- package/packages/server/README.md +3 -4
- package/packages/server/api/admin.routes.js +668 -664
- package/packages/server/api/open.routes.js +68 -67
- package/packages/server/api/surge.routes.js +5 -6
- package/packages/server/api/tool.routes.js +70 -71
- package/packages/server/app.js +70 -73
- package/packages/server/configs/authors.json +40 -0
- package/packages/server/configs/models/built-in/bigmodel.yaml +6 -6
- package/packages/server/configs/models/providers.yaml +4 -4
- package/packages/server/configs/templates/built-in/general-iteration.yaml +1 -1
- package/packages/server/configs/templates/built-in/general-optimize.yaml +1 -1
- package/packages/server/configs/templates/built-in/output-format-optimize.yaml +1 -1
- package/packages/server/index.js +3 -9
- package/packages/server/mcp/heartbeat-patch.js +1 -3
- package/packages/server/mcp/mcp.server.js +64 -134
- package/packages/server/mcp/prompt.handler.js +101 -95
- package/packages/server/middlewares/auth.middleware.js +31 -31
- package/packages/server/server.js +60 -45
- package/packages/server/services/TerminalService.js +156 -70
- package/packages/server/services/WebSocketService.js +35 -34
- package/packages/server/services/author-config.service.js +199 -0
- package/packages/server/services/manager.js +66 -60
- package/packages/server/services/model.service.js +5 -9
- package/packages/server/services/optimization.service.js +25 -22
- package/packages/server/services/template.service.js +3 -8
- package/packages/server/toolm/author-sync.service.js +97 -0
- package/packages/server/toolm/index.js +1 -2
- package/packages/server/toolm/package-installer.service.js +47 -50
- package/packages/server/toolm/tool-context.service.js +64 -62
- package/packages/server/toolm/tool-dependency.service.js +28 -30
- package/packages/server/toolm/tool-description-generator-optimized.service.js +55 -55
- package/packages/server/toolm/tool-description-generator.service.js +20 -23
- package/packages/server/toolm/tool-environment.service.js +45 -44
- package/packages/server/toolm/tool-execution.service.js +49 -48
- package/packages/server/toolm/tool-loader.service.js +13 -18
- package/packages/server/toolm/tool-logger.service.js +33 -39
- package/packages/server/toolm/tool-manager.handler.js +17 -15
- package/packages/server/toolm/tool-manual-generator.service.js +107 -87
- package/packages/server/toolm/tool-mode-handlers.service.js +52 -59
- package/packages/server/toolm/tool-storage.service.js +11 -12
- package/packages/server/toolm/tool-sync.service.js +36 -39
- package/packages/server/toolm/tool-utils.js +0 -1
- package/packages/server/toolm/tool-yaml-parser.service.js +12 -11
- package/packages/server/toolm/validate-system.js +56 -84
- package/packages/server/utils/config.js +97 -12
- package/packages/server/utils/logger.js +1 -1
- package/packages/server/utils/port-checker.js +8 -8
- package/packages/server/utils/util.js +470 -467
- package/packages/resources/tools/cognitive-thinking/README.md +0 -284
- package/packages/resources/tools/cognitive-thinking/cognitive-thinking.tool.js +0 -837
- package/packages/server/mcp/sequential-thinking.handler.js +0 -318
- package/packages/server/mcp/think-plan.handler.js +0 -274
- package/packages/server/mcp/thinking-toolkit.handler.js +0 -380
- package/packages/web/0.d1c5a72339dfc32ad86a.js +0 -1
- package/packages/web/112.8807b976372b2b0541a8.js +0 -1
- package/packages/web/130.584c7e365da413f5d9be.js +0 -1
- package/packages/web/142.72c985bc29720f975cca.js +0 -1
- package/packages/web/165.a05fc53bf84d18db36b8.js +0 -2
- package/packages/web/165.a05fc53bf84d18db36b8.js.LICENSE.txt +0 -9
- package/packages/web/203.724ab9f717b80554c397.js +0 -1
- package/packages/web/241.bf941d4f02866795f64a.js +0 -1
- package/packages/web/249.54cfb224af63f5f5ec55.js +0 -1
- package/packages/web/291.6df35042f8f296fca7cd.js +0 -1
- package/packages/web/319.2fab900a31b29873f666.js +0 -1
- package/packages/web/32.c78d866281995ec33a7b.js +0 -1
- package/packages/web/325.9ca297d0f73f38468ce9.js +0 -1
- package/packages/web/366.2f9b48fdbf8eee039e57.js +0 -1
- package/packages/web/378.6be08c612cd5a3ef97dc.js +0 -1
- package/packages/web/393.7a2f817515c5e90623d7.js +0 -1
- package/packages/web/412.062df5f732d5ba203415.js +0 -1
- package/packages/web/426.08656fef4918b3fb19ad.js +0 -1
- package/packages/web/465.2be8018327130a3bd798.js +0 -1
- package/packages/web/48.8ca96fc93667a715e67a.js +0 -1
- package/packages/web/480.44c1f1a2927486ac3d4f.js +0 -1
- package/packages/web/489.e041a8d0db15dc96d607.js +0 -1
- package/packages/web/490.9ffb26c907de020d671b.js +0 -1
- package/packages/web/492.58781369e348d91fc06a.js +0 -1
- package/packages/web/495.ed63e99791a87167c6b3.js +0 -1
- package/packages/web/510.4cc07ab7d30d5c1cd17f.js +0 -1
- package/packages/web/543.3af155ed4fa237664308.js +0 -1
- package/packages/web/567.f04ab60f8e2c2fb0745a.js +0 -1
- package/packages/web/592.f3ad085fa9c1849daa06.js +0 -1
- package/packages/web/616.b03fb801b3433b17750f.js +0 -1
- package/packages/web/617.d88def54921d2c4dc44c.js +0 -1
- package/packages/web/641.d30787d674f548928261.js +0 -1
- package/packages/web/672.5269c8399fa42a5af95d.js +0 -1
- package/packages/web/731.97cab92b71811c502bda.js +0 -1
- package/packages/web/746.3947c6f0235407e420fb.js +0 -1
- package/packages/web/756.a53233b3f3913900d5ac.js +0 -1
- package/packages/web/77.68801af593a28a631fbf.js +0 -1
- package/packages/web/802.53b2bff3cf2a69f7b80c.js +0 -1
- package/packages/web/815.b6dfab82265f56c7e046.js +0 -1
- package/packages/web/821.f5a13e5c735aac244eb9.js +0 -1
- package/packages/web/846.b9bf97d5f559270675ce.js +0 -1
- package/packages/web/869.7c10403f500e6201407f.js +0 -1
- package/packages/web/885.135050364f99e6924fb5.js +0 -1
- package/packages/web/901.fd5aeb9df630609a2b43.js +0 -1
- package/packages/web/928.f67e590de3caa4daa3ae.js +0 -1
- package/packages/web/955.d833403521ba4dd567ee.js +0 -1
- package/packages/web/981.a45cb745cf424044c8c8.js +0 -1
- package/packages/web/992.645320b60c74c8787482.js +0 -1
- package/packages/web/996.ed9a963dc9e7439eca9a.js +0 -1
- package/packages/web/css/codemirror-theme_xq-light.css +0 -43
- package/packages/web/css/codemirror.css +0 -344
- package/packages/web/css/main.196f434e6a88cd448158.css +0 -7278
- package/packages/web/css/terminal-fix.css +0 -571
- package/packages/web/index.html +0 -3
- package/packages/web/main.dceff50c7307dda04873.js +0 -2
- package/packages/web/main.dceff50c7307dda04873.js.LICENSE.txt +0 -3
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 工具执行上下文服务
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* 职责:
|
|
5
5
|
* 1. 创建工具执行上下文(包含 API、路径解析、模块导入等)
|
|
6
6
|
* 2. 提供统一的工具执行环境
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import path from 'path';
|
|
10
|
-
import os from 'os';
|
|
11
10
|
import { createRequire } from 'module';
|
|
12
11
|
import { logger } from '../utils/logger.js';
|
|
13
12
|
import { getLogger } from './tool-logger.service.js';
|
|
14
13
|
import { getStorage } from './tool-storage.service.js';
|
|
15
14
|
import { loadToolEnvironment, saveToolEnvironment } from './tool-environment.service.js';
|
|
15
|
+
import { config } from '../utils/config.js';
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* 创建工具执行上下文
|
|
@@ -21,23 +21,23 @@ import { loadToolEnvironment, saveToolEnvironment } from './tool-environment.ser
|
|
|
21
21
|
* @returns {object} 工具执行上下文
|
|
22
22
|
*/
|
|
23
23
|
export async function createToolContext(toolName, toolModule) {
|
|
24
|
-
const toolDir =
|
|
25
|
-
|
|
24
|
+
const toolDir = config.getToolDir(toolName);
|
|
25
|
+
|
|
26
26
|
// 1. 加载工具环境变量
|
|
27
27
|
const toolEnvVars = await loadToolEnvironment(toolName);
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
// 2. 创建工具日志记录器
|
|
30
30
|
const toolLogger = getLogger(toolName);
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
// 3. 创建工具存储服务
|
|
33
33
|
const toolStorage = getStorage(toolName);
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
// 4. 创建 API 上下文
|
|
36
36
|
const apiContext = {
|
|
37
37
|
logger: toolLogger,
|
|
38
38
|
storage: toolStorage,
|
|
39
39
|
environment: {
|
|
40
|
-
get:
|
|
40
|
+
get: key => {
|
|
41
41
|
// 优先从工具环境变量获取
|
|
42
42
|
if (toolEnvVars[key] !== undefined) {
|
|
43
43
|
return toolEnvVars[key];
|
|
@@ -56,7 +56,7 @@ export async function createToolContext(toolName, toolModule) {
|
|
|
56
56
|
// 5. 创建工具专用的 require 函数
|
|
57
57
|
const packageJsonPath = path.resolve(path.join(toolDir, 'package.json'));
|
|
58
58
|
const toolRequire = createRequire(packageJsonPath);
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
// 6. 创建工具执行上下文
|
|
61
61
|
const toolContext = {
|
|
62
62
|
api: apiContext,
|
|
@@ -65,28 +65,28 @@ export async function createToolContext(toolName, toolModule) {
|
|
|
65
65
|
// 文件系统初始化状态(框架管理)
|
|
66
66
|
_filesystemInitialized: false,
|
|
67
67
|
_allowedDirectories: null,
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
// 框架提供的文件系统基础能力
|
|
70
70
|
getAllowedDirectories() {
|
|
71
71
|
const { api } = this;
|
|
72
|
-
|
|
72
|
+
|
|
73
73
|
// 默认值
|
|
74
|
-
let allowedDirs = [
|
|
75
|
-
|
|
74
|
+
let allowedDirs = [config.getConfigHome()];
|
|
75
|
+
|
|
76
76
|
if (api && api.environment) {
|
|
77
77
|
try {
|
|
78
78
|
let configStr = api.environment.get('ALLOWED_DIRECTORIES');
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
// 如果直接获取失败,尝试使用工具特定的环境变量名
|
|
81
81
|
if (!configStr) {
|
|
82
82
|
const toolSpecificKey = `${toolName.toUpperCase().replace(/-/g, '_')}_ALLOWED_DIRECTORIES`;
|
|
83
83
|
configStr = process.env[toolSpecificKey];
|
|
84
84
|
}
|
|
85
|
-
|
|
85
|
+
|
|
86
86
|
if (configStr) {
|
|
87
87
|
// 处理转义字符(从 .env 文件解析时可能需要)
|
|
88
88
|
configStr = configStr.replace(/\\"/g, '"').replace(/\\\\/g, '\\');
|
|
89
|
-
|
|
89
|
+
|
|
90
90
|
// 首先尝试作为 JSON 字符串解析
|
|
91
91
|
try {
|
|
92
92
|
const parsed = JSON.parse(configStr);
|
|
@@ -96,7 +96,10 @@ export async function createToolContext(toolName, toolModule) {
|
|
|
96
96
|
} catch (parseError) {
|
|
97
97
|
// 如果不是 JSON,尝试作为逗号分隔的字符串
|
|
98
98
|
if (typeof configStr === 'string' && configStr.includes(',')) {
|
|
99
|
-
allowedDirs = configStr
|
|
99
|
+
allowedDirs = configStr
|
|
100
|
+
.split(',')
|
|
101
|
+
.map(s => s.trim())
|
|
102
|
+
.filter(s => s);
|
|
100
103
|
} else if (configStr) {
|
|
101
104
|
allowedDirs = [configStr];
|
|
102
105
|
}
|
|
@@ -107,126 +110,126 @@ export async function createToolContext(toolName, toolModule) {
|
|
|
107
110
|
api?.logger?.warn('Failed to parse ALLOWED_DIRECTORIES', { error: error.message });
|
|
108
111
|
}
|
|
109
112
|
}
|
|
110
|
-
|
|
113
|
+
|
|
111
114
|
// 展开 ~ 到主目录并规范化路径
|
|
112
115
|
return allowedDirs.map(dir => {
|
|
113
|
-
const expanded = dir.replace(/^~/,
|
|
116
|
+
const expanded = dir.replace(/^~/, config.getConfigHome());
|
|
114
117
|
return path.resolve(expanded);
|
|
115
118
|
});
|
|
116
119
|
},
|
|
117
|
-
|
|
120
|
+
|
|
118
121
|
async initializeFilesystem() {
|
|
119
122
|
if (!this._filesystemInitialized) {
|
|
120
123
|
// 获取允许的目录列表
|
|
121
124
|
const allowedDirectories = this.getAllowedDirectories();
|
|
122
125
|
this._allowedDirectories = allowedDirectories;
|
|
123
126
|
this._filesystemInitialized = true;
|
|
124
|
-
|
|
127
|
+
|
|
125
128
|
// 记录日志
|
|
126
129
|
const { api } = this;
|
|
127
|
-
api?.logger?.info('Filesystem initialized', {
|
|
128
|
-
allowedDirectories: this._allowedDirectories
|
|
130
|
+
api?.logger?.info('Filesystem initialized', {
|
|
131
|
+
allowedDirectories: this._allowedDirectories
|
|
129
132
|
});
|
|
130
133
|
}
|
|
131
134
|
},
|
|
132
|
-
|
|
135
|
+
|
|
133
136
|
resolvePromptManagerPath(inputPath) {
|
|
134
137
|
const { api } = this;
|
|
135
|
-
|
|
138
|
+
|
|
136
139
|
// 获取允许的目录列表
|
|
137
140
|
const allowedDirs = this._allowedDirectories || this.getAllowedDirectories();
|
|
138
|
-
|
|
141
|
+
|
|
139
142
|
if (!inputPath) {
|
|
140
143
|
// 没有路径时返回第一个允许的目录
|
|
141
144
|
return allowedDirs[0];
|
|
142
145
|
}
|
|
143
|
-
|
|
146
|
+
|
|
144
147
|
// 处理 ~ 开头的路径
|
|
145
|
-
const expandedPath = inputPath.replace(/^~/,
|
|
146
|
-
|
|
148
|
+
const expandedPath = inputPath.replace(/^~/, config.getConfigHome());
|
|
149
|
+
|
|
147
150
|
// 如果是绝对路径
|
|
148
151
|
if (path.isAbsolute(expandedPath)) {
|
|
149
152
|
const resolved = path.resolve(expandedPath);
|
|
150
153
|
const normalizedResolved = path.normalize(resolved);
|
|
151
|
-
|
|
154
|
+
|
|
152
155
|
// 检查路径是否在允许的目录范围内
|
|
153
156
|
const isAllowed = allowedDirs.some(dir => {
|
|
154
157
|
const normalizedDir = path.normalize(dir);
|
|
155
|
-
|
|
158
|
+
|
|
156
159
|
// 完全匹配允许的目录
|
|
157
160
|
if (normalizedResolved === normalizedDir) {
|
|
158
161
|
return true;
|
|
159
162
|
}
|
|
160
|
-
|
|
163
|
+
|
|
161
164
|
// 检查是否是允许目录的子路径
|
|
162
165
|
const relativePath = path.relative(normalizedDir, normalizedResolved);
|
|
163
|
-
|
|
166
|
+
|
|
164
167
|
// 如果 relativePath 以 .. 开头,说明路径不在允许目录内
|
|
165
168
|
if (relativePath.startsWith('..')) {
|
|
166
169
|
return false;
|
|
167
170
|
}
|
|
168
|
-
|
|
171
|
+
|
|
169
172
|
// 如果 relativePath 为空,说明是完全匹配(已在上面检查)
|
|
170
173
|
if (relativePath === '') {
|
|
171
174
|
return false;
|
|
172
175
|
}
|
|
173
|
-
|
|
176
|
+
|
|
174
177
|
// 相对路径存在且不以 .. 开头,说明是允许目录的子路径
|
|
175
178
|
return true;
|
|
176
179
|
});
|
|
177
|
-
|
|
180
|
+
|
|
178
181
|
if (!isAllowed) {
|
|
179
182
|
const dirsStr = allowedDirs.join(', ');
|
|
180
183
|
api?.logger?.warn('Path access denied', { path: resolved, allowedDirs });
|
|
181
184
|
throw new Error(`路径越权: ${inputPath} 不在允许的目录范围内 [${dirsStr}]`);
|
|
182
185
|
}
|
|
183
|
-
|
|
186
|
+
|
|
184
187
|
return resolved;
|
|
185
188
|
}
|
|
186
|
-
|
|
189
|
+
|
|
187
190
|
// 相对路径,尝试在每个允许的目录中解析
|
|
188
191
|
const baseDir = allowedDirs[0];
|
|
189
192
|
const fullPath = path.join(baseDir, expandedPath);
|
|
190
193
|
const resolved = path.resolve(fullPath);
|
|
191
194
|
const normalizedResolved = path.normalize(resolved);
|
|
192
|
-
|
|
195
|
+
|
|
193
196
|
// 安全检查:确保解析后的路径在允许的目录内或其子目录中
|
|
194
197
|
const isAllowed = allowedDirs.some(dir => {
|
|
195
198
|
const normalizedDir = path.normalize(dir);
|
|
196
|
-
|
|
199
|
+
|
|
197
200
|
// 完全匹配允许的目录
|
|
198
201
|
if (normalizedResolved === normalizedDir) {
|
|
199
202
|
return true;
|
|
200
203
|
}
|
|
201
|
-
|
|
204
|
+
|
|
202
205
|
// 检查是否是允许目录的子路径
|
|
203
206
|
const relativePath = path.relative(normalizedDir, normalizedResolved);
|
|
204
|
-
|
|
207
|
+
|
|
205
208
|
// 如果 relativePath 以 .. 开头,说明路径不在允许目录内
|
|
206
209
|
if (relativePath.startsWith('..')) {
|
|
207
210
|
return false;
|
|
208
211
|
}
|
|
209
|
-
|
|
212
|
+
|
|
210
213
|
// 如果 relativePath 为空,说明是完全匹配(已在上面检查)
|
|
211
214
|
if (relativePath === '') {
|
|
212
215
|
return false;
|
|
213
216
|
}
|
|
214
|
-
|
|
217
|
+
|
|
215
218
|
// 相对路径存在且不以 .. 开头,说明是允许目录的子路径
|
|
216
219
|
return true;
|
|
217
220
|
});
|
|
218
|
-
|
|
221
|
+
|
|
219
222
|
if (!isAllowed) {
|
|
220
223
|
const dirsStr = allowedDirs.join(', ');
|
|
221
224
|
api?.logger?.warn('Path resolution failed', { path: inputPath, resolved, allowedDirs });
|
|
222
225
|
throw new Error(`路径越权: ${inputPath} 解析后超出允许的目录范围 [${dirsStr}]`);
|
|
223
226
|
}
|
|
224
|
-
|
|
227
|
+
|
|
225
228
|
return resolved;
|
|
226
229
|
},
|
|
227
|
-
|
|
230
|
+
|
|
228
231
|
// 提供工具专用的模块导入函数
|
|
229
|
-
requireToolModule:
|
|
232
|
+
requireToolModule: moduleName => {
|
|
230
233
|
try {
|
|
231
234
|
// 首先尝试从工具的 node_modules 导入
|
|
232
235
|
return toolRequire(moduleName);
|
|
@@ -239,42 +242,42 @@ export async function createToolContext(toolName, toolModule) {
|
|
|
239
242
|
}
|
|
240
243
|
}
|
|
241
244
|
},
|
|
242
|
-
|
|
245
|
+
|
|
243
246
|
// 提供工具专用的动态导入函数(支持 ES 模块和 CommonJS)
|
|
244
|
-
importToolModule: async
|
|
247
|
+
importToolModule: async moduleName => {
|
|
245
248
|
try {
|
|
246
249
|
// 首先尝试使用 require 导入(适用于 CommonJS 模块,如 pdf-parse)
|
|
247
250
|
const module = toolRequire(moduleName);
|
|
248
|
-
|
|
251
|
+
|
|
249
252
|
logger.debug(`模块 ${moduleName} require 成功`, {
|
|
250
253
|
type: typeof module,
|
|
251
254
|
isFunction: typeof module === 'function',
|
|
252
255
|
isObject: typeof module === 'object',
|
|
253
256
|
keys: typeof module === 'object' ? Object.keys(module).slice(0, 10) : []
|
|
254
257
|
});
|
|
255
|
-
|
|
258
|
+
|
|
256
259
|
// pdf-parse 是 CommonJS 模块,直接导出函数
|
|
257
260
|
// 如果 module 是函数,直接返回
|
|
258
261
|
if (typeof module === 'function') {
|
|
259
262
|
return { default: module };
|
|
260
263
|
}
|
|
261
|
-
|
|
264
|
+
|
|
262
265
|
// 如果是对象,检查是否有 default
|
|
263
266
|
if (module && typeof module === 'object') {
|
|
264
267
|
// 如果已经有 default,直接返回
|
|
265
268
|
if (module.default) {
|
|
266
269
|
return module;
|
|
267
270
|
}
|
|
268
|
-
|
|
271
|
+
|
|
269
272
|
// 检查是否有常见的导出名称(如 PDFParse)
|
|
270
273
|
if (module.PDFParse && typeof module.PDFParse === 'function') {
|
|
271
274
|
return { default: module.PDFParse };
|
|
272
275
|
}
|
|
273
|
-
|
|
276
|
+
|
|
274
277
|
// 否则包装为 { default: module }
|
|
275
278
|
return { default: module, ...module };
|
|
276
279
|
}
|
|
277
|
-
|
|
280
|
+
|
|
278
281
|
return module;
|
|
279
282
|
} catch (requireError) {
|
|
280
283
|
logger.debug(`require 失败,尝试 import: ${moduleName}`, { error: requireError.message });
|
|
@@ -285,12 +288,12 @@ export async function createToolContext(toolName, toolModule) {
|
|
|
285
288
|
return await import(modulePath);
|
|
286
289
|
} catch (resolveError) {
|
|
287
290
|
logger.debug(`resolve 失败,尝试特殊路径: ${moduleName}`, { error: resolveError.message });
|
|
288
|
-
|
|
291
|
+
|
|
289
292
|
// 特殊处理:某些包的 main 字段指向错误的路径,需要尝试备用路径
|
|
290
293
|
const fallbackPaths = {
|
|
291
294
|
'chrome-devtools-mcp': 'chrome-devtools-mcp/build/src/index.js'
|
|
292
295
|
};
|
|
293
|
-
|
|
296
|
+
|
|
294
297
|
if (fallbackPaths[moduleName]) {
|
|
295
298
|
try {
|
|
296
299
|
const fallbackPath = toolRequire.resolve(fallbackPaths[moduleName]);
|
|
@@ -300,7 +303,7 @@ export async function createToolContext(toolName, toolModule) {
|
|
|
300
303
|
logger.debug(`备用路径也失败: ${moduleName}`, { error: fallbackError.message });
|
|
301
304
|
}
|
|
302
305
|
}
|
|
303
|
-
|
|
306
|
+
|
|
304
307
|
// 如果 resolve 失败,尝试直接导入(可能从系统 node_modules)
|
|
305
308
|
try {
|
|
306
309
|
logger.debug(`尝试直接导入模块: ${moduleName}`);
|
|
@@ -318,7 +321,7 @@ export async function createToolContext(toolName, toolModule) {
|
|
|
318
321
|
}
|
|
319
322
|
}
|
|
320
323
|
};
|
|
321
|
-
|
|
324
|
+
|
|
322
325
|
// 7. 将工具模块的所有方法复制到上下文中,并绑定this
|
|
323
326
|
// 这样工具方法之间可以相互调用(如 execute 调用 this.initializeFilesystem)
|
|
324
327
|
for (const [key, value] of Object.entries(toolModule)) {
|
|
@@ -328,7 +331,6 @@ export async function createToolContext(toolName, toolModule) {
|
|
|
328
331
|
toolContext[key] = value;
|
|
329
332
|
}
|
|
330
333
|
}
|
|
331
|
-
|
|
334
|
+
|
|
332
335
|
return toolContext;
|
|
333
336
|
}
|
|
334
|
-
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 工具依赖管理服务
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* 职责:
|
|
5
5
|
* 1. 检查工具依赖是否已安装
|
|
6
6
|
* 2. 自动安装工具依赖(使用 @npmcli/arborist,不依赖系统 npm)
|
|
7
7
|
* 3. 验证依赖版本匹配
|
|
8
|
-
*
|
|
8
|
+
*
|
|
9
9
|
* 使用 PackageInstaller 基于 @npmcli/arborist 实现,可在 Electron 环境中直接使用
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import fs from 'fs-extra';
|
|
13
13
|
import path from 'path';
|
|
14
|
-
import os from 'os';
|
|
15
14
|
import { logger } from '../utils/logger.js';
|
|
16
15
|
import { pathExists } from './tool-utils.js';
|
|
17
16
|
import PackageInstaller from './package-installer.service.js';
|
|
17
|
+
import { config } from '../utils/config.js';
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* 确保工具依赖已安装
|
|
@@ -22,34 +22,34 @@ import PackageInstaller from './package-installer.service.js';
|
|
|
22
22
|
* @param {object} toolModule - 工具模块(可选,用于自动创建 package.json)
|
|
23
23
|
*/
|
|
24
24
|
export async function ensureToolDependencies(toolName, toolModule = null) {
|
|
25
|
-
const toolDir =
|
|
25
|
+
const toolDir = config.getToolDir(toolName);
|
|
26
26
|
const packageJsonPath = path.join(toolDir, 'package.json');
|
|
27
27
|
const nodeModulesPath = path.join(toolDir, 'node_modules');
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
// 检查 package.json 是否存在,如果不存在则自动创建
|
|
30
|
-
if (!await pathExists(packageJsonPath)) {
|
|
30
|
+
if (!(await pathExists(packageJsonPath))) {
|
|
31
31
|
logger.info(`工具 ${toolName} 缺少 package.json,正在自动创建...`);
|
|
32
32
|
await createPackageJson(toolName, toolDir, toolModule);
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
const packageJson = await fs.readJson(packageJsonPath);
|
|
36
36
|
const dependencies = packageJson.dependencies || {};
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
// 如果没有依赖,直接返回
|
|
39
39
|
if (Object.keys(dependencies).length === 0) {
|
|
40
40
|
logger.debug(`工具 ${toolName} 无需依赖`);
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
// 检查 node_modules 是否存在,或者检查依赖是否需要更新
|
|
45
|
-
const needsInstall = !await pathExists(nodeModulesPath) || await needsDependencyUpdate(toolDir, dependencies);
|
|
46
|
-
|
|
45
|
+
const needsInstall = !(await pathExists(nodeModulesPath)) || (await needsDependencyUpdate(toolDir, dependencies));
|
|
46
|
+
|
|
47
47
|
if (needsInstall) {
|
|
48
48
|
logger.info(`工具 ${toolName} 依赖需要安装或更新,开始安装...`);
|
|
49
49
|
await installDependencies(toolDir, dependencies);
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
logger.debug(`工具 ${toolName} 依赖已存在且为最新`);
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -62,7 +62,7 @@ export async function ensureToolDependencies(toolName, toolModule = null) {
|
|
|
62
62
|
async function createPackageJson(toolName, toolDir, toolModule) {
|
|
63
63
|
// 确保工具目录存在
|
|
64
64
|
await fs.ensureDir(toolDir);
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
// 获取工具依赖(如果工具模块提供了 getDependencies 方法)
|
|
67
67
|
let dependencies = {};
|
|
68
68
|
if (toolModule && typeof toolModule.getDependencies === 'function') {
|
|
@@ -72,7 +72,7 @@ async function createPackageJson(toolName, toolDir, toolModule) {
|
|
|
72
72
|
logger.warn(`获取工具 ${toolName} 依赖失败:`, error.message);
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
// 获取工具元数据(用于 package.json 的基本信息)
|
|
77
77
|
let metadata = { name: toolName, version: '1.0.0' };
|
|
78
78
|
if (toolModule && typeof toolModule.getMetadata === 'function') {
|
|
@@ -82,7 +82,7 @@ async function createPackageJson(toolName, toolDir, toolModule) {
|
|
|
82
82
|
logger.warn(`获取工具 ${toolName} 元数据失败:`, error.message);
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
-
|
|
85
|
+
|
|
86
86
|
// 创建 package.json
|
|
87
87
|
const packageJson = {
|
|
88
88
|
name: `@prompt-manager/tool-${toolName}`,
|
|
@@ -90,15 +90,15 @@ async function createPackageJson(toolName, toolDir, toolModule) {
|
|
|
90
90
|
description: metadata.description || `Prompt Manager tool: ${toolName}`,
|
|
91
91
|
main: `${toolName}.tool.js`,
|
|
92
92
|
type: 'module',
|
|
93
|
-
dependencies
|
|
93
|
+
dependencies
|
|
94
94
|
};
|
|
95
|
-
|
|
95
|
+
|
|
96
96
|
// 写入 package.json
|
|
97
97
|
const packageJsonPath = path.join(toolDir, 'package.json');
|
|
98
98
|
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
99
|
-
|
|
100
|
-
logger.info(`已为工具 ${toolName} 创建 package.json`, {
|
|
101
|
-
dependencies: Object.keys(dependencies).length
|
|
99
|
+
|
|
100
|
+
logger.info(`已为工具 ${toolName} 创建 package.json`, {
|
|
101
|
+
dependencies: Object.keys(dependencies).length
|
|
102
102
|
});
|
|
103
103
|
}
|
|
104
104
|
|
|
@@ -111,17 +111,17 @@ async function createPackageJson(toolName, toolDir, toolModule) {
|
|
|
111
111
|
async function needsDependencyUpdate(toolDir, expectedDependencies) {
|
|
112
112
|
try {
|
|
113
113
|
// 检查每个依赖是否已安装且版本匹配
|
|
114
|
-
for (const [packageName
|
|
114
|
+
for (const [packageName] of Object.entries(expectedDependencies)) {
|
|
115
115
|
const isInstalled = await PackageInstaller.isPackageInstalled(toolDir, packageName);
|
|
116
116
|
if (!isInstalled) {
|
|
117
117
|
logger.debug(`依赖 ${packageName} 未安装,需要更新`);
|
|
118
118
|
return true;
|
|
119
119
|
}
|
|
120
|
-
|
|
120
|
+
|
|
121
121
|
// 可以进一步检查版本是否匹配(简化版本,暂时只检查是否存在)
|
|
122
122
|
// 如果需要精确版本匹配,可以读取 package.json 并比较版本
|
|
123
123
|
}
|
|
124
|
-
|
|
124
|
+
|
|
125
125
|
return false;
|
|
126
126
|
} catch (error) {
|
|
127
127
|
logger.warn('检查依赖更新状态失败,将重新安装', { error: error.message });
|
|
@@ -136,27 +136,26 @@ async function needsDependencyUpdate(toolDir, expectedDependencies) {
|
|
|
136
136
|
*/
|
|
137
137
|
async function installDependencies(toolDir, dependencies) {
|
|
138
138
|
logger.info(`在目录 ${toolDir} 中安装依赖...`, { dependencies });
|
|
139
|
-
|
|
139
|
+
|
|
140
140
|
try {
|
|
141
141
|
// 使用 PackageInstaller 安装依赖
|
|
142
142
|
// PackageInstaller 使用 @npmcli/arborist,不依赖系统 npm
|
|
143
143
|
// 可在 Electron 环境中直接使用
|
|
144
144
|
const result = await PackageInstaller.install({
|
|
145
145
|
workingDir: toolDir,
|
|
146
|
-
dependencies
|
|
146
|
+
dependencies,
|
|
147
147
|
timeout: 300000 // 5分钟超时
|
|
148
148
|
});
|
|
149
|
-
|
|
149
|
+
|
|
150
150
|
logger.info('依赖安装成功', {
|
|
151
151
|
elapsed: result.elapsed,
|
|
152
152
|
installedCount: result.installedPackages.length,
|
|
153
153
|
packages: result.installedPackages
|
|
154
154
|
});
|
|
155
|
-
|
|
155
|
+
|
|
156
156
|
return result;
|
|
157
|
-
|
|
158
157
|
} catch (error) {
|
|
159
|
-
logger.error('依赖安装失败', {
|
|
158
|
+
logger.error('依赖安装失败', {
|
|
160
159
|
error: error.message,
|
|
161
160
|
toolDir,
|
|
162
161
|
dependencies,
|
|
@@ -165,4 +164,3 @@ async function installDependencies(toolDir, dependencies) {
|
|
|
165
164
|
throw new Error(`依赖安装失败: ${error.message}`);
|
|
166
165
|
}
|
|
167
166
|
}
|
|
168
|
-
|