stigmergy 1.0.68 → 1.0.70

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 (102) hide show
  1. package/README.en.md +306 -300
  2. package/README.md +469 -301
  3. package/package.json +97 -81
  4. package/scripts/publish.js +268 -0
  5. package/scripts/simple-publish.js +59 -0
  6. package/src/index.js +12 -0
  7. package/test/enhanced-main-alignment.test.js +298 -0
  8. package/test/hook-system-integration-test.js +307 -0
  9. package/test/natural-language-skills-test.js +320 -0
  10. package/test/nl-integration-test.js +179 -0
  11. package/test/parameter-parsing-test.js +143 -0
  12. package/test/real-test.js +435 -0
  13. package/test/system-compatibility-test.js +447 -0
  14. package/test/tdd-fixes-test.js +211 -0
  15. package/test/third-party-skills-test.js +321 -0
  16. package/test/tool-selection-integration-test.js +157 -0
  17. package/test/unit/cli-scanner.test.js +291 -0
  18. package/test/unit/cross-cli-executor.test.js +399 -0
  19. package/src/adapters/claude/__init__.py +0 -13
  20. package/src/adapters/claude/claude_skills_integration.py +0 -609
  21. package/src/adapters/claude/hook_adapter.py +0 -663
  22. package/src/adapters/claude/install_claude_integration.py +0 -265
  23. package/src/adapters/claude/skills_hook_adapter.py +0 -841
  24. package/src/adapters/claude/standalone_claude_adapter.py +0 -384
  25. package/src/adapters/cline/__init__.py +0 -20
  26. package/src/adapters/cline/config.py +0 -108
  27. package/src/adapters/cline/install_cline_integration.py +0 -617
  28. package/src/adapters/cline/mcp_server.py +0 -713
  29. package/src/adapters/cline/standalone_cline_adapter.py +0 -459
  30. package/src/adapters/codebuddy/__init__.py +0 -13
  31. package/src/adapters/codebuddy/buddy_adapter.py +0 -1125
  32. package/src/adapters/codebuddy/install_codebuddy_integration.py +0 -279
  33. package/src/adapters/codebuddy/skills_hook_adapter.py +0 -672
  34. package/src/adapters/codebuddy/skills_integration.py +0 -395
  35. package/src/adapters/codebuddy/standalone_codebuddy_adapter.py +0 -403
  36. package/src/adapters/codex/__init__.py +0 -11
  37. package/src/adapters/codex/base.py +0 -46
  38. package/src/adapters/codex/install_codex_integration.py +0 -311
  39. package/src/adapters/codex/mcp_server.py +0 -493
  40. package/src/adapters/codex/natural_language_parser.py +0 -82
  41. package/src/adapters/codex/slash_command_adapter.py +0 -326
  42. package/src/adapters/codex/standalone_codex_adapter.py +0 -362
  43. package/src/adapters/copilot/__init__.py +0 -13
  44. package/src/adapters/copilot/install_copilot_integration.py +0 -564
  45. package/src/adapters/copilot/mcp_adapter.py +0 -772
  46. package/src/adapters/copilot/mcp_server.py +0 -168
  47. package/src/adapters/copilot/standalone_copilot_adapter.py +0 -114
  48. package/src/adapters/gemini/__init__.py +0 -13
  49. package/src/adapters/gemini/extension_adapter.py +0 -690
  50. package/src/adapters/gemini/install_gemini_integration.py +0 -257
  51. package/src/adapters/gemini/standalone_gemini_adapter.py +0 -366
  52. package/src/adapters/iflow/__init__.py +0 -7
  53. package/src/adapters/iflow/hook_adapter.py +0 -1038
  54. package/src/adapters/iflow/hook_installer.py +0 -536
  55. package/src/adapters/iflow/install_iflow_integration.py +0 -271
  56. package/src/adapters/iflow/official_hook_adapter.py +0 -1272
  57. package/src/adapters/iflow/standalone_iflow_adapter.py +0 -48
  58. package/src/adapters/iflow/workflow_adapter.py +0 -793
  59. package/src/adapters/qoder/hook_installer.py +0 -732
  60. package/src/adapters/qoder/install_qoder_integration.py +0 -265
  61. package/src/adapters/qoder/notification_hook_adapter.py +0 -863
  62. package/src/adapters/qoder/standalone_qoder_adapter.py +0 -48
  63. package/src/adapters/qwen/__init__.py +0 -17
  64. package/src/adapters/qwencode/__init__.py +0 -13
  65. package/src/adapters/qwencode/inheritance_adapter.py +0 -818
  66. package/src/adapters/qwencode/install_qwencode_integration.py +0 -276
  67. package/src/adapters/qwencode/standalone_qwencode_adapter.py +0 -399
  68. package/src/atomic_collaboration_handler.py +0 -461
  69. package/src/cli_collaboration_agent.py +0 -697
  70. package/src/collaboration/hooks.py +0 -315
  71. package/src/core/__init__.py +0 -21
  72. package/src/core/ai_environment_scanner.py +0 -331
  73. package/src/core/base_adapter.py +0 -220
  74. package/src/core/cli_hook_integration.py +0 -406
  75. package/src/core/cross_cli_executor.py +0 -713
  76. package/src/core/cross_cli_mapping.py +0 -1165
  77. package/src/core/cross_platform_encoding.py +0 -365
  78. package/src/core/cross_platform_safe_cli.py +0 -894
  79. package/src/core/direct_cli_executor.py +0 -805
  80. package/src/core/direct_cli_hook_system.py +0 -958
  81. package/src/core/enhanced_init_processor.py +0 -467
  82. package/src/core/graceful_cli_executor.py +0 -912
  83. package/src/core/md_enhancer.py +0 -342
  84. package/src/core/md_generator.py +0 -619
  85. package/src/core/models.py +0 -218
  86. package/src/core/parser.py +0 -108
  87. package/src/core/real_cli_hook_system.py +0 -852
  88. package/src/core/real_cross_cli_system.py +0 -925
  89. package/src/core/verified_cross_cli_system.py +0 -961
  90. package/src/deploy.js +0 -737
  91. package/src/enhanced-main.js +0 -626
  92. package/src/enhanced_deploy.js +0 -303
  93. package/src/enhanced_universal_cli_setup.py +0 -930
  94. package/src/kimi_wrapper.py +0 -104
  95. package/src/main.js +0 -1309
  96. package/src/shell_integration.py +0 -398
  97. package/src/simple-main.js +0 -315
  98. package/src/smart_router_creator.py +0 -323
  99. package/src/universal_cli_setup.py +0 -1289
  100. package/src/utils/__init__.py +0 -12
  101. package/src/utils/cli_detector.py +0 -445
  102. package/src/utils/file_utils.py +0 -246
@@ -1,1125 +0,0 @@
1
- """
2
- CodeBuddy CLI Buddy适配器 - 基于CodeBuddy CLI Buddy系统的原生集成
3
-
4
- 基于CodeBuddy CLI的Buddy系统实现跨CLI调用功能。
5
- CodeBuddy CLI使用Buddy模式,每个Buddy代表一个特定的技能或功能领域。
6
-
7
- Buddy系统机制:
8
- - @buddy装饰器: 用于注册Buddy技能
9
- - 能力声明: 声明Buddy的功能和专长
10
- - 优先级系统: Buddy调用时的优先级排序
11
- - 协作协议: Buddy之间的协作机制
12
- - 配置文件: buddy_config.json配置Buddy技能
13
-
14
- 完全符合项目约束条件:
15
- - 使用CodeBuddy CLI官方Buddy机制
16
- - 不改变CLI启动和使用方式
17
- - 不依赖包装器
18
- - 完全无损扩展
19
- """
20
-
21
- import os
22
- import sys
23
- import json
24
- import logging
25
- import asyncio
26
- import importlib
27
- import inspect
28
- from typing import Dict, Any, Optional, List, Callable, Union
29
- from datetime import datetime
30
- from pathlib import Path
31
- from dataclasses import dataclass, field
32
- from functools import wraps
33
-
34
- from ...core.base_adapter import BaseCrossCLIAdapter, IntentResult
35
- from ...core.parser import NaturalLanguageParser
36
-
37
- logger = logging.getLogger(__name__)
38
-
39
-
40
- @dataclass
41
- class BuddySkill:
42
- """Buddy技能数据类"""
43
- name: str
44
- description: str
45
- version: str = "1.0.0"
46
- capabilities: List[str] = field(default_factory=list)
47
- priority: int = 50
48
- supported_clis: List[str] = field(default_factory=list)
49
- protocols: List[str] = field(default_factory=list)
50
- cross_cli_enabled: bool = True
51
- auto_collaboration: bool = False
52
- requires_authorization: bool = False
53
- dependencies: List[str] = field(default_factory=list)
54
- metadata: Dict[str, Any] = field(default_factory=dict)
55
-
56
-
57
- @dataclass
58
- class BuddyContext:
59
- """Buddy上下文"""
60
- session_id: str
61
- user_input: str
62
- intent: Optional[IntentResult] = None
63
- buddy_name: str = ""
64
- stage: str = "processing"
65
- parameters: Dict[str, Any] = field(default_factory=dict)
66
- metadata: Dict[str, Any] = field(default_factory=dict)
67
- timestamp: datetime = field(default_factory=datetime.now)
68
-
69
-
70
- class CodeBuddyBuddyAdapter(BaseCrossCLIAdapter):
71
- """
72
- CodeBuddy CLI Buddy适配器
73
-
74
- 通过CodeBuddy CLI的Buddy系统实现跨CLI调用功能。
75
- 每个Buddy代表一个特定的AI技能或功能领域。
76
-
77
- Buddy机制:
78
- - @buddy装饰器注册技能
79
- - can_handle方法判断处理能力
80
- - handle_request方法执行任务
81
- - get_capabilities获取技能声明
82
- - 优先级和能力匹配
83
- """
84
-
85
- def __init__(self, cli_name: str = "codebuddy"):
86
- """
87
- 初始化CodeBuddy Buddy适配器
88
-
89
- Args:
90
- cli_name: CLI工具名称,默认为"codebuddy"
91
- """
92
- super().__init__(cli_name)
93
-
94
- # Buddy系统配置
95
- self.buddy_config_file = os.path.expanduser("~/.codebuddy/buddy_config.json")
96
- self.buddy_modules_dir = os.path.expanduser("~/.codebuddy/buddies")
97
- self.skills_registry: Dict[str, BuddySkill] = {}
98
- self.active_buddies: Dict[str, Any] = {}
99
- self.buddy_instances: Dict[str, Any] = {}
100
-
101
- # 统计信息
102
- self.buddy_calls_count = 0
103
- self.cross_cli_calls_count = 0
104
- self.processed_requests: List[Dict[str, Any]] = []
105
- self.collaboration_sessions: Dict[str, Dict] = {}
106
-
107
- # 组件
108
- self.parser = NaturalLanguageParser()
109
-
110
- # Buddy配置
111
- self.buddy_config = {
112
- "enabled": True,
113
- "auto_discovery": True,
114
- "max_concurrent_buddies": 10,
115
- "default_timeout": 30,
116
- "fallback_buddy": "general_assistant",
117
- "cross_cli_integration": {
118
- "enabled": True,
119
- "preferred_buddies": [
120
- "cross_cli_coordinator",
121
- "ai_tool_bridge",
122
- "universal_assistant"
123
- ]
124
- }
125
- }
126
-
127
- logger.info("CodeBuddy Buddy适配器初始化完成")
128
-
129
- async def initialize(self) -> bool:
130
- """
131
- 初始化适配器
132
-
133
- Returns:
134
- bool: 初始化是否成功
135
- """
136
- try:
137
- logger.info("开始初始化CodeBuddy Buddy适配器...")
138
-
139
- # 1. 检查CodeBuddy CLI环境
140
- if not self._check_codebuddy_environment():
141
- logger.error("CodeBuddy CLI环境检查失败")
142
- return False
143
-
144
- # 2. 创建Buddy配置目录
145
- await self._ensure_buddy_directories()
146
-
147
- # 3. 加载Buddy配置
148
- await self._load_buddy_config()
149
-
150
- # 4. 注册Buddy技能
151
- if not await self._register_builtin_buddies():
152
- logger.error("Buddy技能注册失败")
153
- return False
154
-
155
- # 5. 发现和加载外部Buddy模块
156
- if self.buddy_config["auto_discovery"]:
157
- await self._discover_buddy_modules()
158
-
159
- # 6. 初始化跨CLI协作系统
160
- await self._initialize_cross_cli_system()
161
-
162
- logger.info("CodeBuddy Buddy适配器初始化成功")
163
- return True
164
-
165
- except Exception as e:
166
- logger.error(f"初始化CodeBuddy Buddy适配器失败: {e}")
167
- self.record_error()
168
- return False
169
-
170
- def _check_codebuddy_environment(self) -> bool:
171
- """
172
- 检查CodeBuddy CLI环境
173
-
174
- Returns:
175
- bool: 环境是否可用
176
- """
177
- try:
178
- # 检查CodeBuddy CLI命令
179
- import subprocess
180
- result = subprocess.run(
181
- ['codebuddy', '--version'],
182
- capture_output=True,
183
- text=True,
184
- timeout=5
185
- )
186
-
187
- if result.returncode == 0:
188
- logger.info(f"检测到CodeBuddy CLI: {result.stdout.strip()}")
189
- return True
190
- else:
191
- logger.warning("CodeBuddy CLI不可用,使用开发模式")
192
- return True # 开发环境中继续
193
-
194
- except (subprocess.TimeoutExpired, FileNotFoundError):
195
- logger.warning("CodeBuddy CLI环境检查失败,使用开发模式")
196
- return True # 开发环境中继续
197
-
198
- async def _ensure_buddy directories(self) -> None:
199
- """确保Buddy目录存在"""
200
- directories = [
201
- os.path.expanduser("~/.codebuddy"),
202
- self.buddy_modules_dir,
203
- os.path.expanduser("~/.codebuddy/logs"),
204
- os.path.expanduser("~/.codebuddy/cache"),
205
- os.path.expanduser("~/.codebuddy/collaboration")
206
- ]
207
-
208
- for directory in directories:
209
- os.makedirs(directory, exist_ok=True)
210
-
211
- async def _load_buddy_config(self) -> None:
212
- """加载Buddy配置"""
213
- try:
214
- if os.path.exists(self.buddy_config_file):
215
- with open(self.buddy_config_file, 'r', encoding='utf-8') as f:
216
- loaded_config = json.load(f)
217
-
218
- # 合并配置
219
- for key, value in loaded_config.items():
220
- if key in self.buddy_config:
221
- if isinstance(self.buddy_config[key], dict) and isinstance(value, dict):
222
- self.buddy_config[key].update(value)
223
- else:
224
- self.buddy_config[key] = value
225
- else:
226
- self.buddy_config[key] = value
227
-
228
- logger.info("Buddy配置加载成功")
229
- else:
230
- logger.info("Buddy配置文件不存在,使用默认配置")
231
- await self._save_buddy_config()
232
-
233
- except Exception as e:
234
- logger.error(f"加载Buddy配置失败: {e}")
235
- logger.info("使用默认Buddy配置")
236
-
237
- async def _save_buddy_config(self) -> bool:
238
- """保存Buddy配置"""
239
- try:
240
- os.makedirs(os.path.dirname(self.buddy_config_file), exist_ok=True)
241
- with open(self.buddy_config_file, 'w', encoding='utf-8') as f:
242
- json.dump(self.buddy_config, f, indent=2, ensure_ascii=False)
243
-
244
- logger.info(f"Buddy配置已保存到: {self.buddy_config_file}")
245
- return True
246
-
247
- except Exception as e:
248
- logger.error(f"保存Buddy配置失败: {e}")
249
- return False
250
-
251
- async def _register_builtin_buddies(self) -> bool:
252
- """
253
- 注册内置Buddy技能
254
-
255
- Returns:
256
- bool: 注册是否成功
257
- """
258
- try:
259
- # 注册跨CLI协作Buddy
260
- await self._register_cross_cli_coordinator_buddy()
261
-
262
- # 注册通用AI工具Buddy
263
- await self._register_ai_tool_bridge_buddy()
264
-
265
- # 注册通用助手Buddy
266
- await self._register_universal_assistant_buddy()
267
-
268
- logger.info("内置Buddy技能注册成功")
269
- return True
270
-
271
- except Exception as e:
272
- logger.error(f"注册内置Buddy技能失败: {e}")
273
- return False
274
-
275
- def buddy(self, name: str = "", description: str = "",
276
- capabilities: List[str] = None, priority: int = 50,
277
- supported_clis: List[str] = None, protocols: List[str] = None,
278
- cross_cli_enabled: bool = True, auto_collaboration: bool = False):
279
- """
280
- Buddy装饰器,用于注册Buddy技能
281
-
282
- Args:
283
- name: Buddy名称
284
- description: Buddy描述
285
- capabilities: Buddy能力列表
286
- priority: 优先级
287
- supported_clis: 支持的CLI工具列表
288
- protocols: 支持的协议列表
289
- cross_cli_enabled: 是否启用跨CLI功能
290
- auto_collaboration: 是否启用自动协作
291
- """
292
- def decorator(func: Callable):
293
- # 创建Buddy技能
294
- buddy_skill = BuddySkill(
295
- name=name or func.__name__,
296
- description=description or f"Buddy技能: {func.__name__}",
297
- version="1.0.0",
298
- capabilities=capabilities or [],
299
- priority=priority,
300
- supported_clis=supported_clis or [],
301
- protocols=protocols or [
302
- "请用{cli}帮我{task}",
303
- "调用{cli}来{task}",
304
- "用{cli}处理{task}",
305
- "use {cli} to {task}",
306
- "ask {cli} for {task}"
307
- ],
308
- cross_cli_enabled=cross_cli_enabled,
309
- auto_collaboration=auto_collaboration
310
- )
311
-
312
- # 存储技能信息
313
- buddy_skill.metadata['function'] = func.__name__
314
- buddy_skill.metadata['module'] = func.__module__
315
- buddy_skill.metadata['docstring'] = func.__doc__
316
-
317
- # 包装原始函数
318
- @wraps(func)
319
- async def wrapped_func(context: BuddyContext, *args, **kwargs) -> Any:
320
- try:
321
- logger.info(f"执行Buddy技能: {buddy_skill.name}")
322
-
323
- # 记录Buddy调用
324
- self.buddy_calls_count += 1
325
-
326
- # 执行原始函数
327
- result = await func(context, *args, **kwargs)
328
-
329
- logger.info(f"Buddy技能 {buddy_skill.name} 执行完成")
330
- return result
331
-
332
- except Exception as e:
333
- logger.error(f"Buddy技能 {buddy_skill.name} 执行失败: {e}")
334
- self.record_error()
335
- raise
336
-
337
- # 注册技能
338
- self.skills_registry[buddy_skill.name] = buddy_skill
339
-
340
- # 如果启用了跨CLI功能,注册跨CLI能力
341
- if buddy_skill.cross_cli_enabled:
342
- await self._register_cross_cli_capabilities(buddy_skill, wrapped_func)
343
-
344
- return wrapped_func
345
-
346
- return decorator
347
-
348
- async def _register_cross_cli_coordinator_buddy(self) -> None:
349
- """注册跨CLI协调器Buddy"""
350
-
351
- @self.buddy(
352
- name="cross_cli_coordinator",
353
- description="跨CLI协调器 - 协调不同AI CLI工具的调用",
354
- capabilities=[
355
- "跨CLI调用协调",
356
- "多工具协作",
357
- "任务路由",
358
- "结果整合"
359
- ],
360
- priority=100,
361
- supported_clis=["claude", "gemini", "qwencode", "iflow", "qoder", "codex"],
362
- cross_cli_enabled=True,
363
- auto_collaboration=True
364
- )
365
- async def cross_cli_coordinator_buddy(context: BuddyContext) -> str:
366
- """跨CLI协调器Buddy处理函数"""
367
- if not context.intent or not context.intent.is_cross_cli:
368
- return "没有检测到跨CLI调用意图"
369
-
370
- target_cli = context.intent.target_cli
371
- task = context.intent.task
372
-
373
- logger.info(f"跨CLI协调器: 调用 {target_cli} 执行任务: {task}")
374
-
375
- # 获取目标CLI适配器
376
- from ...core.base_adapter import get_cross_cli_adapter
377
- target_adapter = get_cross_cli_adapter(target_cli)
378
-
379
- if not target_adapter or not target_adapter.is_available():
380
- return f"目标CLI工具 '{target_cli}' 不可用"
381
-
382
- # 构建执行上下文
383
- execution_context = {
384
- 'source_cli': self.cli_name,
385
- 'target_cli': target_cli,
386
- 'original_task': task,
387
- 'buddy_context': {
388
- 'buddy_name': 'cross_cli_coordinator',
389
- 'capabilities': ['跨CLI调用协调', '多工具协作']
390
- },
391
- 'timestamp': datetime.now().isoformat()
392
- }
393
-
394
- # 执行跨CLI调用
395
- result = await target_adapter.execute_task(task, execution_context)
396
-
397
- # 格式化结果
398
- formatted_result = self._format_buddy_result(
399
- "cross_cli_coordinator",
400
- target_cli,
401
- task,
402
- result
403
- )
404
-
405
- return formatted_result
406
-
407
- async def _register_ai_tool_bridge_buddy(self) -> None:
408
- """注册AI工具桥接Buddy"""
409
-
410
- @self.buddy(
411
- name="ai_tool_bridge",
412
- description="AI工具桥接器 - 连接各种AI工具的通用接口",
413
- capabilities=[
414
- "AI工具调用",
415
- "工具适配",
416
- "结果转换",
417
- "错误处理"
418
- ],
419
- priority=90,
420
- supported_clis=["claude", "gemini", "qwencode", "iflow", "qoder", "codex"],
421
- cross_cli_enabled=True,
422
- auto_collaboration=False
423
- )
424
- async def ai_tool_bridge_buddy(context: BuddyContext) -> str:
425
- """AI工具桥接器Buddy处理函数"""
426
- if not context.intent or not context.intent.is_cross_cli:
427
- return "没有检测到跨CLI调用意图"
428
-
429
- target_cli = context.intent.target_cli
430
- task = context.intent.task
431
-
432
- # 标准化CLI名称
433
- cli_mapping = {
434
- 'claude': 'claude',
435
- 'gemini': 'gemini',
436
- 'qwen': 'qwencode',
437
- 'iflow': 'iflow',
438
- 'qoder': 'qoder',
439
- 'codebuddy': 'codex'
440
- }
441
-
442
- normalized_cli = cli_mapping.get(target_cli.lower(), target_cli)
443
-
444
- logger.info(f"AI工具桥接器: 桥接调用 {normalized_cli} 执行任务: {task}")
445
-
446
- # 获取目标CLI适配器
447
- from ...core.base_adapter import get_cross_cli_adapter
448
- target_adapter = get_cross_cli_adapter(normalized_cli)
449
-
450
- if not target_adapter or not target_adapter.is_available():
451
- return f"目标AI工具 '{normalized_cli}' 不可用或未安装"
452
-
453
- # 预处理任务内容
454
- processed_task = self._preprocess_task_for_cli(task, normalized_cli)
455
-
456
- # 构建执行上下文
457
- execution_context = {
458
- 'source_cli': self.cli_name,
459
- 'target_cli': normalized_cli,
460
- 'original_task': task,
461
- 'processed_task': processed_task,
462
- 'buddy_context': {
463
- 'buddy_name': 'ai_tool_bridge',
464
- 'capabilities': ['AI工具调用', '工具适配', '结果转换']
465
- },
466
- 'timestamp': datetime.now().isoformat()
467
- }
468
-
469
- # 执行跨CLI调用
470
- result = await target_adapter.execute_task(processed_task, execution_context)
471
-
472
- # 后处理结果
473
- processed_result = self._postprocess_result_from_cli(result, normalized_cli)
474
-
475
- # 格式化结果
476
- formatted_result = self._format_buddy_result(
477
- "ai_tool_bridge",
478
- normalized_cli,
479
- task,
480
- processed_result
481
- )
482
-
483
- return formatted_result
484
-
485
- async def _register_universal_assistant_buddy(self) -> None:
486
- """注册通用助手Buddy"""
487
-
488
- @self.buddy(
489
- name="universal_assistant",
490
- description="通用助手 - 处理各种通用任务和协调其他Buddy",
491
- capabilities=[
492
- "通用问题解答",
493
- "任务协调",
494
- "结果整合",
495
- "Buddy协作"
496
- ],
497
- priority=70,
498
- supported_clis=["claude", "gemini", "qwencode", "iflow", "qoder", "codex"],
499
- cross_cli_enabled=True,
500
- auto_collaboration=True
501
- )
502
- async def universal_assistant_buddy(context: BuddyContext) -> str:
503
- """通用助手Buddy处理函数"""
504
- user_input = context.user_input
505
-
506
- # 首先检查是否为跨CLI调用
507
- if context.intent and context.intent.is_cross_cli:
508
- return await self._handle_cross_cli_with_universal_assistant(context)
509
-
510
- # 处理通用任务
511
- result = await self._handle_general_task_with_universal_assistant(context)
512
- return result
513
-
514
- async def _handle_cross_cli_with_universal_assistant(self, context: BuddyContext) -> str:
515
- """通过通用助手处理跨CLI调用"""
516
- target_cli = context.intent.target_cli
517
- task = context.intent.task
518
-
519
- logger.info(f"通用助手: 处理跨CLI调用到 {target_cli}")
520
-
521
- # 使用AI工具桥接器
522
- from ...core.base_adapter import get_cross_cli_adapter
523
- target_adapter = get_cross_cli_adapter(target_cli)
524
-
525
- if not target_adapter or not target_adapter.is_available():
526
- return f"目标工具 '{target_cli}' 不可用"
527
-
528
- execution_context = {
529
- 'source_cli': self.cli_name,
530
- 'target_cli': target_cli,
531
- 'original_task': task,
532
- 'buddy_context': {
533
- 'buddy_name': 'universal_assistant',
534
- 'handling_mode': 'cross_cli'
535
- },
536
- 'timestamp': datetime.now().isoformat()
537
- }
538
-
539
- result = await target_adapter.execute_task(task, execution_context)
540
-
541
- return self._format_buddy_result("universal_assistant", target_cli, task, result)
542
-
543
- async def _handle_general_task_with_universal_assistant(self, context: BuddyContext) -> str:
544
- """通过通用助手处理通用任务"""
545
- user_input = context.user_input
546
-
547
- # 尝试在当前CLI中处理
548
- try:
549
- # 这里可以添加CodeBuddy自身的任务处理逻辑
550
- result = f"CodeBuddy处理任务: {user_input[:100]}..."
551
-
552
- # 记录处理
553
- self.processed_requests.append({
554
- 'type': 'buddy_task',
555
- 'buddy_name': 'universal_assistant',
556
- 'task': user_input,
557
- 'result': result,
558
- 'timestamp': datetime.now().isoformat()
559
- })
560
-
561
- return result
562
-
563
- except Exception as e:
564
- logger.error(f"通用任务处理失败: {e}")
565
- return f"任务处理失败: {str(e)}"
566
-
567
- def _preprocess_task_for_cli(self, task: str, target_cli: str) -> str:
568
- """为特定CLI预处理任务"""
569
- # 根据目标CLI特性调整任务内容
570
- cli_specific_adjustments = {
571
- 'claude': {
572
- 'prefix': 'Please help me ',
573
- 'suffix': ' Provide detailed analysis.'
574
- },
575
- 'gemini': {
576
- 'prefix': 'Analyze and process: ',
577
- 'suffix': ' Give comprehensive insights.'
578
- },
579
- 'qwencode': {
580
- 'prefix': 'Optimize and implement: ',
581
- 'suffix': ' Focus on code quality and best practices.'
582
- },
583
- 'iflow': {
584
- 'prefix': 'Process through workflow: ',
585
- 'suffix': ' Use appropriate stages and tools.'
586
- },
587
- 'qoder': {
588
- 'prefix': 'Analyze and suggest: ',
589
- 'suffix': ' Provide actionable recommendations.'
590
- },
591
- 'codex': {
592
- 'prefix': 'Generate and explain: ',
593
- 'suffix': ' Include code examples and documentation.'
594
- }
595
- }
596
-
597
- if target_cli.lower() in cli_specific_adjustments:
598
- adjustment = cli_specific_adjustments[target_cli.lower()]
599
- return f"{adjustment['prefix']}{task}{adjustment['suffix']}"
600
-
601
- return task
602
-
603
- def _postprocess_result_from_cli(self, result: str, target_cli: str) -> str:
604
- """后处理来自特定CLI的结果"""
605
- # 根据CLI特性调整结果格式
606
- cli_specific_postprocessing = {
607
- 'claude': {
608
- 'add_source_attribution': True,
609
- 'format_response': True
610
- },
611
- 'gemini': {
612
- 'add_confidence_scores': True,
613
- 'format_response': True
614
- }
615
- }
616
-
617
- if target_cli.lower() in cli_specific_postprocessing:
618
- processing = cli_specific_postprocessing[target_cli.lower()]
619
-
620
- if processing.get('format_response', False):
621
- # 简单的响应格式化
622
- if not result.strip().endswith(('.', '!', '?')):
623
- result = result.rstrip('.') + '.'
624
-
625
- if processing.get('add_source_attribution', False):
626
- # 添加来源标注
627
- result = f"[{target_cli.upper()}]\n{result}"
628
-
629
- return result
630
-
631
- def _format_buddy_result(self, buddy_name: str, target_cli: str, task: str, result: str) -> str:
632
- """
633
- 格式化Buddy结果
634
-
635
- Args:
636
- buddy_name: Buddy名称
637
- target_cli: 目标CLI工具
638
- task: 原始任务
639
- result: 执行结果
640
-
641
- Returns:
642
- str: 格式化的结果
643
- """
644
- return f"""## [INSTALL] CodeBuddy Buddy结果
645
-
646
- **执行Buddy**: {buddy_name}
647
- **调用工具**: {target_cli.upper()}
648
- **原始任务**: {task}
649
- **执行时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
650
-
651
- ---
652
-
653
- {result}
654
-
655
- ---
656
-
657
- *此结果由CodeBuddy CLI Buddy系统提供*"""
658
-
659
- # ==================== Buddy技能注册方法 ====================
660
-
661
- async def _register_cross_cli_capabilities(self, buddy_skill: BuddySkill, handler_func: Callable) -> None:
662
- """为Buddy注册跨CLI能力"""
663
- try:
664
- # 动态添加跨CLI检测方法
665
- original_can_handle = getattr(handler_func, 'can_handle', None)
666
-
667
- async def enhanced_can_handle(context: BuddyContext, *args, **kwargs) -> float:
668
- # 优先检查跨CLI调用
669
- if context.intent and context.intent.is_cross_cli:
670
- # 检查Buddy是否支持目标CLI
671
- if (buddy_skill.cross_cli_enabled and
672
- context.intent.target_cli.lower() in [cli.lower() for cli in buddy_skill.supported_clis]):
673
- return 0.9 # 高优先级处理跨CLI调用
674
-
675
- # 如果不是跨CLI调用,调用原始方法
676
- if original_can_handle:
677
- return await original_can_handle(context, *args, **kwargs)
678
-
679
- return 0.0 # 默认不处理
680
-
681
- # 包装原始函数的can_handle方法
682
- setattr(handler_func, 'can_handle', enhanced_can_handle)
683
-
684
- except Exception as e:
685
- logger.error(f"注册跨CLI能力失败: {e}")
686
-
687
- async def _discover_buddy_modules(self) -> None:
688
- """发现和加载外部Buddy模块"""
689
- try:
690
- if not os.path.exists(self.buddy_modules_dir):
691
- logger.info("Buddy模块目录不存在,跳过发现")
692
- return
693
-
694
- # 扫描Python文件
695
- for module_file in Path(self.buddy_modules_dir).glob("*.py"):
696
- if module_file.name.startswith("__"):
697
- continue
698
-
699
- try:
700
- # 动态导入模块
701
- module_name = f"buddies.{module_file.stem}"
702
- spec = importlib.util.spec_from_file_location(module_name, module_file)
703
- module = importlib.util.module_from_spec(spec)
704
-
705
- # 查找Buddy装饰器的方法
706
- for attr_name in dir(module):
707
- attr = getattr(module, attr_name)
708
- if callable(attr) and hasattr(attr, '__wrapped__'):
709
- # 这是一个被@buddy装饰的方法
710
- original_func = attr.__wrapped__
711
-
712
- # 获取Buddy技能信息
713
- buddy_name = getattr(original_func, '_buddy_name', attr_name)
714
- if buddy_name not in self.skills_registry:
715
- # 创建默认技能信息
716
- buddy_skill = BuddySkill(
717
- name=buddy_name,
718
- description=f"外部Buddy技能: {attr_name}",
719
- capabilities=[],
720
- priority=50
721
- )
722
-
723
- # 存储原始函数引用
724
- buddy_skill.metadata['function'] = original_func.__name__
725
- buddy_skill.metadata['module'] = module_name
726
- self.skills_registry[buddy_name] = buddy_skill
727
-
728
- # 注册跨CLI能力
729
- await self._register_cross_cli_capabilities(buddy_skill, attr)
730
-
731
- self.buddy_instances[buddy_name] = attr
732
- self.active_buddies[buddy_name] = {
733
- 'module': module_name,
734
- 'instance': attr,
735
- 'last_used': datetime.now()
736
- }
737
-
738
- logger.info(f"发现并加载Buddy模块: {module_file.name}")
739
-
740
- except Exception as e:
741
- logger.error(f"加载Buddy模块 {module_file} 失败: {e}")
742
-
743
- except Exception as e:
744
- logger.error(f"Buddy模块发现失败: {e}")
745
-
746
- async def _initialize_cross_cli_system(self) -> None:
747
- """初始化跨CLI协作系统"""
748
- try:
749
- logger.info("初始化CodeBuddy跨CLI协作系统")
750
-
751
- # 设置协作会话跟踪
752
- self.collaboration_sessions = {}
753
-
754
- logger.info("跨CLI协作系统初始化完成")
755
-
756
- except Exception as e:
757
- logger.error(f"初始化跨CLI协作系统失败: {e}")
758
-
759
- # ==================== Buddy调用处理 ====================
760
-
761
- async def execute_task(self, task: str, context: Dict[str, Any]) -> str:
762
- """
763
- 执行跨CLI任务 - CodeBuddy适配器的具体实现
764
-
765
- Args:
766
- task: 要执行的任务描述
767
- context: 执行上下文信息
768
-
769
- Returns:
770
- str: 任务执行结果
771
- """
772
- try:
773
- session_id = context.get('session_id', f"task-{datetime.now().timestamp()}")
774
-
775
- # 创建Buddy上下文
776
- buddy_context = BuddyContext(
777
- session_id=session_id,
778
- user_input=task,
779
- parameters=context.get('parameters', {}),
780
- metadata=context.get('metadata', {})
781
- )
782
-
783
- # 解析意图
784
- intent = self.parser.parse_intent(task, "codebuddy")
785
- buddy_context.intent = intent
786
-
787
- # 选择最合适的Buddy
788
- selected_buddy = await self._select_best_buddy(buddy_context)
789
-
790
- if selected_buddy:
791
- # 调用选中的Buddy
792
- buddy_instance = self.active_buddies.get(selected_buddy)
793
- if buddy_instance:
794
- # 更新使用时间
795
- self.active_buddies[selected_buddy]['last_used'] = datetime.now()
796
-
797
- # 设置Buddy名称到上下文
798
- buddy_context.buddy_name = selected_buddy
799
-
800
- try:
801
- # 调用Buddy处理函数
802
- result = await buddy_instance(buddy_context)
803
-
804
- # 记录Buddy调用
805
- self.processed_requests.append({
806
- 'type': 'buddy_call',
807
- 'buddy_name': selected_buddy,
808
- 'task': task,
809
- 'session_id': session_id,
810
- 'success': True,
811
- 'result_length': len(str(result)),
812
- 'timestamp': datetime.now().isoformat()
813
- })
814
-
815
- return result
816
-
817
- except Exception as e:
818
- logger.error(f"Buddy {selected_buddy} 调用失败: {e}")
819
- self.record_error()
820
-
821
- # 记录失败
822
- self.processed_requests.append({
823
- 'type': 'buddy_call',
824
- 'buddy_name': selected_buddy,
825
- 'task': task,
826
- 'session_id': session_id,
827
- 'success': False,
828
- 'error': str(e),
829
- 'timestamp': datetime.now().isoformat()
830
- })
831
-
832
- return f"Buddy {selected_buddy} 调用失败: {str(e)}"
833
- else:
834
- # 没有合适的Buddy,使用通用助手
835
- logger.warning("没有找到合适的Buddy,使用通用助手")
836
- return await self._fallback_to_general_assistant(buddy_context)
837
-
838
- except Exception as e:
839
- logger.error(f"执行任务失败: {task}, 错误: {e}")
840
- self.record_error()
841
- return f"任务执行失败: {str(e)}"
842
-
843
- async def _select_best_buddy(self, context: BuddyContext) -> Optional[str]:
844
- """
845
- 选择最合适的Buddy
846
-
847
- Args:
848
- context: Buddy上下文
849
-
850
- Returns:
851
- Optional[str]: 选择的Buddy名称,如果没有合适的返回None
852
- """
853
- try:
854
- candidates = []
855
-
856
- for buddy_name, buddy_instance in self.active_buddies.items():
857
- try:
858
- # 检查Buddy是否愿意处理
859
- can_handle = await buddy_instance.can_handle(context)
860
- if can_handle > 0:
861
- buddy_skill = self.skills_registry.get(buddy_name)
862
- if buddy_skill:
863
- candidates.append({
864
- 'name': buddy_name,
865
- 'priority': buddy_skill.priority,
866
- 'can_handle': can_handle,
867
- 'buddy_skill': buddy_skill
868
- })
869
- except Exception as e:
870
- logger.warning(f"检查Buddy {buddy_name} 处理能力失败: {e}")
871
- continue
872
-
873
- # 如果是跨CLI调用,优先选择支持跨CLI的Buddy
874
- if context.intent and context.intent.is_cross_cli:
875
- cross_cli_candidates = [
876
- c for c in candidates
877
- if (c['buddy_skill'].cross_cli_enabled and
878
- context.intent.target_cli.lower() in [cli.lower() for cli in c['buddy_skill'].supported_clis])
879
- ]
880
- if cross_cli_candidates:
881
- # 选择优先级最高的跨CLI Buddy
882
- cross_cli_candidates.sort(key=lambda x: (x['priority'], x['can_handle']), reverse=True)
883
- return cross_cli_candidates[0]['name']
884
-
885
- # 按优先级和匹配度排序
886
- if candidates:
887
- candidates.sort(key=lambda x: (x['priority'], x['can_handle']), reverse=True)
888
- return candidates[0]['name']
889
-
890
- return None
891
-
892
- except Exception as e:
893
- logger.error(f"选择Buddy失败: {e}")
894
- return None
895
-
896
- async def _fallback_to_general_assistant(self, context: BuddyContext) -> str:
897
- """回退到通用助手"""
898
- try:
899
- # 使用内置的通用助手Buddy
900
- universal_buddy = self.active_buddies.get('universal_assistant')
901
- if universal_buddy:
902
- context.buddy_name = 'universal_assistant'
903
- return await universal_buddy(context)
904
-
905
- return "CodeBuddy: 没有可用的助手来处理这个任务"
906
-
907
- except Exception as e:
908
- logger.error(f"通用助手回退失败: {e}")
909
- return f"任务处理失败: {str(e)}"
910
-
911
- # ==================== 基础接口实现 ====================
912
-
913
- def is_available(self) -> bool:
914
- """
915
- 检查适配器是否可用
916
-
917
- Returns:
918
- bool: 是否可用
919
- """
920
- return (
921
- len(self.skills_registry) > 0 and
922
- len(self.active_buddies) > 0 and
923
- os.path.exists(self.buddy_config_file)
924
- )
925
-
926
- async def health_check(self) -> Dict[str, Any]:
927
- """
928
- 健康检查
929
-
930
- Returns:
931
- Dict[str, Any]: 健康状态
932
- """
933
- base_health = await super().health_check()
934
-
935
- codebuddy_health = {
936
- 'buddy_config_file': self.buddy_config_file,
937
- 'buddy_modules_dir': self.buddy_modules_dir,
938
- 'config_exists': os.path.exists(self.buddy_config_file),
939
- 'modules_dir_exists': os.path.exists(self.buddy_modules_dir),
940
- 'registered_skills_count': len(self.skills_registry),
941
- 'active_buddies_count': len(self.active_buddies),
942
- 'buddy_calls_count': self.buddy_calls_count,
943
- 'cross_cli_calls_count': self.cross_cli_calls_count,
944
- 'processed_requests_count': len(self.processed_requests),
945
- 'collaboration_sessions_count': len(self.collaboration_sessions),
946
- 'buddy_config': self.buddy_config.copy(),
947
- 'supported_clis': list(set().union(*[
948
- skill.supported_clis for skill in self.skills_registry.values()
949
- ])),
950
- 'enabled_buddies': list(self.skills_registry.keys())
951
- }
952
-
953
- # 检查环境
954
- try:
955
- codebuddy_health['codebuddy_environment'] = self._check_codebuddy_environment()
956
- except Exception as e:
957
- codebuddy_health['codebuddy_environment_error'] = str(e)
958
-
959
- # 检查Buddy状态
960
- try:
961
- for buddy_name, buddy_instance in self.active_buddies.items():
962
- buddy_skill = self.skills_registry.get(buddy_name)
963
- if buddy_skill:
964
- # 尝试检查Buddy是否响应
965
- if hasattr(buddy_instance, 'is_healthy'):
966
- if isinstance(buddy_instance.is_healthy, type(True)):
967
- healthy = buddy_instance.is_healthy()
968
- else:
969
- # 假设为健康
970
- healthy = True
971
- else:
972
- healthy = True
973
-
974
- codebuddy_health[f'buddy_{buddy_name}_healthy'] = healthy
975
-
976
- except Exception as e:
977
- logger.error(f"检查Buddy状态失败: {e}")
978
-
979
- # 合并基础健康信息
980
- base_health.update(codebuddy_health)
981
- return base_health
982
-
983
- def get_statistics(self) -> Dict[str, Any]:
984
- """
985
- 获取适配器统计信息
986
-
987
- Returns:
988
- Dict[str, Any]: 统计信息
989
- """
990
- base_stats = super().get_statistics()
991
-
992
- codebuddy_stats = {
993
- 'registered_skills_count': len(self.skills_registry),
994
- 'active_buddies_count': len(self.active_buddy_instances),
995
- 'buddy_calls_count': self.buddy_calls_count,
996
- 'cross_cli_calls_count': self.cross_cli_calls_count,
997
- 'processed_requests_count': len(self.processed_requests),
998
- 'collaboration_sessions_count': len(self.collaboration_sessions),
999
- 'supported_clis': list(set().union(*[
1000
- skill.supported_clis for skill in self.skills_registry.values()
1001
- ])),
1002
- 'enabled_buddies': list(self.skills_registry.keys()),
1003
- 'buddy_priorities': {
1004
- name: skill.priority for name, skill in self.skills_registry.items()
1005
- }
1006
- }
1007
-
1008
- # 计算Buddy使用统计
1009
- buddy_usage = {}
1010
- for buddy_name, buddy_info in self.active_buddies.items():
1011
- buddy_skill = self.skills_registry.get(buddy_name)
1012
- if buddy_skill:
1013
- buddy_usage[buddy_name] = {
1014
- 'calls': buddy_info.get('call_count', 0),
1015
- 'last_used': buddy_info.get('last_used'),
1016
- 'priority': buddy_skill.priority
1017
- }
1018
-
1019
- codebuddy_stats['buddy_usage'] = buddy_usage
1020
- base_stats.update(codebuddy_stats)
1021
- return base_stats
1022
-
1023
- async def cleanup(self) -> bool:
1024
- """
1025
- 清理适配器资源
1026
-
1027
- Returns:
1028
- bool: 清理是否成功
1029
- """
1030
- try:
1031
- # 清理统计信息
1032
- self.processed_requests.clear()
1033
- self.collaboration_sessions.clear()
1034
- self.buddy_calls_count = 0
1035
- self.cross_cli_calls_count = 0
1036
-
1037
- # 清理Buddy实例
1038
- self.buddy_instances.clear()
1039
- self.active_buddies.clear()
1040
-
1041
- logger.info("CodeBuddy Buddy适配器清理完成")
1042
- return True
1043
-
1044
- except Exception as e:
1045
- logger.error(f"清理CodeBuddy Buddy适配器失败: {e}")
1046
- return False
1047
-
1048
-
1049
- # 创建全局适配器实例
1050
- _global_adapter: Optional[CodeBuddyBuddyAdapter] = None
1051
-
1052
-
1053
- def get_codebuddy_buddy_adapter() -> CodeBuddyBuddyAdapter:
1054
- """
1055
- 获取CodeBuddy Buddy适配器实例
1056
-
1057
- Returns:
1058
- CodeBuddyBuddyAdapter: 适配器实例
1059
- """
1060
- global _global_adapter
1061
- if _global_adapter is None:
1062
- _global_adapter = CodeBuddyBuddyAdapter()
1063
- # 异步初始化需要在调用时进行
1064
- return _global_adapter
1065
-
1066
-
1067
- # 便捷函数
1068
- async def initialize_codebuddy_buddy_adapter() -> bool:
1069
- """
1070
- 初始化CodeBuddy Buddy适配器
1071
-
1072
- Returns:
1073
- bool: 初始化是否成功
1074
- """
1075
- adapter = get_codebuddy_buddy_adapter()
1076
- return await adapter.initialize()
1077
-
1078
-
1079
- def is_codebuddy_buddy_adapter_available() -> bool:
1080
- """
1081
- 检查CodeBuddy Buddy适配器是否可用
1082
-
1083
- Returns:
1084
- bool: 是否可用
1085
- """
1086
- adapter = get_codebuddy_buddy_adapter()
1087
- return adapter.is_available()
1088
-
1089
-
1090
- # 便捷装饰器
1091
- def register_buddy(name: str = "", description: str = "", **kwargs):
1092
- """
1093
- 便捷的Buddy注册装饰器
1094
-
1095
- Args:
1096
- name: Buddy名称
1097
- description: Buddy描述
1098
- **kwargs: 其他参数传递给@buddy装饰器
1099
- """
1100
- adapter = get_codebuddy_buddy_adapter()
1101
- return adapter.buddy(name, description, **kwargs)
1102
-
1103
-
1104
- if __name__ == "__main__":
1105
- import asyncio
1106
-
1107
- async def main():
1108
- """主函数 - 用于测试和独立运行"""
1109
- adapter = CodeBuddyBuddyAdapter()
1110
-
1111
- # 初始化
1112
- if await adapter.initialize():
1113
- print("CodeBuddy Buddy适配器初始化成功")
1114
-
1115
- # 显示统计信息
1116
- stats = adapter.get_statistics()
1117
- print("\nBuddy系统统计:")
1118
- print(f"注册技能数: {stats['registered_skills_count']}")
1119
- print(f"活动Buddy数: {stats['active_buddies_count']}")
1120
- print(f"支持的CLI工具: {', '.join(stats['supported_clis'])}")
1121
-
1122
- else:
1123
- print("CodeBuddy Buddy适配器初始化失败")
1124
-
1125
- asyncio.run(main())