stigmergy 1.0.57
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.
- package/LICENSE +19 -0
- package/README.de.md +301 -0
- package/README.en.md +301 -0
- package/README.es.md +301 -0
- package/README.fr.md +301 -0
- package/README.ja.md +301 -0
- package/README.ko.md +301 -0
- package/README.md +301 -0
- package/README.ru.md +301 -0
- package/README.zh.md +301 -0
- package/package.json +82 -0
- package/src/adapters/claude/__init__.py +13 -0
- package/src/adapters/claude/claude_skills_integration.py +609 -0
- package/src/adapters/claude/hook_adapter.py +663 -0
- package/src/adapters/claude/install_claude_integration.py +265 -0
- package/src/adapters/claude/skills_hook_adapter.py +841 -0
- package/src/adapters/claude/standalone_claude_adapter.py +384 -0
- package/src/adapters/cline/__init__.py +20 -0
- package/src/adapters/cline/config.py +108 -0
- package/src/adapters/cline/install_cline_integration.py +617 -0
- package/src/adapters/cline/mcp_server.py +713 -0
- package/src/adapters/cline/standalone_cline_adapter.py +459 -0
- package/src/adapters/codebuddy/__init__.py +13 -0
- package/src/adapters/codebuddy/buddy_adapter.py +1125 -0
- package/src/adapters/codebuddy/install_codebuddy_integration.py +279 -0
- package/src/adapters/codebuddy/skills_hook_adapter.py +672 -0
- package/src/adapters/codebuddy/skills_integration.py +395 -0
- package/src/adapters/codebuddy/standalone_codebuddy_adapter.py +403 -0
- package/src/adapters/codex/__init__.py +11 -0
- package/src/adapters/codex/base.py +46 -0
- package/src/adapters/codex/install_codex_integration.py +311 -0
- package/src/adapters/codex/mcp_server.py +493 -0
- package/src/adapters/codex/natural_language_parser.py +82 -0
- package/src/adapters/codex/slash_command_adapter.py +326 -0
- package/src/adapters/codex/standalone_codex_adapter.py +362 -0
- package/src/adapters/copilot/__init__.py +13 -0
- package/src/adapters/copilot/install_copilot_integration.py +564 -0
- package/src/adapters/copilot/mcp_adapter.py +772 -0
- package/src/adapters/copilot/mcp_server.py +168 -0
- package/src/adapters/copilot/standalone_copilot_adapter.py +114 -0
- package/src/adapters/gemini/__init__.py +13 -0
- package/src/adapters/gemini/extension_adapter.py +690 -0
- package/src/adapters/gemini/install_gemini_integration.py +257 -0
- package/src/adapters/gemini/standalone_gemini_adapter.py +366 -0
- package/src/adapters/iflow/__init__.py +7 -0
- package/src/adapters/iflow/hook_adapter.py +1038 -0
- package/src/adapters/iflow/hook_installer.py +536 -0
- package/src/adapters/iflow/install_iflow_integration.py +271 -0
- package/src/adapters/iflow/official_hook_adapter.py +1272 -0
- package/src/adapters/iflow/standalone_iflow_adapter.py +48 -0
- package/src/adapters/iflow/workflow_adapter.py +793 -0
- package/src/adapters/qoder/hook_installer.py +732 -0
- package/src/adapters/qoder/install_qoder_integration.py +265 -0
- package/src/adapters/qoder/notification_hook_adapter.py +863 -0
- package/src/adapters/qoder/standalone_qoder_adapter.py +48 -0
- package/src/adapters/qwen/__init__.py +17 -0
- package/src/adapters/qwencode/__init__.py +13 -0
- package/src/adapters/qwencode/inheritance_adapter.py +818 -0
- package/src/adapters/qwencode/install_qwencode_integration.py +276 -0
- package/src/adapters/qwencode/standalone_qwencode_adapter.py +399 -0
- package/src/atomic_collaboration_handler.py +461 -0
- package/src/cli_collaboration_agent.py +697 -0
- package/src/collaboration/hooks.py +315 -0
- package/src/core/__init__.py +21 -0
- package/src/core/ai_environment_scanner.py +331 -0
- package/src/core/base_adapter.py +220 -0
- package/src/core/cli_hook_integration.py +406 -0
- package/src/core/cross_cli_executor.py +713 -0
- package/src/core/cross_cli_mapping.py +1163 -0
- package/src/core/cross_platform_encoding.py +365 -0
- package/src/core/cross_platform_safe_cli.py +894 -0
- package/src/core/direct_cli_executor.py +805 -0
- package/src/core/direct_cli_hook_system.py +958 -0
- package/src/core/enhanced_init_processor.py +427 -0
- package/src/core/graceful_cli_executor.py +912 -0
- package/src/core/md_enhancer.py +342 -0
- package/src/core/md_generator.py +619 -0
- package/src/core/models.py +218 -0
- package/src/core/parser.py +108 -0
- package/src/core/real_cli_hook_system.py +852 -0
- package/src/core/real_cross_cli_system.py +925 -0
- package/src/core/verified_cross_cli_system.py +961 -0
- package/src/deploy.js +737 -0
- package/src/enhanced_deploy.js +303 -0
- package/src/enhanced_universal_cli_setup.py +930 -0
- package/src/kimi_wrapper.py +104 -0
- package/src/main.js +1309 -0
- package/src/shell_integration.py +398 -0
- package/src/simple-main.js +315 -0
- package/src/smart_router_creator.py +323 -0
- package/src/universal_cli_setup.py +1289 -0
- package/src/utils/__init__.py +12 -0
- package/src/utils/cli_detector.py +445 -0
- package/src/utils/file_utils.py +246 -0
|
@@ -0,0 +1,672 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CodeBuddy CLI Skills-based Hook Adapter
|
|
3
|
+
基于CodeBuddy技能系统的钩子适配器,实现技能与钩子的冗余跨CLI协同
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import asyncio
|
|
7
|
+
import json
|
|
8
|
+
import logging
|
|
9
|
+
import os
|
|
10
|
+
import subprocess
|
|
11
|
+
import sys
|
|
12
|
+
import time
|
|
13
|
+
from typing import Dict, List, Optional, Any, Callable
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from dataclasses import dataclass
|
|
16
|
+
from enum import Enum
|
|
17
|
+
|
|
18
|
+
from ..base_adapter import BaseAdapter
|
|
19
|
+
from ..core.unified_intent_parser import UnifiedIntentParser
|
|
20
|
+
from ...core.config_manager import ConfigManager
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class HookType(Enum):
|
|
26
|
+
"""CodeBuddy Hook类型"""
|
|
27
|
+
PRE_COMMAND = "pre_command"
|
|
28
|
+
POST_COMMAND = "post_command"
|
|
29
|
+
ERROR = "error"
|
|
30
|
+
SESSION_START = "session_start"
|
|
31
|
+
SESSION_END = "session_end"
|
|
32
|
+
SKILL_REGISTER = "skill_register"
|
|
33
|
+
CROSS_CLI_REQUEST = "cross_cli_request"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class HookEvent:
|
|
38
|
+
"""Hook事件数据"""
|
|
39
|
+
hook_type: HookType
|
|
40
|
+
command: str = ""
|
|
41
|
+
session_id: str = ""
|
|
42
|
+
user_id: str = ""
|
|
43
|
+
context: Dict[str, Any] = None
|
|
44
|
+
timestamp: float = None
|
|
45
|
+
|
|
46
|
+
def __post_init__(self):
|
|
47
|
+
if self.context is None:
|
|
48
|
+
self.context = {}
|
|
49
|
+
if self.timestamp is None:
|
|
50
|
+
self.timestamp = time.time()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class SkillConfig:
|
|
55
|
+
"""技能配置"""
|
|
56
|
+
name: str
|
|
57
|
+
description: str = ""
|
|
58
|
+
capabilities: List[str] = None
|
|
59
|
+
priority: int = 50
|
|
60
|
+
protocols: List[str] = None
|
|
61
|
+
hooks: List[HookType] = None
|
|
62
|
+
enabled: bool = True
|
|
63
|
+
|
|
64
|
+
def __post_init__(self):
|
|
65
|
+
if self.capabilities is None:
|
|
66
|
+
self.capabilities = []
|
|
67
|
+
if self.protocols is None:
|
|
68
|
+
self.protocols = ["chinese", "english"]
|
|
69
|
+
if self.hooks is None:
|
|
70
|
+
self.hooks = []
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class Skill:
|
|
74
|
+
"""技能基类"""
|
|
75
|
+
def __init__(self, config: SkillConfig):
|
|
76
|
+
self.config = config
|
|
77
|
+
self.registered_hooks = {}
|
|
78
|
+
self.active = False
|
|
79
|
+
|
|
80
|
+
def register_hook(self, hook_type: HookType, handler: Callable):
|
|
81
|
+
"""注册钩子处理器"""
|
|
82
|
+
self.registered_hooks[hook_type] = handler
|
|
83
|
+
logger.debug(f"技能 {self.config.name} 注册钩子: {hook_type.value}")
|
|
84
|
+
|
|
85
|
+
async def trigger_hook(self, event: HookEvent) -> Any:
|
|
86
|
+
"""触发钩子"""
|
|
87
|
+
handler = self.registered_hooks.get(event.hook_type)
|
|
88
|
+
if handler:
|
|
89
|
+
try:
|
|
90
|
+
return await handler(event)
|
|
91
|
+
except Exception as e:
|
|
92
|
+
logger.error(f"钩子处理失败 {event.hook_type.value}: {e}")
|
|
93
|
+
return None
|
|
94
|
+
return None
|
|
95
|
+
|
|
96
|
+
async def activate(self):
|
|
97
|
+
"""激活技能"""
|
|
98
|
+
self.active = True
|
|
99
|
+
logger.info(f"技能 {self.config.name} 已激活")
|
|
100
|
+
|
|
101
|
+
async def deactivate(self):
|
|
102
|
+
"""停用技能"""
|
|
103
|
+
self.active = False
|
|
104
|
+
logger.info(f"技能 {self.config.name} 已停用")
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class CodeBuddySkillsHookAdapter(BaseAdapter):
|
|
108
|
+
"""
|
|
109
|
+
CodeBuddy CLI Skills-based Hook Adapter
|
|
110
|
+
基于技能和钩子的冗余跨CLI协同适配器
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
def __init__(self, config_manager: ConfigManager):
|
|
114
|
+
super().__init__("codebuddy", config_manager)
|
|
115
|
+
self.parser = UnifiedIntentParser()
|
|
116
|
+
|
|
117
|
+
# 技能系统
|
|
118
|
+
self.skills = {}
|
|
119
|
+
self.skill_configs = {}
|
|
120
|
+
self.hook_registry = {hook_type: [] for hook_type in HookType}
|
|
121
|
+
|
|
122
|
+
# 钩子系统
|
|
123
|
+
self.hooks_enabled = True
|
|
124
|
+
self.hook_fallback_enabled = True
|
|
125
|
+
|
|
126
|
+
# 跨CLI协同
|
|
127
|
+
self.cross_cli_skills = {}
|
|
128
|
+
self.active_collaborations = {}
|
|
129
|
+
|
|
130
|
+
# 会话管理
|
|
131
|
+
self.session_hooks = {}
|
|
132
|
+
|
|
133
|
+
# 配置
|
|
134
|
+
self._load_config()
|
|
135
|
+
self._setup_builtin_skills()
|
|
136
|
+
self._setup_hook_system()
|
|
137
|
+
|
|
138
|
+
logger.info("CodeBuddy Skills-Hook Adapter 初始化完成")
|
|
139
|
+
|
|
140
|
+
def _load_config(self):
|
|
141
|
+
"""加载配置"""
|
|
142
|
+
try:
|
|
143
|
+
config_path = Path(__file__).parent / "config.json"
|
|
144
|
+
if config_path.exists():
|
|
145
|
+
with open(config_path, 'r', encoding='utf-8') as f:
|
|
146
|
+
config = json.load(f)
|
|
147
|
+
|
|
148
|
+
self.hooks_enabled = config.get("hooks", {}).get("enabled", True)
|
|
149
|
+
self.hook_fallback_enabled = config.get("hooks", {}).get("fallback_enabled", True)
|
|
150
|
+
|
|
151
|
+
# 加载技能配置
|
|
152
|
+
for skill_config in config.get("skills", []):
|
|
153
|
+
skill_obj = SkillConfig(**skill_config)
|
|
154
|
+
self.skill_configs[skill_obj.name] = skill_obj
|
|
155
|
+
|
|
156
|
+
except Exception as e:
|
|
157
|
+
logger.warning(f"加载CodeBuddy配置失败: {e}")
|
|
158
|
+
|
|
159
|
+
def _setup_builtin_skills(self):
|
|
160
|
+
"""设置内置技能"""
|
|
161
|
+
# 技能1: 跨CLI协调器
|
|
162
|
+
cross_cli_config = SkillConfig(
|
|
163
|
+
name="cross_cli_coordinator",
|
|
164
|
+
description="跨CLI协调器 - 通过钩子系统协调不同AI CLI工具",
|
|
165
|
+
capabilities=["跨CLI调用协调", "多工具协作", "钩子路由", "冗余处理"],
|
|
166
|
+
priority=100,
|
|
167
|
+
hooks=[HookType.CROSS_CLI_REQUEST, HookType.PRE_COMMAND],
|
|
168
|
+
protocols=["chinese", "english"]
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
cross_cli_skill = Skill(cross_cli_config)
|
|
172
|
+
|
|
173
|
+
# 注册钩子处理器
|
|
174
|
+
async def handle_cross_cli_request(event: HookEvent):
|
|
175
|
+
"""处理跨CLI请求钩子"""
|
|
176
|
+
return await self._handle_cross_cli_request(event)
|
|
177
|
+
|
|
178
|
+
async def handle_pre_command(event: HookEvent):
|
|
179
|
+
"""处理命令前钩子 - 冗余检测"""
|
|
180
|
+
if self._should_handle_cross_cli(event.command):
|
|
181
|
+
return await self._redundant_cross_cli_detection(event)
|
|
182
|
+
return None
|
|
183
|
+
|
|
184
|
+
cross_cli_skill.register_hook(HookType.CROSS_CLI_REQUEST, handle_cross_cli_request)
|
|
185
|
+
cross_cli_skill.register_hook(HookType.PRE_COMMAND, handle_pre_command)
|
|
186
|
+
|
|
187
|
+
self.skills[cross_cli_config.name] = cross_cli_skill
|
|
188
|
+
self.cross_cli_skills[cross_cli_config.name] = cross_cli_skill
|
|
189
|
+
|
|
190
|
+
# 技能2: 错误恢复专家
|
|
191
|
+
error_recovery_config = SkillConfig(
|
|
192
|
+
name="error_recovery_expert",
|
|
193
|
+
description="错误恢复专家 - 处理跨CLI调用失败并自动恢复",
|
|
194
|
+
capabilities=["错误检测", "自动恢复", "回退机制", "状态重置"],
|
|
195
|
+
priority=90,
|
|
196
|
+
hooks=[HookType.ERROR, HookType.POST_COMMAND]
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
error_recovery_skill = Skill(error_recovery_config)
|
|
200
|
+
|
|
201
|
+
async def handle_error(event: HookEvent):
|
|
202
|
+
"""处理错误钩子"""
|
|
203
|
+
return await self._handle_cross_cli_error(event)
|
|
204
|
+
|
|
205
|
+
async def handle_post_command(event: HookEvent):
|
|
206
|
+
"""处理命令后钩子 - 验证结果"""
|
|
207
|
+
return await self._verify_cross_cli_result(event)
|
|
208
|
+
|
|
209
|
+
error_recovery_skill.register_hook(HookType.ERROR, handle_error)
|
|
210
|
+
error_recovery_skill.register_hook(HookType.POST_COMMAND, handle_post_command)
|
|
211
|
+
|
|
212
|
+
self.skills[error_recovery_config.name] = error_recovery_skill
|
|
213
|
+
|
|
214
|
+
# 技能3: 会话监控器
|
|
215
|
+
session_monitor_config = SkillConfig(
|
|
216
|
+
name="session_monitor",
|
|
217
|
+
description="会话监控器 - 管理跨CLI会话生命周期",
|
|
218
|
+
capabilities=["会话管理", "状态监控", "生命周期跟踪"],
|
|
219
|
+
priority=80,
|
|
220
|
+
hooks=[HookType.SESSION_START, HookType.SESSION_END, HookType.SKILL_REGISTER]
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
session_monitor_skill = Skill(session_monitor_config)
|
|
224
|
+
|
|
225
|
+
async def handle_session_start(event: HookEvent):
|
|
226
|
+
"""处理会话开始钩子"""
|
|
227
|
+
return await self._setup_session_hooks(event)
|
|
228
|
+
|
|
229
|
+
async def handle_session_end(event: HookEvent):
|
|
230
|
+
"""处理会话结束钩子"""
|
|
231
|
+
return await self._cleanup_session_hooks(event)
|
|
232
|
+
|
|
233
|
+
async def handle_skill_register(event: HookEvent):
|
|
234
|
+
"""处理技能注册钩子"""
|
|
235
|
+
return await self._register_skill_hooks(event)
|
|
236
|
+
|
|
237
|
+
session_monitor_skill.register_hook(HookType.SESSION_START, handle_session_start)
|
|
238
|
+
session_monitor_skill.register_hook(HookType.SESSION_END, handle_session_end)
|
|
239
|
+
session_monitor_skill.register_hook(HookType.SKILL_REGISTER, handle_skill_register)
|
|
240
|
+
|
|
241
|
+
self.skills[session_monitor_config.name] = session_monitor_skill
|
|
242
|
+
|
|
243
|
+
# 激活所有技能
|
|
244
|
+
for skill in self.skills.values():
|
|
245
|
+
asyncio.create_task(skill.activate())
|
|
246
|
+
|
|
247
|
+
def _setup_hook_system(self):
|
|
248
|
+
"""设置钩子系统"""
|
|
249
|
+
# 注册钩子到全局钩子注册表
|
|
250
|
+
for skill in self.skills.values():
|
|
251
|
+
for hook_type in skill.config.hooks:
|
|
252
|
+
if hook_type in skill.registered_hooks:
|
|
253
|
+
self.hook_registry[hook_type].append(skill)
|
|
254
|
+
|
|
255
|
+
logger.info(f"钩子系统设置完成,注册钩子: {list(self.hook_registry.keys())}")
|
|
256
|
+
|
|
257
|
+
async def trigger_hooks(self, hook_type: HookType, event: HookEvent) -> List[Any]:
|
|
258
|
+
"""触发所有相关钩子"""
|
|
259
|
+
if not self.hooks_enabled:
|
|
260
|
+
return []
|
|
261
|
+
|
|
262
|
+
results = []
|
|
263
|
+
skills = self.hook_registry.get(hook_type, [])
|
|
264
|
+
|
|
265
|
+
# 按优先级排序
|
|
266
|
+
skills.sort(key=lambda s: s.config.priority, reverse=True)
|
|
267
|
+
|
|
268
|
+
for skill in skills:
|
|
269
|
+
if skill.active:
|
|
270
|
+
try:
|
|
271
|
+
result = await skill.trigger_hook(event)
|
|
272
|
+
if result is not None:
|
|
273
|
+
results.append(result)
|
|
274
|
+
except Exception as e:
|
|
275
|
+
logger.error(f"技能 {skill.config.name} 钩子执行失败: {e}")
|
|
276
|
+
|
|
277
|
+
return results
|
|
278
|
+
|
|
279
|
+
async def _handle_cross_cli_request(self, event: HookEvent) -> Optional[str]:
|
|
280
|
+
"""处理跨CLI请求钩子"""
|
|
281
|
+
try:
|
|
282
|
+
command = event.command
|
|
283
|
+
user_prompt = command
|
|
284
|
+
|
|
285
|
+
logger.info(f"跨CLI请求钩子触发: {user_prompt}")
|
|
286
|
+
|
|
287
|
+
# 解析跨CLI意图
|
|
288
|
+
intent = self.parser.parse_intent(user_prompt, "codebuddy")
|
|
289
|
+
|
|
290
|
+
if intent.is_cross_cli and intent.target_cli != self.cli_name:
|
|
291
|
+
# 技能处理方式
|
|
292
|
+
result1 = await self._execute_cross_cli_via_skills(intent, event)
|
|
293
|
+
|
|
294
|
+
# 钩子处理方式(冗余)
|
|
295
|
+
result2 = await self._execute_cross_cli_via_hooks(intent, event)
|
|
296
|
+
|
|
297
|
+
# 选择最佳结果
|
|
298
|
+
return self._select_best_result(result1, result2)
|
|
299
|
+
|
|
300
|
+
except Exception as e:
|
|
301
|
+
logger.error(f"处理跨CLI请求钩子失败: {e}")
|
|
302
|
+
return None
|
|
303
|
+
|
|
304
|
+
async def _execute_cross_cli_via_skills(self, intent, event: HookEvent) -> Optional[str]:
|
|
305
|
+
"""通过技能系统执行跨CLI调用"""
|
|
306
|
+
try:
|
|
307
|
+
# 触发跨CLI技能
|
|
308
|
+
cross_cli_event = HookEvent(
|
|
309
|
+
hook_type=HookType.CROSS_CLI_REQUEST,
|
|
310
|
+
command=f"call {intent.target_cli} for {intent.task}",
|
|
311
|
+
session_id=event.session_id,
|
|
312
|
+
context={"intent": intent.__dict__}
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
results = await self.trigger_hooks(HookType.CROSS_CLI_REQUEST, cross_cli_event)
|
|
316
|
+
|
|
317
|
+
if results:
|
|
318
|
+
return results[0] # 返回第一个有效结果
|
|
319
|
+
|
|
320
|
+
except Exception as e:
|
|
321
|
+
logger.error(f"技能系统跨CLI调用失败: {e}")
|
|
322
|
+
|
|
323
|
+
return None
|
|
324
|
+
|
|
325
|
+
async def _execute_cross_cli_via_hooks(self, intent, event: HookEvent) -> Optional[str]:
|
|
326
|
+
"""通过钩子系统执行跨CLI调用"""
|
|
327
|
+
try:
|
|
328
|
+
# 创建临时钩子事件
|
|
329
|
+
hook_event = HookEvent(
|
|
330
|
+
hook_type=HookType.PRE_COMMAND,
|
|
331
|
+
command=f"use {intent.target_cli} to {intent.task}",
|
|
332
|
+
session_id=event.session_id,
|
|
333
|
+
context={"original_event": event.__dict__}
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
results = await self.trigger_hooks(HookType.PRE_COMMAND, hook_event)
|
|
337
|
+
|
|
338
|
+
if results:
|
|
339
|
+
return results[0]
|
|
340
|
+
|
|
341
|
+
except Exception as e:
|
|
342
|
+
logger.error(f"钩子系统跨CLI调用失败: {e}")
|
|
343
|
+
|
|
344
|
+
return None
|
|
345
|
+
|
|
346
|
+
def _select_best_result(self, result1: Optional[str], result2: Optional[str]) -> Optional[str]:
|
|
347
|
+
"""选择最佳结果"""
|
|
348
|
+
# 简单的结果选择逻辑
|
|
349
|
+
if result1 and result2:
|
|
350
|
+
# 选择长度更长且包含成功标记的结果
|
|
351
|
+
if "[OK]" in result1 or "成功" in result1:
|
|
352
|
+
return result1
|
|
353
|
+
elif "[OK]" in result2 or "成功" in result2:
|
|
354
|
+
return result2
|
|
355
|
+
return result1 if len(result1) > len(result2) else result2
|
|
356
|
+
elif result1:
|
|
357
|
+
return result1
|
|
358
|
+
elif result2:
|
|
359
|
+
return result2
|
|
360
|
+
return None
|
|
361
|
+
|
|
362
|
+
async def _redundant_cross_cli_detection(self, event: HookEvent) -> Optional[str]:
|
|
363
|
+
"""冗余跨CLI检测"""
|
|
364
|
+
try:
|
|
365
|
+
command = event.command
|
|
366
|
+
|
|
367
|
+
# 多种检测方式
|
|
368
|
+
detection_methods = [
|
|
369
|
+
self._detect_via_patterns(command),
|
|
370
|
+
self._detect_via_keywords(command),
|
|
371
|
+
self._detect_via_structure(command)
|
|
372
|
+
]
|
|
373
|
+
|
|
374
|
+
# 如果任一方法检测到跨CLI意图
|
|
375
|
+
for detected_intent in detection_methods:
|
|
376
|
+
if detected_intent:
|
|
377
|
+
logger.info(f"冗余检测到跨CLI意图: {detected_intent}")
|
|
378
|
+
|
|
379
|
+
# 创建跨CLI事件
|
|
380
|
+
cross_cli_event = HookEvent(
|
|
381
|
+
hook_type=HookType.CROSS_CLI_REQUEST,
|
|
382
|
+
command=detected_intent["command"],
|
|
383
|
+
session_id=event.session_id,
|
|
384
|
+
context={"detection_method": detected_intent["method"]}
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
results = await self.trigger_hooks(HookType.CROSS_CLI_REQUEST, cross_cli_event)
|
|
388
|
+
if results:
|
|
389
|
+
return results[0]
|
|
390
|
+
|
|
391
|
+
except Exception as e:
|
|
392
|
+
logger.error(f"冗余跨CLI检测失败: {e}")
|
|
393
|
+
|
|
394
|
+
return None
|
|
395
|
+
|
|
396
|
+
def _detect_via_patterns(self, command: str) -> Optional[Dict]:
|
|
397
|
+
"""通过模式检测"""
|
|
398
|
+
patterns = [
|
|
399
|
+
r"用(.*)帮我(.*)",
|
|
400
|
+
r"call (.*) to (.*)",
|
|
401
|
+
r"让(.*)处理(.*)",
|
|
402
|
+
r"use (.*) for (.*)"
|
|
403
|
+
]
|
|
404
|
+
|
|
405
|
+
import re
|
|
406
|
+
for pattern in patterns:
|
|
407
|
+
match = re.search(pattern, command, re.IGNORECASE)
|
|
408
|
+
if match:
|
|
409
|
+
cli, task = match.groups()
|
|
410
|
+
supported_clis = ["claude", "gemini", "qwencode", "iflow", "qoder", "codex"]
|
|
411
|
+
if cli.lower() in supported_clis:
|
|
412
|
+
return {
|
|
413
|
+
"command": command,
|
|
414
|
+
"target_cli": cli.lower(),
|
|
415
|
+
"task": task,
|
|
416
|
+
"method": "pattern_detection"
|
|
417
|
+
}
|
|
418
|
+
return None
|
|
419
|
+
|
|
420
|
+
def _detect_via_keywords(self, command: str) -> Optional[Dict]:
|
|
421
|
+
"""通过关键词检测"""
|
|
422
|
+
keywords = {
|
|
423
|
+
"claude": ["claude", "克劳德"],
|
|
424
|
+
"gemini": ["gemini", "杰米尼"],
|
|
425
|
+
"qwencode": ["qwencode", "qwen"],
|
|
426
|
+
"iflow": ["iflow"],
|
|
427
|
+
"qoder": ["qoder"],
|
|
428
|
+
"codex": ["codex", "代码"]
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
command_lower = command.lower()
|
|
432
|
+
for cli, cli_keywords in keywords.items():
|
|
433
|
+
for keyword in cli_keywords:
|
|
434
|
+
if keyword in command_lower:
|
|
435
|
+
return {
|
|
436
|
+
"command": command,
|
|
437
|
+
"target_cli": cli,
|
|
438
|
+
"task": command, # 整个命令作为任务
|
|
439
|
+
"method": "keyword_detection"
|
|
440
|
+
}
|
|
441
|
+
return None
|
|
442
|
+
|
|
443
|
+
def _detect_via_structure(self, command: str) -> Optional[Dict]:
|
|
444
|
+
"""通过结构检测"""
|
|
445
|
+
# 检测特定的句子结构
|
|
446
|
+
if "帮我" in command or "help me" in command.lower():
|
|
447
|
+
words = command.split()
|
|
448
|
+
for i, word in enumerate(words):
|
|
449
|
+
if word.lower() in ["claude", "gemini", "qwencode", "iflow", "qoder", "codex"]:
|
|
450
|
+
return {
|
|
451
|
+
"command": command,
|
|
452
|
+
"target_cli": word.lower(),
|
|
453
|
+
"task": " ".join(words[i+1:]),
|
|
454
|
+
"method": "structure_detection"
|
|
455
|
+
}
|
|
456
|
+
return None
|
|
457
|
+
|
|
458
|
+
async def _handle_cross_cli_error(self, event: HookEvent) -> Optional[str]:
|
|
459
|
+
"""处理跨CLI错误"""
|
|
460
|
+
try:
|
|
461
|
+
error_context = event.context
|
|
462
|
+
if error_context.get("cross_cli_failed"):
|
|
463
|
+
# 尝试回退方案
|
|
464
|
+
fallback_result = await self._try_fallback_solution(event)
|
|
465
|
+
return fallback_result
|
|
466
|
+
except Exception as e:
|
|
467
|
+
logger.error(f"处理跨CLI错误失败: {e}")
|
|
468
|
+
return None
|
|
469
|
+
|
|
470
|
+
async def _try_fallback_solution(self, event: HookEvent) -> Optional[str]:
|
|
471
|
+
"""尝试回退方案"""
|
|
472
|
+
try:
|
|
473
|
+
# 1. 尝试其他CLI工具
|
|
474
|
+
# 2. 使用本地处理
|
|
475
|
+
# 3. 简化任务重新尝试
|
|
476
|
+
|
|
477
|
+
return f"⚠️ 跨CLI调用失败,已启用回退方案处理"
|
|
478
|
+
|
|
479
|
+
except Exception as e:
|
|
480
|
+
logger.error(f"回退方案执行失败: {e}")
|
|
481
|
+
return None
|
|
482
|
+
|
|
483
|
+
async def _verify_cross_cli_result(self, event: HookEvent) -> Optional[str]:
|
|
484
|
+
"""验证跨CLI结果"""
|
|
485
|
+
try:
|
|
486
|
+
result = event.context.get("result")
|
|
487
|
+
if result and self._is_cross_cli_result(result):
|
|
488
|
+
# 验证结果质量
|
|
489
|
+
if self._validate_result_quality(result):
|
|
490
|
+
return "[OK] 跨CLI结果验证通过"
|
|
491
|
+
else:
|
|
492
|
+
return "⚠️ 跨CLI结果质量不佳,建议重新执行"
|
|
493
|
+
except Exception as e:
|
|
494
|
+
logger.error(f"验证跨CLI结果失败: {e}")
|
|
495
|
+
return None
|
|
496
|
+
|
|
497
|
+
def _is_cross_cli_result(self, result: str) -> bool:
|
|
498
|
+
"""判断是否为跨CLI结果"""
|
|
499
|
+
indicators = ["调用", "called", "执行", "executed", "via", "通过"]
|
|
500
|
+
return any(indicator in result for indicator in indicators)
|
|
501
|
+
|
|
502
|
+
def _validate_result_quality(self, result: str) -> bool:
|
|
503
|
+
"""验证结果质量"""
|
|
504
|
+
# 简单的质量检查
|
|
505
|
+
if len(result) < 10:
|
|
506
|
+
return False
|
|
507
|
+
if result.count("错误") > 2 or result.count("error") > 2:
|
|
508
|
+
return False
|
|
509
|
+
return True
|
|
510
|
+
|
|
511
|
+
async def _setup_session_hooks(self, event: HookEvent) -> Optional[str]:
|
|
512
|
+
"""设置会话钩子"""
|
|
513
|
+
session_id = event.session_id or f"session_{int(time.time())}"
|
|
514
|
+
self.session_hooks[session_id] = {
|
|
515
|
+
"start_time": time.time(),
|
|
516
|
+
"hooks_triggered": 0,
|
|
517
|
+
"cross_cli_calls": 0
|
|
518
|
+
}
|
|
519
|
+
return f"会话 {session_id} 钩子设置完成"
|
|
520
|
+
|
|
521
|
+
async def _cleanup_session_hooks(self, event: HookEvent) -> Optional[str]:
|
|
522
|
+
"""清理会话钩子"""
|
|
523
|
+
session_id = event.session_id
|
|
524
|
+
if session_id in self.session_hooks:
|
|
525
|
+
session_info = self.session_hooks[session_id]
|
|
526
|
+
del self.session_hooks[session_id]
|
|
527
|
+
return f"会话 {session_id} 钩子清理完成,触发钩子 {session_info['hooks_triggered']} 次"
|
|
528
|
+
return None
|
|
529
|
+
|
|
530
|
+
async def _register_skill_hooks(self, event: HookEvent) -> Optional[str]:
|
|
531
|
+
"""注册技能钩子"""
|
|
532
|
+
try:
|
|
533
|
+
# 动态注册新技能的钩子
|
|
534
|
+
skill_info = event.context.get("skill_info")
|
|
535
|
+
if skill_info:
|
|
536
|
+
# 处理技能注册
|
|
537
|
+
return f"技能 {skill_info.get('name')} 钩子注册完成"
|
|
538
|
+
except Exception as e:
|
|
539
|
+
logger.error(f"注册技能钩子失败: {e}")
|
|
540
|
+
return None
|
|
541
|
+
|
|
542
|
+
def _should_handle_cross_cli(self, command: str) -> bool:
|
|
543
|
+
"""判断是否应该处理跨CLI调用"""
|
|
544
|
+
return self._detect_via_patterns(command) is not None or \
|
|
545
|
+
self._detect_via_keywords(command) is not None
|
|
546
|
+
|
|
547
|
+
async def handle_message(self, message: str, user_id: str = None, session_id: str = None) -> Optional[str]:
|
|
548
|
+
"""CodeBuddy消息处理 - 技能与钩子冗余处理"""
|
|
549
|
+
try:
|
|
550
|
+
# 创建钩子事件
|
|
551
|
+
event = HookEvent(
|
|
552
|
+
hook_type=HookType.PRE_COMMAND,
|
|
553
|
+
command=message,
|
|
554
|
+
session_id=session_id,
|
|
555
|
+
user_id=user_id
|
|
556
|
+
)
|
|
557
|
+
|
|
558
|
+
# 触发前置钩子
|
|
559
|
+
pre_results = await self.trigger_hooks(HookType.PRE_COMMAND, event)
|
|
560
|
+
|
|
561
|
+
# 如果前置钩子处理了跨CLI调用
|
|
562
|
+
if pre_results:
|
|
563
|
+
return pre_results[0]
|
|
564
|
+
|
|
565
|
+
# 如果不是跨CLI调用,返回None让CodeBuddy正常处理
|
|
566
|
+
return None
|
|
567
|
+
|
|
568
|
+
except Exception as e:
|
|
569
|
+
logger.error(f"CodeBuddy消息处理失败: {e}")
|
|
570
|
+
return None
|
|
571
|
+
|
|
572
|
+
async def process_response(self, response: str, session_id: str = None) -> str:
|
|
573
|
+
"""处理CodeBuddy响应"""
|
|
574
|
+
try:
|
|
575
|
+
# 创建后置钩子事件
|
|
576
|
+
event = HookEvent(
|
|
577
|
+
hook_type=HookType.POST_COMMAND,
|
|
578
|
+
context={"result": response},
|
|
579
|
+
session_id=session_id
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
# 触发后置钩子
|
|
583
|
+
post_results = await self.trigger_hooks(HookType.POST_COMMAND, event)
|
|
584
|
+
|
|
585
|
+
# 如果后置钩子有处理结果
|
|
586
|
+
if post_results:
|
|
587
|
+
return f"{response}\n\n{post_results[0]}"
|
|
588
|
+
|
|
589
|
+
return response
|
|
590
|
+
|
|
591
|
+
except Exception as e:
|
|
592
|
+
logger.error(f"CodeBuddy响应处理失败: {e}")
|
|
593
|
+
return response
|
|
594
|
+
|
|
595
|
+
async def handle_error(self, error: Exception, context: Dict[str, Any] = None) -> Optional[str]:
|
|
596
|
+
"""处理CodeBuddy错误"""
|
|
597
|
+
try:
|
|
598
|
+
# 创建错误钩子事件
|
|
599
|
+
event = HookEvent(
|
|
600
|
+
hook_type=HookType.ERROR,
|
|
601
|
+
context={"error": str(error), "context": context or {}}
|
|
602
|
+
)
|
|
603
|
+
|
|
604
|
+
# 触发错误钩子
|
|
605
|
+
error_results = await self.trigger_hooks(HookType.ERROR, event)
|
|
606
|
+
|
|
607
|
+
if error_results:
|
|
608
|
+
return error_results[0]
|
|
609
|
+
|
|
610
|
+
return None
|
|
611
|
+
|
|
612
|
+
except Exception as e:
|
|
613
|
+
logger.error(f"CodeBuddy错误处理失败: {e}")
|
|
614
|
+
return None
|
|
615
|
+
|
|
616
|
+
async def register_external_skill(self, skill_name: str, skill_config: Dict[str, Any]) -> bool:
|
|
617
|
+
"""注册外部技能"""
|
|
618
|
+
try:
|
|
619
|
+
config = SkillConfig(name=skill_name, **skill_config)
|
|
620
|
+
skill = Skill(config)
|
|
621
|
+
|
|
622
|
+
# 激活技能
|
|
623
|
+
await skill.activate()
|
|
624
|
+
|
|
625
|
+
# 注册到系统
|
|
626
|
+
self.skills[skill_name] = skill
|
|
627
|
+
|
|
628
|
+
# 更新钩子注册表
|
|
629
|
+
for hook_type in config.hooks:
|
|
630
|
+
self.hook_registry[hook_type].append(skill)
|
|
631
|
+
|
|
632
|
+
# 触发技能注册钩子
|
|
633
|
+
event = HookEvent(
|
|
634
|
+
hook_type=HookType.SKILL_REGISTER,
|
|
635
|
+
context={"skill_info": {"name": skill_name, "config": skill_config}}
|
|
636
|
+
)
|
|
637
|
+
|
|
638
|
+
await self.trigger_hooks(HookType.SKILL_REGISTER, event)
|
|
639
|
+
|
|
640
|
+
logger.info(f"外部技能 {skill_name} 注册成功")
|
|
641
|
+
return True
|
|
642
|
+
|
|
643
|
+
except Exception as e:
|
|
644
|
+
logger.error(f"注册外部技能失败: {e}")
|
|
645
|
+
return False
|
|
646
|
+
|
|
647
|
+
def get_system_status(self) -> Dict[str, Any]:
|
|
648
|
+
"""获取系统状态"""
|
|
649
|
+
active_skills = [name for name, skill in self.skills.items() if skill.active]
|
|
650
|
+
hook_counts = {hook_type.value: len(skills) for hook_type, skills in self.hook_registry.items()}
|
|
651
|
+
|
|
652
|
+
return {
|
|
653
|
+
"adapter_type": "CodeBuddy Skills-Hook",
|
|
654
|
+
"active_skills": active_skills,
|
|
655
|
+
"total_skills": len(self.skills),
|
|
656
|
+
"hook_counts": hook_counts,
|
|
657
|
+
"hooks_enabled": self.hooks_enabled,
|
|
658
|
+
"fallback_enabled": self.hook_fallback_enabled,
|
|
659
|
+
"active_sessions": len(self.session_hooks),
|
|
660
|
+
"cross_cli_skills": list(self.cross_cli_skills.keys())
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
async def cleanup(self):
|
|
664
|
+
"""清理资源"""
|
|
665
|
+
# 停用所有技能
|
|
666
|
+
for skill in self.skills.values():
|
|
667
|
+
await skill.deactivate()
|
|
668
|
+
|
|
669
|
+
# 清理会话钩子
|
|
670
|
+
self.session_hooks.clear()
|
|
671
|
+
|
|
672
|
+
logger.info("CodeBuddy Skills-Hook Adapter 资源清理完成")
|