mofox-plugin-dev-toolkit 0.3.3__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 (66) hide show
  1. {mofox_plugin_dev_toolkit-0.3.3/mofox_plugin_dev_toolkit.egg-info → mofox_plugin_dev_toolkit-0.4.1}/PKG-INFO +1 -1
  2. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1/mofox_plugin_dev_toolkit.egg-info}/PKG-INFO +1 -1
  3. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mofox_plugin_dev_toolkit.egg-info/SOURCES.txt +3 -0
  4. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/__init__.py +1 -1
  5. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/cli.py +1 -1
  6. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/commands/generate.py +278 -64
  7. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/commands/init.py +310 -133
  8. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/templates/__init__.py +20 -24
  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.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/utils/code_parser.py +94 -0
  20. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/utils/config_loader.py +11 -11
  21. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/utils/config_manager.py +9 -16
  22. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/utils/file_ops.py +25 -22
  23. mofox_plugin_dev_toolkit-0.4.1/mpdt/utils/plugin_parser.py +137 -0
  24. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/validators/auto_fix_validator.py +266 -150
  25. mofox_plugin_dev_toolkit-0.4.1/mpdt/validators/component_validator.py +1026 -0
  26. mofox_plugin_dev_toolkit-0.4.1/mpdt/validators/config_validator.py +320 -0
  27. mofox_plugin_dev_toolkit-0.4.1/mpdt/validators/metadata_validator.py +169 -0
  28. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/validators/structure_validator.py +1 -1
  29. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/pyproject.toml +1 -1
  30. mofox_plugin_dev_toolkit-0.3.3/mpdt/templates/action_template.py +0 -102
  31. mofox_plugin_dev_toolkit-0.3.3/mpdt/templates/adapter_template.py +0 -129
  32. mofox_plugin_dev_toolkit-0.3.3/mpdt/templates/chatter_template.py +0 -103
  33. mofox_plugin_dev_toolkit-0.3.3/mpdt/templates/event_template.py +0 -116
  34. mofox_plugin_dev_toolkit-0.3.3/mpdt/templates/plus_command_template.py +0 -150
  35. mofox_plugin_dev_toolkit-0.3.3/mpdt/templates/router_template.py +0 -175
  36. mofox_plugin_dev_toolkit-0.3.3/mpdt/templates/tool_template.py +0 -98
  37. mofox_plugin_dev_toolkit-0.3.3/mpdt/utils/plugin_parser.py +0 -195
  38. mofox_plugin_dev_toolkit-0.3.3/mpdt/validators/component_validator.py +0 -842
  39. mofox_plugin_dev_toolkit-0.3.3/mpdt/validators/config_validator.py +0 -119
  40. mofox_plugin_dev_toolkit-0.3.3/mpdt/validators/metadata_validator.py +0 -107
  41. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/LICENSE +0 -0
  42. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/MANIFEST.in +0 -0
  43. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/README.md +0 -0
  44. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mofox_plugin_dev_toolkit.egg-info/dependency_links.txt +0 -0
  45. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mofox_plugin_dev_toolkit.egg-info/entry_points.txt +0 -0
  46. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mofox_plugin_dev_toolkit.egg-info/requires.txt +0 -0
  47. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mofox_plugin_dev_toolkit.egg-info/top_level.txt +0 -0
  48. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/__main__.py +0 -0
  49. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/commands/__init__.py +0 -0
  50. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/commands/check.py +0 -0
  51. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/commands/dev.py +0 -0
  52. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/dev/bridge_plugin/__init__.py +0 -0
  53. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/dev/bridge_plugin/cleanup_handler.py +0 -0
  54. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/dev/bridge_plugin/dev_config.py +0 -0
  55. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/dev/bridge_plugin/file_watcher.py +0 -0
  56. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/dev/bridge_plugin/plugin.py +0 -0
  57. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/templates/prompt_template.py +0 -0
  58. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/utils/__init__.py +0 -0
  59. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/utils/color_printer.py +0 -0
  60. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/utils/license_generator.py +0 -0
  61. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/utils/template_engine.py +0 -0
  62. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/validators/__init__.py +0 -0
  63. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/validators/base.py +0 -0
  64. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/validators/style_validator.py +0 -0
  65. {mofox_plugin_dev_toolkit-0.3.3 → mofox_plugin_dev_toolkit-0.4.1}/mpdt/validators/type_validator.py +0 -0
  66. {mofox_plugin_dev_toolkit-0.3.3 → 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.3
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.3
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.3"
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(
@@ -97,7 +132,6 @@ def generate_component(
97
132
  plugin_name=plugin_name,
98
133
  author=git_info.get("name", ""),
99
134
  description=description or f"{component_name} 组件",
100
- is_async=True, # 始终生成异步方法
101
135
  )
102
136
 
103
137
  # 生成组件文件
@@ -136,6 +170,11 @@ def generate_component(
136
170
  console.print(" 3. 运行 mpdt test 测试功能")
137
171
 
138
172
 
173
+ # =============================================================================
174
+ # 交互式界面
175
+ # =============================================================================
176
+
177
+
139
178
  def _interactive_generate() -> dict[str, Any]:
140
179
  """交互式生成组件"""
141
180
  console.print("\n[bold cyan]🔧 组件生成向导[/bold cyan]\n")
@@ -146,12 +185,14 @@ def _interactive_generate() -> dict[str, Any]:
146
185
  choices=[
147
186
  questionary.Choice("Action 组件", value="action"),
148
187
  questionary.Choice("Tool 组件", value="tool"),
188
+ questionary.Choice("Collection 集合", value="collection"),
149
189
  questionary.Choice("Event 事件", value="event"),
150
190
  questionary.Choice("Adapter 适配器", value="adapter"),
151
- questionary.Choice("Prompt 提示词", value="prompt"),
152
191
  questionary.Choice("Plus Command 命令", value="plus-command"),
153
192
  questionary.Choice("Chatter 聊天组件", value="chatter"),
154
193
  questionary.Choice("Router 路由组件", value="router"),
194
+ questionary.Choice("Service 服务", value="service"),
195
+ questionary.Choice("Config 配置", value="config"),
155
196
  ],
156
197
  ),
157
198
  component_name=questionary.text(
@@ -178,6 +219,11 @@ def _interactive_generate() -> dict[str, Any]:
178
219
  return answers
179
220
 
180
221
 
222
+ # =============================================================================
223
+ # 插件检测
224
+ # =============================================================================
225
+
226
+
181
227
  def _detect_plugin_name(work_dir: Path) -> str | None:
182
228
  """
183
229
  检测插件名称
@@ -201,6 +247,11 @@ def _detect_plugin_name(work_dir: Path) -> str | None:
201
247
  return work_dir.name
202
248
 
203
249
 
250
+ # =============================================================================
251
+ # 组件文件生成
252
+ # =============================================================================
253
+
254
+
204
255
  def _generate_component_file(
205
256
  work_dir: Path,
206
257
  component_type: str,
@@ -227,13 +278,14 @@ def _generate_component_file(
227
278
  """
228
279
  # 确定组件目录
229
280
  if use_components_folder:
230
- 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
231
283
  ensure_dir(component_dir)
232
284
 
233
285
  # 确保 __init__.py 存在
234
286
  init_file = component_dir / "__init__.py"
235
287
  if not init_file.exists():
236
- 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')
237
289
  else:
238
290
  # 在插件根目录生成
239
291
  component_dir = work_dir
@@ -241,24 +293,14 @@ def _generate_component_file(
241
293
  # 生成组件文件
242
294
  component_file = component_dir / f"{component_name}.py"
243
295
 
244
-
245
- # 组件类型到模板 key 的映射(此时 component_type 已经是标准化的下划线格式)
246
- type_map = {
247
- "action": "action",
248
- "tool": "tool",
249
- "event": "event",
250
- "adapter": "adapter",
251
- "prompt": "prompt",
252
- "plus_command": "plus_command",
253
- "chatter":"chatter",
254
- "router":"router"
255
- }
256
- template_key = type_map.get(component_type)
296
+ # 获取模板 key
297
+ template_key = COMPONENT_TYPE_MAP.get(component_type)
257
298
  if not template_key:
258
299
  print_error(f"不支持的组件类型: {component_type}")
259
300
  return None
260
301
 
261
302
  from mpdt.templates import get_component_template
303
+
262
304
  template = get_component_template(template_key)
263
305
  content = template.format(**context)
264
306
 
@@ -276,7 +318,70 @@ def _generate_component_file(
276
318
  return None
277
319
 
278
320
 
279
- 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(
280
385
  work_dir: Path,
281
386
  component_type: str,
282
387
  component_name: str,
@@ -285,7 +390,7 @@ def _update_plugin_registration(
285
390
  use_components_folder: bool = True,
286
391
  ) -> bool:
287
392
  """
288
- 更新插件注册代码 (使用 CodeParser)
393
+ 更新 plugin.py 中的 get_components() 方法,添加组件导入和类引用
289
394
 
290
395
  Args:
291
396
  work_dir: 工作目录
@@ -303,6 +408,8 @@ def _update_plugin_registration(
303
408
  return False
304
409
 
305
410
  try:
411
+ from mpdt.utils.plugin_parser import extract_plugin_name
412
+
306
413
  # 使用 plugin_parser 验证插件名称
307
414
  parsed_plugin_name = extract_plugin_name(work_dir)
308
415
  if not parsed_plugin_name:
@@ -310,10 +417,12 @@ def _update_plugin_registration(
310
417
  parsed_plugin_name = work_dir.name
311
418
 
312
419
  # 使用 CodeParser 读取和解析源代码
420
+ from mpdt.utils.code_parser import CodeParser
421
+
313
422
  parser = CodeParser.from_file(plugin_file)
314
423
 
315
424
  # 创建转换器
316
- transformer = PluginRegistrationTransformer(
425
+ transformer = ComponentImportTransformer(
317
426
  plugin_name=parsed_plugin_name,
318
427
  component_type=component_type,
319
428
  component_name=component_name,
@@ -327,14 +436,67 @@ def _update_plugin_registration(
327
436
  # 写回文件
328
437
  plugin_file.write_text(modified_tree.code, encoding="utf-8")
329
438
 
330
- 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
331
443
 
332
- except Exception:
444
+ except Exception as e:
445
+ if verbose:
446
+ console.print(f"[dim red]更新 plugin.py 失败: {e}[/dim red]")
333
447
  return False
334
448
 
335
449
 
336
- class PluginRegistrationTransformer(cst.CSTTransformer):
337
- """用于添加组件导入和注册的 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
+ """
338
500
 
339
501
  def __init__(
340
502
  self,
@@ -350,7 +512,8 @@ class PluginRegistrationTransformer(cst.CSTTransformer):
350
512
  self.class_name = class_name
351
513
  self.use_components_folder = use_components_folder
352
514
  self.import_added = False
353
- self.registration_added = False
515
+ self.component_added = False
516
+ self.is_config = component_type == "config"
354
517
 
355
518
  def leave_Module( # noqa: N802
356
519
  self, original_node: cst.Module, updated_node: cst.Module
@@ -361,13 +524,12 @@ class PluginRegistrationTransformer(cst.CSTTransformer):
361
524
 
362
525
  # 根据存放位置构建导入语句
363
526
  if self.use_components_folder:
364
- 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}"
365
529
  else:
366
530
  import_path = f"{self.plugin_name}.{self.component_name}"
367
531
 
368
- import_statement = cst.parse_statement(
369
- f"from {import_path} import {self.class_name}"
370
- )
532
+ import_statement = cst.parse_statement(f"from {import_path} import {self.class_name}")
371
533
 
372
534
  # 检查是否已存在相同的导入
373
535
  for stmt in updated_node.body:
@@ -396,52 +558,104 @@ class PluginRegistrationTransformer(cst.CSTTransformer):
396
558
 
397
559
  return updated_node
398
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
+
399
615
  def leave_FunctionDef( # noqa: N802
400
616
  self, original_node: cst.FunctionDef, updated_node: cst.FunctionDef
401
617
  ) -> cst.FunctionDef:
402
- """在 get_plugin_components 函数中添加注册代码"""
403
- if updated_node.name.value != "get_plugin_components":
618
+ """在 get_components 函数中添加组件类引用(不包括 config 组件)"""
619
+ # config 组件在 configs 类属性中处理,不需要在 get_components 中添加
620
+ if self.is_config:
404
621
  return updated_node
405
-
406
- if self.registration_added:
622
+ if updated_node.name.value != "get_components":
407
623
  return updated_node
408
624
 
409
- # 根据组件类型生成对应的 get_xxx_info() 方法调用
410
- info_method_map = {
411
- "action": "get_action_info",
412
- "tool": "get_tool_info",
413
- "event": "get_event_handler_info",
414
- "adapter": "get_adapter_info",
415
- "prompt": "get_prompt_info",
416
- "plus_command": "get_command_info",
417
- "chatter": "get_chatter_info",
418
- "router": "get_router_info",
419
- }
420
- info_method = info_method_map.get(self.component_type, "get_component_info")
421
-
422
- # 构建注册代码(带注释的语句)
423
- registration_stmt = f"components.append(({self.class_name}.{info_method}(), {self.class_name})) # 注册 {self.class_name}"
424
-
425
- # 检查是否已存在注册代码
426
- function_code = cst.Module([]).code_for_node(updated_node)
427
- if self.class_name in function_code and info_method in function_code:
428
- self.registration_added = True
625
+ if self.component_added:
429
626
  return updated_node
430
627
 
431
- # 找到 return 语句并在其前面插入注册代码
628
+ # 找到 return 语句并修改其返回列表
432
629
  new_body = []
433
630
  for stmt in updated_node.body.body:
434
- # 如果是 return 语句,在前面插入注册代码
435
631
  if isinstance(stmt, cst.SimpleStatementLine):
436
- for s in stmt.body:
437
- if isinstance(s, cst.Return):
438
- # 插入注册代码
439
- new_body.append(cst.parse_statement(registration_stmt))
440
- self.registration_added = True
441
-
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
442
656
  new_body.append(stmt)
443
657
 
444
- if self.registration_added:
658
+ if self.component_added:
445
659
  new_function_body = updated_node.body.with_changes(body=new_body)
446
660
  return updated_node.with_changes(body=new_function_body)
447
661