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,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)))}")
|