sloth-d2c-mcp 1.0.4-beta92 → 1.0.4-beta94

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.
@@ -18,8 +18,11 @@ import multer from 'multer';
18
18
  import { ImageMatcher } from './utils/image-matcher.js';
19
19
  import { initOpenCV } from './utils/opencv-loader.js';
20
20
  import { extractJson } from './utils/extract.js';
21
- import { componentAnalysisPrompt, componentAnalysisPromptVue } from 'sloth-d2c-node/convert';
21
+ import { componentAnalysisPrompt, componentAnalysisPromptVue, chunkOptimizeCodePromptKuikly, aggregationOptimizeCodePromptKuikly, finalOptimizeCodePromptKuikly, chunkOptimizeCodePrompt, aggregationOptimizeCodePrompt, finalOptimizeCodePrompt, chunkOptimizeCodePromptVue, aggregationOptimizeCodePromptVue, finalOptimizeCodePromptVue, frameworkPromptKuikly, noSamplingAggregationPrompt, noSamplingAggregationPromptVue, noSamplingAggregationPromptKuikly, chunkOptimizeCodePromptIosOc, aggregationOptimizeCodePromptIosOc, finalOptimizeCodePromptIosOc, noSamplingAggregationPromptIosOc, chunkOptimizeCodePromptIosSwift, aggregationOptimizeCodePromptIosSwift, finalOptimizeCodePromptIosSwift, noSamplingAggregationPromptIosSwift, } from 'sloth-d2c-node/convert';
22
22
  import { SocketServer } from './socket-server.js';
23
+ import { getParam } from './utils/utils.js';
24
+ import { loadPluginFromGlobalDirAsync } from './plugin/loader.js';
25
+ import { pluginManager } from './plugin/manager.js';
23
26
  /**
24
27
  * 生成组件 ID(4位随机字符串)
25
28
  */
@@ -30,10 +33,6 @@ const upload = multer({
30
33
  storage,
31
34
  limits: { fileSize: 10 * 1024 * 1024 }, // 10MB
32
35
  });
33
- // 导入默认提示词
34
- import { chunkOptimizeCodePrompt, aggregationOptimizeCodePrompt, finalOptimizeCodePrompt, chunkOptimizeCodePromptVue, aggregationOptimizeCodePromptVue, finalOptimizeCodePromptVue, noSamplingAggregationPrompt, noSamplingAggregationPromptVue, } from 'sloth-d2c-node/convert';
35
- import { getParam } from './utils/utils.js';
36
- import { listWorkspacePlugins } from './plugin/loader.js';
37
36
  // 保存 HTTP 服务器实例
38
37
  export let httpServer = null;
39
38
  // 保存 Socket 服务器实例
@@ -50,7 +49,7 @@ let configManager = null; // 配置管理器实例
50
49
  const __filename = fileURLToPath(import.meta.url);
51
50
  const __dirname = path.dirname(__filename);
52
51
  // 获取端口号
53
- let PORT = 0;
52
+ let PORT = 3100;
54
53
  // 导出获取端口号的函数
55
54
  export function getPort() {
56
55
  return PORT;
@@ -77,24 +76,26 @@ export async function loadConfig(mcpServer, configManagerInstance) {
77
76
  Logger.warn(`读取配置文件失败: ${error}`);
78
77
  }
79
78
  }
79
+ // 默认框架列表
80
+ const defaultFrameworks = [
81
+ { value: 'react', label: 'React' },
82
+ { value: 'vue', label: 'Vue' },
83
+ { value: 'ios-oc', label: 'iOS OC' },
84
+ { value: 'ios-swift', label: 'iOS Swift' },
85
+ { value: 'kuikly', label: 'Kuikly' },
86
+ ];
80
87
  // 初始化默认框架配置
81
88
  if (!config.frameworks || config.frameworks.length === 0) {
82
89
  Logger.log('初始化默认框架配置...');
83
- if (!config.frameworks) {
84
- config.frameworks = [];
85
- }
86
- if (typeof config.frameworks[0] === 'string') {
87
- config.frameworks = config.frameworks.map((f) => {
88
- return {
89
- label: f.charAt(0).toUpperCase() + f.slice(1),
90
- value: f,
91
- isCustom: f !== 'react' && f !== 'vue', // todo: 暂时兼容,仅 react 是默认框架,若新增框架需调整
92
- };
93
- });
94
- }
95
- if (!config.frameworks.find((fw) => fw.value === 'react') || !config.frameworks.find((fw) => fw.value === 'vue')) {
96
- const newFrameworks = config.frameworks.filter((fw) => fw.value !== 'react' || fw.value !== 'vue');
97
- config.frameworks = [{ value: 'react', label: 'React' }, { value: 'vue', label: 'Vue' }, ...newFrameworks];
90
+ config.frameworks = [...defaultFrameworks];
91
+ await configManager.save(config);
92
+ }
93
+ else {
94
+ // 检查是否缺少默认框架,补充缺失的
95
+ const existingValues = config.frameworks.map((fw) => fw.value);
96
+ const missingFrameworks = defaultFrameworks.filter((fw) => !existingValues.includes(fw.value));
97
+ if (missingFrameworks.length > 0) {
98
+ config.frameworks = [...config.frameworks, ...missingFrameworks];
98
99
  await configManager.save(config);
99
100
  }
100
101
  }
@@ -135,6 +136,82 @@ export async function loadConfig(mcpServer, configManagerInstance) {
135
136
  ...(vueConfig || {}),
136
137
  });
137
138
  }
139
+ // 检查 ios-oc.json 是否存在,如果不存在则创建
140
+ const iosOcConfigExists = await configManager.frameworkConfigExists('ios-oc');
141
+ if (!iosOcConfigExists) {
142
+ await configManager.saveFrameworkConfig('ios-oc', {
143
+ chunkOptimizePrompt: chunkOptimizeCodePromptIosOc,
144
+ aggregationOptimizePrompt: aggregationOptimizeCodePromptIosOc,
145
+ finalOptimizePrompt: finalOptimizeCodePromptIosOc,
146
+ componentAnalysisPrompt: '',
147
+ noSamplingAggregationPrompt: noSamplingAggregationPromptIosOc,
148
+ });
149
+ const iosOcConfigPath = configManager.getFrameworkConfigPath('ios-oc');
150
+ Logger.log(`已创建默认 ios-oc 配置文件: ${iosOcConfigPath}`);
151
+ }
152
+ else {
153
+ const iosOcConfig = await configManager.loadFrameworkConfig('ios-oc');
154
+ await configManager.saveFrameworkConfig('ios-oc', {
155
+ chunkOptimizePrompt: chunkOptimizeCodePromptIosOc,
156
+ aggregationOptimizePrompt: aggregationOptimizeCodePromptIosOc,
157
+ finalOptimizePrompt: finalOptimizeCodePromptIosOc,
158
+ componentAnalysisPrompt: '',
159
+ noSamplingAggregationPrompt: noSamplingAggregationPromptIosOc,
160
+ ...(iosOcConfig || {}),
161
+ });
162
+ }
163
+ // 检查 ios-swift.json 是否存在,如果不存在则创建
164
+ const iosswiftConfigExists = await configManager.frameworkConfigExists('ios-swift');
165
+ if (!iosswiftConfigExists) {
166
+ await configManager.saveFrameworkConfig('ios-swift', {
167
+ chunkOptimizePrompt: chunkOptimizeCodePromptIosSwift,
168
+ aggregationOptimizePrompt: aggregationOptimizeCodePromptIosSwift,
169
+ finalOptimizePrompt: finalOptimizeCodePromptIosSwift,
170
+ componentAnalysisPrompt: '',
171
+ noSamplingAggregationPrompt: noSamplingAggregationPromptIosSwift,
172
+ });
173
+ const iosswiftConfigPath = configManager.getFrameworkConfigPath('ios-swift');
174
+ Logger.log(`已创建默认 ios-swift 配置文件: ${iosswiftConfigPath}`);
175
+ }
176
+ else {
177
+ const iosSwiftConfig = await configManager.loadFrameworkConfig('ios-swift');
178
+ await configManager.saveFrameworkConfig('ios-swift', {
179
+ chunkOptimizePrompt: chunkOptimizeCodePromptIosSwift,
180
+ aggregationOptimizePrompt: aggregationOptimizeCodePromptIosSwift,
181
+ finalOptimizePrompt: finalOptimizeCodePromptIosSwift,
182
+ componentAnalysisPrompt: '',
183
+ noSamplingAggregationPrompt: noSamplingAggregationPromptIosSwift,
184
+ ...(iosSwiftConfig || {}),
185
+ });
186
+ }
187
+ // 检查 kuikly.json 是否存在,如果不存在则创建
188
+ const kuiklyConfigExists = await configManager.frameworkConfigExists('kuikly');
189
+ if (!kuiklyConfigExists) {
190
+ await configManager.saveFrameworkConfig('kuikly', {
191
+ enableFrameworkGuide: true,
192
+ frameworkGuidePrompt: frameworkPromptKuikly,
193
+ chunkOptimizePrompt: chunkOptimizeCodePromptKuikly,
194
+ aggregationOptimizePrompt: aggregationOptimizeCodePromptKuikly,
195
+ finalOptimizePrompt: finalOptimizeCodePromptKuikly,
196
+ componentAnalysisPrompt: '',
197
+ noSamplingAggregationPrompt: noSamplingAggregationPromptKuikly,
198
+ });
199
+ const kuiklyConfigPath = configManager.getFrameworkConfigPath('kuikly');
200
+ Logger.log(`已创建默认 kuikly 配置文件: ${kuiklyConfigPath}`);
201
+ }
202
+ else {
203
+ const kuiklyConfig = await configManager.loadFrameworkConfig('kuikly');
204
+ await configManager.saveFrameworkConfig('kuikly', {
205
+ enableFrameworkGuide: true,
206
+ frameworkGuidePrompt: frameworkPromptKuikly,
207
+ chunkOptimizePrompt: chunkOptimizeCodePromptKuikly,
208
+ aggregationOptimizePrompt: aggregationOptimizeCodePromptKuikly,
209
+ finalOptimizePrompt: finalOptimizeCodePromptKuikly,
210
+ componentAnalysisPrompt: '',
211
+ noSamplingAggregationPrompt: noSamplingAggregationPromptKuikly,
212
+ ...(kuiklyConfig || {}),
213
+ });
214
+ }
138
215
  }
139
216
  catch (error) {
140
217
  Logger.error(`获取配置信息时出错: ${error}`);
@@ -339,7 +416,8 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
339
416
  const fileKey = req.query.fileKey;
340
417
  const nodeId = req.query.nodeId;
341
418
  const framework = req.query.framework;
342
- const plugins = await listWorkspacePlugins(req.workspaceRoot);
419
+ // const plugins = await listWorkspacePlugins(req.workspaceRoot)
420
+ const plugins = await socketServer?.getTokenExtraField(req.uuid, 'plugins');
343
421
  if (fileKey) {
344
422
  // 如果提供了 fileKey,返回该 fileKey 的特定配置
345
423
  const globalConfig = await configManager.load();
@@ -352,47 +430,16 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
352
430
  let curFramework = fileConfig?.convertSetting?.framework;
353
431
  // 获取框架列表
354
432
  const frameworks = await configManager.getFrameworks();
355
- if (!curFramework || !frameworks.find((fw) => fw.value === curFramework)) {
356
- curFramework = globalConfig.defaultFramework || 'react';
357
- }
358
- const curFrameworkDefaultConfig = (await configManager.loadFrameworkConfig(curFramework)) ||
359
- (curFramework !== 'vue'
360
- ? {
361
- chunkOptimizePrompt: chunkOptimizeCodePrompt,
362
- aggregationOptimizePrompt: aggregationOptimizeCodePrompt,
363
- finalOptimizePrompt: finalOptimizeCodePrompt,
364
- componentAnalysisPrompt: componentAnalysisPrompt,
365
- noSamplingAggregationPrompt: noSamplingAggregationPrompt,
366
- }
367
- : {
368
- chunkOptimizePrompt: chunkOptimizeCodePromptVue,
369
- aggregationOptimizePrompt: aggregationOptimizeCodePromptVue,
370
- finalOptimizePrompt: finalOptimizeCodePromptVue,
371
- componentAnalysisPrompt: componentAnalysisPromptVue,
372
- noSamplingAggregationPrompt: noSamplingAggregationPromptVue,
373
- });
374
433
  // 如果指定了框架,加载框架配置的提示词
375
434
  let promptSetting = {
376
- chunkOptimizePrompt: savedPromptSetting?.chunkOptimizePrompt || curFrameworkDefaultConfig.chunkOptimizePrompt,
377
- aggregationOptimizePrompt: savedPromptSetting?.aggregationOptimizePrompt || curFrameworkDefaultConfig.aggregationOptimizePrompt,
378
- finalOptimizePrompt: savedPromptSetting?.finalOptimizePrompt || curFrameworkDefaultConfig.finalOptimizePrompt,
379
- componentAnalysisPrompt: savedPromptSetting?.componentAnalysisPrompt || curFrameworkDefaultConfig.componentAnalysisPrompt,
380
- noSamplingAggregationPrompt: savedPromptSetting?.noSamplingAggregationPrompt || curFrameworkDefaultConfig.noSamplingAggregationPrompt,
435
+ enableFrameworkGuide: savedPromptSetting?.frameworkGuidePrompt,
436
+ frameworkGuidePrompt: savedPromptSetting?.frameworkGuidePrompt,
437
+ chunkOptimizePrompt: savedPromptSetting?.chunkOptimizePrompt,
438
+ aggregationOptimizePrompt: savedPromptSetting?.aggregationOptimizePrompt,
439
+ finalOptimizePrompt: savedPromptSetting?.finalOptimizePrompt,
440
+ componentAnalysisPrompt: savedPromptSetting?.componentAnalysisPrompt,
441
+ noSamplingAggregationPrompt: savedPromptSetting?.noSamplingAggregationPrompt,
381
442
  };
382
- if (framework) {
383
- // 加载框架配置
384
- const frameworkConfig = await configManager.loadFrameworkConfig(framework);
385
- if (frameworkConfig && Object.keys(frameworkConfig).length > 0) {
386
- // 框架配置优先级更高,但如果框架配置为空,则使用已保存的或默认的
387
- promptSetting = {
388
- chunkOptimizePrompt: frameworkConfig.chunkOptimizePrompt || promptSetting.chunkOptimizePrompt,
389
- aggregationOptimizePrompt: frameworkConfig.aggregationOptimizePrompt || promptSetting.aggregationOptimizePrompt,
390
- finalOptimizePrompt: frameworkConfig.finalOptimizePrompt || promptSetting.finalOptimizePrompt,
391
- componentAnalysisPrompt: frameworkConfig.componentAnalysisPrompt || promptSetting.componentAnalysisPrompt,
392
- noSamplingAggregationPrompt: frameworkConfig.noSamplingAggregationPrompt || promptSetting.noSamplingAggregationPrompt,
393
- };
394
- }
395
- }
396
443
  res.json({
397
444
  success: true,
398
445
  data: {
@@ -404,7 +451,7 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
404
451
  defaultFramework: globalConfig.defaultFramework || 'react',
405
452
  fileKey: fileKey,
406
453
  groupsData: groupsData,
407
- plugins,
454
+ pluginSetting: plugins,
408
455
  },
409
456
  });
410
457
  }
@@ -415,6 +462,8 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
415
462
  }
416
463
  // 如果指定了框架,加载框架配置的提示词
417
464
  let promptSetting = {
465
+ enableFrameworkGuide: false,
466
+ frameworkGuidePrompt: '',
418
467
  chunkOptimizePrompt: chunkOptimizeCodePrompt,
419
468
  aggregationOptimizePrompt: aggregationOptimizeCodePrompt,
420
469
  finalOptimizePrompt: finalOptimizeCodePrompt,
@@ -427,6 +476,8 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
427
476
  if (frameworkConfig && Object.keys(frameworkConfig).length > 0) {
428
477
  // 框架配置优先级更高
429
478
  promptSetting = {
479
+ enableFrameworkGuide: frameworkConfig.frameworkGuidePrompt || promptSetting.enableFrameworkGuide ? true : false,
480
+ frameworkGuidePrompt: frameworkConfig.frameworkGuidePrompt || promptSetting.frameworkGuidePrompt,
430
481
  chunkOptimizePrompt: frameworkConfig.chunkOptimizePrompt || promptSetting.chunkOptimizePrompt,
431
482
  aggregationOptimizePrompt: frameworkConfig.aggregationOptimizePrompt || promptSetting.aggregationOptimizePrompt,
432
483
  finalOptimizePrompt: frameworkConfig.finalOptimizePrompt || promptSetting.finalOptimizePrompt,
@@ -445,7 +496,7 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
445
496
  imageSetting: configStorage.imageSetting || {},
446
497
  promptSetting: promptSetting,
447
498
  frameworks: frameworks,
448
- plugins,
499
+ pluginSetting: plugins,
449
500
  },
450
501
  });
451
502
  }
@@ -476,6 +527,7 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
476
527
  let frameworks = (await configManager.getFrameworks()) || [
477
528
  { value: 'react', label: 'React' },
478
529
  { value: 'vue', label: 'Vue' },
530
+ { value: 'kuikly', label: 'Kuikly' },
479
531
  ];
480
532
  const defaultFramework = globalConfig?.defaultFramework || 'react';
481
533
  let promptSetting = {};
@@ -484,12 +536,12 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
484
536
  promptSetting[fw] = {
485
537
  ...frameworkConfig,
486
538
  enableFrameworkGuide: frameworkConfig.enableFrameworkGuide || false,
487
- frameworkPrompt: frameworkConfig.frameworkPrompt || '',
488
- chunkOptimizePrompt: frameworkConfig.chunkOptimizePrompt || chunkOptimizeCodePrompt,
489
- aggregationOptimizePrompt: frameworkConfig.aggregationOptimizePrompt || aggregationOptimizeCodePrompt,
490
- finalOptimizePrompt: frameworkConfig.finalOptimizePrompt || finalOptimizeCodePrompt,
491
- componentAnalysisPrompt: frameworkConfig.componentAnalysisPrompt || componentAnalysisPrompt,
492
- noSamplingAggregationPrompt: frameworkConfig.noSamplingAggregationPrompt || noSamplingAggregationPrompt,
539
+ frameworkGuidePrompt: frameworkConfig.frameworkGuidePrompt || '',
540
+ chunkOptimizePrompt: frameworkConfig.chunkOptimizePrompt || '',
541
+ aggregationOptimizePrompt: frameworkConfig.aggregationOptimizePrompt || '',
542
+ finalOptimizePrompt: frameworkConfig.finalOptimizePrompt || '',
543
+ componentAnalysisPrompt: frameworkConfig.componentAnalysisPrompt || '',
544
+ noSamplingAggregationPrompt: frameworkConfig.noSamplingAggregationPrompt || '',
493
545
  };
494
546
  res.json({
495
547
  success: true,
@@ -553,6 +605,8 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
553
605
  return;
554
606
  }
555
607
  let promptSetting = {
608
+ enableFrameworkGuide: false,
609
+ frameworkGuidePrompt: '',
556
610
  chunkOptimizePrompt: chunkOptimizeCodePrompt,
557
611
  aggregationOptimizePrompt: aggregationOptimizeCodePrompt,
558
612
  finalOptimizePrompt: finalOptimizeCodePrompt,
@@ -563,6 +617,8 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
563
617
  if (frameworkConfig && Object.keys(frameworkConfig).length > 0) {
564
618
  // 框架配置优先级更高
565
619
  promptSetting = {
620
+ enableFrameworkGuide: frameworkConfig.enableFrameworkGuide || promptSetting.enableFrameworkGuide,
621
+ frameworkGuidePrompt: frameworkConfig.frameworkGuidePrompt || promptSetting.frameworkGuidePrompt,
566
622
  chunkOptimizePrompt: frameworkConfig.chunkOptimizePrompt || promptSetting.chunkOptimizePrompt,
567
623
  aggregationOptimizePrompt: frameworkConfig.aggregationOptimizePrompt || promptSetting.aggregationOptimizePrompt,
568
624
  finalOptimizePrompt: frameworkConfig.finalOptimizePrompt || promptSetting.finalOptimizePrompt,
@@ -598,17 +654,54 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
598
654
  }
599
655
  // 根据框架返回对应的原始默认提示词
600
656
  const isVue = framework.toLowerCase() === 'vue';
657
+ const isIosOc = framework.toLowerCase() === 'ios-oc';
658
+ const isIosSwift = framework.toLowerCase() === 'ios-swift';
659
+ const isKuikly = framework.toLowerCase() === 'kuikly';
601
660
  const promptSetting = {
602
- chunkOptimizePrompt: isVue ? chunkOptimizeCodePromptVue : chunkOptimizeCodePrompt,
603
- aggregationOptimizePrompt: isVue ? aggregationOptimizeCodePromptVue : aggregationOptimizeCodePrompt,
604
- finalOptimizePrompt: isVue ? finalOptimizeCodePromptVue : finalOptimizeCodePrompt,
605
- componentAnalysisPrompt: isVue ? componentAnalysisPromptVue : componentAnalysisPrompt,
606
- noSamplingAggregationPrompt: isVue ? noSamplingAggregationPromptVue : noSamplingAggregationPrompt,
661
+ enableFrameworkGuide: isKuikly ? true : false,
662
+ frameworkGuidePrompt: isKuikly ? frameworkPromptKuikly : '',
663
+ chunkOptimizePrompt: isKuikly
664
+ ? chunkOptimizeCodePromptKuikly
665
+ : isIosOc
666
+ ? chunkOptimizeCodePromptIosOc
667
+ : isIosSwift
668
+ ? chunkOptimizeCodePromptIosSwift
669
+ : isVue
670
+ ? chunkOptimizeCodePromptVue
671
+ : chunkOptimizeCodePrompt,
672
+ aggregationOptimizePrompt: isKuikly
673
+ ? aggregationOptimizeCodePromptKuikly
674
+ : isIosOc
675
+ ? aggregationOptimizeCodePromptIosOc
676
+ : isIosSwift
677
+ ? aggregationOptimizeCodePromptIosSwift
678
+ : isVue
679
+ ? aggregationOptimizeCodePromptVue
680
+ : aggregationOptimizeCodePrompt,
681
+ finalOptimizePrompt: isKuikly
682
+ ? finalOptimizeCodePromptKuikly
683
+ : isIosOc
684
+ ? finalOptimizeCodePromptIosOc
685
+ : isIosSwift
686
+ ? finalOptimizeCodePromptIosSwift
687
+ : isVue
688
+ ? finalOptimizeCodePromptVue
689
+ : finalOptimizeCodePrompt,
690
+ componentAnalysisPrompt: isKuikly ? '' : isIosOc ? '' : isIosSwift ? '' : isVue ? componentAnalysisPromptVue : componentAnalysisPrompt,
691
+ noSamplingAggregationPrompt: isKuikly
692
+ ? noSamplingAggregationPromptKuikly
693
+ : isIosOc
694
+ ? noSamplingAggregationPromptIosOc
695
+ : isIosSwift
696
+ ? noSamplingAggregationPromptIosSwift
697
+ : isVue
698
+ ? noSamplingAggregationPromptVue
699
+ : noSamplingAggregationPrompt,
607
700
  };
608
701
  res.json({
609
702
  success: true,
610
703
  data: promptSetting,
611
- message: '获取默认框架配置成功',
704
+ message: '获取默认框架配置成功1',
612
705
  });
613
706
  }
614
707
  catch (error) {
@@ -620,6 +713,67 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
620
713
  });
621
714
  }
622
715
  });
716
+ // 获取项目中的 Markdown 文件列表(扫描 .sloth/doc 目录)
717
+ app.get('/getMarkdownFiles', async (req, res) => {
718
+ try {
719
+ const projectRoot = getProjectRoot(req.fileManager);
720
+ if (!projectRoot) {
721
+ res.json({
722
+ success: true,
723
+ data: [],
724
+ message: '未找到项目根目录',
725
+ });
726
+ return;
727
+ }
728
+ const markdownFiles = [];
729
+ const promptDir = path.join(projectRoot, '.sloth', 'prompt');
730
+ // 检查 .sloth/prompt 目录是否存在
731
+ if (!fs.existsSync(promptDir)) {
732
+ res.json({
733
+ success: true,
734
+ data: [],
735
+ message: '.sloth/prompt 目录不存在',
736
+ });
737
+ return;
738
+ }
739
+ // 递归查找 prompt 目录下的 .md 文件
740
+ const findMarkdownFiles = (dir) => {
741
+ try {
742
+ const items = fs.readdirSync(dir, { withFileTypes: true });
743
+ for (const item of items) {
744
+ const fullPath = path.join(dir, item.name);
745
+ const relativePath = path.relative(promptDir, fullPath);
746
+ if (item.isDirectory()) {
747
+ findMarkdownFiles(fullPath);
748
+ }
749
+ else if (item.isFile() && item.name.endsWith('.md')) {
750
+ markdownFiles.push({
751
+ path: path.join('.sloth', 'prompt', relativePath),
752
+ name: item.name,
753
+ });
754
+ }
755
+ }
756
+ }
757
+ catch (err) {
758
+ Logger.warn(`无法访问目录: ${dir}`, err);
759
+ }
760
+ };
761
+ findMarkdownFiles(promptDir);
762
+ res.json({
763
+ success: true,
764
+ data: markdownFiles,
765
+ message: `找到 ${markdownFiles.length} 个文档`,
766
+ });
767
+ }
768
+ catch (error) {
769
+ Logger.error('获取文档列表失败:', error);
770
+ res.status(500).json({
771
+ success: false,
772
+ message: '获取文档列表失败',
773
+ error: error instanceof Error ? error.message : String(error),
774
+ });
775
+ }
776
+ });
623
777
  // 认证页面
624
778
  app.get('/auth-page', (req, res) => {
625
779
  try {
@@ -668,6 +822,7 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
668
822
  try {
669
823
  // 安全地解构请求体,处理可能为空的情况
670
824
  const { token, value, fileKey, nodeId } = req.body || {};
825
+ Logger.log('submit req.body', token, value, fileKey, nodeId);
671
826
  if (!token || !value) {
672
827
  res.status(400).send('请求体中缺少 token 或 value');
673
828
  return;
@@ -698,6 +853,9 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
698
853
  Logger.log(`已保存 groupsData 到 fileKey "${fileKey}", nodeId "${nodeId}":`, value.groupsData.length, '个分组');
699
854
  }
700
855
  if (fileKey && value.promptSetting) {
856
+ if (!value.promptSetting.enableFrameworkGuide) {
857
+ value.promptSetting.frameworkGuidePrompt = '';
858
+ }
701
859
  await req.fileManager.savePromptSetting(fileKey, nodeId, value.promptSetting);
702
860
  Logger.log(`已保存 promptSetting 到 fileKey "${fileKey}", nodeId "${nodeId}"`);
703
861
  }
@@ -775,6 +933,25 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
775
933
  message: '日志重连已启动',
776
934
  });
777
935
  });
936
+ // 插件渲染器端点 - 返回JS代码字符串
937
+ app.get('/pluginRenderer', async (req, res) => {
938
+ console.log('pluginRenderer');
939
+ const pluginName = req.query.pluginName;
940
+ let pluginRenderer = null;
941
+ try {
942
+ // @ts-ignore
943
+ pluginRenderer = await loadPluginFromGlobalDirAsync(pluginName);
944
+ }
945
+ catch (error) {
946
+ console.error('加载插件渲染器失败:', error);
947
+ res.type('application/javascript; charset=utf-8').send(`alert(${pluginName}加载失败)`);
948
+ return;
949
+ }
950
+ const renderer = pluginRenderer.default.renderConfigForm;
951
+ console.log('pluginRenderer.default', pluginRenderer.default);
952
+ console.log('renderer', renderer);
953
+ res.type('application/javascript; charset=utf-8').send(renderer);
954
+ });
778
955
  // ==================== 组件映射相关接口 ====================
779
956
  /**
780
957
  * 获取项目根目录
@@ -1470,8 +1647,8 @@ export async function startHttpServer(port = PORT, mcpServer, configManagerInsta
1470
1647
  }
1471
1648
  Logger.log(`分析设计稿变更: old=${oldFileKey}/${oldNodeId}, new=${newFileKey}/${newNodeId}`);
1472
1649
  // 1. 加载新旧 HTML 和 imageMap
1473
- let oldHtml = await fileManager.loadAbsoluteHtml(oldFileKey, oldNodeId);
1474
- let newHtml = await fileManager.loadAbsoluteHtml(newFileKey, newNodeId);
1650
+ let oldHtml = await fileManager.loadAbsoluteHtml(oldFileKey, oldNodeId, true);
1651
+ let newHtml = await fileManager.loadAbsoluteHtml(newFileKey, newNodeId, true);
1475
1652
  Logger.log(`[analyzeChange] 加载 HTML 完成: oldHtml=${oldHtml?.length || 0}字符, newHtml=${newHtml?.length || 0}字符`);
1476
1653
  // 加载 imageMap 用于替换图片路径(flatted 格式)
1477
1654
  let oldImageMap = {};
@@ -1697,9 +1874,9 @@ ${truncatedDiff}
1697
1874
  // 启动 HTTP 服务器,监听端口
1698
1875
  httpServer = app.listen(port, async (err) => {
1699
1876
  if (err) {
1700
- Logger.error('HTTP 服务器启动失败:', err);
1701
1877
  httpServer = null;
1702
- return;
1878
+ Logger.error('HTTP 服务器启动失败:', err, '退出进程');
1879
+ process.exit(0);
1703
1880
  }
1704
1881
  Logger.log(`HTTP server listening on port ${port}`);
1705
1882
  Logger.log(`SSE endpoint available at http://localhost:${port}/sse`);
@@ -1719,7 +1896,7 @@ ${truncatedDiff}
1719
1896
  }
1720
1897
  catch (error) {
1721
1898
  Logger.error('Socket 服务器启动失败:', error);
1722
- Logger.error('进入子进程模式');
1899
+ process.exit(0);
1723
1900
  }
1724
1901
  });
1725
1902
  // 监听 SIGINT 信号,优雅关闭服务器和所有会话
@@ -1729,7 +1906,7 @@ ${truncatedDiff}
1729
1906
  // 清理等待中的认证请求
1730
1907
  pendingRequests.clear();
1731
1908
  // 关闭 Socket 服务器
1732
- await stopSocketServer();
1909
+ await stopHttpServer();
1733
1910
  // 关闭所有活跃的 SSE 和 streamable 传输,释放资源
1734
1911
  await closeTransports(transports.sse);
1735
1912
  await closeTransports(transports.streamable);
@@ -1785,7 +1962,7 @@ export async function getUserInput(payload) {
1785
1962
  Logger.log('Socket 客户端已连接');
1786
1963
  const workspaceRoot = fileManager.getWorkspaceRoot();
1787
1964
  // 注册 token 并等待响应,同时传递 extra 数据给主进程
1788
- const responsePromise = socketClient.registerToken(token, { workspaceRoot });
1965
+ const responsePromise = socketClient.registerToken(token, { workspaceRoot, plugins: pluginManager.getPlugins() });
1789
1966
  // 打开浏览器
1790
1967
  await open(authUrl);
1791
1968
  // 等待认证响应
@@ -1819,14 +1996,14 @@ export async function stopSocketServer() {
1819
1996
  }
1820
1997
  // 停止 HTTP 服务器,并关闭所有 SSE 传输
1821
1998
  export async function stopHttpServer() {
1999
+ // 关闭 Socket 服务器
2000
+ const closeSocket = stopSocketServer();
1822
2001
  if (!httpServer) {
1823
2002
  throw new Error('HTTP 服务器未运行');
1824
2003
  }
1825
2004
  return new Promise((resolve, reject) => {
1826
2005
  // 清理等待中的认证请求
1827
2006
  pendingRequests.clear();
1828
- // 关闭 Socket 服务器
1829
- const closeSocket = stopSocketServer();
1830
2007
  httpServer.close((err) => {
1831
2008
  if (err) {
1832
2009
  reject(err);
@@ -124,7 +124,7 @@ export class SocketClient {
124
124
  const timeout = setTimeout(() => {
125
125
  this.messageHandlers.delete(token);
126
126
  reject(new Error('等待认证响应超时'));
127
- }, 5 * 60 * 1000); // 5分钟超时
127
+ }, 30 * 60 * 1000); // 30分钟超时
128
128
  // 注册消息处理器
129
129
  this.messageHandlers.set(token, (data) => {
130
130
  clearTimeout(timeout);