@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.
- package/package.json +23 -23
- package/packages/resources/tools/agent-browser/README.md +640 -0
- package/packages/resources/tools/agent-browser/agent-browser.tool.js +1388 -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 +98 -13
- 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
|
@@ -27,7 +27,7 @@ class OptimizationService {
|
|
|
27
27
|
// 尝试获取第一个系统优化模板
|
|
28
28
|
template = templateManager.getTemplates().find(t => (t.type || 'optimize') === 'optimize');
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
if (!template) {
|
|
32
32
|
throw new Error(`未找到可用模板: ${templateId}`);
|
|
33
33
|
}
|
|
@@ -132,15 +132,17 @@ class OptimizationService {
|
|
|
132
132
|
|
|
133
133
|
// 3. 构建迭代优化消息列表
|
|
134
134
|
const messages = this.buildIterationMessages(
|
|
135
|
-
currentResult,
|
|
135
|
+
currentResult,
|
|
136
136
|
session.lastResult,
|
|
137
|
-
template,
|
|
138
|
-
session.count,
|
|
137
|
+
template,
|
|
138
|
+
session.count,
|
|
139
139
|
guideText,
|
|
140
140
|
session.originalPrompt // 传入原始提示词
|
|
141
141
|
);
|
|
142
142
|
|
|
143
|
-
logger.info(
|
|
143
|
+
logger.info(
|
|
144
|
+
`开始迭代优化(第 ${session.count + 1} 次),使用模板: ${template.name},模型: ${model.name}${guideText ? ',有优化指导' : ''}`
|
|
145
|
+
);
|
|
144
146
|
|
|
145
147
|
// 4. 调用 AI API(流式)
|
|
146
148
|
const result = await this.callAIModel(messages, model, onChunk);
|
|
@@ -186,10 +188,10 @@ class OptimizationService {
|
|
|
186
188
|
*/
|
|
187
189
|
buildMessages(prompt, template) {
|
|
188
190
|
if (template.format === 'advanced' && Array.isArray(template.content)) {
|
|
189
|
-
const variables = {
|
|
191
|
+
const variables = {
|
|
190
192
|
originalPrompt: prompt,
|
|
191
|
-
prompt
|
|
192
|
-
input: prompt
|
|
193
|
+
prompt, // 兼容旧模板
|
|
194
|
+
input: prompt // 兼容旧模板
|
|
193
195
|
};
|
|
194
196
|
return template.content.map(msg => ({
|
|
195
197
|
role: msg.role,
|
|
@@ -239,7 +241,7 @@ class OptimizationService {
|
|
|
239
241
|
iterationCount: iterationCount + 1,
|
|
240
242
|
guideText: guideText || ''
|
|
241
243
|
};
|
|
242
|
-
|
|
244
|
+
|
|
243
245
|
return template.content.map(msg => ({
|
|
244
246
|
role: msg.role,
|
|
245
247
|
content: this.replaceVariables(msg.content, variables)
|
|
@@ -261,21 +263,20 @@ class OptimizationService {
|
|
|
261
263
|
|
|
262
264
|
// 构建默认迭代上下文(如果模板是简单的且没有包含占位符)
|
|
263
265
|
let finalContent = '';
|
|
264
|
-
|
|
266
|
+
|
|
265
267
|
// 如果没有使用任何变量占位符,执行默认拼接逻辑
|
|
266
|
-
const hasVariables = ['{{prompt}}', '{{previousResult}}', '{{guideText}}']
|
|
267
|
-
.some(v => content.includes(v));
|
|
268
|
+
const hasVariables = ['{{prompt}}', '{{previousResult}}', '{{guideText}}'].some(v => content.includes(v));
|
|
268
269
|
|
|
269
270
|
if (!hasVariables) {
|
|
270
271
|
if (!content.includes('{{previousResult}}')) {
|
|
271
272
|
finalContent += `这是第 ${variables.iterationCount} 次优化。上一次的优化结果如下:\n\n${variables.previousResult}\n\n`;
|
|
272
273
|
}
|
|
273
|
-
|
|
274
|
+
|
|
274
275
|
if (guideText && !content.includes('{{guideText}}')) {
|
|
275
276
|
finalContent += `本次优化的具体要求:\n${guideText}\n\n`;
|
|
276
277
|
}
|
|
277
278
|
|
|
278
|
-
finalContent +=
|
|
279
|
+
finalContent += '请基于以上上下文,继续优化以下内容:\n\n{{prompt}}';
|
|
279
280
|
} else {
|
|
280
281
|
finalContent = content;
|
|
281
282
|
}
|
|
@@ -300,9 +301,11 @@ class OptimizationService {
|
|
|
300
301
|
// 记录请求日志
|
|
301
302
|
logger.info(`[AI Request] 模型: ${model.name}, 消息数: ${messages.length}`);
|
|
302
303
|
messages.forEach((msg, i) => {
|
|
303
|
-
logger.debug(
|
|
304
|
+
logger.debug(
|
|
305
|
+
`[Message ${i}] Role: ${msg.role}, Content: ${msg.content.substring(0, 1000)}${msg.content.length > 1000 ? '...' : ''}`
|
|
306
|
+
);
|
|
304
307
|
});
|
|
305
|
-
|
|
308
|
+
|
|
306
309
|
// 构建 API 请求
|
|
307
310
|
const requestBody = {
|
|
308
311
|
model: model.model,
|
|
@@ -311,8 +314,8 @@ class OptimizationService {
|
|
|
311
314
|
};
|
|
312
315
|
|
|
313
316
|
const headers = {
|
|
314
|
-
'Content-Type': 'application/json'
|
|
315
|
-
}
|
|
317
|
+
'Content-Type': 'application/json'
|
|
318
|
+
};
|
|
316
319
|
if (model.apiKey) {
|
|
317
320
|
headers['Authorization'] = `Bearer ${model.apiKey}`;
|
|
318
321
|
}
|
|
@@ -320,7 +323,7 @@ class OptimizationService {
|
|
|
320
323
|
// 发起请求
|
|
321
324
|
const response = await fetch(model.apiEndpoint, {
|
|
322
325
|
method: 'POST',
|
|
323
|
-
headers
|
|
326
|
+
headers,
|
|
324
327
|
body: JSON.stringify(requestBody)
|
|
325
328
|
});
|
|
326
329
|
|
|
@@ -337,7 +340,7 @@ class OptimizationService {
|
|
|
337
340
|
} catch (e) {
|
|
338
341
|
// 如果不是 JSON,限制长度
|
|
339
342
|
if (errorDetail.length > 200) {
|
|
340
|
-
errorDetail = errorDetail.substring(0, 200)
|
|
343
|
+
errorDetail = `${errorDetail.substring(0, 200)}...`;
|
|
341
344
|
}
|
|
342
345
|
}
|
|
343
346
|
throw new Error(`API 请求失败 (${response.status} ${response.statusText}): ${errorDetail}`);
|
|
@@ -348,7 +351,7 @@ class OptimizationService {
|
|
|
348
351
|
const decoder = new TextDecoder();
|
|
349
352
|
let fullContent = '';
|
|
350
353
|
|
|
351
|
-
|
|
354
|
+
for (;;) {
|
|
352
355
|
const { done, value } = await reader.read();
|
|
353
356
|
|
|
354
357
|
if (done) {
|
|
@@ -454,4 +457,4 @@ class OptimizationService {
|
|
|
454
457
|
export const optimizationService = new OptimizationService();
|
|
455
458
|
|
|
456
459
|
// 导出OptimizationService类供测试使用
|
|
457
|
-
export { OptimizationService };
|
|
460
|
+
export { OptimizationService };
|
|
@@ -1,16 +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
|
-
import { config } from '../utils/config.js';
|
|
10
7
|
import { util } from '../utils/util.js';
|
|
11
|
-
|
|
12
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
-
const __dirname = path.dirname(__filename);
|
|
8
|
+
import { config } from '../utils/config.js';
|
|
14
9
|
|
|
15
10
|
/**
|
|
16
11
|
* 模板数据结构验证schema
|
|
@@ -32,7 +27,7 @@ const TemplateSchema = z.object({
|
|
|
32
27
|
class TemplateManager {
|
|
33
28
|
constructor() {
|
|
34
29
|
this.builtInDir = path.join(util.getBuiltInConfigsDir(), 'templates/built-in');
|
|
35
|
-
this.customDir =
|
|
30
|
+
this.customDir = config.getTemplatesDir();
|
|
36
31
|
this.loadedTemplates = new Map();
|
|
37
32
|
this.idToPathMap = new Map();
|
|
38
33
|
}
|
|
@@ -330,4 +325,4 @@ class TemplateManager {
|
|
|
330
325
|
export const templateManager = new TemplateManager();
|
|
331
326
|
|
|
332
327
|
// 导出TemplateManager类供测试使用
|
|
333
|
-
export { TemplateManager };
|
|
328
|
+
export { TemplateManager };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 作者配置同步服务
|
|
3
|
+
*
|
|
4
|
+
* 职责:
|
|
5
|
+
* 1. 将作者配置从 packages/server/configs/ 同步到 ~/.prompt-manager/configs/
|
|
6
|
+
* 2. 确保配置文件在工作目录可用
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import fs from 'fs-extra';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
import { logger } from '../utils/logger.js';
|
|
13
|
+
import { pathExists } from './tool-utils.js';
|
|
14
|
+
import { config } from '../utils/config.js';
|
|
15
|
+
|
|
16
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
17
|
+
const __dirname = path.dirname(__filename);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 同步作者配置到沙箱环境
|
|
21
|
+
*/
|
|
22
|
+
export async function syncAuthorConfig() {
|
|
23
|
+
logger.info('开始同步作者配置到沙箱环境...');
|
|
24
|
+
|
|
25
|
+
let sourceDir;
|
|
26
|
+
|
|
27
|
+
const isElectronPackaged = process.resourcesPath != null;
|
|
28
|
+
|
|
29
|
+
const isNpmPackage = __dirname.includes('node_modules');
|
|
30
|
+
|
|
31
|
+
if (isElectronPackaged) {
|
|
32
|
+
sourceDir = path.join(process.resourcesPath, 'runtime', 'configs');
|
|
33
|
+
logger.debug('Electron 打包环境,使用配置目录:', { sourceDir });
|
|
34
|
+
} else if (isNpmPackage) {
|
|
35
|
+
sourceDir = path.join(__dirname, '..', 'configs');
|
|
36
|
+
logger.debug('NPM 包环境,使用配置目录:', { sourceDir });
|
|
37
|
+
} else {
|
|
38
|
+
sourceDir = path.join(__dirname, '..', '..', 'server', 'configs');
|
|
39
|
+
logger.debug('开发环境,使用配置目录:', { sourceDir });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const sourceConfigPath = path.join(sourceDir, 'authors.json');
|
|
43
|
+
const targetConfigPath = config.getConfigsDir();
|
|
44
|
+
const targetConfigFile = path.join(targetConfigPath, 'authors.json');
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
if (!(await pathExists(sourceConfigPath))) {
|
|
48
|
+
logger.warn(`作者配置源文件不存在,跳过同步: ${sourceConfigPath}`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
await fs.ensureDir(targetConfigPath);
|
|
53
|
+
|
|
54
|
+
const configExists = await pathExists(targetConfigFile);
|
|
55
|
+
|
|
56
|
+
if (!configExists) {
|
|
57
|
+
logger.info('首次同步,复制作者配置文件');
|
|
58
|
+
await fs.copyFile(sourceConfigPath, targetConfigFile);
|
|
59
|
+
logger.info('作者配置同步成功', { source: sourceConfigPath, target: targetConfigFile });
|
|
60
|
+
} else {
|
|
61
|
+
const sourceMtime = (await fs.stat(sourceConfigPath)).mtimeMs;
|
|
62
|
+
const targetMtime = (await fs.stat(targetConfigFile)).mtimeMs;
|
|
63
|
+
|
|
64
|
+
if (sourceMtime > targetMtime) {
|
|
65
|
+
logger.info('源配置更新,同步作者配置文件');
|
|
66
|
+
await fs.copyFile(sourceConfigPath, targetConfigFile);
|
|
67
|
+
logger.info('作者配置同步成功', { source: sourceConfigPath, target: targetConfigFile });
|
|
68
|
+
} else {
|
|
69
|
+
logger.debug('作者配置已是最新,无需同步');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const configData = await fs.readJson(targetConfigFile);
|
|
74
|
+
const authorCount = Object.keys(configData.authors || {}).length;
|
|
75
|
+
logger.info('作者配置同步完成', {
|
|
76
|
+
author_count: authorCount,
|
|
77
|
+
default_author: configData.settings?.default_author
|
|
78
|
+
});
|
|
79
|
+
} catch (error) {
|
|
80
|
+
logger.error('同步作者配置失败:', error);
|
|
81
|
+
|
|
82
|
+
if (error.code === 'ENOENT' && !(await pathExists(sourceConfigPath))) {
|
|
83
|
+
logger.warn('源配置目录不存在,使用默认配置');
|
|
84
|
+
const defaultConfig = {
|
|
85
|
+
version: '1.0.0',
|
|
86
|
+
last_updated: new Date().toISOString(),
|
|
87
|
+
authors: {},
|
|
88
|
+
settings: {
|
|
89
|
+
default_author: 'default'
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
await fs.ensureDir(targetConfigPath);
|
|
93
|
+
await fs.writeJson(targetConfigFile, defaultConfig);
|
|
94
|
+
logger.info('创建默认作者配置文件');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* PackageInstaller - 基于 Arborist 的完整依赖管理器
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* 使用 npm 官方的 @npmcli/arborist,提供与 npm install 完全一致的行为
|
|
5
5
|
* 自动处理所有传递依赖、版本冲突、循环依赖等复杂场景
|
|
6
6
|
* 不依赖系统 npm,可在 Electron 环境中直接使用
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
|
|
9
9
|
import path from 'path';
|
|
10
10
|
import fs from 'fs-extra';
|
|
11
|
-
import os from 'os';
|
|
12
11
|
import { logger } from '../utils/logger.js';
|
|
13
12
|
|
|
14
13
|
class PackageInstaller {
|
|
@@ -27,11 +26,12 @@ class PackageInstaller {
|
|
|
27
26
|
|
|
28
27
|
// 2. 检测是否在中国地区(基于时区)
|
|
29
28
|
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
30
|
-
const isChina =
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
const isChina =
|
|
30
|
+
timezone?.includes('Shanghai') ||
|
|
31
|
+
timezone?.includes('Hong_Kong') ||
|
|
32
|
+
timezone?.includes('Beijing') ||
|
|
33
|
+
timezone?.includes('Chongqing');
|
|
34
|
+
|
|
35
35
|
if (isChina) {
|
|
36
36
|
// 中国地区使用淘宝镜像
|
|
37
37
|
const chinaRegistry = 'https://registry.npmmirror.com';
|
|
@@ -43,7 +43,6 @@ class PackageInstaller {
|
|
|
43
43
|
const defaultRegistry = 'https://registry.npmjs.org/';
|
|
44
44
|
logger.debug(`[PackageInstaller] Using default registry: ${defaultRegistry}`);
|
|
45
45
|
return defaultRegistry;
|
|
46
|
-
|
|
47
46
|
} catch (error) {
|
|
48
47
|
logger.warn(`[PackageInstaller] Failed to detect optimal registry: ${error.message}`);
|
|
49
48
|
return 'https://registry.npmjs.org/';
|
|
@@ -58,27 +57,27 @@ class PackageInstaller {
|
|
|
58
57
|
* @param {number} options.timeout - 超时时间(毫秒)
|
|
59
58
|
* @returns {Promise<Object>} 安装结果
|
|
60
59
|
*/
|
|
61
|
-
static async install({ workingDir, dependencies
|
|
60
|
+
static async install({ workingDir, dependencies }) {
|
|
62
61
|
const startTime = Date.now();
|
|
63
|
-
|
|
62
|
+
|
|
64
63
|
// 构建依赖列表字符串用于日志
|
|
65
64
|
const depsList = this.buildDependenciesList(dependencies);
|
|
66
|
-
|
|
65
|
+
|
|
67
66
|
logger.info(`[PackageInstaller] Starting installation via Arborist: [${depsList}]`);
|
|
68
67
|
logger.debug(`[PackageInstaller] Working directory: ${workingDir}`);
|
|
69
|
-
|
|
68
|
+
|
|
70
69
|
try {
|
|
71
70
|
// 确保工作目录存在
|
|
72
71
|
await fs.ensureDir(workingDir);
|
|
73
|
-
|
|
72
|
+
|
|
74
73
|
// 读取或创建package.json
|
|
75
74
|
const packageJsonPath = path.join(workingDir, 'package.json');
|
|
76
75
|
let manifest;
|
|
77
|
-
|
|
76
|
+
|
|
78
77
|
try {
|
|
79
78
|
const content = await fs.readFile(packageJsonPath, 'utf8');
|
|
80
79
|
manifest = JSON.parse(content);
|
|
81
|
-
logger.debug(
|
|
80
|
+
logger.debug('[PackageInstaller] Found existing package.json');
|
|
82
81
|
} catch (error) {
|
|
83
82
|
// package.json不存在,创建默认的
|
|
84
83
|
manifest = {
|
|
@@ -88,49 +87,49 @@ class PackageInstaller {
|
|
|
88
87
|
private: true,
|
|
89
88
|
dependencies: {}
|
|
90
89
|
};
|
|
91
|
-
logger.debug(
|
|
90
|
+
logger.debug('[PackageInstaller] Creating new package.json');
|
|
92
91
|
}
|
|
93
|
-
|
|
92
|
+
|
|
94
93
|
// 规范化依赖格式
|
|
95
94
|
const normalizedDeps = this.normalizeDependencies(dependencies);
|
|
96
|
-
|
|
95
|
+
|
|
97
96
|
// 更新 manifest 的 dependencies
|
|
98
97
|
manifest.dependencies = { ...manifest.dependencies, ...normalizedDeps };
|
|
99
98
|
await fs.writeFile(packageJsonPath, JSON.stringify(manifest, null, 2));
|
|
100
|
-
|
|
99
|
+
|
|
101
100
|
logger.debug(`[PackageInstaller] Installing ${Object.keys(normalizedDeps).length} dependencies using Arborist`);
|
|
102
|
-
|
|
101
|
+
|
|
103
102
|
// 使用 Arborist 安装所有依赖(包括传递依赖)
|
|
104
103
|
// @npmcli/arborist 是 CommonJS 模块,使用 createRequire 导入
|
|
105
104
|
const { createRequire } = await import('module');
|
|
106
105
|
const require = createRequire(import.meta.url);
|
|
107
106
|
const { Arborist } = require('@npmcli/arborist');
|
|
108
|
-
|
|
107
|
+
|
|
109
108
|
// 获取最优的registry
|
|
110
109
|
const registry = await this.getOptimalRegistry();
|
|
111
|
-
|
|
110
|
+
|
|
112
111
|
const arb = new Arborist({
|
|
113
112
|
path: workingDir,
|
|
114
|
-
registry
|
|
115
|
-
cache: path.join(
|
|
116
|
-
save: false,
|
|
117
|
-
omit: [],
|
|
113
|
+
registry,
|
|
114
|
+
cache: path.join(process.env.HOME, '.npm', '_cacache'),
|
|
115
|
+
save: false, // 不需要再次更新 package.json
|
|
116
|
+
omit: [], // 安装所有依赖
|
|
118
117
|
force: false,
|
|
119
118
|
fund: false,
|
|
120
119
|
audit: false,
|
|
121
|
-
legacyPeerDeps: true
|
|
120
|
+
legacyPeerDeps: true // 兼容旧包
|
|
122
121
|
});
|
|
123
|
-
|
|
122
|
+
|
|
124
123
|
// 执行安装 - Arborist 会自动处理所有传递依赖
|
|
125
124
|
await arb.reify({
|
|
126
125
|
add: Object.entries(normalizedDeps).map(([name, version]) => `${name}@${version}`)
|
|
127
126
|
});
|
|
128
|
-
|
|
127
|
+
|
|
129
128
|
// 加载实际安装的包信息
|
|
130
129
|
const tree = await arb.loadActual();
|
|
131
130
|
const installedPackages = [];
|
|
132
131
|
const installResults = {};
|
|
133
|
-
|
|
132
|
+
|
|
134
133
|
// 收集安装的包信息
|
|
135
134
|
for (const [name, node] of tree.children) {
|
|
136
135
|
if (node && node.package) {
|
|
@@ -143,28 +142,27 @@ class PackageInstaller {
|
|
|
143
142
|
logger.debug(`[PackageInstaller] ✓ ${name}@${node.package.version} installed`);
|
|
144
143
|
}
|
|
145
144
|
}
|
|
146
|
-
|
|
145
|
+
|
|
147
146
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
148
147
|
logger.info(`[PackageInstaller] Installation completed successfully in ${elapsed}s`);
|
|
149
148
|
logger.info(`[PackageInstaller] Installed ${installedPackages.length} packages with all transitive dependencies`);
|
|
150
|
-
|
|
149
|
+
|
|
151
150
|
return {
|
|
152
151
|
success: true,
|
|
153
|
-
elapsed
|
|
154
|
-
manifest
|
|
152
|
+
elapsed,
|
|
153
|
+
manifest,
|
|
155
154
|
environment: 'arborist',
|
|
156
|
-
installedPackages
|
|
155
|
+
installedPackages,
|
|
157
156
|
results: installResults
|
|
158
157
|
};
|
|
159
|
-
|
|
160
158
|
} catch (error) {
|
|
161
159
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
162
160
|
logger.error(`[PackageInstaller] Installation failed after ${elapsed}s: ${error.message}`);
|
|
163
|
-
|
|
161
|
+
|
|
164
162
|
throw new Error(`Arborist installation failed: ${error.message}`);
|
|
165
163
|
}
|
|
166
164
|
}
|
|
167
|
-
|
|
165
|
+
|
|
168
166
|
/**
|
|
169
167
|
* 构建依赖列表字符串用于日志
|
|
170
168
|
* @param {Object|Array} dependencies - 依赖
|
|
@@ -172,7 +170,7 @@ class PackageInstaller {
|
|
|
172
170
|
*/
|
|
173
171
|
static buildDependenciesList(dependencies) {
|
|
174
172
|
if (!dependencies) return '';
|
|
175
|
-
|
|
173
|
+
|
|
176
174
|
if (typeof dependencies === 'object' && !Array.isArray(dependencies)) {
|
|
177
175
|
// 对象格式:{"package": "version"}
|
|
178
176
|
return Object.keys(dependencies)
|
|
@@ -182,10 +180,10 @@ class PackageInstaller {
|
|
|
182
180
|
// 数组格式:["package@version"]
|
|
183
181
|
return dependencies.join(', ');
|
|
184
182
|
}
|
|
185
|
-
|
|
183
|
+
|
|
186
184
|
return String(dependencies);
|
|
187
185
|
}
|
|
188
|
-
|
|
186
|
+
|
|
189
187
|
/**
|
|
190
188
|
* 规范化依赖格式为对象
|
|
191
189
|
* @param {Object|Array} dependencies - 原始依赖
|
|
@@ -193,12 +191,12 @@ class PackageInstaller {
|
|
|
193
191
|
*/
|
|
194
192
|
static normalizeDependencies(dependencies) {
|
|
195
193
|
if (!dependencies) return {};
|
|
196
|
-
|
|
194
|
+
|
|
197
195
|
if (typeof dependencies === 'object' && !Array.isArray(dependencies)) {
|
|
198
196
|
// 已经是对象格式
|
|
199
197
|
return dependencies;
|
|
200
198
|
}
|
|
201
|
-
|
|
199
|
+
|
|
202
200
|
if (Array.isArray(dependencies)) {
|
|
203
201
|
// 数组格式转对象
|
|
204
202
|
const normalized = {};
|
|
@@ -218,10 +216,10 @@ class PackageInstaller {
|
|
|
218
216
|
}
|
|
219
217
|
return normalized;
|
|
220
218
|
}
|
|
221
|
-
|
|
219
|
+
|
|
222
220
|
return {};
|
|
223
221
|
}
|
|
224
|
-
|
|
222
|
+
|
|
225
223
|
/**
|
|
226
224
|
* 检查包是否已安装
|
|
227
225
|
* @param {string} workingDir - 工作目录
|
|
@@ -230,10 +228,10 @@ class PackageInstaller {
|
|
|
230
228
|
*/
|
|
231
229
|
static async isPackageInstalled(workingDir, packageName) {
|
|
232
230
|
try {
|
|
233
|
-
const packagePath = packageName.startsWith('@')
|
|
231
|
+
const packagePath = packageName.startsWith('@')
|
|
234
232
|
? path.join(workingDir, 'node_modules', ...packageName.split('/'))
|
|
235
233
|
: path.join(workingDir, 'node_modules', packageName);
|
|
236
|
-
|
|
234
|
+
|
|
237
235
|
const packageJsonPath = path.join(packagePath, 'package.json');
|
|
238
236
|
await fs.access(packageJsonPath);
|
|
239
237
|
return true;
|
|
@@ -241,7 +239,7 @@ class PackageInstaller {
|
|
|
241
239
|
return false;
|
|
242
240
|
}
|
|
243
241
|
}
|
|
244
|
-
|
|
242
|
+
|
|
245
243
|
/**
|
|
246
244
|
* 获取已安装包的信息
|
|
247
245
|
* @param {string} workingDir - 工作目录
|
|
@@ -253,7 +251,7 @@ class PackageInstaller {
|
|
|
253
251
|
const packagePath = packageName.startsWith('@')
|
|
254
252
|
? path.join(workingDir, 'node_modules', ...packageName.split('/'))
|
|
255
253
|
: path.join(workingDir, 'node_modules', packageName);
|
|
256
|
-
|
|
254
|
+
|
|
257
255
|
const packageJsonPath = path.join(packagePath, 'package.json');
|
|
258
256
|
const content = await fs.readFile(packageJsonPath, 'utf8');
|
|
259
257
|
return JSON.parse(content);
|
|
@@ -264,4 +262,3 @@ class PackageInstaller {
|
|
|
264
262
|
}
|
|
265
263
|
|
|
266
264
|
export default PackageInstaller;
|
|
267
|
-
|