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.
Files changed (94) hide show
  1. package/LICENSE +19 -0
  2. package/README.de.md +301 -0
  3. package/README.en.md +301 -0
  4. package/README.es.md +301 -0
  5. package/README.fr.md +301 -0
  6. package/README.ja.md +301 -0
  7. package/README.ko.md +301 -0
  8. package/README.md +301 -0
  9. package/README.ru.md +301 -0
  10. package/README.zh.md +301 -0
  11. package/package.json +82 -0
  12. package/src/adapters/claude/__init__.py +13 -0
  13. package/src/adapters/claude/claude_skills_integration.py +609 -0
  14. package/src/adapters/claude/hook_adapter.py +663 -0
  15. package/src/adapters/claude/install_claude_integration.py +265 -0
  16. package/src/adapters/claude/skills_hook_adapter.py +841 -0
  17. package/src/adapters/claude/standalone_claude_adapter.py +384 -0
  18. package/src/adapters/cline/__init__.py +20 -0
  19. package/src/adapters/cline/config.py +108 -0
  20. package/src/adapters/cline/install_cline_integration.py +617 -0
  21. package/src/adapters/cline/mcp_server.py +713 -0
  22. package/src/adapters/cline/standalone_cline_adapter.py +459 -0
  23. package/src/adapters/codebuddy/__init__.py +13 -0
  24. package/src/adapters/codebuddy/buddy_adapter.py +1125 -0
  25. package/src/adapters/codebuddy/install_codebuddy_integration.py +279 -0
  26. package/src/adapters/codebuddy/skills_hook_adapter.py +672 -0
  27. package/src/adapters/codebuddy/skills_integration.py +395 -0
  28. package/src/adapters/codebuddy/standalone_codebuddy_adapter.py +403 -0
  29. package/src/adapters/codex/__init__.py +11 -0
  30. package/src/adapters/codex/base.py +46 -0
  31. package/src/adapters/codex/install_codex_integration.py +311 -0
  32. package/src/adapters/codex/mcp_server.py +493 -0
  33. package/src/adapters/codex/natural_language_parser.py +82 -0
  34. package/src/adapters/codex/slash_command_adapter.py +326 -0
  35. package/src/adapters/codex/standalone_codex_adapter.py +362 -0
  36. package/src/adapters/copilot/__init__.py +13 -0
  37. package/src/adapters/copilot/install_copilot_integration.py +564 -0
  38. package/src/adapters/copilot/mcp_adapter.py +772 -0
  39. package/src/adapters/copilot/mcp_server.py +168 -0
  40. package/src/adapters/copilot/standalone_copilot_adapter.py +114 -0
  41. package/src/adapters/gemini/__init__.py +13 -0
  42. package/src/adapters/gemini/extension_adapter.py +690 -0
  43. package/src/adapters/gemini/install_gemini_integration.py +257 -0
  44. package/src/adapters/gemini/standalone_gemini_adapter.py +366 -0
  45. package/src/adapters/iflow/__init__.py +7 -0
  46. package/src/adapters/iflow/hook_adapter.py +1038 -0
  47. package/src/adapters/iflow/hook_installer.py +536 -0
  48. package/src/adapters/iflow/install_iflow_integration.py +271 -0
  49. package/src/adapters/iflow/official_hook_adapter.py +1272 -0
  50. package/src/adapters/iflow/standalone_iflow_adapter.py +48 -0
  51. package/src/adapters/iflow/workflow_adapter.py +793 -0
  52. package/src/adapters/qoder/hook_installer.py +732 -0
  53. package/src/adapters/qoder/install_qoder_integration.py +265 -0
  54. package/src/adapters/qoder/notification_hook_adapter.py +863 -0
  55. package/src/adapters/qoder/standalone_qoder_adapter.py +48 -0
  56. package/src/adapters/qwen/__init__.py +17 -0
  57. package/src/adapters/qwencode/__init__.py +13 -0
  58. package/src/adapters/qwencode/inheritance_adapter.py +818 -0
  59. package/src/adapters/qwencode/install_qwencode_integration.py +276 -0
  60. package/src/adapters/qwencode/standalone_qwencode_adapter.py +399 -0
  61. package/src/atomic_collaboration_handler.py +461 -0
  62. package/src/cli_collaboration_agent.py +697 -0
  63. package/src/collaboration/hooks.py +315 -0
  64. package/src/core/__init__.py +21 -0
  65. package/src/core/ai_environment_scanner.py +331 -0
  66. package/src/core/base_adapter.py +220 -0
  67. package/src/core/cli_hook_integration.py +406 -0
  68. package/src/core/cross_cli_executor.py +713 -0
  69. package/src/core/cross_cli_mapping.py +1163 -0
  70. package/src/core/cross_platform_encoding.py +365 -0
  71. package/src/core/cross_platform_safe_cli.py +894 -0
  72. package/src/core/direct_cli_executor.py +805 -0
  73. package/src/core/direct_cli_hook_system.py +958 -0
  74. package/src/core/enhanced_init_processor.py +427 -0
  75. package/src/core/graceful_cli_executor.py +912 -0
  76. package/src/core/md_enhancer.py +342 -0
  77. package/src/core/md_generator.py +619 -0
  78. package/src/core/models.py +218 -0
  79. package/src/core/parser.py +108 -0
  80. package/src/core/real_cli_hook_system.py +852 -0
  81. package/src/core/real_cross_cli_system.py +925 -0
  82. package/src/core/verified_cross_cli_system.py +961 -0
  83. package/src/deploy.js +737 -0
  84. package/src/enhanced_deploy.js +303 -0
  85. package/src/enhanced_universal_cli_setup.py +930 -0
  86. package/src/kimi_wrapper.py +104 -0
  87. package/src/main.js +1309 -0
  88. package/src/shell_integration.py +398 -0
  89. package/src/simple-main.js +315 -0
  90. package/src/smart_router_creator.py +323 -0
  91. package/src/universal_cli_setup.py +1289 -0
  92. package/src/utils/__init__.py +12 -0
  93. package/src/utils/cli_detector.py +445 -0
  94. package/src/utils/file_utils.py +246 -0
@@ -0,0 +1,852 @@
1
+ """
2
+ 真实CLI Hook系统 - 基于实际架构的跨CLI协作
3
+ 严格基于真实研究,严禁推测
4
+ """
5
+
6
+ import os
7
+ import sys
8
+ import json
9
+ import subprocess
10
+ import re
11
+ import time
12
+ from pathlib import Path
13
+ from typing import Dict, List, Optional, Any, Callable
14
+ from dataclasses import dataclass, asdict
15
+ from datetime import datetime
16
+ import threading
17
+ from concurrent.futures import ThreadPoolExecutor
18
+
19
+ # 导入编码安全和跨CLI执行器
20
+ sys.path.append(str(Path(__file__).parent))
21
+ from cross_platform_encoding import CrossPlatformEncoding
22
+ from cross_cli_executor import CrossCLIExecutor, RealCLIArchitectures
23
+
24
+ @dataclass
25
+ class CLIHookEvent:
26
+ """CLI Hook事件"""
27
+ timestamp: str
28
+ source_cli: str
29
+ event_type: str # 'input', 'output', 'command', 'file_operation'
30
+ content: str
31
+ working_directory: str
32
+ user_intent: Optional[str] = None
33
+ target_clis: List[str] = None
34
+ confidence: float = 0.0
35
+
36
+ class RealCLIHookManager:
37
+ """基于真实架构的CLI Hook管理器"""
38
+
39
+ def __init__(self, hook_dir: str = None):
40
+ self.hook_dir = Path(hook_dir or Path.home() / '.stigmergy_cli_hooks')
41
+ self.hook_dir.mkdir(parents=True, exist_ok=True)
42
+
43
+ self.cross_executor = CrossCLIExecutor()
44
+ self.architectures = RealCLIArchitectures()
45
+
46
+ # Hook配置文件
47
+ self.hook_config_file = self.hook_dir / 'hook_config.json'
48
+ self.event_log_file = self.hook_dir / 'hook_events.json'
49
+ self.intercept_patterns_file = self.hook_dir / 'intercept_patterns.json'
50
+
51
+ # 运行时状态
52
+ self.active_hooks = {}
53
+ self.intercept_patterns = {}
54
+ self.event_handlers = {}
55
+
56
+ self._initialize_hooks()
57
+
58
+ def _initialize_hooks(self):
59
+ """初始化Hook系统"""
60
+ # 初始化配置
61
+ if not self.hook_config_file.exists():
62
+ config = {
63
+ 'enabled_hooks': ['input_interception', 'collaboration_detection', 'automatic_cross_call'],
64
+ 'detection_confidence_threshold': 0.7,
65
+ 'auto_cross_call_enabled': True,
66
+ 'supported_clis': list(self.architectures.ARCHITECTURES.keys()),
67
+ 'hook_timeout': 30,
68
+ 'max_concurrent_hooks': 5,
69
+ 'version': '1.0.0'
70
+ }
71
+ safe_file_write(self.hook_config_file, json.dumps(config, indent=2, ensure_ascii=False))
72
+
73
+ # 初始化拦截模式
74
+ if not self.intercept_patterns_file.exists():
75
+ patterns = {
76
+ 'cross_cli_indicators': [
77
+ r'(?:call|invoke|use|run|execute)\s+(?:the\s+)?([a-z]+)\s+(?:cli|tool|assistant)',
78
+ r'(?:with|using|via)\s+([a-z]+)',
79
+ r'(?:ask|tell|request)\s+([a-z]+)\s+to',
80
+ r'([a-z]+)(?:\s+can|should|will)\s+(?:help|assist|process|handle)',
81
+ ],
82
+ 'intent_classifiers': {
83
+ 'code_generation': [
84
+ r'generate', r'create', r'write', r'build', r'develop', r'implement'
85
+ ],
86
+ 'code_analysis': [
87
+ r'analyze', r'review', r'check', r'examine', r'inspect', r'audit'
88
+ ],
89
+ 'debugging': [
90
+ r'fix', r'debug', r'repair', r'solve', r'resolve', r'troubleshoot'
91
+ ],
92
+ 'documentation': [
93
+ r'document', r'explain', r'describe', r'comment', r'manual'
94
+ ]
95
+ },
96
+ 'cli_aliases': {
97
+ 'claude': ['claude', 'anthropic', 'ai-assistant'],
98
+ 'gemini': ['gemini', 'google', 'bard'],
99
+ 'copilot': ['copilot', 'github', 'gh'],
100
+ 'iflow': ['iflow', 'flow', 'mindflow'],
101
+ 'qwencode': ['qwencode', 'qwen', 'alibaba'],
102
+ 'qoder': ['qoder', 'code-assistant'],
103
+ 'codebuddy': ['codebuddy', 'tencent', 'buddy'],
104
+ 'codex': ['codex', 'openai', 'gpt'],
105
+ 'cline': ['cline', 'mcp', 'model-context-protocol']
106
+ },
107
+ 'version': '1.0.0'
108
+ }
109
+ safe_file_write(self.intercept_patterns_file, json.dumps(patterns, indent=2, ensure_ascii=False))
110
+
111
+ # 加载配置
112
+ self._load_configurations()
113
+
114
+ def _load_configurations(self):
115
+ """加载配置文件"""
116
+ try:
117
+ with open(self.hook_config_file, 'r', encoding='utf-8') as f:
118
+ self.config = json.load(f)
119
+ except:
120
+ self.config = {'enabled_hooks': [], 'supported_clis': []}
121
+
122
+ try:
123
+ with open(self.intercept_patterns_file, 'r', encoding='utf-8') as f:
124
+ patterns = json.load(f)
125
+ self.intercept_patterns = patterns.get('cross_cli_indicators', [])
126
+ self.intent_classifiers = patterns.get('intent_classifiers', {})
127
+ self.cli_aliases = patterns.get('cli_aliases', {})
128
+ except:
129
+ self.intercept_patterns = []
130
+ self.intent_classifiers = {}
131
+ self.cli_aliases = {}
132
+
133
+ def install_hooks(self, cli_name: str) -> Dict[str, Any]:
134
+ """为指定CLI安装Hook"""
135
+ result = {
136
+ 'success': False,
137
+ 'message': '',
138
+ 'installed_hooks': [],
139
+ 'configuration_changes': []
140
+ }
141
+
142
+ if cli_name not in self.architectures.ARCHITECTURES:
143
+ result['message'] = f"Unsupported CLI: {cli_name}"
144
+ return result
145
+
146
+ arch = self.architectures.ARCHITECTURES[cli_name]
147
+
148
+ try:
149
+ # 检查CLI可用性
150
+ available, message = self.cross_executor.check_cli_availability(cli_name)
151
+ if not available:
152
+ result['message'] = f"CLI not available: {message}"
153
+ return result
154
+
155
+ # 根据CLI架构类型安装Hook
156
+ if arch.architecture_type == 'npm':
157
+ hooks = self._install_npm_hooks(cli_name, arch)
158
+ elif arch.architecture_type == 'python':
159
+ hooks = self._install_python_hooks(cli_name, arch)
160
+ elif arch.architecture_type == 'binary':
161
+ hooks = self._install_binary_hooks(cli_name, arch)
162
+ else:
163
+ hooks = self._install_generic_hooks(cli_name, arch)
164
+
165
+ # 注册Hook处理器
166
+ self._register_hook_handlers(cli_name, hooks)
167
+
168
+ result.update({
169
+ 'success': True,
170
+ 'message': f"Successfully installed hooks for {arch.name}",
171
+ 'installed_hooks': hooks,
172
+ 'configuration_changes': self._get_config_changes(cli_name)
173
+ })
174
+
175
+ except Exception as e:
176
+ result['message'] = f"Hook installation failed: {str(e)}"
177
+
178
+ return result
179
+
180
+ def _install_npm_hooks(self, cli_name: str, arch) -> List[str]:
181
+ """为npm类型CLI安装Hook"""
182
+ hooks = []
183
+
184
+ # 创建npm包装脚本
185
+ wrapper_script = self._create_npm_wrapper(cli_name, arch)
186
+ hooks.append(f"npm_wrapper: {wrapper_script}")
187
+
188
+ # 创建shell别名或函数
189
+ alias_script = self._create_shell_alias(cli_name, arch)
190
+ hooks.append(f"shell_alias: {alias_script}")
191
+
192
+ # 设置环境变量Hook
193
+ env_hook = self._setup_environment_hook(cli_name, arch)
194
+ hooks.append(f"environment_hook: {env_hook}")
195
+
196
+ return hooks
197
+
198
+ def _install_python_hooks(self, cli_name: str, arch) -> List[str]:
199
+ """为Python类型CLI安装Hook"""
200
+ hooks = []
201
+
202
+ # 创建Python包装器
203
+ wrapper_script = self._create_python_wrapper(cli_name, arch)
204
+ hooks.append(f"python_wrapper: {wrapper_script}")
205
+
206
+ # 修改Python site-packages
207
+ if self._can_modify_site_packages(cli_name):
208
+ site_hook = self._install_site_package_hook(cli_name, arch)
209
+ hooks.append(f"site_package_hook: {site_hook}")
210
+
211
+ return hooks
212
+
213
+ def _install_binary_hooks(self, cli_name: str, arch) -> List[str]:
214
+ """为二进制CLI安装Hook"""
215
+ hooks = []
216
+
217
+ # 创建二进制包装器
218
+ wrapper_script = self._create_binary_wrapper(cli_name, arch)
219
+ hooks.append(f"binary_wrapper: {wrapper_script}")
220
+
221
+ # 设置PATH重定向
222
+ path_hook = self._setup_path_redirection(cli_name, arch)
223
+ hooks.append(f"path_redirection: {path_hook}")
224
+
225
+ return hooks
226
+
227
+ def _install_generic_hooks(self, cli_name: str, arch) -> List[str]:
228
+ """安装通用Hook"""
229
+ hooks = []
230
+
231
+ # Shell函数Hook
232
+ shell_hook = self._create_shell_function_hook(cli_name, arch)
233
+ hooks.append(f"shell_function: {shell_hook}")
234
+
235
+ # 启动脚本Hook
236
+ startup_hook = self._create_startup_hook(cli_name, arch)
237
+ hooks.append(f"startup_hook: {startup_hook}")
238
+
239
+ return hooks
240
+
241
+ def _create_npm_wrapper(self, cli_name: str, arch) -> str:
242
+ """创建npm包装脚本"""
243
+ wrapper_dir = self.hook_dir / 'npm_wrappers'
244
+ wrapper_dir.mkdir(exist_ok=True)
245
+
246
+ wrapper_script = wrapper_dir / f"{cli_name}_wrapper.js"
247
+
248
+ wrapper_content = f'''#!/usr/bin/env node
249
+
250
+ /**
251
+ * {arch.name} Hook Wrapper
252
+ * Intercepts calls and enables cross-CLI collaboration
253
+ */
254
+
255
+ const {{ spawn }} = require('child_process');
256
+ const fs = require('fs');
257
+ const path = require('path');
258
+ const os = require('os');
259
+
260
+ // Hook配置
261
+ const HOOK_DIR = '{self.hook_dir}';
262
+ const CLI_NAME = '{cli_name}';
263
+ const ORIGINAL_COMMAND = '{arch.execution_command}';
264
+
265
+ // 事件记录函数
266
+ function logEvent(eventType, content, workingDir) {{
267
+ const event = {{
268
+ timestamp: new Date().toISOString(),
269
+ source_cli: CLI_NAME,
270
+ event_type: eventType,
271
+ content: content,
272
+ working_directory: workingDir || process.cwd(),
273
+ user_intent: null,
274
+ target_clis: [],
275
+ confidence: 0.0
276
+ }};
277
+
278
+ const eventFile = path.join(HOOK_DIR, 'hook_events.json');
279
+ try {{
280
+ let events = [];
281
+ if (fs.existsSync(eventFile)) {{
282
+ const data = fs.readFileSync(eventFile, 'utf8');
283
+ events = JSON.parse(data);
284
+ }}
285
+ events.push(event);
286
+
287
+ // 保留最近1000个事件
288
+ if (events.length > 1000) {{
289
+ events = events.slice(-1000);
290
+ }}
291
+
292
+ fs.writeFileSync(eventFile, JSON.stringify(events, null, 2));
293
+ }} catch (error) {{
294
+ console.error('Failed to log event:', error.message);
295
+ }}
296
+ }}
297
+
298
+ // 检测跨CLI协作意图
299
+ function detectCrossCLIIntent(args) {{
300
+ const input = args.join(' ').toLowerCase();
301
+ const patterns = {json.dumps(self.intercept_patterns)};
302
+
303
+ for (const pattern of patterns) {{
304
+ const regex = new RegExp(pattern, 'i');
305
+ const match = input.match(regex);
306
+ if (match) {{
307
+ return {{
308
+ detected: true,
309
+ target_cli: match[1],
310
+ confidence: 0.8
311
+ }};
312
+ }}
313
+ }}
314
+
315
+ return {{ detected: false }};
316
+ }}
317
+
318
+ // 主执行函数
319
+ function main() {{
320
+ const args = process.argv.slice(2);
321
+ const workingDir = process.cwd();
322
+
323
+ // 记录输入事件
324
+ logEvent('input', args.join(' '), workingDir);
325
+
326
+ // 检测跨CLI意图
327
+ const intent = detectCrossCLIIntent(args);
328
+ if (intent.detected && intent.target_cli !== CLI_NAME) {{
329
+ console.log(`🔗 检测到跨CLI协作意图: {{CLI_NAME}} -> {{intent.target_cli}}`);
330
+
331
+ // 这里可以添加自动跨CLI调用逻辑
332
+ // 暂时记录意图,继续执行原命令
333
+ }}
334
+
335
+ // 执行原始命令
336
+ const originalArgs = ORIGINAL_COMMAND.includes('npx')
337
+ ? ['npx'].concat(ORIGINAL_COMMAND.split(' ').slice(1), args)
338
+ : [ORIGINAL_COMMAND].concat(args);
339
+
340
+ const child = spawn(originalArgs[0], originalArgs.slice(1), {{
341
+ stdio: 'inherit',
342
+ cwd: workingDir,
343
+ env: {{ ...process.env }}
344
+ }});
345
+
346
+ child.on('close', (code) => {{
347
+ // 记录输出事件
348
+ logEvent('output', `Command completed with code: ${{code}}`, workingDir);
349
+ process.exit(code);
350
+ }});
351
+
352
+ child.on('error', (error) => {{
353
+ logEvent('error', error.message, workingDir);
354
+ process.exit(1);
355
+ }});
356
+ }}
357
+
358
+ // 启动Hook
359
+ if (require.main === module) {{
360
+ main();
361
+ }}
362
+
363
+ module.exports = {{ logEvent, detectCrossCLIIntent }};
364
+ '''
365
+
366
+ safe_file_write(str(wrapper_script), wrapper_content)
367
+
368
+ # 设置执行权限
369
+ try:
370
+ os.chmod(wrapper_script, 0o755)
371
+ except:
372
+ pass
373
+
374
+ return str(wrapper_script)
375
+
376
+ def _create_python_wrapper(self, cli_name: str, arch) -> str:
377
+ """创建Python包装器"""
378
+ wrapper_dir = self.hook_dir / 'python_wrappers'
379
+ wrapper_dir.mkdir(exist_ok=True)
380
+
381
+ wrapper_script = wrapper_dir / f"{cli_name}_wrapper.py"
382
+
383
+ wrapper_content = f'''#!/usr/bin/env python3
384
+ """
385
+ {arch.name} Python Hook Wrapper
386
+ Intercepts Python CLI calls and enables cross-CLI collaboration
387
+ """
388
+
389
+ import sys
390
+ import os
391
+ import json
392
+ import subprocess
393
+ import argparse
394
+ from pathlib import Path
395
+ from datetime import datetime
396
+
397
+ # Hook配置
398
+ HOOK_DIR = r"{self.hook_dir}"
399
+ CLI_NAME = "{cli_name}"
400
+ ORIGINAL_COMMAND = "{arch.execution_command}"
401
+
402
+ def log_event(event_type, content, working_dir=None):
403
+ """记录Hook事件"""
404
+ event = {{
405
+ "timestamp": datetime.now().isoformat(),
406
+ "source_cli": CLI_NAME,
407
+ "event_type": event_type,
408
+ "content": content,
409
+ "working_directory": working_dir or os.getcwd(),
410
+ "user_intent": None,
411
+ "target_clis": [],
412
+ "confidence": 0.0
413
+ }}
414
+
415
+ event_file = Path(HOOK_DIR) / 'hook_events.json'
416
+ try:
417
+ if event_file.exists():
418
+ with open(event_file, 'r', encoding='utf-8') as f:
419
+ events = json.load(f)
420
+ else:
421
+ events = []
422
+
423
+ events.append(event)
424
+
425
+ # 保留最近1000个事件
426
+ if len(events) > 1000:
427
+ events = events[-1000:]
428
+
429
+ with open(event_file, 'w', encoding='utf-8') as f:
430
+ json.dump(events, f, indent=2, ensure_ascii=False)
431
+ except Exception as e:
432
+ print(f"Failed to log event: {{e}}", file=sys.stderr)
433
+
434
+ def detect_cross_cli_intent(args):
435
+ """检测跨CLI协作意图"""
436
+ input_text = ' '.join(args).lower()
437
+ patterns = {json.dumps(self.intercept_patterns)}
438
+
439
+ for pattern in patterns:
440
+ import re
441
+ match = re.search(pattern, input_text, re.IGNORECASE)
442
+ if match:
443
+ return {{
444
+ "detected": True,
445
+ "target_cli": match.group(1),
446
+ "confidence": 0.8
447
+ }}
448
+
449
+ return {{"detected": False}}
450
+
451
+ def main():
452
+ """主执行函数"""
453
+ args = sys.argv[1:]
454
+ working_dir = os.getcwd()
455
+
456
+ # 记录输入事件
457
+ log_event('input', ' '.join(args), working_dir)
458
+
459
+ # 检测跨CLI意图
460
+ intent = detect_cross_cli_intent(args)
461
+ if intent["detected"] and intent["target_cli"] != CLI_NAME:
462
+ print(f"🔗 检测到跨CLI协作意图: {{CLI_NAME}} -> {{intent['target_cli']}}")
463
+
464
+ # 这里可以添加自动跨CLI调用逻辑
465
+ # 暂时记录意图,继续执行原命令
466
+
467
+ # 执行原始命令
468
+ try:
469
+ if ORIGINAL_COMMAND == cli_name:
470
+ # 直接执行CLI命令
471
+ result = subprocess.run([ORIGINAL_COMMAND] + args,
472
+ cwd=working_dir,
473
+ capture_output=False,
474
+ text=True)
475
+ else:
476
+ # 执行完整命令
477
+ cmd = ORIGINAL_COMMAND.split() + args
478
+ result = subprocess.run(cmd,
479
+ cwd=working_dir,
480
+ capture_output=False,
481
+ text=True)
482
+
483
+ # 记录输出事件
484
+ log_event('output', f"Command completed with code: {{result.returncode}}", working_dir)
485
+ sys.exit(result.returncode)
486
+
487
+ except Exception as e:
488
+ log_event('error', str(e), working_dir)
489
+ sys.exit(1)
490
+
491
+ if __name__ == '__main__':
492
+ main()
493
+ '''
494
+
495
+ safe_file_write(str(wrapper_script), wrapper_content)
496
+
497
+ # 设置执行权限
498
+ try:
499
+ os.chmod(wrapper_script, 0o755)
500
+ except:
501
+ pass
502
+
503
+ return str(wrapper_script)
504
+
505
+ def _create_shell_alias(self, cli_name: str, arch) -> str:
506
+ """创建Shell别名"""
507
+ alias_file = self.hook_dir / 'shell_aliases' / f"{cli_name}_alias.sh"
508
+ alias_file.parent.mkdir(exist_ok=True)
509
+
510
+ alias_content = f'''#!/bin/bash
511
+ # {arch.name} Hook Alias
512
+
513
+ # 原始命令别名
514
+ alias {cli_name}_original="{arch.execution_command}"
515
+
516
+ # Hook包装函数
517
+ {cli_name}() {{
518
+ # 记录调用事件
519
+ local event_file="{self.hook_dir}/hook_events.json"
520
+ local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ")
521
+ local working_dir=$(pwd)
522
+ local input_args="$*"
523
+
524
+ # 创建事件记录
525
+ local event='{{'
526
+ event+='"timestamp":"'"$timestamp"'",'
527
+ event+='"source_cli":"{cli_name}",'
528
+ event+='"event_type":"input",'
529
+ event+='"content":"'"$input_args"'",'
530
+ event+='"working_directory":"'"$working_dir"'"'
531
+ event+='}}'
532
+
533
+ # 写入事件文件
534
+ echo "$event" >> "$event_file.tmp"
535
+
536
+ # 检测跨CLI意图(简化版)
537
+ if [[ "$input_args" =~ (call|invoke|use|run|execute)\\s+([a-z]+) ]]; then
538
+ echo "🔗 检测到跨CLI协作意图: {cli_name} -> ${{BASH_REMATCH[2]}}"
539
+ fi
540
+
541
+ # 执行原始命令
542
+ {cli_name}_original "$@"
543
+ local exit_code=$?
544
+
545
+ # 记录完成事件
546
+ local completion_event='{{'
547
+ completion_event+='"timestamp":"'"$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ")"'",'
548
+ completion_event+='"source_cli":"{cli_name}",'
549
+ completion_event+='"event_type":"output",'
550
+ completion_event+='"content":"Command completed with code: '"$exit_code"'",'
551
+ completion_event+='"working_directory":"'"$working_dir"'"'
552
+ completion_event+='}}'
553
+
554
+ echo "$completion_event" >> "$event_file.tmp"
555
+
556
+ # 合并临时事件文件
557
+ if [[ -f "$event_file.tmp" ]]; then
558
+ python3 -c "
559
+ import json
560
+ from pathlib import Path
561
+ import sys
562
+
563
+ event_file = Path('{self.hook_dir}/hook_events.json')
564
+ temp_file = Path('{self.hook_dir}/hook_events.json.tmp')
565
+
566
+ try:
567
+ if event_file.exists():
568
+ events = json.loads(event_file.read_text(encoding='utf-8'))
569
+ else:
570
+ events = []
571
+
572
+ if temp_file.exists():
573
+ temp_content = temp_file.read_text(encoding='utf-8').strip()
574
+ for line in temp_content.split('}}\\n'):
575
+ if line.strip():
576
+ try:
577
+ event = json.loads(line + '}}')
578
+ events.append(event)
579
+ except:
580
+ pass
581
+ temp_file.unlink()
582
+
583
+ # 保留最近1000个事件
584
+ if len(events) > 1000:
585
+ events = events[-1000:]
586
+
587
+ event_file.write_text(json.dumps(events, indent=2, ensure_ascii=False), encoding='utf-8')
588
+ except Exception as e:
589
+ print(f'Warning: Failed to merge hook events: {{e}}', file=sys.stderr)
590
+ "
591
+ fi
592
+
593
+ return $exit_code
594
+ }}
595
+ '''
596
+
597
+ safe_file_write(str(alias_file), alias_content)
598
+ return str(alias_file)
599
+
600
+ def _register_hook_handlers(self, cli_name: str, hooks: List[str]):
601
+ """注册Hook处理器"""
602
+ self.active_hooks[cli_name] = {
603
+ 'hooks': hooks,
604
+ 'installed_at': datetime.now().isoformat(),
605
+ 'status': 'active'
606
+ }
607
+
608
+ # 注册事件处理器
609
+ self.event_handlers[cli_name] = {
610
+ 'on_input': self._handle_input_event,
611
+ 'on_output': self._handle_output_event,
612
+ 'on_error': self._handle_error_event,
613
+ 'on_cross_cli_intent': self._handle_cross_cli_intent
614
+ }
615
+
616
+ def _handle_input_event(self, event: CLIHookEvent):
617
+ """处理输入事件"""
618
+ # 检测跨CLI协作意图
619
+ intent = self._analyze_intent(event.content)
620
+ if intent:
621
+ event.user_intent = intent['type']
622
+ event.target_clis = intent['target_clis']
623
+ event.confidence = intent['confidence']
624
+
625
+ # 如果配置了自动跨CLI调用
626
+ if self.config.get('auto_cross_call_enabled', False):
627
+ self._try_auto_cross_call(event)
628
+
629
+ def _handle_output_event(self, event: CLIHookEvent):
630
+ """处理输出事件"""
631
+ # 分析输出结果,学习成功模式
632
+ self._learn_from_output(event)
633
+
634
+ def _handle_error_event(self, event: CLIHookEvent):
635
+ """处理错误事件"""
636
+ # 记录错误,优化后续检测
637
+ self._learn_from_error(event)
638
+
639
+ def _handle_cross_cli_intent(self, event: CLIHookEvent):
640
+ """处理跨CLI协作意图"""
641
+ # 执行跨CLI调用
642
+ for target_cli in event.target_clis:
643
+ result = self.cross_executor.execute_cross_cli_call(
644
+ source_cli=event.source_cli,
645
+ target_cli=target_cli,
646
+ request=event.content,
647
+ working_dir=event.working_directory
648
+ )
649
+
650
+ # 记录结果
651
+ self._log_cross_cli_result(event, target_cli, result)
652
+
653
+ def _analyze_intent(self, content: str) -> Optional[Dict[str, Any]]:
654
+ """分析用户意图"""
655
+ content_lower = content.lower()
656
+
657
+ # 检测跨CLI指示符
658
+ for pattern in self.intercept_patterns:
659
+ match = re.search(pattern, content_lower)
660
+ if match:
661
+ target_cli = match.group(1)
662
+
663
+ # 解析别名
664
+ for canonical_name, aliases in self.cli_aliases.items():
665
+ if target_cli in aliases:
666
+ target_cli = canonical_name
667
+ break
668
+
669
+ if target_cli in self.architectures.ARCHITECTURES:
670
+ return {
671
+ 'type': 'cross_cli_call',
672
+ 'target_clis': [target_cli],
673
+ 'confidence': 0.8,
674
+ 'pattern_used': pattern
675
+ }
676
+
677
+ # 检测意图类型
678
+ for intent_type, patterns in self.intent_classifiers.items():
679
+ for pattern in patterns:
680
+ if re.search(pattern, content_lower):
681
+ return {
682
+ 'type': intent_type,
683
+ 'target_clis': [],
684
+ 'confidence': 0.6,
685
+ 'pattern_used': pattern
686
+ }
687
+
688
+ return None
689
+
690
+ def _try_auto_cross_call(self, event: CLIHookEvent):
691
+ """尝试自动跨CLI调用"""
692
+ if not event.target_clis or event.confidence < self.config.get('detection_confidence_threshold', 0.7):
693
+ return
694
+
695
+ for target_cli in event.target_clis:
696
+ # 检查目标CLI是否可用
697
+ available, _ = self.cross_executor.check_cli_availability(target_cli)
698
+ if not available:
699
+ continue
700
+
701
+ # 执行跨CLI调用
702
+ result = self.cross_executor.execute_cross_cli_call(
703
+ source_cli=event.source_cli,
704
+ target_cli=target_cli,
705
+ request=event.content,
706
+ working_dir=event.working_directory
707
+ )
708
+
709
+ # 如果成功,显示结果
710
+ if result['success']:
711
+ print(f"\\n🔗 跨CLI协作结果 ({event.source_cli} -> {target_cli}):")
712
+ print(result['response'])
713
+ print("-" * 50)
714
+
715
+ def _learn_from_output(self, event: CLIHookEvent):
716
+ """从输出中学习"""
717
+ # 这里可以实现机器学习逻辑
718
+ # 分析哪些类型的调用在什么情况下成功
719
+ pass
720
+
721
+ def _learn_from_error(self, event: CLIHookEvent):
722
+ """从错误中学习"""
723
+ # 记录错误模式,改进检测算法
724
+ pass
725
+
726
+ def _log_cross_cli_result(self, event: CLIHookEvent, target_cli: str, result: Dict[str, Any]):
727
+ """记录跨CLI调用结果"""
728
+ result_event = CLIHookEvent(
729
+ timestamp=datetime.now().isoformat(),
730
+ source_cli=event.source_cli,
731
+ event_type='cross_cli_result',
732
+ content=f"Cross-CLI call to {target_cli}: {result['success']}",
733
+ working_directory=event.working_directory,
734
+ user_intent=event.user_intent,
735
+ target_clis=[target_cli],
736
+ confidence=result.get('confidence', 0.0)
737
+ )
738
+
739
+ self._record_event(result_event)
740
+
741
+ def _record_event(self, event: CLIHookEvent):
742
+ """记录Hook事件"""
743
+ try:
744
+ if self.event_log_file.exists():
745
+ events = json.loads(safe_file_read(self.event_log_file))
746
+ else:
747
+ events = []
748
+
749
+ events.append(asdict(event))
750
+
751
+ # 保留最近1000个事件
752
+ if len(events) > 1000:
753
+ events = events[-1000:]
754
+
755
+ safe_file_write(self.event_log_file, json.dumps(events, indent=2, ensure_ascii=False))
756
+ except Exception as e:
757
+ print(f"Warning: Failed to record hook event: {e}")
758
+
759
+ def get_hook_status(self) -> Dict[str, Any]:
760
+ """获取Hook状态"""
761
+ status = {
762
+ 'active_hooks': self.active_hooks,
763
+ 'event_handlers_count': len(self.event_handlers),
764
+ 'config': self.config,
765
+ 'total_events': 0,
766
+ 'recent_events': []
767
+ }
768
+
769
+ # 统计事件数量
770
+ try:
771
+ if self.event_log_file.exists():
772
+ events = json.loads(safe_file_read(self.event_log_file))
773
+ status['total_events'] = len(events)
774
+ status['recent_events'] = events[-10:] # 最近10个事件
775
+ except:
776
+ pass
777
+
778
+ return status
779
+
780
+ def uninstall_hooks(self, cli_name: str) -> Dict[str, Any]:
781
+ """卸载CLI Hook"""
782
+ result = {
783
+ 'success': False,
784
+ 'message': '',
785
+ 'removed_hooks': []
786
+ }
787
+
788
+ if cli_name not in self.active_hooks:
789
+ result['message'] = f"No hooks installed for {cli_name}"
790
+ return result
791
+
792
+ try:
793
+ # 移除Hook文件
794
+ hooks_info = self.active_hooks[cli_name]['hooks']
795
+ removed_hooks = []
796
+
797
+ for hook in hooks_info:
798
+ if ': ' in hook:
799
+ hook_type, hook_path = hook.split(': ', 1)
800
+ if os.path.exists(hook_path):
801
+ try:
802
+ os.remove(hook_path)
803
+ removed_hooks.append(hook)
804
+ except:
805
+ pass
806
+
807
+ # 清理注册信息
808
+ del self.active_hooks[cli_name]
809
+ if cli_name in self.event_handlers:
810
+ del self.event_handlers[cli_name]
811
+
812
+ result.update({
813
+ 'success': True,
814
+ 'message': f"Successfully uninstalled hooks for {cli_name}",
815
+ 'removed_hooks': removed_hooks
816
+ })
817
+
818
+ except Exception as e:
819
+ result['message'] = f"Hook uninstallation failed: {str(e)}"
820
+
821
+ return result
822
+
823
+ # 使用示例
824
+ if __name__ == '__main__':
825
+ hook_manager = RealCLIHookManager()
826
+
827
+ # 安装Hook示例
828
+ print("=== Installing CLI Hooks ===")
829
+ for cli_name in ['iflow', 'codebuddy']:
830
+ result = hook_manager.install_hooks(cli_name)
831
+ print(f"{cli_name}: {'✓ Success' if result['success'] else '✗ Failed'} - {result['message']}")
832
+
833
+ # 获取Hook状态
834
+ print("\\n=== Hook Status ===")
835
+ status = hook_manager.get_hook_status()
836
+ print(f"Active hooks: {list(status['active_hooks'].keys())}")
837
+ print(f"Total events: {status['total_events']}")
838
+
839
+ # 测试事件记录
840
+ test_event = CLIHookEvent(
841
+ timestamp=datetime.now().isoformat(),
842
+ source_cli='iflow',
843
+ event_type='input',
844
+ content='call claude to analyze this code',
845
+ working_directory=os.getcwd(),
846
+ user_intent='cross_cli_call',
847
+ target_clis=['claude'],
848
+ confidence=0.8
849
+ )
850
+
851
+ hook_manager._record_event(test_event)
852
+ print(f"\\nTest event recorded. Total events: {len(json.loads(safe_file_read(hook_manager.event_log_file)))}")