mofox-plugin-dev-toolkit 0.3.5__tar.gz → 0.4.1__tar.gz

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 (65) hide show
  1. {mofox_plugin_dev_toolkit-0.3.5/mofox_plugin_dev_toolkit.egg-info → mofox_plugin_dev_toolkit-0.4.1}/PKG-INFO +1 -1
  2. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1/mofox_plugin_dev_toolkit.egg-info}/PKG-INFO +1 -1
  3. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mofox_plugin_dev_toolkit.egg-info/SOURCES.txt +3 -0
  4. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/__init__.py +1 -1
  5. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/cli.py +1 -1
  6. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/commands/generate.py +278 -63
  7. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/commands/init.py +310 -132
  8. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/templates/__init__.py +18 -21
  9. mofox_plugin_dev_toolkit-0.4.1/mpdt/templates/action_template.py +64 -0
  10. mofox_plugin_dev_toolkit-0.4.1/mpdt/templates/adapter_template.py +127 -0
  11. mofox_plugin_dev_toolkit-0.4.1/mpdt/templates/chatter_template.py +115 -0
  12. mofox_plugin_dev_toolkit-0.4.1/mpdt/templates/collection_template.py +104 -0
  13. mofox_plugin_dev_toolkit-0.4.1/mpdt/templates/config_template.py +57 -0
  14. mofox_plugin_dev_toolkit-0.4.1/mpdt/templates/event_template.py +101 -0
  15. mofox_plugin_dev_toolkit-0.4.1/mpdt/templates/plus_command_template.py +92 -0
  16. mofox_plugin_dev_toolkit-0.4.1/mpdt/templates/router_template.py +114 -0
  17. mofox_plugin_dev_toolkit-0.4.1/mpdt/templates/service_template.py +105 -0
  18. mofox_plugin_dev_toolkit-0.4.1/mpdt/templates/tool_template.py +90 -0
  19. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/utils/code_parser.py +94 -0
  20. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/validators/auto_fix_validator.py +266 -150
  21. mofox_plugin_dev_toolkit-0.4.1/mpdt/validators/component_validator.py +1026 -0
  22. mofox_plugin_dev_toolkit-0.4.1/mpdt/validators/config_validator.py +320 -0
  23. mofox_plugin_dev_toolkit-0.4.1/mpdt/validators/metadata_validator.py +169 -0
  24. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/validators/structure_validator.py +1 -1
  25. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/pyproject.toml +1 -1
  26. mofox_plugin_dev_toolkit-0.3.5/mpdt/templates/action_template.py +0 -102
  27. mofox_plugin_dev_toolkit-0.3.5/mpdt/templates/adapter_template.py +0 -129
  28. mofox_plugin_dev_toolkit-0.3.5/mpdt/templates/chatter_template.py +0 -103
  29. mofox_plugin_dev_toolkit-0.3.5/mpdt/templates/event_template.py +0 -116
  30. mofox_plugin_dev_toolkit-0.3.5/mpdt/templates/plus_command_template.py +0 -150
  31. mofox_plugin_dev_toolkit-0.3.5/mpdt/templates/router_template.py +0 -175
  32. mofox_plugin_dev_toolkit-0.3.5/mpdt/templates/tool_template.py +0 -98
  33. mofox_plugin_dev_toolkit-0.3.5/mpdt/validators/component_validator.py +0 -842
  34. mofox_plugin_dev_toolkit-0.3.5/mpdt/validators/config_validator.py +0 -119
  35. mofox_plugin_dev_toolkit-0.3.5/mpdt/validators/metadata_validator.py +0 -107
  36. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/LICENSE +0 -0
  37. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/MANIFEST.in +0 -0
  38. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/README.md +0 -0
  39. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mofox_plugin_dev_toolkit.egg-info/dependency_links.txt +0 -0
  40. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mofox_plugin_dev_toolkit.egg-info/entry_points.txt +0 -0
  41. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mofox_plugin_dev_toolkit.egg-info/requires.txt +0 -0
  42. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mofox_plugin_dev_toolkit.egg-info/top_level.txt +0 -0
  43. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/__main__.py +0 -0
  44. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/commands/__init__.py +0 -0
  45. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/commands/check.py +0 -0
  46. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/commands/dev.py +0 -0
  47. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/dev/bridge_plugin/__init__.py +0 -0
  48. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/dev/bridge_plugin/cleanup_handler.py +0 -0
  49. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/dev/bridge_plugin/dev_config.py +0 -0
  50. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/dev/bridge_plugin/file_watcher.py +0 -0
  51. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/dev/bridge_plugin/plugin.py +0 -0
  52. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/templates/prompt_template.py +0 -0
  53. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/utils/__init__.py +0 -0
  54. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/utils/color_printer.py +0 -0
  55. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/utils/config_loader.py +0 -0
  56. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/utils/config_manager.py +0 -0
  57. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/utils/file_ops.py +0 -0
  58. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/utils/license_generator.py +0 -0
  59. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/utils/plugin_parser.py +0 -0
  60. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/utils/template_engine.py +0 -0
  61. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/validators/__init__.py +0 -0
  62. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/validators/base.py +0 -0
  63. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/validators/style_validator.py +0 -0
  64. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/validators/type_validator.py +0 -0
  65. {mofox_plugin_dev_toolkit-0.3.5 → mofox_plugin_dev_toolkit-0.4.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mofox-plugin-dev-toolkit
3
- Version: 0.3.5
3
+ Version: 0.4.1
4
4
  Summary: 开发工具集,用于快速创建、开发和测试 MoFox-Bot 插件
5
5
  Author-email: MoFox-Studio <wwwww95915@qq.com>
6
6
  License: GPL-3.0-or-later
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mofox-plugin-dev-toolkit
3
- Version: 0.3.5
3
+ Version: 0.4.1
4
4
  Summary: 开发工具集,用于快速创建、开发和测试 MoFox-Bot 插件
5
5
  Author-email: MoFox-Studio <wwwww95915@qq.com>
6
6
  License: GPL-3.0-or-later
@@ -25,10 +25,13 @@ mpdt/templates/__init__.py
25
25
  mpdt/templates/action_template.py
26
26
  mpdt/templates/adapter_template.py
27
27
  mpdt/templates/chatter_template.py
28
+ mpdt/templates/collection_template.py
29
+ mpdt/templates/config_template.py
28
30
  mpdt/templates/event_template.py
29
31
  mpdt/templates/plus_command_template.py
30
32
  mpdt/templates/prompt_template.py
31
33
  mpdt/templates/router_template.py
34
+ mpdt/templates/service_template.py
32
35
  mpdt/templates/tool_template.py
33
36
  mpdt/utils/__init__.py
34
37
  mpdt/utils/code_parser.py
@@ -4,7 +4,7 @@ MoFox Plugin Dev Toolkit
4
4
  一个用于 MoFox-Bot 插件开发的工具集
5
5
  """
6
6
 
7
- __version__ = "0.3.5"
7
+ __version__ = "0.4.1"
8
8
  __author__ = "MoFox-Studio"
9
9
  __license__ = "GPL-3.0-or-later"
10
10
 
@@ -67,7 +67,7 @@ def init(ctx: click.Context, plugin_name: str | None, template: str, author: str
67
67
 
68
68
 
69
69
  @cli.command()
70
- @click.argument("component_type", type=click.Choice(["action", "tool", "event", "adapter", "prompt", "plus-command","router","chatter"]), required=False)
70
+ @click.argument("component_type", type=click.Choice(["action", "tool", "event", "adapter", "plus-command", "router", "chatter", "service", "config"]), required=False)
71
71
  @click.argument("component_name", required=False)
72
72
  @click.option("--description", "-d", help="组件描述")
73
73
  @click.option("--output", "-o", type=click.Path(), help="输出目录")
@@ -9,7 +9,6 @@ import libcst as cst
9
9
  import questionary
10
10
 
11
11
  from mpdt.templates import prepare_component_context
12
- from mpdt.utils.code_parser import CodeParser
13
12
  from mpdt.utils.color_printer import (
14
13
  console,
15
14
  print_error,
@@ -24,7 +23,43 @@ from mpdt.utils.file_ops import (
24
23
  to_snake_case,
25
24
  validate_component_name,
26
25
  )
27
- from mpdt.utils.plugin_parser import extract_plugin_name
26
+
27
+ # =============================================================================
28
+ # 常量定义
29
+ # =============================================================================
30
+
31
+ # 组件类型到目录名的映射(统一管理)
32
+ COMPONENT_DIR_MAP = {
33
+ "action": "actions",
34
+ "tool": "tools",
35
+ "plus_command": "plus_command",
36
+ "event": "events",
37
+ "adapter": "adapters",
38
+ "chatter": "chatters",
39
+ "router": "routers",
40
+ "service": "services",
41
+ "config": "configs",
42
+ "collection": "collections",
43
+ }
44
+
45
+ # 组件类型到模板 key 的映射
46
+ COMPONENT_TYPE_MAP = {
47
+ "action": "action",
48
+ "tool": "tool",
49
+ "event": "event",
50
+ "adapter": "adapter",
51
+ "plus_command": "plus_command",
52
+ "chatter": "chatter",
53
+ "router": "router",
54
+ "service": "service",
55
+ "config": "config",
56
+ "collection": "collection",
57
+ }
58
+
59
+
60
+ # =============================================================================
61
+ # 主入口函数
62
+ # =============================================================================
28
63
 
29
64
 
30
65
  def generate_component(
@@ -135,6 +170,11 @@ def generate_component(
135
170
  console.print(" 3. 运行 mpdt test 测试功能")
136
171
 
137
172
 
173
+ # =============================================================================
174
+ # 交互式界面
175
+ # =============================================================================
176
+
177
+
138
178
  def _interactive_generate() -> dict[str, Any]:
139
179
  """交互式生成组件"""
140
180
  console.print("\n[bold cyan]🔧 组件生成向导[/bold cyan]\n")
@@ -145,12 +185,14 @@ def _interactive_generate() -> dict[str, Any]:
145
185
  choices=[
146
186
  questionary.Choice("Action 组件", value="action"),
147
187
  questionary.Choice("Tool 组件", value="tool"),
188
+ questionary.Choice("Collection 集合", value="collection"),
148
189
  questionary.Choice("Event 事件", value="event"),
149
190
  questionary.Choice("Adapter 适配器", value="adapter"),
150
- questionary.Choice("Prompt 提示词", value="prompt"),
151
191
  questionary.Choice("Plus Command 命令", value="plus-command"),
152
192
  questionary.Choice("Chatter 聊天组件", value="chatter"),
153
193
  questionary.Choice("Router 路由组件", value="router"),
194
+ questionary.Choice("Service 服务", value="service"),
195
+ questionary.Choice("Config 配置", value="config"),
154
196
  ],
155
197
  ),
156
198
  component_name=questionary.text(
@@ -177,6 +219,11 @@ def _interactive_generate() -> dict[str, Any]:
177
219
  return answers
178
220
 
179
221
 
222
+ # =============================================================================
223
+ # 插件检测
224
+ # =============================================================================
225
+
226
+
180
227
  def _detect_plugin_name(work_dir: Path) -> str | None:
181
228
  """
182
229
  检测插件名称
@@ -200,6 +247,11 @@ def _detect_plugin_name(work_dir: Path) -> str | None:
200
247
  return work_dir.name
201
248
 
202
249
 
250
+ # =============================================================================
251
+ # 组件文件生成
252
+ # =============================================================================
253
+
254
+
203
255
  def _generate_component_file(
204
256
  work_dir: Path,
205
257
  component_type: str,
@@ -226,13 +278,14 @@ def _generate_component_file(
226
278
  """
227
279
  # 确定组件目录
228
280
  if use_components_folder:
229
- component_dir = work_dir / "components" / f"{component_type}s"
281
+ dir_name = COMPONENT_DIR_MAP.get(component_type, f"{component_type}s")
282
+ component_dir = work_dir / "components" / dir_name
230
283
  ensure_dir(component_dir)
231
284
 
232
285
  # 确保 __init__.py 存在
233
286
  init_file = component_dir / "__init__.py"
234
287
  if not init_file.exists():
235
- safe_write_file(init_file, f'"""\n{component_type.title()}s 组件\n"""\n')
288
+ safe_write_file(init_file, f'"""\n{dir_name.title()} 组件\n"""\n')
236
289
  else:
237
290
  # 在插件根目录生成
238
291
  component_dir = work_dir
@@ -240,24 +293,14 @@ def _generate_component_file(
240
293
  # 生成组件文件
241
294
  component_file = component_dir / f"{component_name}.py"
242
295
 
243
-
244
- # 组件类型到模板 key 的映射(此时 component_type 已经是标准化的下划线格式)
245
- type_map = {
246
- "action": "action",
247
- "tool": "tool",
248
- "event": "event",
249
- "adapter": "adapter",
250
- "prompt": "prompt",
251
- "plus_command": "plus_command",
252
- "chatter":"chatter",
253
- "router":"router"
254
- }
255
- template_key = type_map.get(component_type)
296
+ # 获取模板 key
297
+ template_key = COMPONENT_TYPE_MAP.get(component_type)
256
298
  if not template_key:
257
299
  print_error(f"不支持的组件类型: {component_type}")
258
300
  return None
259
301
 
260
302
  from mpdt.templates import get_component_template
303
+
261
304
  template = get_component_template(template_key)
262
305
  content = template.format(**context)
263
306
 
@@ -275,7 +318,70 @@ def _generate_component_file(
275
318
  return None
276
319
 
277
320
 
278
- def _update_plugin_registration(
321
+ # =============================================================================
322
+ # 插件注册更新
323
+ # =============================================================================
324
+
325
+
326
+ def _update_manifest_json(
327
+ work_dir: Path,
328
+ component_type: str,
329
+ component_name: str,
330
+ verbose: bool,
331
+ ) -> bool:
332
+ """
333
+ 更新 manifest.json 文件,添加新组件
334
+
335
+ Args:
336
+ work_dir: 工作目录
337
+ component_type: 组件类型
338
+ component_name: 组件名称
339
+ verbose: 详细输出
340
+
341
+ Returns:
342
+ 是否更新成功
343
+ """
344
+ import json
345
+
346
+ manifest_file = work_dir / "manifest.json"
347
+ if not manifest_file.exists():
348
+ if verbose:
349
+ console.print("[dim yellow]⚠ 未找到 manifest.json 文件[/dim yellow]")
350
+ return False
351
+
352
+ try:
353
+ # 读取现有 manifest
354
+ with open(manifest_file, encoding="utf-8") as f:
355
+ manifest = json.load(f)
356
+
357
+ # 检查组件是否已存在
358
+ include_list = manifest.get("include", [])
359
+ for item in include_list:
360
+ if item.get("component_name") == component_name and item.get("component_type") == component_type:
361
+ if verbose:
362
+ console.print(f"[dim]组件 {component_name} 已在 manifest.json 中[/dim]")
363
+ return True
364
+
365
+ # 添加新组件
366
+ new_component = {"component_type": component_type, "component_name": component_name, "dependencies": []}
367
+ include_list.append(new_component)
368
+ manifest["include"] = include_list
369
+
370
+ # 写回文件
371
+ with open(manifest_file, "w", encoding="utf-8") as f:
372
+ json.dump(manifest, f, ensure_ascii=False, indent=4)
373
+
374
+ if verbose:
375
+ console.print("[dim]✓ 已更新 manifest.json[/dim]")
376
+ return True
377
+
378
+ except Exception as e:
379
+ if verbose:
380
+ console.print(f"[dim red]更新 manifest.json 失败: {e}[/dim red]")
381
+ return False
382
+
383
+
384
+ def _update_plugin_py_components(
279
385
  work_dir: Path,
280
386
  component_type: str,
281
387
  component_name: str,
@@ -284,7 +390,7 @@ def _update_plugin_registration(
284
390
  use_components_folder: bool = True,
285
391
  ) -> bool:
286
392
  """
287
- 更新插件注册代码 (使用 CodeParser)
393
+ 更新 plugin.py 中的 get_components() 方法,添加组件导入和类引用
288
394
 
289
395
  Args:
290
396
  work_dir: 工作目录
@@ -302,6 +408,8 @@ def _update_plugin_registration(
302
408
  return False
303
409
 
304
410
  try:
411
+ from mpdt.utils.plugin_parser import extract_plugin_name
412
+
305
413
  # 使用 plugin_parser 验证插件名称
306
414
  parsed_plugin_name = extract_plugin_name(work_dir)
307
415
  if not parsed_plugin_name:
@@ -309,10 +417,12 @@ def _update_plugin_registration(
309
417
  parsed_plugin_name = work_dir.name
310
418
 
311
419
  # 使用 CodeParser 读取和解析源代码
420
+ from mpdt.utils.code_parser import CodeParser
421
+
312
422
  parser = CodeParser.from_file(plugin_file)
313
423
 
314
424
  # 创建转换器
315
- transformer = PluginRegistrationTransformer(
425
+ transformer = ComponentImportTransformer(
316
426
  plugin_name=parsed_plugin_name,
317
427
  component_type=component_type,
318
428
  component_name=component_name,
@@ -326,14 +436,67 @@ def _update_plugin_registration(
326
436
  # 写回文件
327
437
  plugin_file.write_text(modified_tree.code, encoding="utf-8")
328
438
 
329
- return transformer.import_added or transformer.registration_added
439
+ if verbose:
440
+ console.print("[dim]✓ 已更新 plugin.py[/dim]")
441
+
442
+ return transformer.import_added or transformer.component_added
330
443
 
331
- except Exception:
444
+ except Exception as e:
445
+ if verbose:
446
+ console.print(f"[dim red]更新 plugin.py 失败: {e}[/dim red]")
332
447
  return False
333
448
 
334
449
 
335
- class PluginRegistrationTransformer(cst.CSTTransformer):
336
- """用于添加组件导入和注册的 CST 转换器"""
450
+ def _update_plugin_registration(
451
+ work_dir: Path,
452
+ component_type: str,
453
+ component_name: str,
454
+ context: dict,
455
+ verbose: bool,
456
+ use_components_folder: bool = True,
457
+ ) -> bool:
458
+ """
459
+ 更新插件注册代码(Neo-MoFox 架构)
460
+
461
+ 更新两个文件:
462
+ 1. manifest.json - 添加组件声明
463
+ 2. plugin.py - 添加组件导入和 get_components() 返回列表
464
+
465
+ Args:
466
+ work_dir: 工作目录
467
+ component_type: 组件类型
468
+ component_name: 组件名称
469
+ context: 模板上下文
470
+ verbose: 详细输出
471
+ use_components_folder: 是否使用 components 文件夹
472
+
473
+ Returns:
474
+ 是否更新成功
475
+ """
476
+ # 更新 manifest.json
477
+ manifest_updated = _update_manifest_json(work_dir, component_type, component_name, verbose)
478
+
479
+ # 更新 plugin.py
480
+ plugin_updated = _update_plugin_py_components(
481
+ work_dir, component_type, component_name, context, verbose, use_components_folder
482
+ )
483
+
484
+ return manifest_updated or plugin_updated
485
+
486
+
487
+ # =============================================================================
488
+ # CST 代码转换器
489
+ # =============================================================================
490
+
491
+
492
+ class ComponentImportTransformer(cst.CSTTransformer):
493
+ """用于添加组件导入和更新插件类的 CST 转换器(Neo-MoFox 架构)
494
+
495
+ 功能:
496
+ 1. 添加组件导入语句
497
+ 2. 对于 config 组件:更新 configs 类属性
498
+ 3. 对于其他组件:更新 get_components() 方法返回列表
499
+ """
337
500
 
338
501
  def __init__(
339
502
  self,
@@ -349,7 +512,8 @@ class PluginRegistrationTransformer(cst.CSTTransformer):
349
512
  self.class_name = class_name
350
513
  self.use_components_folder = use_components_folder
351
514
  self.import_added = False
352
- self.registration_added = False
515
+ self.component_added = False
516
+ self.is_config = component_type == "config"
353
517
 
354
518
  def leave_Module( # noqa: N802
355
519
  self, original_node: cst.Module, updated_node: cst.Module
@@ -360,13 +524,12 @@ class PluginRegistrationTransformer(cst.CSTTransformer):
360
524
 
361
525
  # 根据存放位置构建导入语句
362
526
  if self.use_components_folder:
363
- import_path = f"{self.plugin_name}.components.{self.component_type}s.{self.component_name}"
527
+ dir_name = COMPONENT_DIR_MAP.get(self.component_type, f"{self.component_type}s")
528
+ import_path = f"{self.plugin_name}.components.{dir_name}.{self.component_name}"
364
529
  else:
365
530
  import_path = f"{self.plugin_name}.{self.component_name}"
366
531
 
367
- import_statement = cst.parse_statement(
368
- f"from {import_path} import {self.class_name}"
369
- )
532
+ import_statement = cst.parse_statement(f"from {import_path} import {self.class_name}")
370
533
 
371
534
  # 检查是否已存在相同的导入
372
535
  for stmt in updated_node.body:
@@ -395,52 +558,104 @@ class PluginRegistrationTransformer(cst.CSTTransformer):
395
558
 
396
559
  return updated_node
397
560
 
561
+ def leave_ClassDef( # noqa: N802
562
+ self, original_node: cst.ClassDef, updated_node: cst.ClassDef
563
+ ) -> cst.ClassDef:
564
+ """更新插件类的 config 类属性(仅用于 config 组件)"""
565
+ # 只有 config 组件才需要更新 config 类属性
566
+ if not self.is_config:
567
+ return updated_node
568
+
569
+ if self.component_added:
570
+ return updated_node
571
+
572
+ # 检查是否已存在 config 属性
573
+ new_body = []
574
+ config_found = False
575
+
576
+ for stmt in updated_node.body.body:
577
+ # 查找 config 类属性定义
578
+ if isinstance(stmt, cst.SimpleStatementLine):
579
+ for assign in stmt.body:
580
+ if isinstance(assign, cst.AnnAssign) and isinstance(assign.target, cst.Name):
581
+ if assign.target.value == "config":
582
+ config_found = True
583
+ # 检查是否已包含当前配置类
584
+ if assign.value and isinstance(assign.value, cst.List):
585
+ existing_elements = list(assign.value.elements)
586
+ # 检查是否已存在
587
+ has_class = any(
588
+ isinstance(elem.value, cst.Name) and elem.value.value == self.class_name
589
+ for elem in existing_elements
590
+ )
591
+ if not has_class:
592
+ # 添加新配置类
593
+ new_element = cst.Element(value=cst.Name(self.class_name))
594
+ existing_elements.append(new_element)
595
+ new_list = assign.value.with_changes(elements=existing_elements)
596
+ new_assign = assign.with_changes(value=new_list)
597
+ new_stmt_body = [new_assign if s is assign else s for s in stmt.body]
598
+ stmt = stmt.with_changes(body=new_stmt_body)
599
+ self.component_added = True
600
+ else:
601
+ # 已存在,标记为已添加
602
+ self.component_added = True
603
+ new_body.append(stmt)
604
+
605
+ # 如果找到 config 属性(无论是否更新)
606
+ if config_found:
607
+ if self.component_added:
608
+ return updated_node.with_changes(body=updated_node.body.with_changes(body=new_body))
609
+ else:
610
+ # 找到了 config 但没有更新,说明已存在
611
+ self.component_added = True
612
+
613
+ return updated_node
614
+
398
615
  def leave_FunctionDef( # noqa: N802
399
616
  self, original_node: cst.FunctionDef, updated_node: cst.FunctionDef
400
617
  ) -> cst.FunctionDef:
401
- """在 get_plugin_components 函数中添加注册代码"""
402
- if updated_node.name.value != "get_plugin_components":
618
+ """在 get_components 函数中添加组件类引用(不包括 config 组件)"""
619
+ # config 组件在 configs 类属性中处理,不需要在 get_components 中添加
620
+ if self.is_config:
403
621
  return updated_node
404
-
405
- if self.registration_added:
622
+ if updated_node.name.value != "get_components":
406
623
  return updated_node
407
624
 
408
- # 根据组件类型生成对应的 get_xxx_info() 方法调用
409
- info_method_map = {
410
- "action": "get_action_info",
411
- "tool": "get_tool_info",
412
- "event": "get_event_handler_info",
413
- "adapter": "get_adapter_info",
414
- "prompt": "get_prompt_info",
415
- "plus_command": "get_command_info",
416
- "chatter": "get_chatter_info",
417
- "router": "get_router_info",
418
- }
419
- info_method = info_method_map.get(self.component_type, "get_component_info")
420
-
421
- # 构建注册代码(带注释的语句)
422
- registration_stmt = f"components.append(({self.class_name}.{info_method}(), {self.class_name})) # 注册 {self.class_name}"
423
-
424
- # 检查是否已存在注册代码
425
- function_code = cst.Module([]).code_for_node(updated_node)
426
- if self.class_name in function_code and info_method in function_code:
427
- self.registration_added = True
625
+ if self.component_added:
428
626
  return updated_node
429
627
 
430
- # 找到 return 语句并在其前面插入注册代码
628
+ # 找到 return 语句并修改其返回列表
431
629
  new_body = []
432
630
  for stmt in updated_node.body.body:
433
- # 如果是 return 语句,在前面插入注册代码
434
631
  if isinstance(stmt, cst.SimpleStatementLine):
435
- for s in stmt.body:
436
- if isinstance(s, cst.Return):
437
- # 插入注册代码
438
- new_body.append(cst.parse_statement(registration_stmt))
439
- self.registration_added = True
440
-
632
+ for i, s in enumerate(stmt.body):
633
+ if isinstance(s, cst.Return) and s.value:
634
+ # 尝试解析返回值
635
+ if isinstance(s.value, cst.List):
636
+ # 检查是否已存在该组件
637
+ existing_elements = list(s.value.elements)
638
+ has_component = any(
639
+ isinstance(elem.value, cst.Name) and elem.value.value == self.class_name
640
+ for elem in existing_elements
641
+ )
642
+
643
+ if has_component:
644
+ self.component_added = True
645
+ return updated_node
646
+
647
+ # 如果是列表,添加新组件
648
+ new_element = cst.Element(value=cst.Name(self.class_name))
649
+ existing_elements.append(new_element)
650
+ new_list = s.value.with_changes(elements=existing_elements)
651
+ new_return = s.with_changes(value=new_list)
652
+ new_stmt_body = list(stmt.body)
653
+ new_stmt_body[i] = new_return
654
+ stmt = stmt.with_changes(body=new_stmt_body)
655
+ self.component_added = True
441
656
  new_body.append(stmt)
442
657
 
443
- if self.registration_added:
658
+ if self.component_added:
444
659
  new_function_body = updated_node.body.with_changes(body=new_body)
445
660
  return updated_node.with_changes(body=new_function_body)
446
661