sloth-d2c-mcp 1.0.4-beta89 → 1.0.4-beta91

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.
@@ -0,0 +1,127 @@
1
+ import { loadAllPlugins, loadWorkspacePlugins } from './loader.js';
2
+ /**
3
+ * 插件管理器 - 负责管理生命周期 hooks 并按顺序调用插件
4
+ */
5
+ class PluginManager {
6
+ plugins = [];
7
+ initialized = false;
8
+ workspaceRoot = '';
9
+ /**
10
+ * 设置工作区根目录
11
+ * @param root 工作区根目录
12
+ */
13
+ setWorkspaceRoot(root) {
14
+ this.workspaceRoot = root;
15
+ // 重置初始化状态,以便重新加载工作区插件
16
+ if (this.initialized) {
17
+ this.reset();
18
+ }
19
+ }
20
+ /**
21
+ * 获取工作区根目录
22
+ */
23
+ getWorkspaceRoot() {
24
+ return this.workspaceRoot;
25
+ }
26
+ /**
27
+ * 初始化插件管理器
28
+ * 如果设置了工作区根目录,则加载工作区插件
29
+ * 否则加载全局插件(兼容旧逻辑)
30
+ */
31
+ async initialize() {
32
+ if (this.initialized) {
33
+ return;
34
+ }
35
+ try {
36
+ if (this.workspaceRoot) {
37
+ // 加载工作区声明的插件
38
+ console.log(`[sloth] 从工作区加载插件: ${this.workspaceRoot}`);
39
+ this.plugins = await loadWorkspacePlugins(this.workspaceRoot);
40
+ }
41
+ else {
42
+ // 兼容旧逻辑:加载全局插件
43
+ console.log(`[sloth] 未设置工作区,加载全局插件`);
44
+ this.plugins = await loadAllPlugins();
45
+ }
46
+ this.initialized = true;
47
+ console.log(`[sloth] 插件管理器初始化完成,已加载 ${this.plugins.length} 个插件`);
48
+ }
49
+ catch (error) {
50
+ console.error('[sloth] 插件管理器初始化失败:', error);
51
+ // 如果是工作区模式,抛出错误让调用方知道
52
+ if (this.workspaceRoot) {
53
+ throw error;
54
+ }
55
+ this.plugins = [];
56
+ this.initialized = true;
57
+ }
58
+ }
59
+ /**
60
+ * 获取已加载的插件列表
61
+ */
62
+ getPlugins() {
63
+ return [...this.plugins];
64
+ }
65
+ /**
66
+ * 注册一个插件
67
+ */
68
+ registerPlugin(plugin) {
69
+ this.plugins.push(plugin);
70
+ console.log(`[sloth] 插件 ${plugin.name} 已注册`);
71
+ }
72
+ /**
73
+ * 执行指定的 hook
74
+ * @param hookName hook 名称
75
+ * @param params hook 参数
76
+ * 按顺序调用所有插件,每个插件都会执行,返回最后一个成功的结果
77
+ * 每个插件执行时会收到上一个插件的信息 { lastPlugin, returnVal }
78
+ */
79
+ async executeHook(hookName, params) {
80
+ if (!this.initialized) {
81
+ await this.initialize();
82
+ }
83
+ const pluginsWithHook = this.plugins.filter((p) => typeof p[hookName] === 'function');
84
+ if (pluginsWithHook.length === 0) {
85
+ console.log(`[sloth] 没有插件注册 ${hookName} hook`);
86
+ return params;
87
+ }
88
+ let lastPlugin = '';
89
+ let lastReturnVal = null;
90
+ for (const plugin of pluginsWithHook) {
91
+ try {
92
+ console.log(`[sloth] 执行插件 ${plugin.name} 的 ${hookName} hook`);
93
+ const hookFn = plugin[hookName];
94
+ const context = {
95
+ lastPlugin,
96
+ returnVal: lastReturnVal,
97
+ config: plugin._config,
98
+ };
99
+ const result = await hookFn({
100
+ ...params,
101
+ ...(lastReturnVal || {}),
102
+ _config: context.config,
103
+ }, context);
104
+ // 更新上一个插件信息
105
+ lastPlugin = plugin.name;
106
+ lastReturnVal = {
107
+ ...params,
108
+ ...(lastReturnVal || {}),
109
+ ...(result || {}),
110
+ };
111
+ }
112
+ catch (error) {
113
+ console.error(`[sloth] 插件 ${plugin.name} 执行 ${hookName} 出错:`, error);
114
+ }
115
+ }
116
+ return lastReturnVal || params;
117
+ }
118
+ /**
119
+ * 重置插件管理器
120
+ */
121
+ reset() {
122
+ this.plugins = [];
123
+ this.initialized = false;
124
+ }
125
+ }
126
+ // 导出单例实例
127
+ export const pluginManager = new PluginManager();
@@ -0,0 +1 @@
1
+ export {};
@@ -33,6 +33,7 @@ const upload = multer({
33
33
  // 导入默认提示词
34
34
  import { chunkOptimizeCodePrompt, aggregationOptimizeCodePrompt, finalOptimizeCodePrompt, chunkOptimizeCodePromptVue, aggregationOptimizeCodePromptVue, finalOptimizeCodePromptVue, noSamplingAggregationPrompt, noSamplingAggregationPromptVue, } from 'sloth-d2c-node/convert';
35
35
  import { getParam } from './utils/utils.js';
36
+ import { listWorkspacePlugins } from './plugin/loader.js';
36
37
  // 保存 HTTP 服务器实例
37
38
  export let httpServer = null;
38
39
  // 保存 Socket 服务器实例
@@ -202,6 +203,7 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
202
203
  const uuid = getParam(req.headers.referer || '', 'token') || '';
203
204
  req.uuid = uuid;
204
205
  req.fileManager = fileManager.withUUID(uuid);
206
+ req.workspaceRoot = req.fileManager.getWorkspaceRoot();
205
207
  next();
206
208
  });
207
209
  // 处理流式 HTTP 的 POST 请求,支持会话复用和初始化
@@ -337,6 +339,7 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
337
339
  const fileKey = req.query.fileKey;
338
340
  const nodeId = req.query.nodeId;
339
341
  const framework = req.query.framework;
342
+ const plugins = await listWorkspacePlugins(req.workspaceRoot);
340
343
  if (fileKey) {
341
344
  // 如果提供了 fileKey,返回该 fileKey 的特定配置
342
345
  const globalConfig = await configManager.load();
@@ -401,6 +404,7 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
401
404
  defaultFramework: globalConfig.defaultFramework || 'react',
402
405
  fileKey: fileKey,
403
406
  groupsData: groupsData,
407
+ plugins,
404
408
  },
405
409
  });
406
410
  }
@@ -441,6 +445,7 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
441
445
  imageSetting: configStorage.imageSetting || {},
442
446
  promptSetting: promptSetting,
443
447
  frameworks: frameworks,
448
+ plugins,
444
449
  },
445
450
  });
446
451
  }
@@ -1,10 +1,10 @@
1
1
  {
2
- "buildTime": "2025-12-31T04:53:16.839Z",
2
+ "buildTime": "2026-01-07T05:29:02.885Z",
3
3
  "mode": "build",
4
4
  "pages": {
5
5
  "main": {
6
6
  "file": "index.html",
7
- "size": 1642308,
7
+ "size": 1643352,
8
8
  "sizeFormatted": "1.57 MB"
9
9
  },
10
10
  "detail": {
@@ -13,6 +13,6 @@
13
13
  "sizeFormatted": "275.19 KB"
14
14
  }
15
15
  },
16
- "totalSize": 1924107,
17
- "totalSizeFormatted": "1.83 MB"
16
+ "totalSize": 1925151,
17
+ "totalSizeFormatted": "1.84 MB"
18
18
  }