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,1038 +0,0 @@
1
- """
2
- iFlow CLI Hook适配器 - 基于iFlow CLI官方Hook系统的原生集成
3
-
4
- 这是TDD驱动的实现,基于test_iflow_adapter.py中的测试用例
5
- 完全符合项目约束条件:
6
- - 使用iFlow CLI官方Hook机制
7
- - 不改变CLI启动和使用方式
8
- - 不依赖包装器
9
- - 完全无损扩展
10
- """
11
-
12
- import os
13
- import json
14
- import logging
15
- import asyncio
16
- import yaml
17
- from typing import Dict, Any, Optional, List, Callable
18
- from datetime import datetime
19
- from pathlib import Path
20
- from dataclasses import dataclass
21
-
22
- from ...core.base_adapter import BaseCrossCLIAdapter, IntentResult
23
- from ...core.parser import NaturalLanguageParser
24
-
25
- logger = logging.getLogger(__name__)
26
-
27
-
28
- @dataclass
29
- class IFlowHookContext:
30
- """iFlow CLI Hook上下文"""
31
- command: str = ""
32
- args: List[str] = None
33
- kwargs: Dict[str, Any] = None
34
- user_input: str = ""
35
- pipeline_name: str = ""
36
- workflow_id: str = ""
37
- stage_name: str = ""
38
- metadata: Dict[str, Any] = None
39
- timestamp: datetime = None
40
-
41
- def __post_init__(self):
42
- if self.args is None:
43
- self.args = []
44
- if self.kwargs is None:
45
- self.kwargs = {}
46
- if self.metadata is None:
47
- self.metadata = {}
48
- if self.timestamp is None:
49
- self.timestamp = datetime.now()
50
-
51
-
52
- @dataclass
53
- class IFlowEvent:
54
- """iFlow事件对象"""
55
- event_type: str
56
- data: Dict[str, Any]
57
- source: str
58
- timestamp: datetime
59
- context: Optional[IFlowHookContext] = None
60
-
61
-
62
- class IFlowHookAdapter(BaseCrossCLIAdapter):
63
- """
64
- iFlow CLI Hook适配器
65
-
66
- 通过iFlow CLI官方Hook系统实现跨CLI调用功能。
67
- 这是完全基于原生机制的无损扩展实现。
68
-
69
- Hook机制:
70
- - on_command_start: 命令开始执行时触发
71
- - on_command_end: 命令执行完成时触发
72
- - on_user_input: 用户输入时触发
73
- - on_workflow_stage: 工作流阶段执行时触发
74
- - on_pipeline_execute: 流水线执行时触发
75
- - on_error: 错误发生时触发
76
- """
77
-
78
- def __init__(self, cli_name: str = "iflow"):
79
- """
80
- 初始化iFlow Hook适配器
81
-
82
- Args:
83
- cli_name: CLI工具名称,默认为"iflow"
84
- """
85
- super().__init__(cli_name)
86
-
87
- # Hook相关配置
88
- self.hooks_config_file = os.path.expanduser("~/.config/iflow/hooks.yml")
89
- self.iflow_config_dir = os.path.expanduser("~/.config/iflow")
90
- self.hooks_registered = False
91
- self.hook_handlers = {
92
- 'on_command_start': self.on_command_start,
93
- 'on_command_end': self.on_command_end,
94
- 'on_user_input': self.on_user_input,
95
- 'on_workflow_stage': self.on_workflow_stage,
96
- 'on_pipeline_execute': self.on_pipeline_execute,
97
- 'on_error': self.on_error,
98
- 'on_output_render': self.on_output_render,
99
- }
100
-
101
- # 统计信息
102
- self.hook_calls_count = 0
103
- self.cross_cli_calls_count = 0
104
- self.processed_events: List[IFlowEvent] = []
105
- self.command_interceptions: List[Dict[str, Any]] = []
106
-
107
- # 配置
108
- self.hook_config: Dict[str, Any] = {}
109
- self.iflow_version = "unknown"
110
-
111
- # 组件
112
- self.parser = NaturalLanguageParser()
113
-
114
- # 事件总线
115
- self.event_listeners: Dict[str, List[Callable]] = {}
116
-
117
- # 协作状态
118
- self.collaboration_enabled = True
119
- self.active_workflows: Dict[str, Dict] = {}
120
-
121
- logger.info("iFlow Hook适配器初始化完成")
122
-
123
- async def initialize(self) -> bool:
124
- """
125
- 初始化适配器
126
-
127
- Returns:
128
- bool: 初始化是否成功
129
- """
130
- try:
131
- logger.info("开始初始化iFlow Hook适配器...")
132
-
133
- # 1. 检查iFlow CLI环境
134
- if not self._check_iflow_environment():
135
- logger.error("iFlow CLI环境检查失败")
136
- return False
137
-
138
- # 2. 加载Hook配置
139
- if not await self._load_hook_config():
140
- logger.error("Hook配置加载失败")
141
- return False
142
-
143
- # 3. 注册Hook
144
- if not await self._register_iflow_hooks():
145
- logger.error("Hook注册失败")
146
- return False
147
-
148
- # 4. 初始化事件总线
149
- if not await self._initialize_event_bus():
150
- logger.error("事件总线初始化失败")
151
- return False
152
-
153
- # 5. 创建配置目录
154
- await self._ensure_config_directory()
155
-
156
- # 6. 初始化协作系统
157
- await self._initialize_collaboration_system()
158
-
159
- self.hooks_registered = True
160
- logger.info("iFlow Hook适配器初始化成功")
161
- return True
162
-
163
- except Exception as e:
164
- logger.error(f"初始化iFlow Hook适配器失败: {e}")
165
- self.record_error()
166
- return False
167
-
168
- def _check_iflow_environment(self) -> bool:
169
- """
170
- 检查iFlow CLI环境
171
-
172
- Returns:
173
- bool: 环境是否可用
174
- """
175
- try:
176
- # 检查iFlow CLI命令是否可用
177
- import subprocess
178
- result = subprocess.run(
179
- ['iflow', '--version'],
180
- capture_output=True,
181
- text=True,
182
- timeout=5
183
- )
184
-
185
- if result.returncode == 0:
186
- self.iflow_version = result.stdout.strip()
187
- logger.info(f"检测到iFlow CLI版本: {self.iflow_version}")
188
- return True
189
- else:
190
- logger.warning("iFlow CLI命令不可用")
191
- return False
192
-
193
- except (subprocess.TimeoutExpired, FileNotFoundError) as e:
194
- logger.warning(f"iFlow CLI环境检查失败: {e}")
195
- # 在开发环境中,即使没有真实的iFlow CLI也返回True
196
- return True
197
-
198
- async def _load_hook_config(self) -> bool:
199
- """
200
- 加载Hook配置
201
-
202
- Returns:
203
- bool: 加载是否成功
204
- """
205
- try:
206
- # 读取adapter配置
207
- config_path = Path(__file__).parent / "config.json"
208
- if config_path.exists():
209
- with open(config_path, 'r', encoding='utf-8') as f:
210
- adapter_config = json.load(f)
211
- self.hook_config = adapter_config.get('hook_config', {})
212
-
213
- # 读取iFlow hooks配置
214
- if os.path.exists(self.hooks_config_file):
215
- with open(self.hooks_config_file, 'r', encoding='utf-8') as f:
216
- hooks_config = yaml.safe_load(f) or {}
217
- else:
218
- hooks_config = self._get_default_hook_config()
219
- await self._save_hook_config(hooks_config)
220
-
221
- logger.info("Hook配置加载成功")
222
- return True
223
-
224
- except Exception as e:
225
- logger.error(f"加载Hook配置失败: {e}")
226
- return False
227
-
228
- def _get_default_hook_config(self) -> Dict[str, Any]:
229
- """获取默认Hook配置"""
230
- return {
231
- "version": "1.0",
232
- "hooks": [],
233
- "plugins": [
234
- {
235
- "name": "cross-cli-adapter",
236
- "module": "src.adapters.iflow.hook_adapter",
237
- "class": "IFlowHookAdapter",
238
- "enabled": True,
239
- "priority": 100,
240
- "hooks": [
241
- "on_user_input",
242
- "on_command_start",
243
- "on_workflow_stage",
244
- "on_pipeline_execute",
245
- "on_command_end"
246
- ],
247
- "config": {
248
- "cross_cli_enabled": True,
249
- "collaboration_mode": "active",
250
- "timeout": 30,
251
- "error_handling": "continue"
252
- }
253
- }
254
- ]
255
- }
256
-
257
- async def _save_hook_config(self, config: Dict[str, Any]) -> bool:
258
- """
259
- 保存Hook配置
260
-
261
- Args:
262
- config: Hook配置
263
-
264
- Returns:
265
- bool: 保存是否成功
266
- """
267
- try:
268
- os.makedirs(os.path.dirname(self.hooks_config_file), exist_ok=True)
269
-
270
- with open(self.hooks_config_file, 'w', encoding='utf-8') as f:
271
- yaml.dump(config, f, default_flow_style=False, allow_unicode=True)
272
-
273
- logger.info(f"保存Hook配置到: {self.hooks_config_file}")
274
- return True
275
-
276
- except Exception as e:
277
- logger.error(f"保存Hook配置失败: {e}")
278
- return False
279
-
280
- async def _register_iflow_hooks(self) -> bool:
281
- """
282
- 注册Hook到iFlow CLI
283
-
284
- Returns:
285
- bool: 注册是否成功
286
- """
287
- try:
288
- # 读取现有hooks配置
289
- hooks_config = self._get_default_hook_config()
290
- if os.path.exists(self.hooks_config_file):
291
- with open(self.hooks_config_file, 'r', encoding='utf-8') as f:
292
- hooks_config = yaml.safe_load(f) or {}
293
-
294
- # 添加我们的Hook插件
295
- cross_cli_hook = {
296
- "name": "cross-cli-adapter",
297
- "module": "src.adapters.iflow.hook_adapter",
298
- "class": "IFlowHookAdapter",
299
- "enabled": True,
300
- "priority": 100,
301
- "hooks": list(self.hook_handlers.keys()),
302
- "config": self.hook_config
303
- }
304
-
305
- # 检查是否已存在
306
- plugins = hooks_config.get('plugins', [])
307
- hook_exists = any(
308
- plugin.get('name') == cross_cli_hook['name']
309
- for plugin in plugins
310
- )
311
-
312
- if not hook_exists:
313
- plugins.append(cross_cli_hook)
314
- hooks_config['plugins'] = plugins
315
-
316
- # 保存配置
317
- await self._save_hook_config(hooks_config)
318
- logger.info(f"注册Hook插件: {cross_cli_hook['name']}")
319
- else:
320
- logger.info("Hook插件已存在,跳过注册")
321
-
322
- return True
323
-
324
- except Exception as e:
325
- logger.error(f"注册Hook失败: {e}")
326
- return False
327
-
328
- async def _initialize_event_bus(self) -> bool:
329
- """
330
- 初始化事件总线
331
-
332
- Returns:
333
- bool: 初始化是否成功
334
- """
335
- try:
336
- # 初始化事件监听器
337
- self.event_listeners = {
338
- 'cross_cli_detected': [],
339
- 'workflow_started': [],
340
- 'workflow_completed': [],
341
- 'error_occurred': []
342
- }
343
-
344
- logger.info("事件总线初始化成功")
345
- return True
346
-
347
- except Exception as e:
348
- logger.error(f"初始化事件总线失败: {e}")
349
- return False
350
-
351
- async def _ensure_config_directory(self) -> None:
352
- """确保配置目录存在"""
353
- config_dirs = [
354
- self.iflow_config_dir,
355
- os.path.join(self.iflow_config_dir, "adapters"),
356
- os.path.join(self.iflow_config_dir, "hooks"),
357
- os.path.join(self.iflow_config_dir, "workflows"),
358
- os.path.join(self.iflow_config_dir, "logs")
359
- ]
360
-
361
- for config_dir in config_dirs:
362
- os.makedirs(config_dir, exist_ok=True)
363
-
364
- async def _initialize_collaboration_system(self) -> None:
365
- """初始化协作系统"""
366
- self.collaboration_enabled = True
367
- self.active_workflows = {}
368
- logger.info("协作系统初始化完成")
369
-
370
- # ==================== Hook处理器 ====================
371
-
372
- async def on_user_input(self, context: IFlowHookContext) -> Optional[str]:
373
- """
374
- 用户输入Hook处理函数
375
-
376
- 这是核心Hook,用于检测和执行跨CLI调用。
377
-
378
- Args:
379
- context: Hook上下文
380
-
381
- Returns:
382
- Optional[str]: 处理结果,如果返回None则让iFlow继续正常处理
383
- """
384
- try:
385
- self.hook_calls_count += 1
386
- user_input = context.user_input or context.command
387
-
388
- if not user_input:
389
- return None
390
-
391
- # 记录事件
392
- event = IFlowEvent(
393
- event_type="user_input",
394
- data={"input": user_input, "metadata": context.metadata},
395
- source="iflow_hook_adapter",
396
- timestamp=datetime.now(),
397
- context=context
398
- )
399
- self.processed_events.append(event)
400
-
401
- # 1. 检测是否为跨CLI调用意图
402
- intent = self.parser.parse_intent(user_input, "iflow")
403
-
404
- if not intent.is_cross_cli:
405
- # 不是跨CLI调用,让iFlow继续处理
406
- return None
407
-
408
- # 2. 避免自我调用
409
- if intent.target_cli == self.cli_name:
410
- # 目标是iFlow自己,让iFlow处理
411
- return None
412
-
413
- # 3. 触发跨CLI检测事件
414
- await self._emit_event("cross_cli_detected", {
415
- "intent": intent,
416
- "context": context
417
- })
418
-
419
- # 4. 执行跨CLI调用
420
- result = await self._execute_cross_cli_call(
421
- intent.target_cli,
422
- intent.task,
423
- context
424
- )
425
-
426
- if result:
427
- self.cross_cli_calls_count += 1
428
- return result
429
-
430
- return None
431
-
432
- except Exception as e:
433
- logger.error(f"用户输入Hook处理失败: {e}")
434
- self.record_error()
435
- return None
436
-
437
- async def on_command_start(self, context: IFlowHookContext) -> Optional[str]:
438
- """
439
- 命令开始Hook处理函数
440
-
441
- Args:
442
- context: Hook上下文
443
-
444
- Returns:
445
- Optional[str]: 处理结果
446
- """
447
- try:
448
- self.hook_calls_count += 1
449
-
450
- # 记录命令拦截
451
- interception = {
452
- 'type': 'command_start',
453
- 'command': context.command,
454
- 'args': context.args,
455
- 'timestamp': datetime.now().isoformat()
456
- }
457
- self.command_interceptions.append(interception)
458
-
459
- logger.debug(f"命令开始: {context.command}")
460
- return None
461
-
462
- except Exception as e:
463
- logger.error(f"命令开始Hook处理失败: {e}")
464
- return None
465
-
466
- async def on_command_end(self, context: IFlowHookContext, result: Any) -> Optional[str]:
467
- """
468
- 命令结束Hook处理函数
469
-
470
- Args:
471
- context: Hook上下文
472
- result: 命令执行结果
473
-
474
- Returns:
475
- Optional[str]: 处理结果
476
- """
477
- try:
478
- self.hook_calls_count += 1
479
-
480
- # 记录命令完成
481
- completion = {
482
- 'type': 'command_end',
483
- 'command': context.command,
484
- 'result_length': len(str(result)) if result else 0,
485
- 'timestamp': datetime.now().isoformat()
486
- }
487
- self.command_interceptions.append(completion)
488
-
489
- logger.debug(f"命令结束: {context.command}")
490
- return None
491
-
492
- except Exception as e:
493
- logger.error(f"命令结束Hook处理失败: {e}")
494
- return None
495
-
496
- async def on_workflow_stage(self, context: IFlowHookContext, stage_data: Dict[str, Any]) -> Optional[str]:
497
- """
498
- 工作流阶段Hook处理函数
499
-
500
- Args:
501
- context: Hook上下文
502
- stage_data: 阶段数据
503
-
504
- Returns:
505
- Optional[str]: 处理结果
506
- """
507
- try:
508
- self.hook_calls_count += 1
509
-
510
- # 更新活动工作流状态
511
- if context.workflow_id:
512
- self.active_workflows[context.workflow_id] = {
513
- 'stage': context.stage_name,
514
- 'timestamp': datetime.now().isoformat(),
515
- 'data': stage_data
516
- }
517
-
518
- # 检测跨CLI协作机会
519
- collaboration_result = await self._check_collaboration_opportunity(context, stage_data)
520
- if collaboration_result:
521
- return collaboration_result
522
-
523
- logger.debug(f"工作流阶段: {context.stage_name}")
524
- return None
525
-
526
- except Exception as e:
527
- logger.error(f"工作流阶段Hook处理失败: {e}")
528
- return None
529
-
530
- async def on_pipeline_execute(self, context: IFlowHookContext, pipeline_config: Dict[str, Any]) -> Optional[str]:
531
- """
532
- 流水线执行Hook处理函数
533
-
534
- Args:
535
- context: Hook上下文
536
- pipeline_config: 流水线配置
537
-
538
- Returns:
539
- Optional[str]: 处理结果
540
- """
541
- try:
542
- self.hook_calls_count += 1
543
-
544
- # 触发流水线执行事件
545
- await self._emit_event("pipeline_executing", {
546
- "context": context,
547
- "pipeline_config": pipeline_config
548
- })
549
-
550
- logger.debug(f"流水线执行: {context.pipeline_name}")
551
- return None
552
-
553
- except Exception as e:
554
- logger.error(f"流水线执行Hook处理失败: {e}")
555
- return None
556
-
557
- async def on_error(self, context: IFlowHookContext, error: Exception) -> Optional[str]:
558
- """
559
- 错误Hook处理函数
560
-
561
- Args:
562
- context: Hook上下文
563
- error: 错误信息
564
-
565
- Returns:
566
- Optional[str]: 处理结果
567
- """
568
- try:
569
- self.hook_calls_count += 1
570
-
571
- # 记录错误事件
572
- error_event = IFlowEvent(
573
- event_type="error",
574
- data={
575
- "error": str(error),
576
- "error_type": type(error).__name__,
577
- "context": context.__dict__
578
- },
579
- source="iflow_hook_adapter",
580
- timestamp=datetime.now()
581
- )
582
- self.processed_events.append(error_event)
583
-
584
- # 触发错误事件
585
- await self._emit_event("error_occurred", {
586
- "context": context,
587
- "error": error
588
- })
589
-
590
- logger.error(f"iFlow Hook错误: {error}")
591
- return None
592
-
593
- except Exception as e:
594
- logger.error(f"错误Hook处理失败: {e}")
595
- return None
596
-
597
- async def on_output_render(self, context: IFlowHookContext, output: str) -> Optional[str]:
598
- """
599
- 输出渲染Hook处理函数
600
-
601
- Args:
602
- context: Hook上下文
603
- output: 原始输出
604
-
605
- Returns:
606
- Optional[str]: 处理后的输出
607
- """
608
- try:
609
- self.hook_calls_count += 1
610
-
611
- # 可以在这里对输出进行后处理
612
- # 例如添加跨CLI调用的元信息
613
-
614
- return output
615
-
616
- except Exception as e:
617
- logger.error(f"输出渲染Hook处理失败: {e}")
618
- return output
619
-
620
- # ==================== 跨CLI功能 ====================
621
-
622
- async def _execute_cross_cli_call(
623
- self,
624
- target_cli: str,
625
- task: str,
626
- context: IFlowHookContext
627
- ) -> Optional[str]:
628
- """
629
- 执行跨CLI调用
630
-
631
- Args:
632
- target_cli: 目标CLI工具
633
- task: 要执行的任务
634
- context: Hook上下文
635
-
636
- Returns:
637
- Optional[str]: 执行结果
638
- """
639
- try:
640
- logger.info(f"执行跨CLI调用: {target_cli} -> {task}")
641
-
642
- # 获取目标CLI适配器
643
- from ...core.base_adapter import get_cross_cli_adapter
644
- target_adapter = get_cross_cli_adapter(target_cli)
645
-
646
- if not target_adapter:
647
- logger.warning(f"目标CLI适配器不可用: {target_cli}")
648
- return self._format_error_result(
649
- target_cli,
650
- task,
651
- f"目标CLI工具 '{target_cli}' 不可用或未安装"
652
- )
653
-
654
- if not target_adapter.is_available():
655
- logger.warning(f"目标CLI工具不可用: {target_cli}")
656
- return self._format_error_result(
657
- target_cli,
658
- task,
659
- f"目标CLI工具 '{target_cli}' 当前不可用"
660
- )
661
-
662
- # 构建执行上下文
663
- execution_context = {
664
- 'source_cli': self.cli_name,
665
- 'target_cli': target_cli,
666
- 'original_task': task,
667
- 'hook_context': context.__dict__,
668
- 'iflow_context': {
669
- 'command': context.command,
670
- 'args': context.args,
671
- 'pipeline_name': context.pipeline_name,
672
- 'workflow_id': context.workflow_id
673
- },
674
- 'timestamp': datetime.now().isoformat()
675
- }
676
-
677
- # 执行任务
678
- result = await target_adapter.execute_task(task, execution_context)
679
-
680
- # 记录成功的跨CLI调用
681
- self.processed_requests.append({
682
- 'type': 'cross_cli_execution',
683
- 'target_cli': target_cli,
684
- 'task': task,
685
- 'success': True,
686
- 'result_length': len(result),
687
- 'timestamp': datetime.now().isoformat(),
688
- 'iflow_workflow_id': context.workflow_id
689
- })
690
-
691
- # 格式化结果
692
- formatted_result = self._format_success_result(target_cli, task, result, context)
693
-
694
- logger.info(f"跨CLI调用成功: {target_cli}")
695
- return formatted_result
696
-
697
- except Exception as e:
698
- logger.error(f"跨CLI调用失败: {target_cli}, {e}")
699
- self.record_error()
700
-
701
- self.processed_requests.append({
702
- 'type': 'cross_cli_execution',
703
- 'target_cli': target_cli,
704
- 'task': task,
705
- 'success': False,
706
- 'error': str(e),
707
- 'timestamp': datetime.now().isoformat(),
708
- 'iflow_workflow_id': context.workflow_id
709
- })
710
-
711
- return self._format_error_result(target_cli, task, str(e))
712
-
713
- async def _check_collaboration_opportunity(
714
- self,
715
- context: IFlowHookContext,
716
- stage_data: Dict[str, Any]
717
- ) -> Optional[str]:
718
- """
719
- 检查协作机会
720
-
721
- Args:
722
- context: Hook上下文
723
- stage_data: 阶段数据
724
-
725
- Returns:
726
- Optional[str]: 协作结果
727
- """
728
- try:
729
- if not self.collaboration_enabled:
730
- return None
731
-
732
- # 检查是否有协作机会
733
- # 这里可以基于PROJECT_SPEC.json或其他协作机制
734
-
735
- # 简单示例:如果阶段数据包含特定标识,触发协作
736
- if stage_data.get('collaboration_request'):
737
- target_cli = stage_data.get('target_cli')
738
- collaboration_task = stage_data.get('task', '')
739
-
740
- if target_cli and target_cli != self.cli_name:
741
- return await self._execute_cross_cli_call(
742
- target_cli,
743
- collaboration_task,
744
- context
745
- )
746
-
747
- return None
748
-
749
- except Exception as e:
750
- logger.error(f"检查协作机会失败: {e}")
751
- return None
752
-
753
- # ==================== 事件系统 ====================
754
-
755
- async def _emit_event(self, event_type: str, data: Dict[str, Any]) -> None:
756
- """
757
- 触发事件
758
-
759
- Args:
760
- event_type: 事件类型
761
- data: 事件数据
762
- """
763
- try:
764
- listeners = self.event_listeners.get(event_type, [])
765
-
766
- for listener in listeners:
767
- try:
768
- if asyncio.iscoroutinefunction(listener):
769
- await listener(data)
770
- else:
771
- listener(data)
772
- except Exception as e:
773
- logger.error(f"事件监听器执行失败: {e}")
774
-
775
- except Exception as e:
776
- logger.error(f"触发事件失败: {e}")
777
-
778
- def add_event_listener(self, event_type: str, listener: Callable) -> None:
779
- """
780
- 添加事件监听器
781
-
782
- Args:
783
- event_type: 事件类型
784
- listener: 监听器函数
785
- """
786
- if event_type not in self.event_listeners:
787
- self.event_listeners[event_type] = []
788
- self.event_listeners[event_type].append(listener)
789
-
790
- # ==================== 结果格式化 ====================
791
-
792
- def _format_success_result(
793
- self,
794
- target_cli: str,
795
- task: str,
796
- result: str,
797
- context: IFlowHookContext
798
- ) -> str:
799
- """
800
- 格式化成功的跨CLI调用结果
801
-
802
- Args:
803
- target_cli: 目标CLI工具
804
- task: 原始任务
805
- result: 执行结果
806
- context: Hook上下文
807
-
808
- Returns:
809
- str: 格式化的结果
810
- """
811
- workflow_info = ""
812
- if context.workflow_id:
813
- workflow_info = f"\n**工作流ID**: {context.workflow_id}"
814
- if context.stage_name:
815
- workflow_info += f"\n**当前阶段**: {context.stage_name}"
816
-
817
- return f"""## 🔗 跨CLI调用结果 (iFlow Hook)
818
-
819
- **源工具**: iFlow CLI
820
- **目标工具**: {target_cli.upper()}
821
- **原始任务**: {task}{workflow_info}
822
- **执行时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
823
-
824
- ---
825
-
826
- {result}
827
-
828
- ---
829
-
830
- *此结果由跨CLI集成系统通过iFlow CLI Hook提供*"""
831
-
832
- def _format_error_result(
833
- self,
834
- target_cli: str,
835
- task: str,
836
- error_message: str
837
- ) -> str:
838
- """
839
- 格式化错误的跨CLI调用结果
840
-
841
- Args:
842
- target_cli: 目标CLI工具
843
- task: 原始任务
844
- error_message: 错误信息
845
-
846
- Returns:
847
- str: 格式化的错误结果
848
- """
849
- return f"""## ❌ 跨CLI调用失败
850
-
851
- **源工具**: iFlow CLI
852
- **目标工具**: {target_cli.upper()}
853
- **原始任务**: {task}
854
- **错误信息**: {error_message}
855
- **失败时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
856
-
857
- 请检查目标CLI工具是否正确安装和配置。
858
-
859
- ---
860
-
861
- *此错误由跨CLI集成系统报告*"""
862
-
863
- # ==================== 基础接口实现 ====================
864
-
865
- def is_available(self) -> bool:
866
- """
867
- 检查适配器是否可用
868
-
869
- Returns:
870
- bool: 是否可用
871
- """
872
- return (
873
- self.hooks_registered and
874
- self._check_iflow_environment() and
875
- len(self.hook_handlers) > 0
876
- )
877
-
878
- async def execute_task(self, task: str, context: Dict[str, Any]) -> str:
879
- """
880
- 执行跨CLI任务 - iFlow适配器的具体实现
881
-
882
- Args:
883
- task: 要执行的任务描述
884
- context: 执行上下文信息
885
-
886
- Returns:
887
- str: 任务执行结果
888
- """
889
- try:
890
- # 创建Hook上下文
891
- hook_context = IFlowHookContext(
892
- command=task,
893
- user_input=task,
894
- metadata=context.get('metadata', {}),
895
- workflow_id=context.get('workflow_id', ''),
896
- stage_name=context.get('stage_name', 'execution')
897
- )
898
-
899
- # 检查是否为跨CLI调用
900
- intent = self.parser.parse_intent(task, "iflow")
901
- if intent.is_cross_cli and intent.target_cli != self.cli_name:
902
- # 执行跨CLI调用
903
- result = await self._execute_cross_cli_call(
904
- intent.target_cli,
905
- intent.task,
906
- hook_context
907
- )
908
- return result or f"iFlow Hook适配器处理了跨CLI任务: {task}"
909
- else:
910
- # 本地iFlow任务处理
911
- return f"iFlow Hook适配器本地处理: {task}"
912
-
913
- except Exception as e:
914
- logger.error(f"执行任务失败: {task}, 错误: {e}")
915
- self.record_error()
916
- return f"任务执行失败: {str(e)}"
917
-
918
- async def health_check(self) -> Dict[str, Any]:
919
- """
920
- 健康检查
921
-
922
- Returns:
923
- Dict[str, Any]: 健康状态
924
- """
925
- base_health = await super().health_check()
926
-
927
- iflow_health = {
928
- 'hooks_registered': self.hooks_registered,
929
- 'hook_calls_count': self.hook_calls_count,
930
- 'cross_cli_calls_count': self.cross_cli_calls_count,
931
- 'processed_events_count': len(self.processed_events),
932
- 'command_interceptions_count': len(self.command_interceptions),
933
- 'active_workflows_count': len(self.active_workflows),
934
- 'hooks_config_file': self.hooks_config_file,
935
- 'hooks_config_exists': os.path.exists(self.hooks_config_file),
936
- 'iflow_version': self.iflow_version,
937
- 'collaboration_enabled': self.collaboration_enabled,
938
- 'event_listeners_count': sum(len(listeners) for listeners in self.event_listeners.values())
939
- }
940
-
941
- # 检查环境
942
- try:
943
- iflow_health['iflow_environment'] = self._check_iflow_environment()
944
- except Exception as e:
945
- iflow_health['iflow_environment_error'] = str(e)
946
-
947
- # 合并基础健康信息
948
- base_health.update(iflow_health)
949
- return base_health
950
-
951
- def get_statistics(self) -> Dict[str, Any]:
952
- """
953
- 获取适配器统计信息
954
-
955
- Returns:
956
- Dict[str, Any]: 统计信息
957
- """
958
- base_stats = super().get_statistics()
959
-
960
- iflow_stats = {
961
- 'hooks_registered': self.hooks_registered,
962
- 'hook_calls_count': self.hook_calls_count,
963
- 'cross_cli_calls_count': self.cross_cli_calls_count,
964
- 'processed_events_count': len(self.processed_events),
965
- 'command_interceptions_count': len(self.command_interceptions),
966
- 'active_workflows_count': len(self.active_workflows),
967
- 'supported_hooks': list(self.hook_handlers.keys()),
968
- 'event_types': list(self.event_listeners.keys()),
969
- 'collaboration_enabled': self.collaboration_enabled,
970
- 'iflow_version': self.iflow_version
971
- }
972
-
973
- base_stats.update(iflow_stats)
974
- return base_stats
975
-
976
- async def cleanup(self) -> bool:
977
- """
978
- 清理适配器资源
979
-
980
- Returns:
981
- bool: 清理是否成功
982
- """
983
- try:
984
- # 清理统计信息
985
- self.processed_events.clear()
986
- self.command_interceptions.clear()
987
- self.active_workflows.clear()
988
-
989
- # 清理事件监听器
990
- self.event_listeners.clear()
991
-
992
- logger.info("iFlow Hook适配器清理完成")
993
- return True
994
-
995
- except Exception as e:
996
- logger.error(f"清理iFlow Hook适配器失败: {e}")
997
- return False
998
-
999
-
1000
- # 创建全局适配器实例
1001
- _global_adapter: Optional[IFlowHookAdapter] = None
1002
-
1003
-
1004
- def get_iflow_hook_adapter() -> IFlowHookAdapter:
1005
- """
1006
- 获取iFlow Hook适配器实例
1007
-
1008
- Returns:
1009
- IFlowHookAdapter: 适配器实例
1010
- """
1011
- global _global_adapter
1012
- if _global_adapter is None:
1013
- _global_adapter = IFlowHookAdapter()
1014
- # 异步初始化需要在调用时进行
1015
- return _global_adapter
1016
-
1017
-
1018
- # 便捷函数
1019
- async def initialize_iflow_adapter() -> bool:
1020
- """
1021
- 初始化iFlow Hook适配器
1022
-
1023
- Returns:
1024
- bool: 初始化是否成功
1025
- """
1026
- adapter = get_iflow_hook_adapter()
1027
- return await adapter.initialize()
1028
-
1029
-
1030
- def is_iflow_adapter_available() -> bool:
1031
- """
1032
- 检查iFlow Hook适配器是否可用
1033
-
1034
- Returns:
1035
- bool: 是否可用
1036
- """
1037
- adapter = get_iflow_hook_adapter()
1038
- return adapter.is_available()