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,958 @@
|
|
|
1
|
+
"""
|
|
2
|
+
真实CLI Hook系统 - 基于已安装CLI的直接Hook和调用
|
|
3
|
+
严格基于真实研究,严禁推测
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import sys
|
|
8
|
+
import json
|
|
9
|
+
import subprocess
|
|
10
|
+
import time
|
|
11
|
+
import signal
|
|
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 real_cross_cli_system import RealCrossCLISystem
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class CLIHookEvent:
|
|
25
|
+
"""CLI Hook事件"""
|
|
26
|
+
timestamp: str
|
|
27
|
+
source_cli: str
|
|
28
|
+
event_type: str # 'input', 'output', 'command', 'cross_cli_intent'
|
|
29
|
+
content: str
|
|
30
|
+
working_directory: str
|
|
31
|
+
user_intent: Optional[str] = None
|
|
32
|
+
target_clis: List[str] = None
|
|
33
|
+
confidence: float = 0.0
|
|
34
|
+
detected_pattern: Optional[str] = None
|
|
35
|
+
|
|
36
|
+
class DirectCLIHookManager:
|
|
37
|
+
"""直接CLI Hook管理器 - 基于已安装CLI的真实Hook"""
|
|
38
|
+
|
|
39
|
+
def __init__(self, hook_dir: str = None):
|
|
40
|
+
self.hook_dir = Path(hook_dir or Path.home() / '.direct_cli_hooks')
|
|
41
|
+
self.hook_dir.mkdir(parents=True, exist_ok=True)
|
|
42
|
+
|
|
43
|
+
# 跨CLI调用系统
|
|
44
|
+
self.cross_system = RealCrossCLISystem()
|
|
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
|
+
self.hook_scripts_dir = self.hook_dir / 'hook_scripts'
|
|
51
|
+
self.hook_scripts_dir.mkdir(exist_ok=True)
|
|
52
|
+
|
|
53
|
+
# 运行时状态
|
|
54
|
+
self.active_hooks = {}
|
|
55
|
+
self.event_processors = {}
|
|
56
|
+
self.pattern_matchers = {}
|
|
57
|
+
|
|
58
|
+
self._initialize_hooks()
|
|
59
|
+
|
|
60
|
+
def _initialize_hooks(self):
|
|
61
|
+
"""初始化Hook系统"""
|
|
62
|
+
# 初始化配置
|
|
63
|
+
if not self.hook_config_file.exists():
|
|
64
|
+
config = {
|
|
65
|
+
'enabled_hooks': ['shell_interception', 'intent_detection', 'auto_cross_call'],
|
|
66
|
+
'detection_confidence_threshold': 0.7,
|
|
67
|
+
'auto_cross_call_enabled': True,
|
|
68
|
+
'supported_clis': list(self.cross_system.cli_methods.keys()),
|
|
69
|
+
'hook_timeout': 30,
|
|
70
|
+
'max_concurrent_hooks': 5,
|
|
71
|
+
'shell_integration': True,
|
|
72
|
+
'version': '1.0.0'
|
|
73
|
+
}
|
|
74
|
+
self._safe_write_json(self.hook_config_file, config)
|
|
75
|
+
|
|
76
|
+
# 初始化拦截模式
|
|
77
|
+
if not self.intercept_patterns_file.exists():
|
|
78
|
+
patterns = {
|
|
79
|
+
'cross_cli_patterns': [
|
|
80
|
+
r'(?:call|invoke|use|run|execute|ask|tell|request)\s+(?:the\s+)?([a-z]+)\s+(?:cli|tool|assistant|ai)',
|
|
81
|
+
r'(?:with|using|via|through)\s+([a-z]+)',
|
|
82
|
+
r'(?:let|have|can|should)\s+([a-z]+)\s+(?:help|assist|process|handle|deal)',
|
|
83
|
+
r'(?:switch|change|switch to)\s+([a-z]+)',
|
|
84
|
+
r'(?:in|using)\s+([a-z]+)\s+(?:mode|context)',
|
|
85
|
+
],
|
|
86
|
+
'intent_keywords': {
|
|
87
|
+
'code_generation': [
|
|
88
|
+
'generate', 'create', 'write', 'build', 'develop', 'implement', 'make', 'produce'
|
|
89
|
+
],
|
|
90
|
+
'code_analysis': [
|
|
91
|
+
'analyze', 'review', 'check', 'examine', 'inspect', 'audit', 'look at', 'scan'
|
|
92
|
+
],
|
|
93
|
+
'debugging': [
|
|
94
|
+
'fix', 'debug', 'repair', 'solve', 'resolve', 'troubleshoot', 'correct'
|
|
95
|
+
],
|
|
96
|
+
'documentation': [
|
|
97
|
+
'document', 'explain', 'describe', 'comment', 'manual', 'guide'
|
|
98
|
+
],
|
|
99
|
+
'optimization': [
|
|
100
|
+
'optimize', 'improve', 'refactor', 'enhance', 'better', 'faster'
|
|
101
|
+
],
|
|
102
|
+
'testing': [
|
|
103
|
+
'test', 'validate', 'verify', 'check', 'run tests'
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
'cli_aliases': {
|
|
107
|
+
'claude': ['claude', 'anthropic', 'ai-assistant'],
|
|
108
|
+
'gemini': ['gemini', 'google', 'bard'],
|
|
109
|
+
'copilot': ['copilot', 'github', 'gh'],
|
|
110
|
+
'iflow': ['iflow', 'flow', 'mindflow'],
|
|
111
|
+
'qwencode': ['qwencode', 'qwen', 'alibaba'],
|
|
112
|
+
'qoder': ['qoder', 'code-assistant'],
|
|
113
|
+
'codebuddy': ['codebuddy', 'tencent', 'buddy'],
|
|
114
|
+
'codex': ['codex', 'openai', 'gpt']
|
|
115
|
+
},
|
|
116
|
+
'version': '1.0.0'
|
|
117
|
+
}
|
|
118
|
+
self._safe_write_json(self.intercept_patterns_file, patterns)
|
|
119
|
+
|
|
120
|
+
# 加载配置
|
|
121
|
+
self._load_configurations()
|
|
122
|
+
|
|
123
|
+
def _load_configurations(self):
|
|
124
|
+
"""加载配置文件"""
|
|
125
|
+
try:
|
|
126
|
+
with open(self.hook_config_file, 'r', encoding='utf-8') as f:
|
|
127
|
+
self.config = json.load(f)
|
|
128
|
+
except:
|
|
129
|
+
self.config = {'enabled_hooks': [], 'supported_clis': []}
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
with open(self.intercept_patterns_file, 'r', encoding='utf-8') as f:
|
|
133
|
+
patterns = json.load(f)
|
|
134
|
+
self.cross_cli_patterns = patterns.get('cross_cli_patterns', [])
|
|
135
|
+
self.intent_keywords = patterns.get('intent_keywords', {})
|
|
136
|
+
self.cli_aliases = patterns.get('cli_aliases', {})
|
|
137
|
+
except:
|
|
138
|
+
self.cross_cli_patterns = []
|
|
139
|
+
self.intent_keywords = {}
|
|
140
|
+
self.cli_aliases = {}
|
|
141
|
+
|
|
142
|
+
def install_shell_hooks(self) -> Dict[str, Any]:
|
|
143
|
+
"""安装Shell级别Hook - 不修改CLI本身,Hook Shell输入"""
|
|
144
|
+
result = {
|
|
145
|
+
'success': False,
|
|
146
|
+
'message': '',
|
|
147
|
+
'installed_hooks': [],
|
|
148
|
+
'shell_type': '',
|
|
149
|
+
'integration_method': ''
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
try:
|
|
153
|
+
# 检测Shell类型
|
|
154
|
+
shell_type = self._detect_shell_type()
|
|
155
|
+
|
|
156
|
+
if shell_type == 'bash':
|
|
157
|
+
hooks = self._install_bash_hooks()
|
|
158
|
+
elif shell_type == 'zsh':
|
|
159
|
+
hooks = self._install_zsh_hooks()
|
|
160
|
+
elif shell_type == 'powershell':
|
|
161
|
+
hooks = self._install_powershell_hooks()
|
|
162
|
+
elif shell_type == 'cmd':
|
|
163
|
+
hooks = self._install_cmd_hooks()
|
|
164
|
+
else:
|
|
165
|
+
hooks = self._install_generic_hooks()
|
|
166
|
+
|
|
167
|
+
result.update({
|
|
168
|
+
'success': True,
|
|
169
|
+
'message': f"Successfully installed Shell hooks for {shell_type}",
|
|
170
|
+
'installed_hooks': hooks,
|
|
171
|
+
'shell_type': shell_type,
|
|
172
|
+
'integration_method': 'shell_function_interception'
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
# 注册事件处理器
|
|
176
|
+
self._register_event_processors()
|
|
177
|
+
|
|
178
|
+
except Exception as e:
|
|
179
|
+
result['message'] = f"Hook installation failed: {str(e)}"
|
|
180
|
+
|
|
181
|
+
return result
|
|
182
|
+
|
|
183
|
+
def _detect_shell_type(self) -> str:
|
|
184
|
+
"""检测当前Shell类型"""
|
|
185
|
+
shell = os.environ.get('SHELL', '').lower()
|
|
186
|
+
|
|
187
|
+
if 'bash' in shell:
|
|
188
|
+
return 'bash'
|
|
189
|
+
elif 'zsh' in shell:
|
|
190
|
+
return 'zsh'
|
|
191
|
+
elif 'powershell' in shell or 'pwsh' in shell:
|
|
192
|
+
return 'powershell'
|
|
193
|
+
elif 'cmd' in shell or os.name == 'nt':
|
|
194
|
+
return 'cmd'
|
|
195
|
+
else:
|
|
196
|
+
return 'generic'
|
|
197
|
+
|
|
198
|
+
def _install_bash_hooks(self) -> List[str]:
|
|
199
|
+
"""安装Bash Hook"""
|
|
200
|
+
hooks = []
|
|
201
|
+
|
|
202
|
+
# 创建Bash Hook函数
|
|
203
|
+
bash_hook_content = f'''#!/bin/bash
|
|
204
|
+
# Direct CLI Hook System for Bash
|
|
205
|
+
|
|
206
|
+
# Hook配置目录
|
|
207
|
+
HOOK_DIR="{self.hook_dir}"
|
|
208
|
+
EVENT_LOG="$HOOK_DIR/hook_events.json"
|
|
209
|
+
|
|
210
|
+
# 记录Hook事件
|
|
211
|
+
log_hook_event() {{
|
|
212
|
+
local event_type="$1"
|
|
213
|
+
local content="$2"
|
|
214
|
+
local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ")
|
|
215
|
+
local working_dir=$(pwd)
|
|
216
|
+
|
|
217
|
+
# 创建事件JSON
|
|
218
|
+
local event='{{'
|
|
219
|
+
event+='"timestamp":"'"$timestamp"'",'
|
|
220
|
+
event+='"source_cli":"shell",'
|
|
221
|
+
event+='"event_type":"'"$event_type"'",'
|
|
222
|
+
event+='"content":"'"$content"'",'
|
|
223
|
+
event+='"working_directory":"'"$working_dir"'"'
|
|
224
|
+
event+='}}'
|
|
225
|
+
|
|
226
|
+
# 添加到事件日志
|
|
227
|
+
echo "$event" >> "$EVENT_LOG.tmp"
|
|
228
|
+
|
|
229
|
+
# 检测跨CLI意图
|
|
230
|
+
if [[ "$event_type" == "input" ]]; then
|
|
231
|
+
detect_cross_cli_intent "$content" &
|
|
232
|
+
fi
|
|
233
|
+
}}
|
|
234
|
+
|
|
235
|
+
# 检测跨CLI意图
|
|
236
|
+
detect_cross_cli_intent() {{
|
|
237
|
+
local input="$1"
|
|
238
|
+
local intent_file="$HOOK_DIR/intent_detection.tmp"
|
|
239
|
+
|
|
240
|
+
# 调用Python脚本进行意图检测
|
|
241
|
+
echo "$input" | python3 "{Path(__file__).parent}/intent_detector.py" "$intent_file" &
|
|
242
|
+
|
|
243
|
+
# 等待检测结果
|
|
244
|
+
wait
|
|
245
|
+
|
|
246
|
+
if [[ -f "$intent_file" ]]; then
|
|
247
|
+
local detection=$(cat "$intent_file")
|
|
248
|
+
if [[ "$detection" != "none" ]]; then
|
|
249
|
+
echo "🔗 检测到跨CLI协作意图: $detection"
|
|
250
|
+
|
|
251
|
+
# 触发跨CLI调用(如果启用)
|
|
252
|
+
if {str(self.config.get('auto_cross_call_enabled', False)).lower()}; then
|
|
253
|
+
execute_cross_cli_call "$input" "$detection" &
|
|
254
|
+
fi
|
|
255
|
+
fi
|
|
256
|
+
rm -f "$intent_file"
|
|
257
|
+
fi
|
|
258
|
+
}}
|
|
259
|
+
|
|
260
|
+
# 执行跨CLI调用
|
|
261
|
+
execute_cross_cli_call() {{
|
|
262
|
+
local input="$1"
|
|
263
|
+
local detection="$2"
|
|
264
|
+
local python_script="{Path(__file__).parent}/cross_cli_executor.py"
|
|
265
|
+
|
|
266
|
+
# 调用Python执行器
|
|
267
|
+
python3 "$python_script" --shell-input "$input" --target-cli "$detection" &
|
|
268
|
+
}}
|
|
269
|
+
|
|
270
|
+
# Hook命令执行
|
|
271
|
+
hook_command_execution() {{
|
|
272
|
+
local command="$*"
|
|
273
|
+
|
|
274
|
+
# 记录输入事件
|
|
275
|
+
log_hook_event "input" "$command"
|
|
276
|
+
|
|
277
|
+
# 执行原始命令
|
|
278
|
+
eval "$command"
|
|
279
|
+
local exit_code=$?
|
|
280
|
+
|
|
281
|
+
# 记录输出事件
|
|
282
|
+
log_hook_event "output" "Command completed with exit code: $exit_code"
|
|
283
|
+
|
|
284
|
+
return $exit_code
|
|
285
|
+
}}
|
|
286
|
+
|
|
287
|
+
# Shell集成:重写命令执行函数
|
|
288
|
+
if [[ "{self.config.get('shell_integration', True)}" == "True" ]]; then
|
|
289
|
+
# 创建alias来hook常见命令
|
|
290
|
+
alias {self.config.get('hooked_commands', ['echo', 'cat', 'ls'])[0]}='hook_command_execution {self.config.get('hooked_commands', ['echo', 'cat', 'ls'])[0]}'
|
|
291
|
+
|
|
292
|
+
# 重写PROMPT_COMMAND来捕获命令
|
|
293
|
+
if [[ -z "$PROMPT_COMMAND" ]]; then
|
|
294
|
+
PROMPT_COMMAND="log_hook_event prompt \$PWD"
|
|
295
|
+
else
|
|
296
|
+
PROMPT_COMMAND="$PROMPT_COMMAND; log_hook_event prompt \$PWD"
|
|
297
|
+
fi
|
|
298
|
+
fi
|
|
299
|
+
'''
|
|
300
|
+
|
|
301
|
+
bash_hook_file = self.hook_scripts_dir / 'bash_hooks.sh'
|
|
302
|
+
self._safe_write_file(bash_hook_file, bash_hook_content)
|
|
303
|
+
hooks.append(f"bash_hook_script: {bash_hook_file}")
|
|
304
|
+
|
|
305
|
+
# 创建加载脚本
|
|
306
|
+
loader_content = f'''#!/bin/bash
|
|
307
|
+
# Load Direct CLI Hooks
|
|
308
|
+
|
|
309
|
+
if [[ -f "{bash_hook_file}" ]]; then
|
|
310
|
+
source "{bash_hook_file}"
|
|
311
|
+
echo "✅ Direct CLI Hooks loaded in Bash"
|
|
312
|
+
else
|
|
313
|
+
echo "❌ Hook file not found: {bash_hook_file}"
|
|
314
|
+
fi
|
|
315
|
+
'''
|
|
316
|
+
|
|
317
|
+
loader_file = self.hook_scripts_dir / 'load_bash_hooks.sh'
|
|
318
|
+
self._safe_write_file(loader_file, loader_content)
|
|
319
|
+
hooks.append(f"bash_loader: {loader_file}")
|
|
320
|
+
|
|
321
|
+
return hooks
|
|
322
|
+
|
|
323
|
+
def _install_powershell_hooks(self) -> List[str]:
|
|
324
|
+
"""安装PowerShell Hook"""
|
|
325
|
+
hooks = []
|
|
326
|
+
|
|
327
|
+
ps_hook_content = f'''# Direct CLI Hook System for PowerShell
|
|
328
|
+
|
|
329
|
+
# Hook配置
|
|
330
|
+
$Global:HookDir = "{self.hook_dir}"
|
|
331
|
+
$Global:EventLog = Join-Path $HookDir "hook_events.json"
|
|
332
|
+
|
|
333
|
+
# 记录Hook事件
|
|
334
|
+
function Log-HookEvent {{
|
|
335
|
+
param(
|
|
336
|
+
[string]$EventType,
|
|
337
|
+
[string]$Content
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
$timestamp = Get-Date -Format "yyyy-MM-ddTHH:mm:ss.fffZ"
|
|
341
|
+
$workingDir = Get-Location
|
|
342
|
+
|
|
343
|
+
$event = @{{
|
|
344
|
+
timestamp = $timestamp
|
|
345
|
+
source_cli = "powershell"
|
|
346
|
+
event_type = $EventType
|
|
347
|
+
content = $Content
|
|
348
|
+
working_directory = $workingDir
|
|
349
|
+
}}
|
|
350
|
+
|
|
351
|
+
$eventJson = $event | ConvertTo-Json -Compress
|
|
352
|
+
Add-Content -Path "$($Global:EventLog).tmp" -Value $eventJson
|
|
353
|
+
|
|
354
|
+
# 检测跨CLI意图
|
|
355
|
+
if ($EventType -eq "input") {{
|
|
356
|
+
Detect-CrossCLIIntent -Input $Content
|
|
357
|
+
}}
|
|
358
|
+
}}
|
|
359
|
+
|
|
360
|
+
# 检测跨CLI意图
|
|
361
|
+
function Detect-CrossCLIIntent {{
|
|
362
|
+
param([string]$Input)
|
|
363
|
+
|
|
364
|
+
$intentFile = Join-Path $Global:HookDir "intent_detection.tmp"
|
|
365
|
+
$pythonScript = "{Path(__file__).parent}/intent_detector.py"
|
|
366
|
+
|
|
367
|
+
try {{
|
|
368
|
+
$Input | python3 $pythonScript $intentFile
|
|
369
|
+
if (Test-Path $intentFile) {{
|
|
370
|
+
$detection = Get-Content $intentFile
|
|
371
|
+
if ($detection -ne "none") {{
|
|
372
|
+
Write-Host "🔗 检测到跨CLI协作意图: $detection" -ForegroundColor Green
|
|
373
|
+
|
|
374
|
+
if ({str(self.config.get('auto_cross_call_enabled', False)).lower()}) {{
|
|
375
|
+
Execute-CrossCLICall -Input $Input -TargetCLI $detection
|
|
376
|
+
}}
|
|
377
|
+
}}
|
|
378
|
+
Remove-Item $intentFile -ErrorAction SilentlyContinue
|
|
379
|
+
}}
|
|
380
|
+
}} catch {{
|
|
381
|
+
# 意图检测失败,继续执行
|
|
382
|
+
}}
|
|
383
|
+
}}
|
|
384
|
+
|
|
385
|
+
# 执行跨CLI调用
|
|
386
|
+
function Execute-CrossCLICall {{
|
|
387
|
+
param(
|
|
388
|
+
[string]$Input,
|
|
389
|
+
[string]$TargetCLI
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
$pythonScript = "{Path(__file__).parent}/cross_cli_executor.py"
|
|
393
|
+
|
|
394
|
+
Start-Job -ScriptBlock {{
|
|
395
|
+
param($Script, $Input, $Target)
|
|
396
|
+
& python3 $Script --shell-input $Input --target-cli $Target
|
|
397
|
+
}} -ArgumentList $pythonScript, $Input, $TargetCLI | Out-Null
|
|
398
|
+
}}
|
|
399
|
+
|
|
400
|
+
# Hook命令执行
|
|
401
|
+
function Invoke-OriginalCommand {{
|
|
402
|
+
param([string]$Command)
|
|
403
|
+
|
|
404
|
+
# 记录输入事件
|
|
405
|
+
Log-HookEvent -EventType "input" -Content $Command
|
|
406
|
+
|
|
407
|
+
# 执行原始命令
|
|
408
|
+
try {{
|
|
409
|
+
$result = Invoke-Expression $Command
|
|
410
|
+
$exitCode = $LASTEXITCODE
|
|
411
|
+
|
|
412
|
+
# 记录输出事件
|
|
413
|
+
Log-HookEvent -EventType "output" -Content "Command completed with exit code: $exitCode"
|
|
414
|
+
|
|
415
|
+
return $result
|
|
416
|
+
}} catch {{
|
|
417
|
+
Log-HookEvent -EventType "error" -Content "Command failed: $($_.Exception.Message)"
|
|
418
|
+
throw
|
|
419
|
+
}}
|
|
420
|
+
}}
|
|
421
|
+
|
|
422
|
+
# PowerShell集成
|
|
423
|
+
if ({str(self.config.get('shell_integration', True)).lower()}) {{
|
|
424
|
+
# 重写一些常用的PowerShell命令
|
|
425
|
+
Set-Alias -Name hooked-echo -Value Invoke-OriginalCommand
|
|
426
|
+
|
|
427
|
+
# 添加到PowerShell Profile
|
|
428
|
+
$profilePath = $PROFILE.CurrentUserAllHosts
|
|
429
|
+
if (-not (Test-Path $profilePath)) {{
|
|
430
|
+
New-Item -ItemType File -Path $profilePath -Force
|
|
431
|
+
}}
|
|
432
|
+
|
|
433
|
+
# 避免重复加载
|
|
434
|
+
$hookLine = "# Direct CLI Hooks loaded"
|
|
435
|
+
$profileContent = Get-Content $profilePath -ErrorAction SilentlyContinue
|
|
436
|
+
if ($hookLine -notin $profileContent) {{
|
|
437
|
+
Add-Content -Path $profilePath -Value @"
|
|
438
|
+
# Direct CLI Hooks - Auto-generated
|
|
439
|
+
$hookLine
|
|
440
|
+
if (Test-Path "{self.hook_scripts_dir}/powershell_hooks.ps1") {{
|
|
441
|
+
. "{self.hook_scripts_dir}/powershell_hooks.ps1"
|
|
442
|
+
Write-Host "✅ Direct CLI Hooks loaded in PowerShell" -ForegroundColor Green
|
|
443
|
+
}}
|
|
444
|
+
"@
|
|
445
|
+
}}
|
|
446
|
+
}}
|
|
447
|
+
'''
|
|
448
|
+
|
|
449
|
+
ps_hook_file = self.hook_scripts_dir / 'powershell_hooks.ps1'
|
|
450
|
+
self._safe_write_file(ps_hook_file, ps_hook_content)
|
|
451
|
+
hooks.append(f"powershell_hook_script: {ps_hook_file}")
|
|
452
|
+
|
|
453
|
+
return hooks
|
|
454
|
+
|
|
455
|
+
def _install_zsh_hooks(self) -> List[str]:
|
|
456
|
+
"""安装Zsh Hook"""
|
|
457
|
+
hooks = []
|
|
458
|
+
|
|
459
|
+
zsh_hook_content = f'''#!/bin/zsh
|
|
460
|
+
# Direct CLI Hook System for Zsh
|
|
461
|
+
|
|
462
|
+
# Hook配置目录
|
|
463
|
+
HOOK_DIR="{self.hook_dir}"
|
|
464
|
+
EVENT_LOG="$HOOK_DIR/hook_events.json"
|
|
465
|
+
|
|
466
|
+
# 记录Hook事件
|
|
467
|
+
log_hook_event() {{
|
|
468
|
+
local event_type="$1"
|
|
469
|
+
local content="$2"
|
|
470
|
+
local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ")
|
|
471
|
+
local working_dir=$(pwd)
|
|
472
|
+
|
|
473
|
+
# 创建事件JSON
|
|
474
|
+
local event='{{'
|
|
475
|
+
event+='"timestamp":"'"$timestamp"'",'
|
|
476
|
+
event+='"source_cli":"zsh",'
|
|
477
|
+
event+='"event_type":"'"$event_type"'",'
|
|
478
|
+
event+='"content":"'"$content"'",'
|
|
479
|
+
event+='"working_directory":"'"$working_dir"'"'
|
|
480
|
+
event+='}}'
|
|
481
|
+
|
|
482
|
+
# 添加到事件日志
|
|
483
|
+
echo "$event" >> "$EVENT_LOG.tmp"
|
|
484
|
+
|
|
485
|
+
# 检测跨CLI意图
|
|
486
|
+
if [[ "$event_type" == "input" ]]; then
|
|
487
|
+
detect_cross_cli_intent "$content" &
|
|
488
|
+
fi
|
|
489
|
+
}}
|
|
490
|
+
|
|
491
|
+
# Zsh特定Hook:使用preexec和precmd
|
|
492
|
+
autoload -Uz add-zsh-hook
|
|
493
|
+
|
|
494
|
+
# 命令执行前Hook
|
|
495
|
+
hook_preexec() {{
|
|
496
|
+
local command="$1"
|
|
497
|
+
log_hook_event "input" "$command"
|
|
498
|
+
}}
|
|
499
|
+
|
|
500
|
+
# 命令执行后Hook
|
|
501
|
+
hook_precmd() {{
|
|
502
|
+
local exit_code=$?
|
|
503
|
+
log_hook_event "output" "Command completed with exit code: $exit_code"
|
|
504
|
+
}}
|
|
505
|
+
|
|
506
|
+
# 注册Hook
|
|
507
|
+
add-zsh-hook preexec hook_preexec
|
|
508
|
+
add-zsh-hook precmd hook_precmd
|
|
509
|
+
|
|
510
|
+
echo "✅ Direct CLI Hooks loaded in Zsh"
|
|
511
|
+
'''
|
|
512
|
+
|
|
513
|
+
zsh_hook_file = self.hook_scripts_dir / 'zsh_hooks.zsh'
|
|
514
|
+
self._safe_write_file(zsh_hook_file, zsh_hook_content)
|
|
515
|
+
hooks.append(f"zsh_hook_script: {zsh_hook_file}")
|
|
516
|
+
|
|
517
|
+
return hooks
|
|
518
|
+
|
|
519
|
+
def _install_cmd_hooks(self) -> List[str]:
|
|
520
|
+
"""安装Windows CMD Hook"""
|
|
521
|
+
hooks = []
|
|
522
|
+
|
|
523
|
+
# CMD Hook需要使用批处理文件和doskey
|
|
524
|
+
cmd_hook_content = f'''@echo off
|
|
525
|
+
REM Direct CLI Hook System for Windows CMD
|
|
526
|
+
|
|
527
|
+
set HOOK_DIR={self.hook_dir}
|
|
528
|
+
set EVENT_LOG=%HOOK_DIR%\\hook_events.json
|
|
529
|
+
|
|
530
|
+
REM 记录Hook事件
|
|
531
|
+
:log_hook_event
|
|
532
|
+
set event_type=%1
|
|
533
|
+
set content=%2
|
|
534
|
+
|
|
535
|
+
REM 获取时间戳
|
|
536
|
+
for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "dt=%%a"
|
|
537
|
+
set timestamp=%dt:~0,4%-%dt:~4,2%-%dt:~6,2%T%dt:~8,2%:%dt:~10,2%:%dt:~12,2%.%dt:~15,3%Z
|
|
538
|
+
|
|
539
|
+
REM 获取当前目录
|
|
540
|
+
set working_dir=%CD%
|
|
541
|
+
|
|
542
|
+
REM 创建事件JSON(简化版)
|
|
543
|
+
echo { "timestamp": "%timestamp%", "source_cli": "cmd", "event_type": "%event_type%", "content": "%content%", "working_directory": "%working_dir%" } >> "%EVENT_LOG%.tmp"
|
|
544
|
+
|
|
545
|
+
goto :eof
|
|
546
|
+
|
|
547
|
+
REM 主Hook函数
|
|
548
|
+
:hook_command
|
|
549
|
+
set command=%*
|
|
550
|
+
call :log_hook_event "input" "%command%"
|
|
551
|
+
|
|
552
|
+
REM 执行原始命令
|
|
553
|
+
%command%
|
|
554
|
+
set exit_code=%errorlevel%
|
|
555
|
+
|
|
556
|
+
call :log_hook_event "output" "Command completed with exit code: %exit_code%"
|
|
557
|
+
|
|
558
|
+
goto :eof
|
|
559
|
+
'''
|
|
560
|
+
|
|
561
|
+
cmd_hook_file = self.hook_scripts_dir / 'cmd_hooks.bat'
|
|
562
|
+
self._safe_write_file(cmd_hook_file, cmd_hook_content)
|
|
563
|
+
hooks.append(f"cmd_hook_script: {cmd_hook_file}")
|
|
564
|
+
|
|
565
|
+
# 创建doskey加载脚本
|
|
566
|
+
doskey_content = f'''@echo off
|
|
567
|
+
REM Load Direct CLI Hooks for CMD
|
|
568
|
+
|
|
569
|
+
doskey hook=call "{cmd_hook_file}" $*
|
|
570
|
+
echo ✅ Direct CLI Hooks loaded in CMD
|
|
571
|
+
'''
|
|
572
|
+
|
|
573
|
+
doskey_file = self.hook_scripts_dir / 'load_cmd_hooks.bat'
|
|
574
|
+
self._safe_write_file(doskey_file, doskey_content)
|
|
575
|
+
hooks.append(f"cmd_doskey_loader: {doskey_file}")
|
|
576
|
+
|
|
577
|
+
return hooks
|
|
578
|
+
|
|
579
|
+
def _install_generic_hooks(self) -> List[str]:
|
|
580
|
+
"""安装通用Hook"""
|
|
581
|
+
hooks = []
|
|
582
|
+
|
|
583
|
+
# 创建通用Python脚本作为Hook入口
|
|
584
|
+
generic_hook_content = f'''#!/usr/bin/env python3
|
|
585
|
+
"""
|
|
586
|
+
Direct CLI Hook System - Generic Hook
|
|
587
|
+
"""
|
|
588
|
+
|
|
589
|
+
import os
|
|
590
|
+
import sys
|
|
591
|
+
import json
|
|
592
|
+
import subprocess
|
|
593
|
+
from datetime import datetime
|
|
594
|
+
|
|
595
|
+
# Hook配置
|
|
596
|
+
HOOK_DIR = "{self.hook_dir}"
|
|
597
|
+
EVENT_LOG = os.path.join(HOOK_DIR, "hook_events.json")
|
|
598
|
+
|
|
599
|
+
def log_hook_event(event_type, content):
|
|
600
|
+
"""记录Hook事件"""
|
|
601
|
+
timestamp = datetime.now().isoformat() + "Z"
|
|
602
|
+
working_dir = os.getcwd()
|
|
603
|
+
|
|
604
|
+
event = {{
|
|
605
|
+
"timestamp": timestamp,
|
|
606
|
+
"source_cli": "generic",
|
|
607
|
+
"event_type": event_type,
|
|
608
|
+
"content": content,
|
|
609
|
+
"working_directory": working_dir
|
|
610
|
+
}}
|
|
611
|
+
|
|
612
|
+
# 添加到事件日志
|
|
613
|
+
with open(f"{{EVENT_LOG}}.tmp", "a", encoding="utf-8") as f:
|
|
614
|
+
f.write(json.dumps(event, ensure_ascii=False) + "\\n")
|
|
615
|
+
|
|
616
|
+
def main():
|
|
617
|
+
if len(sys.argv) < 3:
|
|
618
|
+
print("Usage: python generic_hook.py <event_type> <content>")
|
|
619
|
+
return 1
|
|
620
|
+
|
|
621
|
+
event_type = sys.argv[1]
|
|
622
|
+
content = " ".join(sys.argv[2:])
|
|
623
|
+
|
|
624
|
+
log_hook_event(event_type, content)
|
|
625
|
+
return 0
|
|
626
|
+
|
|
627
|
+
if __name__ == "__main__":
|
|
628
|
+
sys.exit(main())
|
|
629
|
+
'''
|
|
630
|
+
|
|
631
|
+
generic_hook_file = self.hook_scripts_dir / 'generic_hook.py'
|
|
632
|
+
self._safe_write_file(generic_hook_file, generic_hook_content)
|
|
633
|
+
hooks.append(f"generic_hook_script: {generic_hook_file}")
|
|
634
|
+
|
|
635
|
+
# 创建Shell别名生成脚本
|
|
636
|
+
alias_generator_content = f'''#!/bin/bash
|
|
637
|
+
# Generate Shell Aliases for Direct CLI Hooks
|
|
638
|
+
|
|
639
|
+
GENERIC_HOOK="{generic_hook_file}"
|
|
640
|
+
|
|
641
|
+
echo "# Direct CLI Hooks - Generated Aliases"
|
|
642
|
+
echo "# Add these to your shell configuration (.bashrc, .zshrc, etc.)"
|
|
643
|
+
echo ""
|
|
644
|
+
|
|
645
|
+
# 为常见命令生成别名
|
|
646
|
+
commands=("ls" "cat" "echo" "grep" "find" "mkdir" "rm" "cp" "mv")
|
|
647
|
+
|
|
648
|
+
for cmd in "${{commands[@]}}"; do
|
|
649
|
+
echo "alias $cmd='python3 $GENERIC_HOOK input \"\\$*\" && $cmd'"
|
|
650
|
+
done
|
|
651
|
+
|
|
652
|
+
echo ""
|
|
653
|
+
echo "# Load aliases with: source generated_aliases.sh"
|
|
654
|
+
'''
|
|
655
|
+
|
|
656
|
+
alias_file = self.hook_scripts_dir / 'generate_aliases.sh'
|
|
657
|
+
self._safe_write_file(alias_file, alias_generator_content)
|
|
658
|
+
hooks.append(f"alias_generator: {alias_file}")
|
|
659
|
+
|
|
660
|
+
return hooks
|
|
661
|
+
|
|
662
|
+
def _register_event_processors(self):
|
|
663
|
+
"""注册事件处理器"""
|
|
664
|
+
self.event_processors = {
|
|
665
|
+
'input': self._process_input_event,
|
|
666
|
+
'output': self._process_output_event,
|
|
667
|
+
'error': self._process_error_event,
|
|
668
|
+
'cross_cli_intent': self._process_cross_cli_intent_event
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
# 注册模式匹配器
|
|
672
|
+
self.pattern_matchers = {
|
|
673
|
+
'cross_cli_detection': self._detect_cross_cli_patterns,
|
|
674
|
+
'intent_classification': self._classify_user_intent
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
def _process_input_event(self, event: CLIHookEvent):
|
|
678
|
+
"""处理输入事件"""
|
|
679
|
+
# 检测跨CLI意图
|
|
680
|
+
intent = self._detect_cross_cli_patterns(event.content)
|
|
681
|
+
if intent:
|
|
682
|
+
event.user_intent = 'cross_cli_call'
|
|
683
|
+
event.target_clis = intent['target_clis']
|
|
684
|
+
event.confidence = intent['confidence']
|
|
685
|
+
event.detected_pattern = intent['pattern']
|
|
686
|
+
|
|
687
|
+
# 如果启用自动调用
|
|
688
|
+
if self.config.get('auto_cross_call_enabled', False):
|
|
689
|
+
self._execute_auto_cross_call(event)
|
|
690
|
+
|
|
691
|
+
def _process_output_event(self, event: CLIHookEvent):
|
|
692
|
+
"""处理输出事件"""
|
|
693
|
+
# 分析输出,学习成功模式
|
|
694
|
+
pass
|
|
695
|
+
|
|
696
|
+
def _process_error_event(self, event: CLIHookEvent):
|
|
697
|
+
"""处理错误事件"""
|
|
698
|
+
# 记录错误,优化检测
|
|
699
|
+
pass
|
|
700
|
+
|
|
701
|
+
def _process_cross_cli_intent_event(self, event: CLIHookEvent):
|
|
702
|
+
"""处理跨CLI意图事件"""
|
|
703
|
+
# 执行跨CLI调用
|
|
704
|
+
for target_cli in event.target_clis:
|
|
705
|
+
result = self.cross_system.call_cli(
|
|
706
|
+
source_cli=event.source_cli,
|
|
707
|
+
target_cli=target_cli,
|
|
708
|
+
request=event.content,
|
|
709
|
+
working_dir=event.working_directory
|
|
710
|
+
)
|
|
711
|
+
|
|
712
|
+
# 显示结果
|
|
713
|
+
if result['success']:
|
|
714
|
+
print(f"\\n🔗 跨CLI协作结果 ({event.source_cli} -> {target_cli}):")
|
|
715
|
+
print(result['response'][:500] + '...' if len(result['response']) > 500 else result['response'])
|
|
716
|
+
print("-" * 50)
|
|
717
|
+
|
|
718
|
+
def _detect_cross_cli_patterns(self, content: str) -> Optional[Dict[str, Any]]:
|
|
719
|
+
"""检测跨CLI协作模式"""
|
|
720
|
+
content_lower = content.lower()
|
|
721
|
+
|
|
722
|
+
# 检测跨CLI模式
|
|
723
|
+
for pattern in self.cross_cli_patterns:
|
|
724
|
+
import re
|
|
725
|
+
match = re.search(pattern, content_lower)
|
|
726
|
+
if match:
|
|
727
|
+
target_cli = match.group(1)
|
|
728
|
+
|
|
729
|
+
# 解析CLI别名
|
|
730
|
+
for canonical_name, aliases in self.cli_aliases.items():
|
|
731
|
+
if target_cli in aliases:
|
|
732
|
+
target_cli = canonical_name
|
|
733
|
+
break
|
|
734
|
+
|
|
735
|
+
if target_cli in self.cross_system.cli_methods:
|
|
736
|
+
return {
|
|
737
|
+
'target_clis': [target_cli],
|
|
738
|
+
'confidence': 0.8,
|
|
739
|
+
'pattern': pattern,
|
|
740
|
+
'detected_text': match.group(0)
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
return None
|
|
744
|
+
|
|
745
|
+
def _classify_user_intent(self, content: str) -> Optional[str]:
|
|
746
|
+
"""分类用户意图"""
|
|
747
|
+
content_lower = content.lower()
|
|
748
|
+
|
|
749
|
+
for intent_type, keywords in self.intent_keywords.items():
|
|
750
|
+
for keyword in keywords:
|
|
751
|
+
if keyword in content_lower:
|
|
752
|
+
return intent_type
|
|
753
|
+
|
|
754
|
+
return None
|
|
755
|
+
|
|
756
|
+
def _execute_auto_cross_call(self, event: CLIHookEvent):
|
|
757
|
+
"""执行自动跨CLI调用"""
|
|
758
|
+
if not event.target_clis or event.confidence < self.config.get('detection_confidence_threshold', 0.7):
|
|
759
|
+
return
|
|
760
|
+
|
|
761
|
+
for target_cli in event.target_clis:
|
|
762
|
+
# 检查目标CLI是否可用
|
|
763
|
+
status = self.cross_system.check_cli_status(target_cli)
|
|
764
|
+
if not status['exists']:
|
|
765
|
+
continue
|
|
766
|
+
|
|
767
|
+
# 异步执行跨CLI调用
|
|
768
|
+
def async_call():
|
|
769
|
+
result = self.cross_system.call_cli(
|
|
770
|
+
source_cli=event.source_cli,
|
|
771
|
+
target_cli=target_cli,
|
|
772
|
+
request=event.content,
|
|
773
|
+
working_dir=event.working_directory
|
|
774
|
+
)
|
|
775
|
+
|
|
776
|
+
if result['success']:
|
|
777
|
+
self._display_cross_cli_result(event, target_cli, result)
|
|
778
|
+
|
|
779
|
+
# 在后台线程中执行
|
|
780
|
+
threading.Thread(target=async_call, daemon=True).start()
|
|
781
|
+
|
|
782
|
+
def _display_cross_cli_result(self, event: CLIHookEvent, target_cli: str, result: Dict[str, Any]):
|
|
783
|
+
"""显示跨CLI调用结果"""
|
|
784
|
+
print(f"\\n🔗 跨CLI协作结果 ({event.source_cli} -> {target_cli}):")
|
|
785
|
+
print(f"⏱️ 执行时间: {result.get('execution_time', 0):.2f}s")
|
|
786
|
+
|
|
787
|
+
response = result.get('response', '')
|
|
788
|
+
if len(response) > 800:
|
|
789
|
+
print(response[:800] + "\\n... (响应已截断)")
|
|
790
|
+
else:
|
|
791
|
+
print(response)
|
|
792
|
+
|
|
793
|
+
print("-" * 50)
|
|
794
|
+
|
|
795
|
+
def process_pending_events(self):
|
|
796
|
+
"""处理待处理的事件"""
|
|
797
|
+
temp_event_file = self.event_log_file.with_suffix('.json.tmp')
|
|
798
|
+
|
|
799
|
+
if not temp_event_file.exists():
|
|
800
|
+
return
|
|
801
|
+
|
|
802
|
+
try:
|
|
803
|
+
# 读取临时事件文件
|
|
804
|
+
with open(temp_event_file, 'r', encoding='utf-8') as f:
|
|
805
|
+
lines = f.readlines()
|
|
806
|
+
|
|
807
|
+
if not lines:
|
|
808
|
+
return
|
|
809
|
+
|
|
810
|
+
# 处理每个事件
|
|
811
|
+
for line in lines:
|
|
812
|
+
line = line.strip()
|
|
813
|
+
if not line:
|
|
814
|
+
continue
|
|
815
|
+
|
|
816
|
+
try:
|
|
817
|
+
event_data = json.loads(line)
|
|
818
|
+
event = CLIHookEvent(**event_data)
|
|
819
|
+
|
|
820
|
+
# 根据事件类型处理
|
|
821
|
+
if event.event_type in self.event_processors:
|
|
822
|
+
self.event_processors[event.event_type](event)
|
|
823
|
+
|
|
824
|
+
# 记录到主事件日志
|
|
825
|
+
self._record_event(event)
|
|
826
|
+
|
|
827
|
+
except json.JSONDecodeError:
|
|
828
|
+
continue
|
|
829
|
+
except Exception as e:
|
|
830
|
+
print(f"Warning: Failed to process event: {e}")
|
|
831
|
+
continue
|
|
832
|
+
|
|
833
|
+
# 清空临时文件
|
|
834
|
+
temp_event_file.unlink()
|
|
835
|
+
|
|
836
|
+
except Exception as e:
|
|
837
|
+
print(f"Warning: Failed to process pending events: {e}")
|
|
838
|
+
|
|
839
|
+
def _record_event(self, event: CLIHookEvent):
|
|
840
|
+
"""记录Hook事件到主日志"""
|
|
841
|
+
try:
|
|
842
|
+
if self.event_log_file.exists():
|
|
843
|
+
with open(self.event_log_file, 'r', encoding='utf-8') as f:
|
|
844
|
+
events = json.load(f)
|
|
845
|
+
else:
|
|
846
|
+
events = []
|
|
847
|
+
|
|
848
|
+
events.append(asdict(event))
|
|
849
|
+
|
|
850
|
+
# 保留最近1000个事件
|
|
851
|
+
if len(events) > 1000:
|
|
852
|
+
events = events[-1000:]
|
|
853
|
+
|
|
854
|
+
self._safe_write_json(self.event_log_file, events)
|
|
855
|
+
|
|
856
|
+
except Exception as e:
|
|
857
|
+
print(f"Warning: Failed to record event: {e}")
|
|
858
|
+
|
|
859
|
+
def _safe_write_file(self, file_path: Path, content: str):
|
|
860
|
+
"""安全写入文件"""
|
|
861
|
+
try:
|
|
862
|
+
with open(file_path, 'w', encoding='utf-8') as f:
|
|
863
|
+
f.write(content)
|
|
864
|
+
|
|
865
|
+
# 设置执行权限(对于脚本文件)
|
|
866
|
+
if file_path.suffix in ['.sh', '.py', '.bat', '.ps1', '.zsh']:
|
|
867
|
+
os.chmod(file_path, 0o755)
|
|
868
|
+
|
|
869
|
+
except Exception as e:
|
|
870
|
+
raise Exception(f"Failed to write file {file_path}: {e}")
|
|
871
|
+
|
|
872
|
+
def _safe_write_json(self, file_path: Path, data: Any):
|
|
873
|
+
"""安全写入JSON文件"""
|
|
874
|
+
try:
|
|
875
|
+
with open(file_path, 'w', encoding='utf-8') as f:
|
|
876
|
+
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
877
|
+
except Exception as e:
|
|
878
|
+
raise Exception(f"Failed to write JSON file {file_path}: {e}")
|
|
879
|
+
|
|
880
|
+
def get_hook_status(self) -> Dict[str, Any]:
|
|
881
|
+
"""获取Hook状态"""
|
|
882
|
+
status = {
|
|
883
|
+
'config': self.config,
|
|
884
|
+
'hook_directory': str(self.hook_dir),
|
|
885
|
+
'hook_scripts': [],
|
|
886
|
+
'event_count': 0,
|
|
887
|
+
'recent_events': [],
|
|
888
|
+
'active_processors': list(self.event_processors.keys()),
|
|
889
|
+
'pattern_matchers': list(self.pattern_matchers.keys())
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
# 列出Hook脚本
|
|
893
|
+
if self.hook_scripts_dir.exists():
|
|
894
|
+
status['hook_scripts'] = [f.name for f in self.hook_scripts_dir.iterdir() if f.is_file()]
|
|
895
|
+
|
|
896
|
+
# 统计事件数量
|
|
897
|
+
try:
|
|
898
|
+
if self.event_log_file.exists():
|
|
899
|
+
with open(self.event_log_file, 'r', encoding='utf-8') as f:
|
|
900
|
+
events = json.load(f)
|
|
901
|
+
status['event_count'] = len(events)
|
|
902
|
+
status['recent_events'] = events[-5:] # 最近5个事件
|
|
903
|
+
except:
|
|
904
|
+
pass
|
|
905
|
+
|
|
906
|
+
return status
|
|
907
|
+
|
|
908
|
+
# 使用示例
|
|
909
|
+
if __name__ == '__main__':
|
|
910
|
+
hook_manager = DirectCLIHookManager()
|
|
911
|
+
|
|
912
|
+
print("🔗 真实CLI Hook系统")
|
|
913
|
+
print("=" * 50)
|
|
914
|
+
|
|
915
|
+
# 安装Shell Hook
|
|
916
|
+
print("🔧 安装Shell Hook...")
|
|
917
|
+
install_result = hook_manager.install_shell_hooks()
|
|
918
|
+
|
|
919
|
+
if install_result['success']:
|
|
920
|
+
print(f"✅ Hook安装成功: {install_result['shell_type']}")
|
|
921
|
+
print(f"📁 Hook目录: {hook_manager.hook_dir}")
|
|
922
|
+
print(f"📄 安装的Hook: {len(install_result['installed_hooks'])}")
|
|
923
|
+
|
|
924
|
+
for hook in install_result['installed_hooks']:
|
|
925
|
+
print(f" - {hook}")
|
|
926
|
+
|
|
927
|
+
# 处理待处理事件
|
|
928
|
+
print("\\n🔄 处理待处理事件...")
|
|
929
|
+
hook_manager.process_pending_events()
|
|
930
|
+
|
|
931
|
+
# 获取Hook状态
|
|
932
|
+
print("\\n📊 Hook状态:")
|
|
933
|
+
status = hook_manager.get_hook_status()
|
|
934
|
+
print(f" Hook脚本数量: {len(status['hook_scripts'])}")
|
|
935
|
+
print(f" 事件处理器: {', '.join(status['active_processors'])}")
|
|
936
|
+
print(f" 模式匹配器: {', '.join(status['pattern_matchers'])}")
|
|
937
|
+
print(f" 事件数量: {status['event_count']}")
|
|
938
|
+
|
|
939
|
+
# 显示使用说明
|
|
940
|
+
print("\\n📖 使用说明:")
|
|
941
|
+
if install_result['shell_type'] == 'bash':
|
|
942
|
+
print(" 在Bash中运行: source ~/.direct_cli_hooks/hook_scripts/load_bash_hooks.sh")
|
|
943
|
+
elif install_result['shell_type'] == 'powershell':
|
|
944
|
+
print(" 在PowerShell中重新启动或运行: . ~/.direct_cli_hooks/hook_scripts/powershell_hooks.ps1")
|
|
945
|
+
elif install_result['shell_type'] == 'zsh':
|
|
946
|
+
print(" 在Zsh中运行: source ~/.direct_cli_hooks/hook_scripts/zsh_hooks.zsh")
|
|
947
|
+
else:
|
|
948
|
+
print(" 手动加载Hook脚本中的函数到你的Shell配置文件")
|
|
949
|
+
|
|
950
|
+
print("\\n🔍 Hook现在可以检测跨CLI协作意图:")
|
|
951
|
+
print(" 示例: 'call claude to analyze this file'")
|
|
952
|
+
print(" 示例: 'using gemini to generate code'")
|
|
953
|
+
print(" 示例: 'ask copilot to help with debugging'")
|
|
954
|
+
|
|
955
|
+
else:
|
|
956
|
+
print(f"❌ Hook安装失败: {install_result['message']}")
|
|
957
|
+
|
|
958
|
+
print("\\n✅ Hook系统初始化完成!")
|