ErisPulse 2.3.3__py3-none-any.whl → 2.3.4.dev0__py3-none-any.whl

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 (76) hide show
  1. ErisPulse/Core/Event/wrapper.py +2 -3
  2. ErisPulse/Core/Event/wrapper.pyi +2 -3
  3. ErisPulse/Core/__init__.py +0 -5
  4. ErisPulse/Core/__init__.pyi +0 -1
  5. ErisPulse/__init__.py +0 -4
  6. ErisPulse/__init__.pyi +0 -1
  7. ErisPulse/sdk_protocol.py +0 -7
  8. ErisPulse/sdk_protocol.pyi +0 -3
  9. ErisPulse/utils/__init__.py +1 -1
  10. ErisPulse/utils/cli/__init__.py +11 -0
  11. ErisPulse/utils/cli/__init__.pyi +13 -0
  12. ErisPulse/utils/cli/__main__.py +225 -0
  13. ErisPulse/utils/cli/__main__.pyi +81 -0
  14. ErisPulse/utils/cli/base.py +52 -0
  15. ErisPulse/utils/cli/base.pyi +50 -0
  16. ErisPulse/utils/cli/commands/__init__.py +6 -0
  17. ErisPulse/utils/cli/commands/__init__.pyi +12 -0
  18. ErisPulse/utils/cli/commands/init.py +400 -0
  19. ErisPulse/utils/cli/commands/init.pyi +82 -0
  20. ErisPulse/utils/cli/commands/install.py +307 -0
  21. ErisPulse/utils/cli/commands/install.pyi +70 -0
  22. ErisPulse/utils/cli/commands/list.py +165 -0
  23. ErisPulse/utils/cli/commands/list.pyi +56 -0
  24. ErisPulse/utils/cli/commands/list_remote.py +128 -0
  25. ErisPulse/utils/cli/commands/list_remote.pyi +47 -0
  26. ErisPulse/utils/cli/commands/run.py +112 -0
  27. ErisPulse/utils/cli/commands/run.pyi +48 -0
  28. ErisPulse/utils/cli/commands/self_update.py +237 -0
  29. ErisPulse/utils/cli/commands/self_update.pyi +59 -0
  30. ErisPulse/utils/cli/commands/uninstall.py +37 -0
  31. ErisPulse/utils/cli/commands/uninstall.pyi +37 -0
  32. ErisPulse/utils/cli/commands/upgrade.py +62 -0
  33. ErisPulse/utils/cli/commands/upgrade.pyi +38 -0
  34. ErisPulse/utils/cli/registry.py +112 -0
  35. ErisPulse/utils/cli/registry.pyi +99 -0
  36. {erispulse-2.3.3.dist-info → erispulse-2.3.4.dev0.dist-info}/METADATA +6 -20
  37. erispulse-2.3.4.dev0.dist-info/RECORD +89 -0
  38. {erispulse-2.3.3.dist-info → erispulse-2.3.4.dev0.dist-info}/licenses/LICENSE +3 -3
  39. ErisPulse/Core/ux.py +0 -635
  40. ErisPulse/Core/ux.pyi +0 -94
  41. ErisPulse/utils/cli.py +0 -1097
  42. ErisPulse/utils/cli.pyi +0 -145
  43. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/Bases/__init__.pyi +0 -14
  44. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/Bases/adapter.pyi +0 -140
  45. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/Bases/module.pyi +0 -52
  46. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/Event/__init__.pyi +0 -26
  47. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/Event/base.pyi +0 -62
  48. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/Event/command.pyi +0 -113
  49. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/Event/exceptions.pyi +0 -43
  50. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/Event/message.pyi +0 -93
  51. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/Event/meta.pyi +0 -92
  52. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/Event/notice.pyi +0 -108
  53. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/Event/request.pyi +0 -76
  54. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/Event/wrapper.pyi +0 -404
  55. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/__init__.pyi +0 -17
  56. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/_self_config.pyi +0 -72
  57. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/adapter.pyi +0 -229
  58. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/config.pyi +0 -70
  59. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/exceptions.pyi +0 -60
  60. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/lifecycle.pyi +0 -92
  61. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/logger.pyi +0 -168
  62. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/module.pyi +0 -178
  63. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/router.pyi +0 -120
  64. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/storage.pyi +0 -273
  65. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/Core/ux.pyi +0 -94
  66. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/__init__.pyi +0 -310
  67. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/__main__.pyi +0 -24
  68. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/sdk_protocol.pyi +0 -100
  69. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/utils/__init__.pyi +0 -16
  70. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/utils/cli.pyi +0 -145
  71. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/utils/console.pyi +0 -20
  72. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/utils/package_manager.pyi +0 -224
  73. erispulse-2.3.3.data/data/ErisPulse-stubs/ErisPulse/utils/reload_handler.pyi +0 -64
  74. erispulse-2.3.3.dist-info/RECORD +0 -98
  75. {erispulse-2.3.3.dist-info → erispulse-2.3.4.dev0.dist-info}/WHEEL +0 -0
  76. {erispulse-2.3.3.dist-info → erispulse-2.3.4.dev0.dist-info}/entry_points.txt +0 -0
ErisPulse/Core/ux.py DELETED
@@ -1,635 +0,0 @@
1
- """
2
- ErisPulse UX优化模块
3
-
4
- 提供更友好的初始化和API接口,简化常用操作
5
- """
6
-
7
- import json
8
- import asyncio
9
- from typing import List, Dict
10
- from pathlib import Path
11
- from rich.console import Console
12
- from rich.table import Table
13
- from rich.panel import Panel
14
- from rich.prompt import Confirm
15
-
16
- class UXManager:
17
- """
18
- UX优化管理器
19
-
20
- 提供用户友好的界面和简化操作
21
- """
22
-
23
- def __init__(self):
24
- self.console = Console()
25
- self._adapter_cache = None
26
- self._adapter_cache_time = 0
27
- self._cache_duration = 300 # 缓存5分钟
28
-
29
- async def _fetch_available_adapters(self) -> Dict[str, str]:
30
- """
31
- 从云端获取可用适配器列表
32
-
33
- :return: 适配器名称到描述的映射
34
- """
35
- # 检查缓存是否有效
36
- current_time = asyncio.get_event_loop().time()
37
- if self._adapter_cache and (current_time - self._adapter_cache_time) < self._cache_duration:
38
- return self._adapter_cache
39
-
40
- try:
41
- # 使用与 PackageManager 相同的机制获取远程包列表
42
- from ..utils.package_manager import PackageManager
43
- package_manager = PackageManager()
44
- remote_packages = await package_manager.get_remote_packages()
45
-
46
- adapters = {}
47
- for name, info in remote_packages.get("adapters", {}).items():
48
- adapters[name] = info.get("description", "")
49
-
50
- if adapters:
51
- # 更新缓存
52
- self._adapter_cache = adapters
53
- self._adapter_cache_time = current_time
54
- return adapters
55
- else:
56
- self.console.print("[yellow]从远程源获取的适配器列表为空[/yellow]")
57
- except Exception as e:
58
- self.console.print(f"[red]从远程源获取适配器列表时出错: {e}[/red]")
59
-
60
- # 如果云端请求失败,返回默认适配器列表
61
- self.console.print("[yellow]使用默认适配器列表[/yellow]")
62
- return {
63
- "yunhu": "云湖平台适配器",
64
- "telegram": "Telegram机器人适配器",
65
- "onebot11": "OneBot11标准适配器",
66
- "email": "邮件适配器"
67
- }
68
-
69
- def welcome(self, version: str = None) -> None:
70
- """
71
- 显示欢迎信息
72
-
73
- :param version: 框架版本号
74
- """
75
- version_text = f" v{version}" if version else ""
76
- welcome_text = f"[bold blue]欢迎使用 ErisPulse{version_text}[/bold blue]\n"
77
- welcome_text += "[dim]异步机器人开发框架,让开发更简单[/dim]"
78
-
79
- panel = Panel(
80
- welcome_text,
81
- border_style="blue",
82
- padding=(1, 2)
83
- )
84
- self.console.print(panel)
85
-
86
- def show_status(self) -> None:
87
- """
88
- 显示系统状态概览
89
- """
90
- table = Table(title="系统状态概览")
91
- table.add_column("组件", style="cyan", no_wrap=True)
92
- table.add_column("状态", style="magenta")
93
- table.add_column("详情", style="green")
94
-
95
- # 框架核心状态
96
- table.add_row("框架核心", "[green]运行中[/green]", "ErisPulse SDK 已加载")
97
-
98
- # 模块状态
99
- try:
100
- from .. import sdk
101
- loaded_modules = sdk.module.list_loaded()
102
- table.add_row(
103
- "模块系统",
104
- "[green]运行中[/green]" if loaded_modules else "[yellow]空闲[/yellow]",
105
- f"已加载 {len(loaded_modules)} 个模块"
106
- )
107
- except Exception:
108
- table.add_row("模块系统", "[red]错误[/red]", "无法获取模块状态")
109
-
110
- # 适配器状态
111
- try:
112
- from .. import sdk
113
- adapter_list = sdk.adapter.list_adapters()
114
- enabled_count = sum(1 for status in adapter_list.values() if status)
115
- table.add_row(
116
- "适配器系统",
117
- "[green]运行中[/green]" if adapter_list else "[yellow]空闲[/yellow]",
118
- f"已注册 {len(adapter_list)} 个适配器,{enabled_count} 个已启用"
119
- )
120
- except Exception:
121
- table.add_row("适配器系统", "[red]错误[/red]", "无法获取适配器状态")
122
-
123
- self.console.print(table)
124
-
125
- def list_modules(self, detailed: bool = False) -> None:
126
- """
127
- 列出所有模块状态
128
-
129
- :param detailed: 是否显示详细信息
130
- """
131
- try:
132
- from .. import sdk
133
- modules = sdk.module.list_modules()
134
-
135
- if not modules:
136
- self.console.print("[yellow]没有找到任何模块[/yellow]")
137
- return
138
-
139
- table = Table(title="模块状态")
140
- table.add_column("模块名", style="cyan", no_wrap=True)
141
- table.add_column("状态", style="magenta")
142
- table.add_column("是否已加载", style="green")
143
-
144
- for module_name, enabled in modules.items():
145
- loaded = sdk.module.is_loaded(module_name)
146
- status = "[green]启用[/green]" if enabled else "[red]禁用[/red]"
147
- is_loaded = "[green]已加载[/green]" if loaded else "[red]未加载[/red]"
148
-
149
- table.add_row(module_name, status, is_loaded)
150
-
151
- self.console.print(table)
152
-
153
- if detailed:
154
- loaded_modules = sdk.module.list_loaded()
155
- if loaded_modules:
156
- self.console.print("\n[bold]已加载模块详情:[/bold]")
157
- for module_name in loaded_modules:
158
- try:
159
- module_instance = sdk.module.get(module_name)
160
- info = getattr(module_instance, "moduleInfo", {})
161
- if info:
162
- self.console.print(f"[cyan]{module_name}:[/cyan] {json.dumps(info, indent=2, ensure_ascii=False)}")
163
- except Exception as e:
164
- self.console.print(f"[cyan]{module_name}:[/cyan] [red]获取信息失败: {e}[/red]")
165
-
166
- except Exception as e:
167
- self.console.print(f"[red]获取模块列表失败: {e}[/red]")
168
-
169
- def list_adapters(self, detailed: bool = False) -> None:
170
- """
171
- 列出所有适配器状态
172
-
173
- :param detailed: 是否显示详细信息
174
- """
175
- try:
176
- from .. import sdk
177
- adapters = sdk.adapter.list_adapters()
178
-
179
- if not adapters:
180
- self.console.print("[yellow]没有找到任何适配器[/yellow]")
181
- return
182
-
183
- table = Table(title="适配器状态")
184
- table.add_column("适配器名", style="cyan", no_wrap=True)
185
- table.add_column("状态", style="magenta")
186
-
187
- for adapter_name, enabled in adapters.items():
188
- status = "[green]启用[/green]" if enabled else "[red]禁用[/red]"
189
- table.add_row(adapter_name, status)
190
-
191
- self.console.print(table)
192
-
193
- if detailed:
194
- self.console.print("\n[bold]已注册适配器详情:[/bold]")
195
- for adapter_name in adapters:
196
- try:
197
- adapter_instance = sdk.adapter.get(adapter_name)
198
- if adapter_instance:
199
- info = getattr(adapter_instance, "_adapter_info", {})
200
- if info:
201
- self.console.print(f"[cyan]{adapter_name}:[/cyan] {json.dumps(info, indent=2, ensure_ascii=False)}")
202
- except Exception as e:
203
- self.console.print(f"[cyan]{adapter_name}:[/cyan] [red]获取信息失败: {e}[/red]")
204
-
205
- except Exception as e:
206
- self.console.print(f"[red]获取适配器列表失败: {e}[/red]")
207
-
208
-
209
- def init_project(self, project_name: str, adapter_list: List[str] = None) -> bool:
210
- """
211
- 初始化新项目
212
-
213
- :param project_name: 项目名称
214
- :param adapter_list: 需要初始化的适配器列表
215
- :return: 是否初始化成功
216
- """
217
- try:
218
- project_path = Path(project_name)
219
- if project_path.exists():
220
- if project_path.is_dir():
221
- self.console.print(f"[yellow]目录 {project_name} 已存在[/yellow]")
222
- else:
223
- self.console.print(f"[red]文件 {project_name} 已存在且不是目录[/red]")
224
- return False
225
- else:
226
- project_path.mkdir()
227
- self.console.print(f"[green]创建项目目录: {project_name}[/green]")
228
-
229
- # 创建基本目录结构
230
- dirs = ["config", "logs"]
231
- for dir_name in dirs:
232
- dir_path = project_path / dir_name
233
- dir_path.mkdir(exist_ok=True)
234
- self.console.print(f"[green]创建目录: {dir_name}[/green]")
235
-
236
- # 创建配置文件
237
- config_file = project_path / "config.toml"
238
- if not config_file.exists():
239
- with open(config_file, "w", encoding="utf-8") as f:
240
- f.write("# ErisPulse 配置文件\n\n")
241
- f.write("[ErisPulse]\n")
242
- f.write("# 全局配置\n\n")
243
- f.write("[ErisPulse.server]\n")
244
- f.write('host = "0.0.0.0"\n')
245
- f.write("port = 8000\n\n")
246
- f.write("[ErisPulse.logger]\n")
247
- f.write('level = "INFO"\n')
248
- f.write("log_files = [\"logs/app.log\"]\n")
249
- f.write("memory_limit = 1000\n\n")
250
-
251
- # 添加适配器配置
252
- if adapter_list:
253
- f.write("[ErisPulse.adapters]\n")
254
- f.write("# 适配器配置\n\n")
255
- f.write("[ErisPulse.adapters.status]\n")
256
- for adapter in adapter_list:
257
- f.write(f'{adapter} = false # 默认禁用,需要时启用\n')
258
- f.write("\n")
259
-
260
- self.console.print("[green]创建配置文件: config.toml[/green]")
261
-
262
- # 创建主程序文件
263
- main_file = project_path / "main.py"
264
- if not main_file.exists():
265
- with open(main_file, "w", encoding="utf-8") as f:
266
- f.write('"""')
267
- f.write(f"\n{project_name} 主程序\n\n")
268
- f.write("这是 ErisPulse 自动生成的主程序文件\n")
269
- f.write("您可以根据需要修改此文件\n")
270
- f.write('"""\n\n')
271
- f.write("import asyncio\n")
272
- f.write("from ErisPulse import sdk\n\n")
273
- f.write("async def main():\n")
274
- f.write(' """主程序入口"""\n')
275
- f.write(" # 初始化 SDK\n")
276
- f.write(" await sdk.init()\n\n")
277
- f.write(" # 启动适配器\n")
278
- f.write(" await sdk.adapter.startup()\n\n")
279
- f.write(' print("ErisPulse 已启动,按 Ctrl+C 退出")\n')
280
- f.write(" try:\n")
281
- f.write(" while True:\n")
282
- f.write(" await asyncio.sleep(1)\n")
283
- f.write(" except KeyboardInterrupt:\n")
284
- f.write(" print(\"\\n正在关闭...\")\n")
285
- f.write(" await sdk.adapter.shutdown()\n\n")
286
- f.write("if __name__ == \"__main__\":\n")
287
- f.write(" asyncio.run(main())\n")
288
-
289
- self.console.print("[green]创建主程序文件: main.py[/green]")
290
-
291
- self.console.print("\n[bold green]项目 {} 初始化成功![/bold green]".format(project_name))
292
- self.console.print("\n[cyan]接下来您可以:[/cyan]")
293
- self.console.print(f"1. 编辑 {project_name}/config.toml 配置适配器")
294
- self.console.print(f"2. 运行 [cyan]cd {project_name} \n ep run[/cyan] 启动项目")
295
- self.console.print("\n访问 https://github.com/ErisPulse/ErisPulse/tree/main/docs 获取更多信息和文档")
296
- return True
297
-
298
- except Exception as e:
299
- self.console.print(f"[red]初始化项目失败: {e}[/red]")
300
- return False
301
-
302
- def interactive_init(self, project_name: str = None, force: bool = False) -> bool:
303
- """
304
- 交互式初始化项目,包括项目创建和配置设置
305
-
306
- :param project_name: 项目名称,可为None
307
- :param force: 是否强制覆盖现有配置
308
- :return: 是否初始化成功
309
- """
310
- try:
311
- # 获取项目名称(如果未提供)
312
- if not project_name:
313
- project_name = self.console.input("[cyan]请输入项目名称 (默认: my_erispulse_project):[/cyan] ")
314
- if not project_name:
315
- project_name = "my_erispulse_project"
316
-
317
- # 检查项目是否已存在
318
- project_path = Path(project_name)
319
- if project_path.exists() and not force:
320
- if not Confirm.ask("[yellow]目录 {} 已存在,是否覆盖?[/yellow]".format(project_name), default=False):
321
- self.console.print("[info]操作已取消[/]")
322
- return False
323
-
324
- # 创建项目
325
- if not self.init_project(project_name, []):
326
- return False
327
-
328
- # 加载项目配置
329
- from .. import config as config
330
- project_config_path = project_path / "config.toml"
331
-
332
- # 更新配置文件路径并重新加载配置
333
- config.CONFIG_FILE = str(project_config_path)
334
- config.reload()
335
-
336
- # 交互式配置向导
337
- self.console.print("\n[bold blue]现在进行基本配置:[/bold blue]")
338
-
339
- # 获取日志级别配置
340
- current_level = config.getConfig("ErisPulse.logger.level", "INFO")
341
- self.console.print("\n当前日志级别: [cyan]{}[/cyan]".format(current_level))
342
- new_level = self.console.input("[yellow]请输入新的日志级别 (DEBUG/INFO/WARNING/ERROR/CRITICAL),回车保持当前值:[/yellow] ")
343
-
344
- if new_level and new_level.upper() in ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]:
345
- config.setConfig("ErisPulse.logger.level", new_level.upper())
346
- self.console.print("[green]日志级别已更新为: {}[/green]".format(new_level.upper()))
347
- elif new_level:
348
- self.console.print("[red]无效的日志级别: {}[/red]".format(new_level))
349
-
350
- # 获取服务器配置
351
- self.console.print("\n[bold]服务器配置[/bold]")
352
- current_host = config.getConfig("ErisPulse.server.host", "0.0.0.0")
353
- current_port = config.getConfig("ErisPulse.server.port", 8000)
354
-
355
- self.console.print("当前主机: [cyan]{}[/cyan]".format(current_host))
356
- new_host = self.console.input("[yellow]请输入主机地址,回车保持当前值:[/yellow] ")
357
-
358
- if new_host:
359
- config.setConfig("ErisPulse.server.host", new_host)
360
- self.console.print("[green]主机地址已更新为: {}[/green]".format(new_host))
361
-
362
- self.console.print("当前端口: [cyan]{}[/cyan]".format(current_port))
363
- new_port = self.console.input("[yellow]请输入端口号,回车保持当前值:[/yellow] ")
364
-
365
- if new_port:
366
- try:
367
- port_int = int(new_port)
368
- config.setConfig("ErisPulse.server.port", port_int)
369
- self.console.print("[green]端口已更新为: {}[/green]".format(port_int))
370
- except ValueError:
371
- self.console.print("[red]无效的端口号: {}[/red]".format(new_port))
372
-
373
- # 询问是否要配置适配器
374
- if Confirm.ask("\n[cyan]是否要配置适配器?[/cyan]", default=True):
375
- # 使用同步版本的适配器配置方法
376
- self._configure_adapters_interactive_sync(str(project_path))
377
-
378
- # 保存配置
379
- config.force_save()
380
- self.console.print("\n[bold green]项目和配置初始化完成![/bold green]")
381
-
382
- # 显示下一步操作
383
- self.console.print("\n[cyan]接下来您可以:[/cyan]")
384
- self.console.print("1. 编辑 {}/config.toml 进一步配置".format(project_name))
385
- self.console.print("2. 运行 [cyan]cd {} \n ep run[/cyan] 启动项目".format(project_name))
386
-
387
- return True
388
-
389
- except Exception as e:
390
- self.console.print("[red]交互式初始化失败: {}[/red]".format(e))
391
- return False
392
-
393
- def _configure_adapters_interactive_sync(self, project_path: str = None) -> None:
394
- """
395
- 交互式配置适配器的同步版本,从云端获取适配器列表
396
-
397
- :param project_path: 项目路径,用于加载项目特定的配置
398
- """
399
- from . import config
400
- from ..utils.package_manager import PackageManager
401
-
402
- # 如果提供了项目路径,则加载项目配置
403
- if project_path:
404
- project_config_path = Path(project_path) / "config.toml"
405
- if project_config_path.exists():
406
- # 更新配置文件路径并重新加载配置
407
- config.CONFIG_FILE = str(project_config_path)
408
- config.reload()
409
- self.console.print(f"[green]已加载项目配置: {project_config_path}[/green]")
410
-
411
- self.console.print("\n[bold]配置适配器[/bold]")
412
- self.console.print("[info]正在从云端获取可用适配器列表...[/info]")
413
-
414
- # 获取可用适配器列表(同步方式)
415
- try:
416
- # 使用线程池在同步上下文中运行异步函数
417
- import concurrent.futures
418
-
419
- with concurrent.futures.ThreadPoolExecutor() as executor:
420
- future = executor.submit(asyncio.run, self._fetch_available_adapters())
421
- adapters = future.result(timeout=10)
422
- except Exception as e:
423
- self.console.print(f"[red]获取适配器列表失败: {e}[/red]")
424
- adapters = {}
425
-
426
- if not adapters:
427
- self.console.print("[red]未能获取到适配器列表[/red]")
428
- return
429
-
430
- # 显示可用适配器列表
431
- adapter_list = list(adapters.items())
432
- for i, (name, desc) in enumerate(adapter_list, 1):
433
- self.console.print(f" {i}. {name} - {desc}")
434
-
435
- # 选择适配器
436
- selected_indices = self.console.input("\n[cyan]请输入要启用的适配器序号,多个用逗号分隔 (如: 1,3):[/cyan] ")
437
- if not selected_indices:
438
- self.console.print("[info]未选择任何适配器[/info]")
439
- return
440
-
441
- try:
442
- indices = [int(idx.strip()) for idx in selected_indices.split(",")]
443
- enabled_adapters = []
444
-
445
- for idx in indices:
446
- if 1 <= idx <= len(adapter_list):
447
- adapter_name = adapter_list[idx-1][0]
448
- enabled_adapters.append(adapter_name)
449
- config.setConfig(f"ErisPulse.adapters.status.{adapter_name}", True)
450
- self.console.print("[green]已启用适配器: {}[/green]".format(adapter_name))
451
- else:
452
- self.console.print("[red]无效的序号: {}[/red]".format(idx))
453
-
454
- # 禁用未选择的适配器
455
- all_adapter_names = [name for name, _ in adapter_list]
456
- for name in all_adapter_names:
457
- if name not in enabled_adapters:
458
- config.setConfig(f"ErisPulse.adapters.status.{name}", False)
459
-
460
- self.console.print("\n[info]已启用 {} 个适配器[/info]".format(len(enabled_adapters)))
461
-
462
- # 询问是否要安装适配器
463
- if enabled_adapters and Confirm.ask("\n[cyan]是否要安装选中的适配器?[/cyan]", default=True):
464
- package_manager = PackageManager()
465
-
466
- for adapter_name in enabled_adapters:
467
- # 从适配器列表中获取包名
468
- package_name = None
469
- # 尝试通过 PackageManager 获取包名
470
- try:
471
- # 使用同步方式获取远程包信息
472
- remote_packages = package_manager._cache.get("remote_packages", {})
473
- if not remote_packages:
474
- # 如果没有缓存,尝试同步获取
475
- with concurrent.futures.ThreadPoolExecutor() as executor:
476
- future = executor.submit(asyncio.run, package_manager.get_remote_packages())
477
- remote_packages = future.result(timeout=10)
478
-
479
- if adapter_name in remote_packages.get("adapters", {}):
480
- package_name = remote_packages["adapters"][adapter_name].get("package")
481
- except Exception:
482
- pass
483
-
484
- # 如果没有找到包名,使用适配器名称作为包名
485
- if not package_name:
486
- package_name = adapter_name
487
-
488
- # 安装适配器
489
- self.console.print(f"[info]正在安装适配器: {adapter_name} ({package_name})[/info]")
490
- success = package_manager.install_package([package_name])
491
-
492
- if success:
493
- self.console.print(f"[green]适配器 {adapter_name} 安装成功[/green]")
494
- else:
495
- # 如果标准安装失败,尝试使用 uv
496
- self.console.print("[yellow]标准安装失败,尝试使用 uv 安装...[/yellow]")
497
- try:
498
- import subprocess
499
- import sys
500
-
501
- # 尝试使用 uv pip install
502
- result = subprocess.run(
503
- [sys.executable, "-m", "uv", "pip", "install", package_name],
504
- capture_output=True,
505
- text=True,
506
- timeout=300
507
- )
508
-
509
- if result.returncode == 0:
510
- self.console.print(f"[green]适配器 {adapter_name} 通过 uv 安装成功[/green]")
511
- success = True
512
- else:
513
- self.console.print(f"[red]适配器 {adapter_name} 通过 uv 安装失败[/red]")
514
- self.console.print(f"[dim]{result.stderr}[/dim]")
515
- except Exception as e:
516
- self.console.print(f"[red]适配器 {adapter_name} 通过 uv 安装时出错: {e}[/red]")
517
-
518
- # 如果 uv 也失败了,尝试直接使用 pip
519
- if not success:
520
- self.console.print("[yellow]尝试使用 pip 直接安装...[/yellow]")
521
- try:
522
- import subprocess
523
- import sys
524
-
525
- # 尝试直接使用 pip
526
- result = subprocess.run(
527
- [sys.executable, "-m", "pip", "install", package_name],
528
- capture_output=True,
529
- text=True,
530
- timeout=300
531
- )
532
-
533
- if result.returncode == 0:
534
- self.console.print(f"[green]适配器 {adapter_name} 通过 pip 直接安装成功[/green]")
535
- success = True
536
- else:
537
- self.console.print(f"[red]适配器 {adapter_name} 通过 pip 直接安装失败[/red]")
538
- self.console.print(f"[dim]{result.stderr}[/dim]")
539
- except Exception as e:
540
- self.console.print(f"[red]适配器 {adapter_name} 通过 pip 直接安装时出错: {e}[/red]")
541
-
542
- if not success:
543
- self.console.print(f"[red]适配器 {adapter_name} 安装失败,请手动安装: pip install {package_name}[/red]")
544
-
545
- # 保存配置
546
- config.force_save()
547
-
548
- except ValueError:
549
- self.console.print("[red]输入格式错误,请输入数字序号[/red]")
550
-
551
- async def _configure_adapters_interactive(self, project_path: str = None) -> None:
552
- """
553
- 交互式配置适配器,从云端获取适配器列表
554
-
555
- :param project_path: 项目路径,用于加载项目特定的配置
556
- """
557
- from .. import config
558
- from ..utils.package_manager import PackageManager
559
- package_manager = PackageManager()
560
-
561
- # 如果提供了项目路径,则加载项目配置
562
- if project_path:
563
- project_config_path = Path(project_path) / "config.toml"
564
- if project_config_path.exists():
565
- # 更新配置文件路径并重新加载配置
566
- config.CONFIG_FILE = str(project_config_path)
567
- config.reload()
568
- self.console.print(f"[green]已加载项目配置: {project_config_path}[/green]")
569
-
570
- self.console.print("\n[bold]配置适配器[/bold]")
571
- self.console.print("[info]正在从云端获取可用适配器列表...[/info]")
572
-
573
- # 从云端获取可用适配器列表
574
- adapters = await self._fetch_available_adapters()
575
-
576
- if not adapters:
577
- self.console.print("[red]未能获取到适配器列表[/red]")
578
- return
579
-
580
- # 显示可用适配器列表
581
- adapter_list = list(adapters.items())
582
- for i, (name, desc) in enumerate(adapter_list, 1):
583
- self.console.print(f" {i}. {name} - {desc}")
584
-
585
- # 选择适配器
586
- selected_indices = self.console.input("\n[cyan]请输入要启用的适配器序号,多个用逗号分隔 (如: 1,3):[/cyan] ")
587
- if not selected_indices:
588
- self.console.print("[info]未选择任何适配器[/info]")
589
- return
590
-
591
- try:
592
- indices = [int(idx.strip()) for idx in selected_indices.split(",")]
593
- enabled_adapters = []
594
-
595
- for idx in indices:
596
- if 1 <= idx <= len(adapter_list):
597
- adapter_name = adapter_list[idx-1][0]
598
- enabled_adapters.append(adapter_name)
599
- config.setConfig(f"ErisPulse.adapters.status.{adapter_name}", True)
600
- self.console.print("[green]已启用适配器: {}[/green]".format(adapter_name))
601
- else:
602
- self.console.print("[red]无效的序号: {}[/red]".format(idx))
603
-
604
- # 禁用未选择的适配器
605
- all_adapter_names = [name for name, _ in adapter_list]
606
- for name in all_adapter_names:
607
- if name not in enabled_adapters:
608
- config.setConfig(f"ErisPulse.adapters.status.{name}", False)
609
-
610
- self.console.print("\n[info]已启用 {} 个适配器[/info]".format(len(enabled_adapters)))
611
-
612
- # 询问是否要安装适配器
613
- if enabled_adapters and Confirm.ask("\n[cyan]是否要安装选中的适配器?[/cyan]", default=True):
614
- # 直接使用CLI中的安装功能
615
- success = package_manager.install_package(enabled_adapters)
616
-
617
- if success:
618
- self.console.print("[green]适配器安装成功[/green]")
619
- else:
620
- self.console.print("[red]适配器安装失败,请手动安装或检查网络连接[/red]")
621
-
622
- # 保存配置
623
- config.force_save()
624
-
625
- except ValueError:
626
- self.console.print("[red]输入格式错误,请输入数字序号[/red]")
627
-
628
-
629
- # 创建全局UX管理器实例
630
- ux = UXManager()
631
-
632
- __all__ = [
633
- "ux",
634
- "UXManager"
635
- ]