stigmergy 1.0.68 → 1.0.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +306 -300
- package/README.md +469 -301
- package/package.json +97 -81
- package/scripts/publish.js +268 -0
- package/scripts/simple-publish.js +59 -0
- package/src/index.js +12 -0
- package/test/enhanced-main-alignment.test.js +298 -0
- package/test/hook-system-integration-test.js +307 -0
- package/test/natural-language-skills-test.js +320 -0
- package/test/nl-integration-test.js +179 -0
- package/test/parameter-parsing-test.js +143 -0
- package/test/real-test.js +435 -0
- package/test/system-compatibility-test.js +447 -0
- package/test/tdd-fixes-test.js +211 -0
- package/test/third-party-skills-test.js +321 -0
- package/test/tool-selection-integration-test.js +157 -0
- package/test/unit/cli-scanner.test.js +291 -0
- package/test/unit/cross-cli-executor.test.js +399 -0
- package/src/adapters/claude/__init__.py +0 -13
- package/src/adapters/claude/claude_skills_integration.py +0 -609
- package/src/adapters/claude/hook_adapter.py +0 -663
- package/src/adapters/claude/install_claude_integration.py +0 -265
- package/src/adapters/claude/skills_hook_adapter.py +0 -841
- package/src/adapters/claude/standalone_claude_adapter.py +0 -384
- package/src/adapters/cline/__init__.py +0 -20
- package/src/adapters/cline/config.py +0 -108
- package/src/adapters/cline/install_cline_integration.py +0 -617
- package/src/adapters/cline/mcp_server.py +0 -713
- package/src/adapters/cline/standalone_cline_adapter.py +0 -459
- package/src/adapters/codebuddy/__init__.py +0 -13
- package/src/adapters/codebuddy/buddy_adapter.py +0 -1125
- package/src/adapters/codebuddy/install_codebuddy_integration.py +0 -279
- package/src/adapters/codebuddy/skills_hook_adapter.py +0 -672
- package/src/adapters/codebuddy/skills_integration.py +0 -395
- package/src/adapters/codebuddy/standalone_codebuddy_adapter.py +0 -403
- package/src/adapters/codex/__init__.py +0 -11
- package/src/adapters/codex/base.py +0 -46
- package/src/adapters/codex/install_codex_integration.py +0 -311
- package/src/adapters/codex/mcp_server.py +0 -493
- package/src/adapters/codex/natural_language_parser.py +0 -82
- package/src/adapters/codex/slash_command_adapter.py +0 -326
- package/src/adapters/codex/standalone_codex_adapter.py +0 -362
- package/src/adapters/copilot/__init__.py +0 -13
- package/src/adapters/copilot/install_copilot_integration.py +0 -564
- package/src/adapters/copilot/mcp_adapter.py +0 -772
- package/src/adapters/copilot/mcp_server.py +0 -168
- package/src/adapters/copilot/standalone_copilot_adapter.py +0 -114
- package/src/adapters/gemini/__init__.py +0 -13
- package/src/adapters/gemini/extension_adapter.py +0 -690
- package/src/adapters/gemini/install_gemini_integration.py +0 -257
- package/src/adapters/gemini/standalone_gemini_adapter.py +0 -366
- package/src/adapters/iflow/__init__.py +0 -7
- package/src/adapters/iflow/hook_adapter.py +0 -1038
- package/src/adapters/iflow/hook_installer.py +0 -536
- package/src/adapters/iflow/install_iflow_integration.py +0 -271
- package/src/adapters/iflow/official_hook_adapter.py +0 -1272
- package/src/adapters/iflow/standalone_iflow_adapter.py +0 -48
- package/src/adapters/iflow/workflow_adapter.py +0 -793
- package/src/adapters/qoder/hook_installer.py +0 -732
- package/src/adapters/qoder/install_qoder_integration.py +0 -265
- package/src/adapters/qoder/notification_hook_adapter.py +0 -863
- package/src/adapters/qoder/standalone_qoder_adapter.py +0 -48
- package/src/adapters/qwen/__init__.py +0 -17
- package/src/adapters/qwencode/__init__.py +0 -13
- package/src/adapters/qwencode/inheritance_adapter.py +0 -818
- package/src/adapters/qwencode/install_qwencode_integration.py +0 -276
- package/src/adapters/qwencode/standalone_qwencode_adapter.py +0 -399
- package/src/atomic_collaboration_handler.py +0 -461
- package/src/cli_collaboration_agent.py +0 -697
- package/src/collaboration/hooks.py +0 -315
- package/src/core/__init__.py +0 -21
- package/src/core/ai_environment_scanner.py +0 -331
- package/src/core/base_adapter.py +0 -220
- package/src/core/cli_hook_integration.py +0 -406
- package/src/core/cross_cli_executor.py +0 -713
- package/src/core/cross_cli_mapping.py +0 -1165
- package/src/core/cross_platform_encoding.py +0 -365
- package/src/core/cross_platform_safe_cli.py +0 -894
- package/src/core/direct_cli_executor.py +0 -805
- package/src/core/direct_cli_hook_system.py +0 -958
- package/src/core/enhanced_init_processor.py +0 -467
- package/src/core/graceful_cli_executor.py +0 -912
- package/src/core/md_enhancer.py +0 -342
- package/src/core/md_generator.py +0 -619
- package/src/core/models.py +0 -218
- package/src/core/parser.py +0 -108
- package/src/core/real_cli_hook_system.py +0 -852
- package/src/core/real_cross_cli_system.py +0 -925
- package/src/core/verified_cross_cli_system.py +0 -961
- package/src/deploy.js +0 -737
- package/src/enhanced-main.js +0 -626
- package/src/enhanced_deploy.js +0 -303
- package/src/enhanced_universal_cli_setup.py +0 -930
- package/src/kimi_wrapper.py +0 -104
- package/src/main.js +0 -1309
- package/src/shell_integration.py +0 -398
- package/src/simple-main.js +0 -315
- package/src/smart_router_creator.py +0 -323
- package/src/universal_cli_setup.py +0 -1289
- package/src/utils/__init__.py +0 -12
- package/src/utils/cli_detector.py +0 -445
- package/src/utils/file_utils.py +0 -246
|
@@ -1,863 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
QoderCLI通知Hook适配器 - 基于QoderCLI通知Hook系统的原生集成
|
|
3
|
-
|
|
4
|
-
基于QoderCLI官方通知Hook机制实现跨CLI调用功能。
|
|
5
|
-
Qoder CLI 目前主要支持通知类 Hooks,使用 AppleScript 进行 macOS 通知。
|
|
6
|
-
|
|
7
|
-
QoderCLI Hook机制:
|
|
8
|
-
- 通知类Hooks:通过osascript发送macOS系统通知
|
|
9
|
-
- 环境变量Hook:通过QODER_CROSS_CLI_* 环境变量进行通信
|
|
10
|
-
- 钩子点:任务执行前、执行后、错误处理
|
|
11
|
-
- 平台支持:主要针对macOS,兼容其他平台的fallback机制
|
|
12
|
-
|
|
13
|
-
完全符合项目约束条件:
|
|
14
|
-
- 使用Qoder CLI官方Hook机制
|
|
15
|
-
- 不改变CLI启动和使用方式
|
|
16
|
-
- 不依赖包装器
|
|
17
|
-
- 完全无损扩展
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
import os
|
|
21
|
-
import sys
|
|
22
|
-
import json
|
|
23
|
-
import logging
|
|
24
|
-
import asyncio
|
|
25
|
-
import subprocess
|
|
26
|
-
import platform
|
|
27
|
-
import tempfile
|
|
28
|
-
from typing import Dict, Any, Optional, List
|
|
29
|
-
from datetime import datetime
|
|
30
|
-
from pathlib import Path
|
|
31
|
-
from dataclasses import dataclass
|
|
32
|
-
|
|
33
|
-
from ...core.base_adapter import BaseCrossCLIAdapter, IntentResult
|
|
34
|
-
from ...core.parser import NaturalLanguageParser
|
|
35
|
-
|
|
36
|
-
logger = logging.getLogger(__name__)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
@dataclass
|
|
40
|
-
class QoderHookEvent:
|
|
41
|
-
"""Qoder Hook事件对象"""
|
|
42
|
-
hook_type: str
|
|
43
|
-
stage: str
|
|
44
|
-
data: Dict[str, Any]
|
|
45
|
-
timestamp: datetime
|
|
46
|
-
session_id: str
|
|
47
|
-
command: Optional[str] = None
|
|
48
|
-
exit_code: Optional[int] = None
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class QoderNotificationHookAdapter(BaseCrossCLIAdapter):
|
|
52
|
-
"""
|
|
53
|
-
QoderCLI通知Hook适配器
|
|
54
|
-
|
|
55
|
-
基于Qoder CLI的通知Hook系统和环境变量机制实现跨CLI调用功能。
|
|
56
|
-
主要通过通知系统进行状态提示,环境变量进行实际数据交换。
|
|
57
|
-
"""
|
|
58
|
-
|
|
59
|
-
def __init__(self, cli_name: str = "qoder"):
|
|
60
|
-
"""
|
|
61
|
-
初始化Qoder通知Hook适配器
|
|
62
|
-
|
|
63
|
-
Args:
|
|
64
|
-
cli_name: CLI工具名称,默认为"qoder"
|
|
65
|
-
"""
|
|
66
|
-
super().__init__(cli_name)
|
|
67
|
-
|
|
68
|
-
# Qoder Hook相关配置
|
|
69
|
-
self.is_macos = platform.system() == "Darwin"
|
|
70
|
-
self.hook_enabled = False
|
|
71
|
-
self.cross_cli_enabled = True
|
|
72
|
-
|
|
73
|
-
# 环境变量配置
|
|
74
|
-
self.env_vars = {
|
|
75
|
-
'QODER_CROSS_CLI_ENABLED': '1',
|
|
76
|
-
'QODER_CROSS_CLI_RESPONSE_FILE': '',
|
|
77
|
-
'QODER_CROSS_CLI_REQUEST_FILE': '',
|
|
78
|
-
'QODER_CROSS_CLI_STATUS_FILE': '',
|
|
79
|
-
'QODER_HOOK_STAGE': '',
|
|
80
|
-
'QODER_HOOK_COMMAND': '',
|
|
81
|
-
'QODER_HOOK_SESSION_ID': ''
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
# 统计信息
|
|
85
|
-
self.hook_executions = {
|
|
86
|
-
'pre_command': 0,
|
|
87
|
-
'post_command': 0,
|
|
88
|
-
'error_handling': 0,
|
|
89
|
-
'notification_sent': 0
|
|
90
|
-
}
|
|
91
|
-
self.cross_cli_calls = 0
|
|
92
|
-
self.processed_events: List[QoderHookEvent] = []
|
|
93
|
-
self.active_sessions: Dict[str, Dict] = {}
|
|
94
|
-
|
|
95
|
-
# Hook脚本路径
|
|
96
|
-
self.hook_script_dir = os.path.expanduser("~/.qoder/hooks")
|
|
97
|
-
self.temp_dir = None
|
|
98
|
-
|
|
99
|
-
# 组件
|
|
100
|
-
self.parser = NaturalLanguageParser()
|
|
101
|
-
|
|
102
|
-
logger.info("Qoder通知Hook适配器初始化完成")
|
|
103
|
-
|
|
104
|
-
async def initialize(self) -> bool:
|
|
105
|
-
"""
|
|
106
|
-
初始化适配器
|
|
107
|
-
|
|
108
|
-
Returns:
|
|
109
|
-
bool: 初始化是否成功
|
|
110
|
-
"""
|
|
111
|
-
try:
|
|
112
|
-
logger.info("开始初始化Qoder通知Hook适配器...")
|
|
113
|
-
|
|
114
|
-
# 1. 检查Qoder CLI环境
|
|
115
|
-
if not self._check_qoder_environment():
|
|
116
|
-
logger.error("Qoder CLI环境检查失败")
|
|
117
|
-
return False
|
|
118
|
-
|
|
119
|
-
# 2. 创建临时目录和Hook目录
|
|
120
|
-
await self._create_directories()
|
|
121
|
-
|
|
122
|
-
# 3. 设置环境变量
|
|
123
|
-
await self._setup_environment_variables()
|
|
124
|
-
|
|
125
|
-
# 4. 创建Hook脚本
|
|
126
|
-
if not await self._create_hook_scripts():
|
|
127
|
-
logger.error("Hook脚本创建失败")
|
|
128
|
-
return False
|
|
129
|
-
|
|
130
|
-
# 5. 初始化通知系统
|
|
131
|
-
await self._initialize_notification_system()
|
|
132
|
-
|
|
133
|
-
self.hook_enabled = True
|
|
134
|
-
logger.info("Qoder通知Hook适配器初始化成功")
|
|
135
|
-
return True
|
|
136
|
-
|
|
137
|
-
except Exception as e:
|
|
138
|
-
logger.error(f"初始化Qoder通知Hook适配器失败: {e}")
|
|
139
|
-
self.record_error()
|
|
140
|
-
return False
|
|
141
|
-
|
|
142
|
-
def _check_qoder_environment(self) -> bool:
|
|
143
|
-
"""
|
|
144
|
-
检查Qoder CLI环境
|
|
145
|
-
|
|
146
|
-
Returns:
|
|
147
|
-
bool: 环境是否可用
|
|
148
|
-
"""
|
|
149
|
-
try:
|
|
150
|
-
# 检查Qoder CLI命令
|
|
151
|
-
result = subprocess.run(
|
|
152
|
-
['qoder', '--version'],
|
|
153
|
-
capture_output=True,
|
|
154
|
-
text=True,
|
|
155
|
-
timeout=5
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
if result.returncode == 0:
|
|
159
|
-
logger.info(f"检测到Qoder CLI: {result.stdout.strip()}")
|
|
160
|
-
return True
|
|
161
|
-
else:
|
|
162
|
-
logger.warning("Qoder CLI不可用,使用开发模式")
|
|
163
|
-
return True # 开发环境中继续
|
|
164
|
-
|
|
165
|
-
except (subprocess.TimeoutExpired, FileNotFoundError):
|
|
166
|
-
logger.warning("Qoder CLI环境检查失败,使用开发模式")
|
|
167
|
-
return True # 开发环境中继续
|
|
168
|
-
|
|
169
|
-
async def _create_directories(self) -> None:
|
|
170
|
-
"""创建必要的目录"""
|
|
171
|
-
directories = [
|
|
172
|
-
self.hook_script_dir,
|
|
173
|
-
os.path.expanduser("~/.qoder/logs"),
|
|
174
|
-
os.path.expanduser("~/.qoder/cache")
|
|
175
|
-
]
|
|
176
|
-
|
|
177
|
-
for directory in directories:
|
|
178
|
-
os.makedirs(directory, exist_ok=True)
|
|
179
|
-
|
|
180
|
-
# 创建临时目录
|
|
181
|
-
self.temp_dir = tempfile.mkdtemp(prefix="qoder_cross_cli_")
|
|
182
|
-
logger.info(f"临时目录: {self.temp_dir}")
|
|
183
|
-
|
|
184
|
-
async def _setup_environment_variables(self) -> None:
|
|
185
|
-
"""设置环境变量"""
|
|
186
|
-
# 设置响应文件路径
|
|
187
|
-
response_file = os.path.join(self.temp_dir, "cross_cli_response.json")
|
|
188
|
-
request_file = os.path.join(self.temp_dir, "cross_cli_request.json")
|
|
189
|
-
status_file = os.path.join(self.temp_dir, "cross_cli_status.json")
|
|
190
|
-
|
|
191
|
-
self.env_vars.update({
|
|
192
|
-
'QODER_CROSS_CLI_RESPONSE_FILE': response_file,
|
|
193
|
-
'QODER_CROSS_CLI_REQUEST_FILE': request_file,
|
|
194
|
-
'QODER_CROSS_CLI_STATUS_FILE': status_file
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
# 设置环境变量
|
|
198
|
-
for key, value in self.env_vars.items():
|
|
199
|
-
os.environ[key] = value
|
|
200
|
-
|
|
201
|
-
logger.info("环境变量设置完成")
|
|
202
|
-
|
|
203
|
-
async def _create_hook_scripts(self) -> bool:
|
|
204
|
-
"""
|
|
205
|
-
创建Hook脚本
|
|
206
|
-
|
|
207
|
-
Returns:
|
|
208
|
-
bool: 创建是否成功
|
|
209
|
-
"""
|
|
210
|
-
try:
|
|
211
|
-
# 创建前置Hook脚本
|
|
212
|
-
pre_hook_script = '''#!/bin/bash
|
|
213
|
-
# Qoder CLI前置Hook脚本
|
|
214
|
-
# 用于检测跨CLI调用意图
|
|
215
|
-
|
|
216
|
-
COMMAND="$1"
|
|
217
|
-
STAGE="pre_command"
|
|
218
|
-
SESSION_ID="${QODER_HOOK_SESSION_ID:-$(date +%s)}"
|
|
219
|
-
|
|
220
|
-
# 设置环境变量
|
|
221
|
-
export QODER_HOOK_STAGE="$STAGE"
|
|
222
|
-
export QODER_HOOK_COMMAND="$COMMAND"
|
|
223
|
-
export QODER_HOOK_SESSION_ID="$SESSION_ID"
|
|
224
|
-
|
|
225
|
-
# 记录请求到文件
|
|
226
|
-
REQUEST_FILE="$QODER_CROSS_CLI_REQUEST_FILE"
|
|
227
|
-
if [ -n "$REQUEST_FILE" ]; then
|
|
228
|
-
cat > "$REQUEST_FILE" << EOF
|
|
229
|
-
{
|
|
230
|
-
"stage": "$STAGE",
|
|
231
|
-
"command": "$COMMAND",
|
|
232
|
-
"session_id": "$SESSION_ID",
|
|
233
|
-
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
|
234
|
-
"env_vars": $(env | grep QODER_ | jq -R 'split("="; {key: .[0], value: .[1]}' | jq -s 'from_entries')
|
|
235
|
-
}
|
|
236
|
-
EOF
|
|
237
|
-
fi
|
|
238
|
-
|
|
239
|
-
# 检测跨CLI调用意图
|
|
240
|
-
if echo "$COMMAND" | grep -E "(请用|调用|用|让).*claude|gemini|qwencode|iflow|qoder|codebuddy|codex" > /dev/null 2>&1; then
|
|
241
|
-
# 发送跨CLI检测通知
|
|
242
|
-
if command -v osascript > /dev/null 2>&1; then
|
|
243
|
-
osascript -e "display notification \"检测到跨CLI调用意图\" with title \"QoderCLI\" subtitle \"准备调用其他AI工具\""
|
|
244
|
-
fi
|
|
245
|
-
fi
|
|
246
|
-
|
|
247
|
-
exit 0
|
|
248
|
-
'''
|
|
249
|
-
|
|
250
|
-
# 创建后置Hook脚本
|
|
251
|
-
post_hook_script = '''#!/bin/bash
|
|
252
|
-
# Qoder CLI后置Hook脚本
|
|
253
|
-
# 用于处理跨CLI调用结果
|
|
254
|
-
|
|
255
|
-
EXIT_CODE=$?
|
|
256
|
-
STAGE="post_command"
|
|
257
|
-
COMMAND="$1"
|
|
258
|
-
SESSION_ID="${QODER_HOOK_SESSION_ID:-$(date +%s)}"
|
|
259
|
-
|
|
260
|
-
# 设置环境变量
|
|
261
|
-
export QODER_HOOK_STAGE="$STAGE"
|
|
262
|
-
export QODER_HOOK_COMMAND="$COMMAND"
|
|
263
|
-
export QODER_HOOK_SESSION_ID="$SESSION_ID"
|
|
264
|
-
|
|
265
|
-
# 记录完成状态
|
|
266
|
-
if [ -n "$QODER_CROSS_CLI_STATUS_FILE" ]; then
|
|
267
|
-
cat > "$QODER_CROSS_CLI_STATUS_FILE" << EOF
|
|
268
|
-
{
|
|
269
|
-
"stage": "$STAGE",
|
|
270
|
-
"command": "$COMMAND",
|
|
271
|
-
"session_id": "$SESSION_ID",
|
|
272
|
-
"exit_code": $EXIT_CODE,
|
|
273
|
-
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
|
274
|
-
"completed": true
|
|
275
|
-
}
|
|
276
|
-
EOF
|
|
277
|
-
fi
|
|
278
|
-
|
|
279
|
-
# 检查是否有跨CLI响应
|
|
280
|
-
RESPONSE_FILE="$QODER_CROSS_CLI_RESPONSE_FILE"
|
|
281
|
-
if [ -f "$RESPONSE_FILE" ] && [ -s "$RESPONSE_FILE" ]; then
|
|
282
|
-
# 发送完成通知
|
|
283
|
-
if command -v osascript > /dev/null 2>&1; then
|
|
284
|
-
osascript -e 'display notification "[OK] 跨CLI调用完成" with title "QoderCLI"'
|
|
285
|
-
fi
|
|
286
|
-
fi
|
|
287
|
-
|
|
288
|
-
exit $EXIT_CODE
|
|
289
|
-
'''
|
|
290
|
-
|
|
291
|
-
# 创建错误处理Hook脚本
|
|
292
|
-
error_hook_script = '''#!/bin/bash
|
|
293
|
-
# Qoder CLI错误处理Hook脚本
|
|
294
|
-
# 用于处理跨CLI调用错误
|
|
295
|
-
|
|
296
|
-
EXIT_CODE=$?
|
|
297
|
-
STAGE="error_handling"
|
|
298
|
-
COMMAND="$1"
|
|
299
|
-
SESSION_ID="${QODER_HOOK_SESSION_ID:-$(date +%s)}"
|
|
300
|
-
|
|
301
|
-
# 设置环境变量
|
|
302
|
-
export QODER_HOOK_STAGE="$STAGE"
|
|
303
|
-
export QODER_HOOK_COMMAND="$COMMAND"
|
|
304
|
-
export QODER_HOOK_SESSION_ID="$SESSION_ID"
|
|
305
|
-
|
|
306
|
-
# 如果有错误,发送通知
|
|
307
|
-
if [ $EXIT_CODE -ne 0 ]; then
|
|
308
|
-
if command -v osascript > /dev/null 2>&1; then
|
|
309
|
-
osascript -e 'display notification "⌛️ 你提交的任务需要授权呀…" with title "QoderCLI"'
|
|
310
|
-
fi
|
|
311
|
-
fi
|
|
312
|
-
|
|
313
|
-
exit 0
|
|
314
|
-
'''
|
|
315
|
-
|
|
316
|
-
# 写入脚本文件
|
|
317
|
-
scripts = {
|
|
318
|
-
'pre_hook.sh': pre_hook_script,
|
|
319
|
-
'post_hook.sh': post_hook_script,
|
|
320
|
-
'error_hook.sh': error_hook_script
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
for filename, content in scripts.items():
|
|
324
|
-
script_path = os.path.join(self.hook_script_dir, filename)
|
|
325
|
-
with open(script_path, 'w', encoding='utf-8') as f:
|
|
326
|
-
f.write(content)
|
|
327
|
-
os.chmod(script_path, 0o755)
|
|
328
|
-
|
|
329
|
-
logger.info("Qoder Hook脚本创建完成")
|
|
330
|
-
return True
|
|
331
|
-
|
|
332
|
-
except Exception as e:
|
|
333
|
-
logger.error(f"创建Hook脚本失败: {e}")
|
|
334
|
-
return False
|
|
335
|
-
|
|
336
|
-
async def _initialize_notification_system(self) -> None:
|
|
337
|
-
"""初始化通知系统"""
|
|
338
|
-
if self.is_macos:
|
|
339
|
-
# 测试AppleScript是否可用
|
|
340
|
-
try:
|
|
341
|
-
subprocess.run([
|
|
342
|
-
'osascript', '-e', 'display notification "Qoder CLI Hook系统初始化" with title "测试通知"'
|
|
343
|
-
], check=True, capture_output=True, timeout=5)
|
|
344
|
-
logger.info("macOS通知系统初始化成功")
|
|
345
|
-
except subprocess.CalledProcessError:
|
|
346
|
-
logger.warning("macOS通知系统不可用,将使用fallback通知")
|
|
347
|
-
else:
|
|
348
|
-
logger.info("非macOS系统,将使用fallback通知机制")
|
|
349
|
-
|
|
350
|
-
# ==================== 跨CLI功能实现 ====================
|
|
351
|
-
|
|
352
|
-
async def handle_cross_cli_detection(self, command: str, session_id: str) -> Optional[str]:
|
|
353
|
-
"""
|
|
354
|
-
处理跨CLI调用检测
|
|
355
|
-
|
|
356
|
-
Args:
|
|
357
|
-
command: 命令内容
|
|
358
|
-
session_id: 会话ID
|
|
359
|
-
|
|
360
|
-
Returns:
|
|
361
|
-
Optional[str]: 跨CLI调用结果
|
|
362
|
-
"""
|
|
363
|
-
try:
|
|
364
|
-
logger.info(f"检测跨CLI调用: {command}")
|
|
365
|
-
|
|
366
|
-
# 解析跨CLI意图
|
|
367
|
-
intent = self.parser.parse_intent(command, "qoder")
|
|
368
|
-
|
|
369
|
-
if not intent.is_cross_cli:
|
|
370
|
-
return None
|
|
371
|
-
|
|
372
|
-
# 避免自我调用
|
|
373
|
-
if intent.target_cli == self.cli_name:
|
|
374
|
-
return None
|
|
375
|
-
|
|
376
|
-
# 发送检测通知
|
|
377
|
-
await self._send_notification(
|
|
378
|
-
f"检测到跨CLI调用: {intent.target_cli}",
|
|
379
|
-
"QoderCLI",
|
|
380
|
-
subtitle=f"任务: {intent.task[:50]}..."
|
|
381
|
-
)
|
|
382
|
-
|
|
383
|
-
# 执行跨CLI调用
|
|
384
|
-
result = await self._execute_cross_cli_call(
|
|
385
|
-
intent.target_cli,
|
|
386
|
-
intent.task,
|
|
387
|
-
{"command": command, "session_id": session_id}
|
|
388
|
-
)
|
|
389
|
-
|
|
390
|
-
if result:
|
|
391
|
-
self.cross_cli_calls += 1
|
|
392
|
-
|
|
393
|
-
# 将结果写入响应文件
|
|
394
|
-
await self._write_response_file(result)
|
|
395
|
-
|
|
396
|
-
# 发送完成通知
|
|
397
|
-
await self._send_notification(
|
|
398
|
-
"[OK] 跨CLI调用完成",
|
|
399
|
-
"QoderCLI",
|
|
400
|
-
subtitle=f"{intent.target_cli.upper()} 任务已完成"
|
|
401
|
-
)
|
|
402
|
-
|
|
403
|
-
return result
|
|
404
|
-
|
|
405
|
-
return None
|
|
406
|
-
|
|
407
|
-
except Exception as e:
|
|
408
|
-
logger.error(f"处理跨CLI检测失败: {e}")
|
|
409
|
-
self.record_error()
|
|
410
|
-
return None
|
|
411
|
-
|
|
412
|
-
async def _execute_cross_cli_call(
|
|
413
|
-
self,
|
|
414
|
-
target_cli: str,
|
|
415
|
-
task: str,
|
|
416
|
-
context: Dict[str, Any]
|
|
417
|
-
) -> Optional[str]:
|
|
418
|
-
"""
|
|
419
|
-
执行跨CLI调用
|
|
420
|
-
|
|
421
|
-
Args:
|
|
422
|
-
target_cli: 目标CLI工具
|
|
423
|
-
task: 要执行的任务
|
|
424
|
-
context: 执行上下文
|
|
425
|
-
|
|
426
|
-
Returns:
|
|
427
|
-
Optional[str]: 执行结果
|
|
428
|
-
"""
|
|
429
|
-
try:
|
|
430
|
-
logger.info(f"执行跨CLI调用: {target_cli} -> {task}")
|
|
431
|
-
|
|
432
|
-
# 获取目标CLI适配器
|
|
433
|
-
from ...core.base_adapter import get_cross_cli_adapter
|
|
434
|
-
target_adapter = get_cross_cli_adapter(target_cli)
|
|
435
|
-
|
|
436
|
-
if not target_adapter:
|
|
437
|
-
logger.warning(f"目标CLI适配器不可用: {target_cli}")
|
|
438
|
-
return self._format_error_result(target_cli, task, f"目标CLI工具 '{target_cli}' 不可用")
|
|
439
|
-
|
|
440
|
-
if not target_adapter.is_available():
|
|
441
|
-
logger.warning(f"目标CLI工具不可用: {target_cli}")
|
|
442
|
-
return self._format_error_result(target_cli, task, f"目标CLI工具 '{target_cli}' 当前不可用")
|
|
443
|
-
|
|
444
|
-
# 构建执行上下文
|
|
445
|
-
execution_context = {
|
|
446
|
-
'source_cli': self.cli_name,
|
|
447
|
-
'target_cli': target_cli,
|
|
448
|
-
'original_task': task,
|
|
449
|
-
'qoder_context': context,
|
|
450
|
-
'timestamp': datetime.now().isoformat()
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
# 执行任务
|
|
454
|
-
result = await target_adapter.execute_task(task, execution_context)
|
|
455
|
-
|
|
456
|
-
# 记录成功的跨CLI调用
|
|
457
|
-
self.processed_requests.append({
|
|
458
|
-
'type': 'cross_cli_execution',
|
|
459
|
-
'target_cli': target_cli,
|
|
460
|
-
'task': task,
|
|
461
|
-
'success': True,
|
|
462
|
-
'result_length': len(result),
|
|
463
|
-
'timestamp': datetime.now().isoformat()
|
|
464
|
-
})
|
|
465
|
-
|
|
466
|
-
# 格式化结果
|
|
467
|
-
formatted_result = self._format_success_result(target_cli, task, result)
|
|
468
|
-
|
|
469
|
-
logger.info(f"跨CLI调用成功: {target_cli}")
|
|
470
|
-
return formatted_result
|
|
471
|
-
|
|
472
|
-
except Exception as e:
|
|
473
|
-
logger.error(f"跨CLI调用失败: {target_cli}, {e}")
|
|
474
|
-
self.record_error()
|
|
475
|
-
|
|
476
|
-
self.processed_requests.append({
|
|
477
|
-
'type': 'cross_cli_execution',
|
|
478
|
-
'target_cli': target_cli,
|
|
479
|
-
'task': task,
|
|
480
|
-
'success': False,
|
|
481
|
-
'error': str(e),
|
|
482
|
-
'timestamp': datetime.now().isoformat()
|
|
483
|
-
})
|
|
484
|
-
|
|
485
|
-
return self._format_error_result(target_cli, task, str(e))
|
|
486
|
-
|
|
487
|
-
async def _send_notification(self, message: str, title: str = "QoderCLI", subtitle: str = "") -> None:
|
|
488
|
-
"""
|
|
489
|
-
发送通知
|
|
490
|
-
|
|
491
|
-
Args:
|
|
492
|
-
message: 通知消息
|
|
493
|
-
title: 通知标题
|
|
494
|
-
subtitle: 副标题
|
|
495
|
-
"""
|
|
496
|
-
try:
|
|
497
|
-
if self.is_macos:
|
|
498
|
-
# 使用AppleScript发送macOS通知
|
|
499
|
-
script = f'display notification "{message}" with title "{title}"'
|
|
500
|
-
if subtitle:
|
|
501
|
-
script += f' subtitle "{subtitle}"'
|
|
502
|
-
|
|
503
|
-
subprocess.run(['osascript', '-e', script], check=True, capture_output=True, timeout=5)
|
|
504
|
-
self.hook_executions['notification_sent'] += 1
|
|
505
|
-
else:
|
|
506
|
-
# 非macOS系统的fallback通知
|
|
507
|
-
logger.info(f"[NOTIFICATION] {title}: {message} ({subtitle})")
|
|
508
|
-
|
|
509
|
-
except Exception as e:
|
|
510
|
-
logger.error(f"发送通知失败: {e}")
|
|
511
|
-
# Fallback到日志
|
|
512
|
-
logger.info(f"[NOTIFICATION] {title}: {message}")
|
|
513
|
-
|
|
514
|
-
async def _write_response_file(self, result: str) -> None:
|
|
515
|
-
"""
|
|
516
|
-
写入响应文件
|
|
517
|
-
|
|
518
|
-
Args:
|
|
519
|
-
result: 响应结果
|
|
520
|
-
"""
|
|
521
|
-
try:
|
|
522
|
-
response_file = self.env_vars.get('QODER_CROSS_CLI_RESPONSE_FILE')
|
|
523
|
-
if response_file:
|
|
524
|
-
response_data = {
|
|
525
|
-
'result': result,
|
|
526
|
-
'timestamp': datetime.now().isoformat(),
|
|
527
|
-
'cross_cli': True
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
with open(response_file, 'w', encoding='utf-8') as f:
|
|
531
|
-
json.dump(response_data, f, ensure_ascii=False, indent=2)
|
|
532
|
-
|
|
533
|
-
logger.debug(f"响应已写入: {response_file}")
|
|
534
|
-
|
|
535
|
-
except Exception as e:
|
|
536
|
-
logger.error(f"写入响应文件失败: {e}")
|
|
537
|
-
|
|
538
|
-
def _format_success_result(self, target_cli: str, task: str, result: str) -> str:
|
|
539
|
-
"""
|
|
540
|
-
格式化成功的跨CLI调用结果
|
|
541
|
-
|
|
542
|
-
Args:
|
|
543
|
-
target_cli: 目标CLI工具
|
|
544
|
-
task: 原始任务
|
|
545
|
-
result: 执行结果
|
|
546
|
-
|
|
547
|
-
Returns:
|
|
548
|
-
str: 格式化的结果
|
|
549
|
-
"""
|
|
550
|
-
return f"""## 🔗 跨CLI调用结果 (Qoder Hook)
|
|
551
|
-
|
|
552
|
-
**源工具**: Qoder CLI
|
|
553
|
-
**目标工具**: {target_cli.upper()}
|
|
554
|
-
**原始任务**: {task}
|
|
555
|
-
**执行时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
|
556
|
-
|
|
557
|
-
---
|
|
558
|
-
|
|
559
|
-
{result}
|
|
560
|
-
|
|
561
|
-
---
|
|
562
|
-
|
|
563
|
-
*此结果由跨CLI集成系统通过Qoder CLI通知Hook提供*"""
|
|
564
|
-
|
|
565
|
-
def _format_error_result(self, target_cli: str, task: str, error_message: str) -> str:
|
|
566
|
-
"""
|
|
567
|
-
格式化错误的跨CLI调用结果
|
|
568
|
-
|
|
569
|
-
Args:
|
|
570
|
-
target_cli: 目标CLI工具
|
|
571
|
-
task: 原始任务
|
|
572
|
-
error_message: 错误信息
|
|
573
|
-
|
|
574
|
-
Returns:
|
|
575
|
-
str: 格式化的错误结果
|
|
576
|
-
"""
|
|
577
|
-
return f"""## ❌ 跨CLI调用失败
|
|
578
|
-
|
|
579
|
-
**源工具**: Qoder CLI
|
|
580
|
-
**目标工具**: {target_cli.upper()}
|
|
581
|
-
**原始任务**: {task}
|
|
582
|
-
**错误信息**: {error_message}
|
|
583
|
-
**失败时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
|
584
|
-
|
|
585
|
-
请检查目标CLI工具是否正确安装和配置。
|
|
586
|
-
|
|
587
|
-
---
|
|
588
|
-
|
|
589
|
-
*此错误由跨CLI集成系统报告*"""
|
|
590
|
-
|
|
591
|
-
# ==================== Hook监控 ====================
|
|
592
|
-
|
|
593
|
-
async def monitor_hook_events(self) -> None:
|
|
594
|
-
"""监控Hook事件"""
|
|
595
|
-
try:
|
|
596
|
-
request_file = self.env_vars.get('QODER_CROSS_CLI_REQUEST_FILE')
|
|
597
|
-
status_file = self.env_vars.get('QODER_CROSS_CLI_STATUS_FILE')
|
|
598
|
-
|
|
599
|
-
if request_file and os.path.exists(request_file):
|
|
600
|
-
await self._process_request_file(request_file)
|
|
601
|
-
|
|
602
|
-
if status_file and os.path.exists(status_file):
|
|
603
|
-
await self._process_status_file(status_file)
|
|
604
|
-
|
|
605
|
-
except Exception as e:
|
|
606
|
-
logger.error(f"监控Hook事件失败: {e}")
|
|
607
|
-
|
|
608
|
-
async def _process_request_file(self, file_path: str) -> None:
|
|
609
|
-
"""处理请求文件"""
|
|
610
|
-
try:
|
|
611
|
-
with open(file_path, 'r', encoding='utf-8') as f:
|
|
612
|
-
request_data = json.load(f)
|
|
613
|
-
|
|
614
|
-
event = QoderHookEvent(
|
|
615
|
-
hook_type='notification',
|
|
616
|
-
stage=request_data.get('stage', ''),
|
|
617
|
-
data=request_data,
|
|
618
|
-
timestamp=datetime.now(),
|
|
619
|
-
session_id=request_data.get('session_id', ''),
|
|
620
|
-
command=request_data.get('command', '')
|
|
621
|
-
)
|
|
622
|
-
|
|
623
|
-
self.processed_events.append(event)
|
|
624
|
-
|
|
625
|
-
# 如果是前置命令,检测跨CLI调用
|
|
626
|
-
if event.stage == 'pre_command' and event.command:
|
|
627
|
-
cross_cli_result = await self.handle_cross_cli_detection(
|
|
628
|
-
event.command,
|
|
629
|
-
event.session_id
|
|
630
|
-
)
|
|
631
|
-
|
|
632
|
-
if cross_cli_result:
|
|
633
|
-
logger.info("通过Hook检测到并处理了跨CLI调用")
|
|
634
|
-
|
|
635
|
-
except Exception as e:
|
|
636
|
-
logger.error(f"处理请求文件失败: {e}")
|
|
637
|
-
|
|
638
|
-
async def _process_status_file(self, file_path: str) -> None:
|
|
639
|
-
"""处理状态文件"""
|
|
640
|
-
try:
|
|
641
|
-
with open(file_path, 'r', encoding='utf-8') as f:
|
|
642
|
-
status_data = json.load(f)
|
|
643
|
-
|
|
644
|
-
logger.debug(f"Hook状态: {status_data}")
|
|
645
|
-
|
|
646
|
-
# 更新会话统计
|
|
647
|
-
session_id = status_data.get('session_id', '')
|
|
648
|
-
if session_id:
|
|
649
|
-
if session_id not in self.active_sessions:
|
|
650
|
-
self.active_sessions[session_id] = {
|
|
651
|
-
'start_time': datetime.now(),
|
|
652
|
-
'commands': [],
|
|
653
|
-
'cross_cli_calls': 0
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
session = self.active_sessions[session_id]
|
|
657
|
-
session['commands'].append(status_data)
|
|
658
|
-
|
|
659
|
-
except Exception as e:
|
|
660
|
-
logger.error(f"处理状态文件失败: {e}")
|
|
661
|
-
|
|
662
|
-
# ==================== 基础接口实现 ====================
|
|
663
|
-
|
|
664
|
-
def is_available(self) -> bool:
|
|
665
|
-
"""
|
|
666
|
-
检查适配器是否可用
|
|
667
|
-
|
|
668
|
-
Returns:
|
|
669
|
-
bool: 是否可用
|
|
670
|
-
"""
|
|
671
|
-
return (
|
|
672
|
-
self.hook_enabled and
|
|
673
|
-
os.path.exists(self.hook_script_dir) and
|
|
674
|
-
self.temp_dir is not None
|
|
675
|
-
)
|
|
676
|
-
|
|
677
|
-
async def execute_task(self, task: str, context: Dict[str, Any]) -> str:
|
|
678
|
-
"""
|
|
679
|
-
执行跨CLI任务 - Qoder适配器的具体实现
|
|
680
|
-
|
|
681
|
-
Args:
|
|
682
|
-
task: 要执行的任务描述
|
|
683
|
-
context: 执行上下文信息
|
|
684
|
-
|
|
685
|
-
Returns:
|
|
686
|
-
str: 任务执行结果
|
|
687
|
-
"""
|
|
688
|
-
try:
|
|
689
|
-
session_id = context.get('session_id', f"task-{datetime.now().timestamp()}")
|
|
690
|
-
|
|
691
|
-
# 直接处理跨CLI检测
|
|
692
|
-
cross_cli_result = await self.handle_cross_cli_detection(task, session_id)
|
|
693
|
-
|
|
694
|
-
if cross_cli_result:
|
|
695
|
-
return cross_cli_result
|
|
696
|
-
|
|
697
|
-
return f"Qoder通知Hook适配器处理: {task}"
|
|
698
|
-
|
|
699
|
-
except Exception as e:
|
|
700
|
-
logger.error(f"执行任务失败: {task}, 错误: {e}")
|
|
701
|
-
self.record_error()
|
|
702
|
-
return f"任务执行失败: {str(e)}"
|
|
703
|
-
|
|
704
|
-
async def health_check(self) -> Dict[str, Any]:
|
|
705
|
-
"""
|
|
706
|
-
健康检查
|
|
707
|
-
|
|
708
|
-
Returns:
|
|
709
|
-
Dict[str, Any]: 健康状态
|
|
710
|
-
"""
|
|
711
|
-
base_health = await super().health_check()
|
|
712
|
-
|
|
713
|
-
qoder_health = {
|
|
714
|
-
'hook_enabled': self.hook_enabled,
|
|
715
|
-
'is_macos': self.is_macos,
|
|
716
|
-
'hook_executions': self.hook_executions.copy(),
|
|
717
|
-
'cross_cli_calls': self.cross_cli_calls,
|
|
718
|
-
'processed_events_count': len(self.processed_events),
|
|
719
|
-
'active_sessions_count': len(self.active_sessions),
|
|
720
|
-
'hook_script_dir': self.hook_script_dir,
|
|
721
|
-
'hook_scripts_exist': os.path.exists(os.path.join(self.hook_script_dir, 'pre_hook.sh')),
|
|
722
|
-
'temp_dir': self.temp_dir,
|
|
723
|
-
'env_vars_configured': all(key in os.environ for key in self.env_vars.keys())
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
# 检查环境
|
|
727
|
-
try:
|
|
728
|
-
qoder_health['qoder_environment'] = self._check_qoder_environment()
|
|
729
|
-
except Exception as e:
|
|
730
|
-
qoder_health['qoder_environment_error'] = str(e)
|
|
731
|
-
|
|
732
|
-
# 合并基础健康信息
|
|
733
|
-
base_health.update(qoder_health)
|
|
734
|
-
return base_health
|
|
735
|
-
|
|
736
|
-
def get_statistics(self) -> Dict[str, Any]:
|
|
737
|
-
"""
|
|
738
|
-
获取适配器统计信息
|
|
739
|
-
|
|
740
|
-
Returns:
|
|
741
|
-
Dict[str, Any]: 统计信息
|
|
742
|
-
"""
|
|
743
|
-
base_stats = super().get_statistics()
|
|
744
|
-
|
|
745
|
-
qoder_stats = {
|
|
746
|
-
'hook_enabled': self.hook_enabled,
|
|
747
|
-
'is_macos': self.is_macos,
|
|
748
|
-
'hook_executions': self.hook_executions.copy(),
|
|
749
|
-
'cross_cli_calls': self.cross_cli_calls,
|
|
750
|
-
'processed_events_count': len(self.processed_events),
|
|
751
|
-
'active_sessions_count': len(self.active_sessions),
|
|
752
|
-
'total_hook_calls': sum(self.hook_executions.values()),
|
|
753
|
-
'notification_sent': self.hook_executions['notification_sent'],
|
|
754
|
-
'hook_script_dir': self.hook_script_dir
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
base_stats.update(qoder_stats)
|
|
758
|
-
return base_stats
|
|
759
|
-
|
|
760
|
-
async def cleanup(self) -> bool:
|
|
761
|
-
"""
|
|
762
|
-
清理适配器资源
|
|
763
|
-
|
|
764
|
-
Returns:
|
|
765
|
-
bool: 清理是否成功
|
|
766
|
-
"""
|
|
767
|
-
try:
|
|
768
|
-
# 清理统计信息
|
|
769
|
-
self.processed_events.clear()
|
|
770
|
-
self.active_sessions.clear()
|
|
771
|
-
self.hook_executions = {key: 0 for key in self.hook_executions.keys()}
|
|
772
|
-
|
|
773
|
-
# 清理临时目录
|
|
774
|
-
if self.temp_dir and os.path.exists(self.temp_dir):
|
|
775
|
-
import shutil
|
|
776
|
-
shutil.rmtree(self.temp_dir, ignore_errors=True)
|
|
777
|
-
self.temp_dir = None
|
|
778
|
-
|
|
779
|
-
logger.info("Qoder通知Hook适配器清理完成")
|
|
780
|
-
return True
|
|
781
|
-
|
|
782
|
-
except Exception as e:
|
|
783
|
-
logger.error(f"清理Qoder通知Hook适配器失败: {e}")
|
|
784
|
-
return False
|
|
785
|
-
|
|
786
|
-
async def start_monitoring(self) -> None:
|
|
787
|
-
"""开始监控Hook事件"""
|
|
788
|
-
if not self.is_available():
|
|
789
|
-
logger.warning("适配器不可用,无法开始监控")
|
|
790
|
-
return
|
|
791
|
-
|
|
792
|
-
logger.info("开始监控Qoder Hook事件")
|
|
793
|
-
try:
|
|
794
|
-
while self.hook_enabled:
|
|
795
|
-
await self.monitor_hook_events()
|
|
796
|
-
await asyncio.sleep(1) # 每秒检查一次
|
|
797
|
-
except asyncio.CancelledError:
|
|
798
|
-
logger.info("Hook监控已停止")
|
|
799
|
-
except Exception as e:
|
|
800
|
-
logger.error(f"Hook监控异常: {e}")
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
# 创建全局适配器实例
|
|
804
|
-
_global_adapter: Optional[QoderNotificationHookAdapter] = None
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
def get_qoder_notification_hook_adapter() -> QoderNotificationHookAdapter:
|
|
808
|
-
"""
|
|
809
|
-
获取Qoder通知Hook适配器实例
|
|
810
|
-
|
|
811
|
-
Returns:
|
|
812
|
-
QoderNotificationHookAdapter: 适配器实例
|
|
813
|
-
"""
|
|
814
|
-
global _global_adapter
|
|
815
|
-
if _global_adapter is None:
|
|
816
|
-
_global_adapter = QoderNotificationHookAdapter()
|
|
817
|
-
# 异步初始化需要在调用时进行
|
|
818
|
-
return _global_adapter
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
# 便捷函数
|
|
822
|
-
async def initialize_qoder_notification_adapter() -> bool:
|
|
823
|
-
"""
|
|
824
|
-
初始化Qoder通知Hook适配器
|
|
825
|
-
|
|
826
|
-
Returns:
|
|
827
|
-
bool: 初始化是否成功
|
|
828
|
-
"""
|
|
829
|
-
adapter = get_qoder_notification_hook_adapter()
|
|
830
|
-
return await adapter.initialize()
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
def is_qoder_notification_adapter_available() -> bool:
|
|
834
|
-
"""
|
|
835
|
-
检查Qoder通知Hook适配器是否可用
|
|
836
|
-
|
|
837
|
-
Returns:
|
|
838
|
-
bool: 是否可用
|
|
839
|
-
"""
|
|
840
|
-
adapter = get_qoder_notification_hook_adapter()
|
|
841
|
-
return adapter.is_available()
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
if __name__ == "__main__":
|
|
845
|
-
import asyncio
|
|
846
|
-
|
|
847
|
-
async def main():
|
|
848
|
-
"""主函数 - 用于测试和独立运行"""
|
|
849
|
-
adapter = QoderNotificationHookAdapter()
|
|
850
|
-
|
|
851
|
-
# 初始化
|
|
852
|
-
if await adapter.initialize():
|
|
853
|
-
print("Qoder通知Hook适配器初始化成功")
|
|
854
|
-
|
|
855
|
-
# 开始监控
|
|
856
|
-
try:
|
|
857
|
-
await adapter.start_monitoring()
|
|
858
|
-
except KeyboardInterrupt:
|
|
859
|
-
print("\n停止监控")
|
|
860
|
-
else:
|
|
861
|
-
print("Qoder通知Hook适配器初始化失败")
|
|
862
|
-
|
|
863
|
-
asyncio.run(main())
|