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,961 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
真实CLI调用系统 - 基于真实参数规范和文件传递
|
|
3
|
-
严格基于真实CLI参数,使用自动化参数和文件上下文传递
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import os
|
|
7
|
-
import sys
|
|
8
|
-
import json
|
|
9
|
-
import subprocess
|
|
10
|
-
import tempfile
|
|
11
|
-
import time
|
|
12
|
-
from pathlib import Path
|
|
13
|
-
from typing import Dict, List, Optional, Tuple, Any, Union
|
|
14
|
-
from dataclasses import dataclass
|
|
15
|
-
from datetime import datetime
|
|
16
|
-
import re
|
|
17
|
-
|
|
18
|
-
# 导入编码安全模块
|
|
19
|
-
sys.path.append(str(Path(__file__).parent))
|
|
20
|
-
from cross_platform_encoding import safe_file_write, safe_file_read
|
|
21
|
-
|
|
22
|
-
@dataclass
|
|
23
|
-
class RealCLISpecs:
|
|
24
|
-
"""真实CLI规范 - 基于实际文档和参数"""
|
|
25
|
-
name: str
|
|
26
|
-
call_patterns: List[str] # 按优先级排序的真实调用方式
|
|
27
|
-
install_command: str
|
|
28
|
-
type: str # npm, python, binary
|
|
29
|
-
auto_params: List[str] # 自动化参数
|
|
30
|
-
context_params: List[str] # 文件上下文参数
|
|
31
|
-
prompt_params: Dict[str, str] # 提示词参数格式
|
|
32
|
-
version_check: str
|
|
33
|
-
api_env: Optional[str]
|
|
34
|
-
|
|
35
|
-
class VerifiedCrossCLISystem:
|
|
36
|
-
"""已验证的真实跨CLI调用系统"""
|
|
37
|
-
|
|
38
|
-
def __init__(self):
|
|
39
|
-
# 基于真实CLI规范的调用方式
|
|
40
|
-
self.cli_specs = {
|
|
41
|
-
'qwen': RealCLISpecs(
|
|
42
|
-
name='Qwen CLI',
|
|
43
|
-
call_patterns=[
|
|
44
|
-
'qwen', # 直接命令
|
|
45
|
-
'python -m qwen', # python -m方式
|
|
46
|
-
'python3 -m qwen' # python3方式
|
|
47
|
-
],
|
|
48
|
-
install_command='pip install qwen-cli',
|
|
49
|
-
type='python',
|
|
50
|
-
auto_params=[
|
|
51
|
-
'--approval-mode yolo', # 自动批准所有操作
|
|
52
|
-
'--dangerously-bypass-approvals-and-sandbox' # 跳过确认和沙箱
|
|
53
|
-
],
|
|
54
|
-
context_params=[
|
|
55
|
-
'--file', # 文件引用
|
|
56
|
-
'--context-file' # 上下文文件
|
|
57
|
-
],
|
|
58
|
-
prompt_params={
|
|
59
|
-
'direct': '{prompt}', # 直接传递提示词
|
|
60
|
-
'flag': '--prompt "{prompt}"' # 使用prompt参数
|
|
61
|
-
},
|
|
62
|
-
version_check='qwen --version',
|
|
63
|
-
api_env='QWEN_API_KEY'
|
|
64
|
-
),
|
|
65
|
-
|
|
66
|
-
'iflow': RealCLISpecs(
|
|
67
|
-
name='iFlow CLI',
|
|
68
|
-
call_patterns=[
|
|
69
|
-
'iflow', # 直接命令
|
|
70
|
-
'npx @iflow-ai/iflow-cli', # npx方式
|
|
71
|
-
'iflow-cli' # 别名
|
|
72
|
-
],
|
|
73
|
-
install_command='npm install -g @iflow-ai/iflow-cli',
|
|
74
|
-
type='npm',
|
|
75
|
-
auto_params=[
|
|
76
|
-
'--yolo', # 自动接受所有操作
|
|
77
|
-
'--approval-mode auto' # 自动审批模式
|
|
78
|
-
],
|
|
79
|
-
context_params=[
|
|
80
|
-
'--file', # 文件引用
|
|
81
|
-
'--context', # 上下文
|
|
82
|
-
'--input-file' # 输入文件
|
|
83
|
-
],
|
|
84
|
-
prompt_params={
|
|
85
|
-
'direct': '{prompt}', # 直接传递提示词
|
|
86
|
-
'flag': '--prompt "{prompt}"' # 使用prompt参数
|
|
87
|
-
},
|
|
88
|
-
version_check='iflow --version',
|
|
89
|
-
api_env='IFLOW_API_KEY'
|
|
90
|
-
),
|
|
91
|
-
|
|
92
|
-
'gemini': RealCLISpecs(
|
|
93
|
-
name='Gemini CLI',
|
|
94
|
-
call_patterns=[
|
|
95
|
-
'gemini', # 直接命令
|
|
96
|
-
'npx @google/gemini-cli', # npx方式
|
|
97
|
-
'gemini-cli' # 别名
|
|
98
|
-
],
|
|
99
|
-
install_command='npm install -g @google/gemini-cli',
|
|
100
|
-
type='npm',
|
|
101
|
-
auto_params=[
|
|
102
|
-
'--auto-approve', # 自动批准
|
|
103
|
-
'--no-confirmation' # 无需确认
|
|
104
|
-
],
|
|
105
|
-
context_params=[
|
|
106
|
-
'--file', # 文件引用
|
|
107
|
-
'--context-file', # 上下文文件
|
|
108
|
-
'--input' # 输入文件
|
|
109
|
-
],
|
|
110
|
-
prompt_params={
|
|
111
|
-
'direct': '{prompt}', # 直接传递提示词
|
|
112
|
-
'flag': '--prompt "{prompt}"' # 使用prompt参数
|
|
113
|
-
},
|
|
114
|
-
version_check='gemini --version',
|
|
115
|
-
api_env='GOOGLE_AI_API_KEY'
|
|
116
|
-
),
|
|
117
|
-
|
|
118
|
-
'copilot': RealCLISpecs(
|
|
119
|
-
name='GitHub Copilot CLI',
|
|
120
|
-
call_patterns=[
|
|
121
|
-
'copilot', # 直接命令
|
|
122
|
-
'npx @github/copilot', # npx方式
|
|
123
|
-
'github-copilot' # 别名
|
|
124
|
-
],
|
|
125
|
-
install_command='npm install -g @github/copilot',
|
|
126
|
-
type='npm',
|
|
127
|
-
auto_params=[
|
|
128
|
-
'--allow-all-tools', # 允许所有工具自动运行
|
|
129
|
-
'--auto-approve' # 自动批准
|
|
130
|
-
],
|
|
131
|
-
context_params=[
|
|
132
|
-
'--file', # 文件引用
|
|
133
|
-
'--context', # 上下文
|
|
134
|
-
'--workspace' # 工作区
|
|
135
|
-
],
|
|
136
|
-
prompt_params={
|
|
137
|
-
'short': '-p "{prompt}"', # 使用-p参数
|
|
138
|
-
'long': '--prompt "{prompt}"' # 使用--prompt参数
|
|
139
|
-
},
|
|
140
|
-
version_check='copilot --version',
|
|
141
|
-
api_env='GITHUB_TOKEN'
|
|
142
|
-
),
|
|
143
|
-
|
|
144
|
-
'codex': RealCLISpecs(
|
|
145
|
-
name='OpenAI Codex CLI',
|
|
146
|
-
call_patterns=[
|
|
147
|
-
'codex', # 直接命令
|
|
148
|
-
'openai-codex', # 别名
|
|
149
|
-
'codex exec' # exec子命令
|
|
150
|
-
],
|
|
151
|
-
install_command='curl -fsSL https://openai.com/codex-cli/install.sh | bash',
|
|
152
|
-
type='binary',
|
|
153
|
-
auto_params=[
|
|
154
|
-
'--full-auto', # 完全自动化
|
|
155
|
-
'--auto-execute' # 自动执行
|
|
156
|
-
],
|
|
157
|
-
context_params=[
|
|
158
|
-
'--file', # 文件引用
|
|
159
|
-
'--context-file', # 上下文文件
|
|
160
|
-
'--input', # 输入
|
|
161
|
-
'--workspace' # 工作区
|
|
162
|
-
],
|
|
163
|
-
prompt_params={
|
|
164
|
-
'direct': '"{prompt}"', # 直接传递提示词
|
|
165
|
-
'exec': 'exec "{prompt}"' # 使用exec子命令
|
|
166
|
-
},
|
|
167
|
-
version_check='codex --version',
|
|
168
|
-
api_env='OPENAI_API_KEY'
|
|
169
|
-
),
|
|
170
|
-
|
|
171
|
-
'claude': RealCLISpecs(
|
|
172
|
-
name='Claude Code CLI',
|
|
173
|
-
call_patterns=[
|
|
174
|
-
'claude', # 直接命令
|
|
175
|
-
'npx @anthropic/claude-code', # npx方式
|
|
176
|
-
'claude-code' # 别名
|
|
177
|
-
],
|
|
178
|
-
install_command='npm install -g @anthropic/claude-code',
|
|
179
|
-
type='npm',
|
|
180
|
-
auto_params=[
|
|
181
|
-
'--auto-approve', # 自动批准
|
|
182
|
-
'--no-confirmation', # 无需确认
|
|
183
|
-
'--dangerously-bypass-approvals' # 跳过审批(危险)
|
|
184
|
-
],
|
|
185
|
-
context_params=[
|
|
186
|
-
'--file', # 文件引用
|
|
187
|
-
'--context-file', # 上下文文件
|
|
188
|
-
'--project', # 项目
|
|
189
|
-
'--workspace' # 工作区
|
|
190
|
-
],
|
|
191
|
-
prompt_params={
|
|
192
|
-
'direct': '{prompt}', # 直接传递提示词
|
|
193
|
-
'flag': '--prompt "{prompt}"', # 使用prompt参数
|
|
194
|
-
'message': '--message "{prompt}"' # 使用message参数
|
|
195
|
-
},
|
|
196
|
-
version_check='claude --version',
|
|
197
|
-
api_env='ANTHROPIC_API_KEY'
|
|
198
|
-
)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
# 内存系统
|
|
202
|
-
self.memory_dir = Path.home() / '.verified_cross_cli'
|
|
203
|
-
self.memory_dir.mkdir(exist_ok=True)
|
|
204
|
-
self.context_dir = self.memory_dir / 'context_files'
|
|
205
|
-
self.context_dir.mkdir(exist_ok=True)
|
|
206
|
-
|
|
207
|
-
self.call_history_file = self.memory_dir / 'verified_call_history.json'
|
|
208
|
-
self.context_cache_file = self.memory_dir / 'context_cache.json'
|
|
209
|
-
|
|
210
|
-
def check_cli_availability(self, cli_name: str) -> Dict[str, Any]:
|
|
211
|
-
"""检查CLI可用性 - 基于真实规范"""
|
|
212
|
-
if cli_name not in self.cli_specs:
|
|
213
|
-
return {
|
|
214
|
-
'exists': False,
|
|
215
|
-
'error': f'Unknown CLI: {cli_name}',
|
|
216
|
-
'available_methods': [],
|
|
217
|
-
'best_method': None,
|
|
218
|
-
'needs_install': True
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
spec = self.cli_specs[cli_name]
|
|
222
|
-
available_methods = []
|
|
223
|
-
best_method = None
|
|
224
|
-
|
|
225
|
-
# 按优先级测试每种调用方式
|
|
226
|
-
for call_pattern in spec.call_patterns:
|
|
227
|
-
if self._test_call_method(call_pattern, spec):
|
|
228
|
-
available_methods.append(call_pattern)
|
|
229
|
-
if not best_method:
|
|
230
|
-
best_method = call_pattern
|
|
231
|
-
|
|
232
|
-
return {
|
|
233
|
-
'exists': len(available_methods) > 0,
|
|
234
|
-
'cli_name': cli_name,
|
|
235
|
-
'type': spec.type,
|
|
236
|
-
'available_methods': available_methods,
|
|
237
|
-
'best_method': best_method,
|
|
238
|
-
'needs_install': len(available_methods) == 0,
|
|
239
|
-
'install_command': spec.install_command,
|
|
240
|
-
'api_env': spec.api_env,
|
|
241
|
-
'version_info': self._get_version_info(best_method, spec) if best_method else None
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
def _test_call_method(self, call_pattern: str, spec: RealCLISpecs) -> bool:
|
|
245
|
-
"""测试真实的CLI调用方法"""
|
|
246
|
-
try:
|
|
247
|
-
# 提取基础命令进行测试
|
|
248
|
-
if ' ' in call_pattern:
|
|
249
|
-
base_command = call_pattern.split()[0]
|
|
250
|
-
else:
|
|
251
|
-
base_command = call_pattern
|
|
252
|
-
|
|
253
|
-
# 首先检查命令是否存在
|
|
254
|
-
if spec.type == 'python':
|
|
255
|
-
# Python类型特殊处理
|
|
256
|
-
if call_pattern.startswith('python -m'):
|
|
257
|
-
# 测试python -m方式
|
|
258
|
-
module = call_pattern.split()[-1]
|
|
259
|
-
result = subprocess.run(
|
|
260
|
-
['python', '-c', f'import {module}'],
|
|
261
|
-
capture_output=True,
|
|
262
|
-
text=True,
|
|
263
|
-
timeout=5
|
|
264
|
-
)
|
|
265
|
-
if result.returncode == 0:
|
|
266
|
-
return True
|
|
267
|
-
else:
|
|
268
|
-
# 直接命令测试
|
|
269
|
-
result = subprocess.run(
|
|
270
|
-
f"where {base_command}" if os.name == 'nt' else f"which {base_command}",
|
|
271
|
-
shell=True,
|
|
272
|
-
capture_output=True,
|
|
273
|
-
text=True,
|
|
274
|
-
timeout=5
|
|
275
|
-
)
|
|
276
|
-
if result.returncode == 0:
|
|
277
|
-
# 进一步测试版本
|
|
278
|
-
version_result = subprocess.run(
|
|
279
|
-
[base_command, '--version'],
|
|
280
|
-
capture_output=True,
|
|
281
|
-
text=True,
|
|
282
|
-
timeout=10
|
|
283
|
-
)
|
|
284
|
-
return version_result.returncode == 0 or version_result.returncode == 1 # 有些CLI版本检查返回1
|
|
285
|
-
|
|
286
|
-
elif spec.type == 'npm':
|
|
287
|
-
# npm类型处理
|
|
288
|
-
if call_pattern.startswith('npx '):
|
|
289
|
-
# 测试npx方式
|
|
290
|
-
try:
|
|
291
|
-
result = subprocess.run(
|
|
292
|
-
call_pattern.split() + ['--version'],
|
|
293
|
-
capture_output=True,
|
|
294
|
-
text=True,
|
|
295
|
-
timeout=15
|
|
296
|
-
)
|
|
297
|
-
return result.returncode == 0 or result.returncode == 1
|
|
298
|
-
except:
|
|
299
|
-
pass
|
|
300
|
-
else:
|
|
301
|
-
# 直接命令测试
|
|
302
|
-
result = subprocess.run(
|
|
303
|
-
f"where {base_command}" if os.name == 'nt' else f"which {base_command}",
|
|
304
|
-
shell=True,
|
|
305
|
-
capture_output=True,
|
|
306
|
-
text=True,
|
|
307
|
-
timeout=5
|
|
308
|
-
)
|
|
309
|
-
if result.returncode == 0:
|
|
310
|
-
# 测试版本
|
|
311
|
-
version_result = subprocess.run(
|
|
312
|
-
[base_command, '--version'],
|
|
313
|
-
capture_output=True,
|
|
314
|
-
text=True,
|
|
315
|
-
timeout=10
|
|
316
|
-
)
|
|
317
|
-
return version_result.returncode == 0 or version_result.returncode == 1
|
|
318
|
-
|
|
319
|
-
elif spec.type == 'binary':
|
|
320
|
-
# 二进制类型处理
|
|
321
|
-
if 'exec' in call_pattern:
|
|
322
|
-
# codex exec特殊处理
|
|
323
|
-
base_cmd = 'codex'
|
|
324
|
-
else:
|
|
325
|
-
base_cmd = base_command
|
|
326
|
-
|
|
327
|
-
result = subprocess.run(
|
|
328
|
-
f"where {base_cmd}" if os.name == 'nt' else f"which {base_cmd}",
|
|
329
|
-
shell=True,
|
|
330
|
-
capture_output=True,
|
|
331
|
-
text=True,
|
|
332
|
-
timeout=5
|
|
333
|
-
)
|
|
334
|
-
if result.returncode == 0:
|
|
335
|
-
# 测试版本
|
|
336
|
-
version_result = subprocess.run(
|
|
337
|
-
[base_cmd, '--version'],
|
|
338
|
-
capture_output=True,
|
|
339
|
-
text=True,
|
|
340
|
-
timeout=10
|
|
341
|
-
)
|
|
342
|
-
return version_result.returncode == 0 or version_result.returncode == 1
|
|
343
|
-
|
|
344
|
-
return False
|
|
345
|
-
|
|
346
|
-
except subprocess.TimeoutExpired:
|
|
347
|
-
return False
|
|
348
|
-
except Exception:
|
|
349
|
-
return False
|
|
350
|
-
|
|
351
|
-
def _get_version_info(self, call_pattern: str, spec: RealCLISpecs) -> Optional[str]:
|
|
352
|
-
"""获取CLI版本信息"""
|
|
353
|
-
try:
|
|
354
|
-
if ' ' in call_pattern:
|
|
355
|
-
cmd_parts = call_pattern.split()
|
|
356
|
-
else:
|
|
357
|
-
cmd_parts = [call_pattern]
|
|
358
|
-
|
|
359
|
-
# 构建版本检查命令
|
|
360
|
-
if spec.type == 'python' and call_pattern.startswith('python -m'):
|
|
361
|
-
module = call_pattern.split()[-1]
|
|
362
|
-
result = subprocess.run(
|
|
363
|
-
['python', '-m', module, '--version'],
|
|
364
|
-
capture_output=True,
|
|
365
|
-
text=True,
|
|
366
|
-
timeout=10
|
|
367
|
-
)
|
|
368
|
-
else:
|
|
369
|
-
base_cmd = cmd_parts[0]
|
|
370
|
-
result = subprocess.run(
|
|
371
|
-
[base_cmd, '--version'],
|
|
372
|
-
capture_output=True,
|
|
373
|
-
text=True,
|
|
374
|
-
timeout=10
|
|
375
|
-
)
|
|
376
|
-
|
|
377
|
-
if result.returncode == 0:
|
|
378
|
-
return result.stdout.strip() or result.stderr.strip()
|
|
379
|
-
elif result.returncode == 1 and (result.stdout.strip() or result.stderr.strip()):
|
|
380
|
-
# 有些CLI版本检查返回1但有输出
|
|
381
|
-
return result.stdout.strip() or result.stderr.strip()
|
|
382
|
-
|
|
383
|
-
return None
|
|
384
|
-
|
|
385
|
-
except:
|
|
386
|
-
return None
|
|
387
|
-
|
|
388
|
-
def call_cli_with_file_context(self,
|
|
389
|
-
source_cli: str,
|
|
390
|
-
target_cli: str,
|
|
391
|
-
request: str,
|
|
392
|
-
context_files: List[str] = None,
|
|
393
|
-
working_dir: str = None,
|
|
394
|
-
auto_mode: bool = True,
|
|
395
|
-
timeout: int = 120) -> Dict[str, Any]:
|
|
396
|
-
"""使用文件上下文调用CLI - 基于真实参数规范"""
|
|
397
|
-
|
|
398
|
-
result = {
|
|
399
|
-
'success': False,
|
|
400
|
-
'response': '',
|
|
401
|
-
'error': '',
|
|
402
|
-
'command_used': '',
|
|
403
|
-
'context_files_used': [],
|
|
404
|
-
'auto_mode_used': auto_mode,
|
|
405
|
-
'timestamp': datetime.now().isoformat(),
|
|
406
|
-
'execution_time': 0
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
start_time = time.time()
|
|
410
|
-
|
|
411
|
-
# 检查目标CLI状态
|
|
412
|
-
status = self.check_cli_availability(target_cli)
|
|
413
|
-
|
|
414
|
-
if not status['exists']:
|
|
415
|
-
result.update(self._handle_missing_cli(source_cli, target_cli, request, status))
|
|
416
|
-
result['execution_time'] = time.time() - start_time
|
|
417
|
-
self._record_call(source_cli, target_cli, request, result)
|
|
418
|
-
return result
|
|
419
|
-
|
|
420
|
-
try:
|
|
421
|
-
spec = self.cli_specs[target_cli]
|
|
422
|
-
best_method = status['best_method']
|
|
423
|
-
|
|
424
|
-
# 创建上下文文件
|
|
425
|
-
context_file_path = self._create_context_file(request, context_files, working_dir, target_cli)
|
|
426
|
-
result['context_files_used'] = [context_file_path]
|
|
427
|
-
|
|
428
|
-
# 构建基于真实参数的命令
|
|
429
|
-
command = self._build_verified_command(best_method, spec, request, context_file_path, auto_mode)
|
|
430
|
-
result['command_used'] = command
|
|
431
|
-
|
|
432
|
-
# 准备环境
|
|
433
|
-
env = self._prepare_environment(spec)
|
|
434
|
-
|
|
435
|
-
# 设置工作目录
|
|
436
|
-
exec_working_dir = working_dir or os.getcwd()
|
|
437
|
-
|
|
438
|
-
# 执行命令
|
|
439
|
-
process_result = subprocess.run(
|
|
440
|
-
command,
|
|
441
|
-
shell=True,
|
|
442
|
-
capture_output=True,
|
|
443
|
-
text=True,
|
|
444
|
-
timeout=timeout,
|
|
445
|
-
cwd=exec_working_dir,
|
|
446
|
-
env=env
|
|
447
|
-
)
|
|
448
|
-
|
|
449
|
-
result['execution_time'] = time.time() - start_time
|
|
450
|
-
result['stderr'] = process_result.stderr
|
|
451
|
-
result['stdout'] = process_result.stdout
|
|
452
|
-
|
|
453
|
-
if process_result.returncode == 0:
|
|
454
|
-
result.update({
|
|
455
|
-
'success': True,
|
|
456
|
-
'response': process_result.stdout,
|
|
457
|
-
'method_used': best_method,
|
|
458
|
-
'auto_params_used': spec.auto_params if auto_mode else []
|
|
459
|
-
})
|
|
460
|
-
else:
|
|
461
|
-
# 尝试其他调用方法或提供降级
|
|
462
|
-
result.update(self._handle_execution_failure(source_cli, target_cli, request, status, process_result.stderr, context_file_path))
|
|
463
|
-
|
|
464
|
-
except subprocess.TimeoutExpired:
|
|
465
|
-
result['execution_time'] = time.time() - start_time
|
|
466
|
-
result.update(self._handle_timeout(source_cli, target_cli, request))
|
|
467
|
-
|
|
468
|
-
except Exception as e:
|
|
469
|
-
result['execution_time'] = time.time() - start_time
|
|
470
|
-
result.update(self._handle_exception(source_cli, target_cli, request, str(e)))
|
|
471
|
-
|
|
472
|
-
# 清理临时文件
|
|
473
|
-
if 'context_file_path' in locals() and os.path.exists(context_file_path):
|
|
474
|
-
try:
|
|
475
|
-
os.unlink(context_file_path)
|
|
476
|
-
except:
|
|
477
|
-
pass
|
|
478
|
-
|
|
479
|
-
# 记录调用历史
|
|
480
|
-
self._record_call(source_cli, target_cli, request, result)
|
|
481
|
-
|
|
482
|
-
return result
|
|
483
|
-
|
|
484
|
-
def _create_context_file(self, request: str, context_files: List[str], working_dir: str, target_cli: str) -> str:
|
|
485
|
-
"""创建上下文文件 - 基于不同CLI的最佳格式"""
|
|
486
|
-
|
|
487
|
-
# 创建临时文件
|
|
488
|
-
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
489
|
-
context_filename = f"{target_cli}_context_{timestamp}.md"
|
|
490
|
-
context_file_path = self.context_dir / context_filename
|
|
491
|
-
|
|
492
|
-
# 构建上下文内容
|
|
493
|
-
context_content = []
|
|
494
|
-
|
|
495
|
-
# 添加请求作为主要任务
|
|
496
|
-
context_content.append(f"# 任务请求\n\n{request}\n")
|
|
497
|
-
|
|
498
|
-
# 添加工作目录信息
|
|
499
|
-
if working_dir:
|
|
500
|
-
context_content.append(f"\n# 工作目录\n\n{working_dir}\n")
|
|
501
|
-
|
|
502
|
-
# 添加文件上下文
|
|
503
|
-
if context_files:
|
|
504
|
-
context_content.append(f"\n# 文件上下文\n\n")
|
|
505
|
-
for file_path in context_files:
|
|
506
|
-
if os.path.exists(file_path):
|
|
507
|
-
try:
|
|
508
|
-
# 读取文件内容
|
|
509
|
-
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
|
|
510
|
-
content = f.read()
|
|
511
|
-
|
|
512
|
-
# 限制文件大小以避免超时
|
|
513
|
-
if len(content) > 5000:
|
|
514
|
-
content = content[:5000] + "\n... (内容已截断)"
|
|
515
|
-
|
|
516
|
-
context_content.append(f"## {file_path}\n\n```")
|
|
517
|
-
# 根据文件扩展名添加语言标识
|
|
518
|
-
ext = Path(file_path).suffix.lower()
|
|
519
|
-
lang_map = {
|
|
520
|
-
'.py': 'python',
|
|
521
|
-
'.js': 'javascript',
|
|
522
|
-
'.ts': 'typescript',
|
|
523
|
-
'.jsx': 'jsx',
|
|
524
|
-
'.tsx': 'tsx',
|
|
525
|
-
'.java': 'java',
|
|
526
|
-
'.cpp': 'cpp',
|
|
527
|
-
'.c': 'c',
|
|
528
|
-
'.cs': 'csharp',
|
|
529
|
-
'.php': 'php',
|
|
530
|
-
'.rb': 'ruby',
|
|
531
|
-
'.go': 'go',
|
|
532
|
-
'.rs': 'rust',
|
|
533
|
-
'.sql': 'sql',
|
|
534
|
-
'.html': 'html',
|
|
535
|
-
'.css': 'css',
|
|
536
|
-
'.scss': 'scss',
|
|
537
|
-
'.sass': 'sass',
|
|
538
|
-
'.json': 'json',
|
|
539
|
-
'.yaml': 'yaml',
|
|
540
|
-
'.yml': 'yaml',
|
|
541
|
-
'.xml': 'xml',
|
|
542
|
-
'.md': 'markdown',
|
|
543
|
-
'.txt': 'text'
|
|
544
|
-
}
|
|
545
|
-
lang = lang_map.get(ext, 'text')
|
|
546
|
-
context_content.append(lang)
|
|
547
|
-
context_content.append(f"\n{content}\n```\n")
|
|
548
|
-
except Exception as e:
|
|
549
|
-
context_content.append(f"## {file_path}\n\n无法读取文件: {str(e)}\n")
|
|
550
|
-
else:
|
|
551
|
-
context_content.append(f"## {file_path}\n\n文件不存在\n")
|
|
552
|
-
|
|
553
|
-
# 添加执行指令
|
|
554
|
-
context_content.append(f"\n# 执行指令\n\n")
|
|
555
|
-
context_content.append("请基于上述任务请求和文件上下文,完成相应的工作。")
|
|
556
|
-
context_content.append("请提供详细的解决方案,包括必要的代码、解释和步骤。\n")
|
|
557
|
-
|
|
558
|
-
# 写入上下文文件
|
|
559
|
-
context_text = '\n'.join(context_content)
|
|
560
|
-
safe_file_write(str(context_file_path), context_text)
|
|
561
|
-
|
|
562
|
-
return str(context_file_path)
|
|
563
|
-
|
|
564
|
-
def _build_verified_command(self, base_method: str, spec: RealCLISpecs, request: str, context_file: str, auto_mode: bool) -> str:
|
|
565
|
-
"""构建基于真实参数规范的命令"""
|
|
566
|
-
|
|
567
|
-
# 基础命令
|
|
568
|
-
if spec.type == 'python' and base_method.startswith('python -m'):
|
|
569
|
-
command_parts = base_method.split()
|
|
570
|
-
elif spec.type == 'npm' and base_method.startswith('npx '):
|
|
571
|
-
command_parts = base_method.split()
|
|
572
|
-
else:
|
|
573
|
-
command_parts = [base_method]
|
|
574
|
-
|
|
575
|
-
# 添加自动化参数
|
|
576
|
-
if auto_mode:
|
|
577
|
-
command_parts.extend(spec.auto_params)
|
|
578
|
-
|
|
579
|
-
# 根据CLI类型添加提示词和上下文
|
|
580
|
-
cli_name = next(k for k, v in self.cli_specs.items() if v == spec)
|
|
581
|
-
|
|
582
|
-
if cli_name in ['qwen', 'iflow', 'gemini', 'claude']:
|
|
583
|
-
# 使用直接提示词或--prompt参数
|
|
584
|
-
if auto_mode:
|
|
585
|
-
# 自动模式下优先使用文件上下文
|
|
586
|
-
command_parts.extend(['--file', context_file])
|
|
587
|
-
# 添加简化的任务提示
|
|
588
|
-
command_parts.extend(['--prompt', f'基于上下文文件完成任务: {request[:100]}'])
|
|
589
|
-
else:
|
|
590
|
-
# 非自动模式使用完整提示词
|
|
591
|
-
if len(request.split()) <= 3:
|
|
592
|
-
command_parts.append(request)
|
|
593
|
-
else:
|
|
594
|
-
command_parts.extend(['--prompt', f'"{request}"'])
|
|
595
|
-
|
|
596
|
-
elif cli_name == 'copilot':
|
|
597
|
-
# Copilot使用-p参数
|
|
598
|
-
if auto_mode:
|
|
599
|
-
command_parts.extend(['--file', context_file])
|
|
600
|
-
command_parts.extend(['-p', f'基于上下文文件完成任务: {request[:100]}'])
|
|
601
|
-
else:
|
|
602
|
-
command_parts.extend(['-p', f'"{request}"'])
|
|
603
|
-
command_parts.extend(['--file', context_file])
|
|
604
|
-
|
|
605
|
-
elif cli_name == 'codex':
|
|
606
|
-
# Codex使用exec或直接传递
|
|
607
|
-
if auto_mode:
|
|
608
|
-
command_parts.extend(['--file', context_file])
|
|
609
|
-
command_parts.extend(['exec', f'基于上下文文件完成任务: {request[:100]}'])
|
|
610
|
-
else:
|
|
611
|
-
if 'exec' in command_parts:
|
|
612
|
-
command_parts.extend([f'"{request}"'])
|
|
613
|
-
else:
|
|
614
|
-
command_parts.extend([f'"{request}"'])
|
|
615
|
-
command_parts.extend(['--file', context_file])
|
|
616
|
-
|
|
617
|
-
# 构建完整命令
|
|
618
|
-
if spec.type == 'python' and base_method.startswith('python -m'):
|
|
619
|
-
# Python -m 保持原格式
|
|
620
|
-
full_command = f"{command_parts[0]} {command_parts[1]} {' '.join(command_parts[2:])}"
|
|
621
|
-
elif spec.type == 'npm' and base_method.startswith('npx '):
|
|
622
|
-
# npx保持原格式
|
|
623
|
-
full_command = f"{command_parts[0]} {command_parts[1]} {' '.join(command_parts[2:])}"
|
|
624
|
-
else:
|
|
625
|
-
full_command = ' '.join(command_parts)
|
|
626
|
-
|
|
627
|
-
return full_command
|
|
628
|
-
|
|
629
|
-
def _prepare_environment(self, spec: RealCLISpecs) -> Dict[str, str]:
|
|
630
|
-
"""准备CLI执行环境"""
|
|
631
|
-
env = os.environ.copy()
|
|
632
|
-
|
|
633
|
-
# 根据CLI类型设置环境
|
|
634
|
-
if spec.type == 'npm':
|
|
635
|
-
# npm环境配置
|
|
636
|
-
npm_config_prefix = env.get('NPM_CONFIG_PREFIX')
|
|
637
|
-
if not npm_config_prefix:
|
|
638
|
-
npm_config_prefix = os.path.join(os.path.expanduser('~'), '.npm-global')
|
|
639
|
-
env['NPM_CONFIG_PREFIX'] = npm_config_prefix
|
|
640
|
-
|
|
641
|
-
# 确保全局npm包在PATH中
|
|
642
|
-
global_bin = os.path.join(npm_config_prefix, 'bin')
|
|
643
|
-
if global_bin not in env.get('PATH', ''):
|
|
644
|
-
env['PATH'] = f"{global_bin}{os.pathsep}{env.get('PATH', '')}"
|
|
645
|
-
|
|
646
|
-
elif spec.type == 'python':
|
|
647
|
-
# Python环境配置
|
|
648
|
-
user_base = os.path.join(os.path.expanduser('~'), '.local')
|
|
649
|
-
user_bin = os.path.join(user_base, 'bin')
|
|
650
|
-
if user_bin not in env.get('PATH', ''):
|
|
651
|
-
env['PATH'] = f"{user_bin}{os.pathsep}{env.get('PATH', '')}"
|
|
652
|
-
|
|
653
|
-
# 设置API密钥环境变量(如果需要且存在)
|
|
654
|
-
if spec.api_env and spec.api_env in env:
|
|
655
|
-
pass # API密钥已存在
|
|
656
|
-
|
|
657
|
-
return env
|
|
658
|
-
|
|
659
|
-
def _handle_missing_cli(self, source_cli: str, target_cli: str, request: str, status: Dict[str, Any]) -> Dict[str, Any]:
|
|
660
|
-
"""处理缺失CLI的情况"""
|
|
661
|
-
spec = self.cli_specs[target_cli]
|
|
662
|
-
|
|
663
|
-
guidance = f"""# CLI安装指导
|
|
664
|
-
|
|
665
|
-
## {spec.name} 未安装
|
|
666
|
-
|
|
667
|
-
### 快速安装命令:
|
|
668
|
-
```bash
|
|
669
|
-
{status['install_command']}
|
|
670
|
-
```
|
|
671
|
-
|
|
672
|
-
### 安装后验证:
|
|
673
|
-
```bash
|
|
674
|
-
{spec.version_check}
|
|
675
|
-
```
|
|
676
|
-
|
|
677
|
-
### 可用调用方式:
|
|
678
|
-
"""
|
|
679
|
-
for i, method in enumerate(spec.call_patterns[:3]):
|
|
680
|
-
guidance += f"{i+1}. `{method}`\\n"
|
|
681
|
-
|
|
682
|
-
if status['api_env']:
|
|
683
|
-
guidance += f"""
|
|
684
|
-
### 环境变量配置:
|
|
685
|
-
```bash
|
|
686
|
-
export {status['api_env']}='your-api-key-here'
|
|
687
|
-
```
|
|
688
|
-
"""
|
|
689
|
-
|
|
690
|
-
return {
|
|
691
|
-
'success': True,
|
|
692
|
-
'response': guidance,
|
|
693
|
-
'fallback_used': True,
|
|
694
|
-
'fallback_level': 'install_guidance',
|
|
695
|
-
'fallback_reason': f'{target_cli} not installed'
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
def _handle_execution_failure(self, source_cli: str, target_cli: str, request: str, status: Dict[str, Any], error_msg: str, context_file: str) -> Dict[str, Any]:
|
|
699
|
-
"""处理执行失败"""
|
|
700
|
-
spec = self.cli_specs[target_cli]
|
|
701
|
-
|
|
702
|
-
# 尝试其他可用方法
|
|
703
|
-
alternative_methods = [m for m in status['available_methods'] if m != status['best_method']]
|
|
704
|
-
|
|
705
|
-
if alternative_methods:
|
|
706
|
-
# 尝试备用方法
|
|
707
|
-
alt_method = alternative_methods[0]
|
|
708
|
-
alt_command = self._build_verified_command(alt_method, spec, request, context_file, True)
|
|
709
|
-
|
|
710
|
-
try:
|
|
711
|
-
process_result = subprocess.run(
|
|
712
|
-
alt_command,
|
|
713
|
-
shell=True,
|
|
714
|
-
capture_output=True,
|
|
715
|
-
text=True,
|
|
716
|
-
timeout=60,
|
|
717
|
-
cwd=os.getcwd(),
|
|
718
|
-
env=self._prepare_environment(spec)
|
|
719
|
-
)
|
|
720
|
-
|
|
721
|
-
if process_result.returncode == 0:
|
|
722
|
-
return {
|
|
723
|
-
'success': True,
|
|
724
|
-
'response': process_result.stdout,
|
|
725
|
-
'stderr': process_result.stderr,
|
|
726
|
-
'command_used': alt_command,
|
|
727
|
-
'method_used': alt_method,
|
|
728
|
-
'fallback_used': True,
|
|
729
|
-
'fallback_level': 'alternative_method'
|
|
730
|
-
}
|
|
731
|
-
except:
|
|
732
|
-
pass
|
|
733
|
-
|
|
734
|
-
# 提供手动执行指导
|
|
735
|
-
manual_guidance = f"""# 执行失败处理
|
|
736
|
-
|
|
737
|
-
{spec.name} 执行失败,请尝试以下手动方式:
|
|
738
|
-
|
|
739
|
-
### 可用调用方法:
|
|
740
|
-
"""
|
|
741
|
-
for i, method in enumerate(status['available_methods']):
|
|
742
|
-
cmd = self._build_verified_command(method, spec, request, context_file, True)
|
|
743
|
-
manual_guidance += f"#### 方法 {i+1}:
|
|
744
|
-
```bash
|
|
745
|
-
{cmd}
|
|
746
|
-
```
|
|
747
|
-
\\n"
|
|
748
|
-
|
|
749
|
-
manual_guidance += f"""
|
|
750
|
-
### 原始错误信息:
|
|
751
|
-
```
|
|
752
|
-
{error_msg}
|
|
753
|
-
```
|
|
754
|
-
|
|
755
|
-
### 故障排除:
|
|
756
|
-
1. 检查API密钥配置
|
|
757
|
-
2. 验证网络连接
|
|
758
|
-
3. 确认上下文文件可访问
|
|
759
|
-
4. 尝试简化请求内容
|
|
760
|
-
"""
|
|
761
|
-
|
|
762
|
-
return {
|
|
763
|
-
'success': True,
|
|
764
|
-
'response': manual_guidance,
|
|
765
|
-
'fallback_used': True,
|
|
766
|
-
'fallback_level': 'manual_guidance',
|
|
767
|
-
'fallback_reason': 'execution_failed'
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
def _handle_timeout(self, source_cli: str, target_cli: str, request: str) -> Dict[str, Any]:
|
|
771
|
-
"""处理超时"""
|
|
772
|
-
timeout_guidance = f"""# 执行超时处理
|
|
773
|
-
|
|
774
|
-
{target_cli} 执行超时。
|
|
775
|
-
|
|
776
|
-
### 可能原因:
|
|
777
|
-
1. 网络连接问题
|
|
778
|
-
2. API密钥配置错误
|
|
779
|
-
3. 请求过于复杂或文件过大
|
|
780
|
-
4. 服务端响应缓慢
|
|
781
|
-
|
|
782
|
-
### 建议解决方案:
|
|
783
|
-
1. 检查网络连接和API密钥
|
|
784
|
-
2. 简化请求内容
|
|
785
|
-
3. 减少上下文文件数量
|
|
786
|
-
4. 使用自动模式 (`auto_mode=True`)
|
|
787
|
-
|
|
788
|
-
### 手动尝试:
|
|
789
|
-
```bash
|
|
790
|
-
# 使用简化请求
|
|
791
|
-
{target_cli} --approval-mode yolo --prompt "简化版请求"
|
|
792
|
-
```
|
|
793
|
-
"""
|
|
794
|
-
|
|
795
|
-
return {
|
|
796
|
-
'success': False,
|
|
797
|
-
'response': timeout_guidance,
|
|
798
|
-
'fallback_used': True,
|
|
799
|
-
'fallback_level': 'timeout_guidance',
|
|
800
|
-
'fallback_reason': 'execution_timeout'
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
def _handle_exception(self, source_cli: str, target_cli: str, request: str, error_msg: str) -> Dict[str, Any]:
|
|
804
|
-
"""处理异常"""
|
|
805
|
-
exception_guidance = f"""# 执行异常处理
|
|
806
|
-
|
|
807
|
-
{target_cli} 执行出现异常: {error_msg}
|
|
808
|
-
|
|
809
|
-
### 可能解决方案:
|
|
810
|
-
1. 检查CLI是否正确安装: `{self.cli_specs[target_cli].version_check}`
|
|
811
|
-
2. 验证环境变量配置
|
|
812
|
-
3. 检查文件权限和路径
|
|
813
|
-
4. 查看详细错误日志
|
|
814
|
-
|
|
815
|
-
### 重新安装:
|
|
816
|
-
```bash
|
|
817
|
-
{self.cli_specs[target_cli].install_command}
|
|
818
|
-
```
|
|
819
|
-
"""
|
|
820
|
-
|
|
821
|
-
return {
|
|
822
|
-
'success': False,
|
|
823
|
-
'response': exception_guidance,
|
|
824
|
-
'fallback_used': True,
|
|
825
|
-
'fallback_level': 'exception_guidance',
|
|
826
|
-
'fallback_reason': 'execution_exception'
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
def _record_call(self, source_cli: str, target_cli: str, request: str, result: Dict[str, Any]):
|
|
830
|
-
"""记录调用历史"""
|
|
831
|
-
try:
|
|
832
|
-
# 加载现有历史
|
|
833
|
-
if self.call_history_file.exists():
|
|
834
|
-
history = json.loads(safe_file_read(self.call_history_file))
|
|
835
|
-
else:
|
|
836
|
-
history = {'calls': [], 'stats': {}}
|
|
837
|
-
|
|
838
|
-
# 添加新记录
|
|
839
|
-
call_record = {
|
|
840
|
-
'timestamp': result['timestamp'],
|
|
841
|
-
'source_cli': source_cli,
|
|
842
|
-
'target_cli': target_cli,
|
|
843
|
-
'request': request[:200] + '...' if len(request) > 200 else request,
|
|
844
|
-
'success': result['success'],
|
|
845
|
-
'execution_time': result.get('execution_time', 0),
|
|
846
|
-
'command_used': result.get('command_used', ''),
|
|
847
|
-
'context_files_used': result.get('context_files_used', []),
|
|
848
|
-
'auto_mode_used': result.get('auto_mode_used', False),
|
|
849
|
-
'fallback_used': result.get('fallback_used', False),
|
|
850
|
-
'fallback_level': result.get('fallback_level', '')
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
history['calls'].append(call_record)
|
|
854
|
-
|
|
855
|
-
# 保留最近1000条记录
|
|
856
|
-
if len(history['calls']) > 1000:
|
|
857
|
-
history['calls'] = history['calls'][-1000:]
|
|
858
|
-
|
|
859
|
-
# 更新统计
|
|
860
|
-
pattern = f"{source_cli}->{target_cli}"
|
|
861
|
-
if pattern not in history['stats']:
|
|
862
|
-
history['stats'][pattern] = {
|
|
863
|
-
'total_calls': 0,
|
|
864
|
-
'successful_calls': 0,
|
|
865
|
-
'avg_execution_time': 0,
|
|
866
|
-
'last_call': None
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
history['stats'][pattern]['total_calls'] += 1
|
|
870
|
-
if result['success']:
|
|
871
|
-
history['stats'][pattern]['successful_calls'] += 1
|
|
872
|
-
|
|
873
|
-
if result.get('execution_time', 0) > 0:
|
|
874
|
-
current_avg = history['stats'][pattern]['avg_execution_time']
|
|
875
|
-
total_calls = history['stats'][pattern]['total_calls']
|
|
876
|
-
history['stats'][pattern]['avg_execution_time'] = (
|
|
877
|
-
(current_avg * (total_calls - 1) + result['execution_time']) / total_calls
|
|
878
|
-
)
|
|
879
|
-
|
|
880
|
-
history['stats'][pattern]['last_call'] = result['timestamp']
|
|
881
|
-
|
|
882
|
-
# 保存历史
|
|
883
|
-
safe_file_write(self.call_history_file, json.dumps(history, indent=2, ensure_ascii=False))
|
|
884
|
-
|
|
885
|
-
except Exception as e:
|
|
886
|
-
print(f"Warning: Failed to record call history: {e}")
|
|
887
|
-
|
|
888
|
-
# 使用示例
|
|
889
|
-
if __name__ == '__main__':
|
|
890
|
-
system = VerifiedCrossCLISystem()
|
|
891
|
-
|
|
892
|
-
print("🔬 验证真实CLI调用系统")
|
|
893
|
-
print("基于真实CLI参数规范,使用文件上下文传递")
|
|
894
|
-
print("=" * 60)
|
|
895
|
-
|
|
896
|
-
# 检查CLI状态
|
|
897
|
-
print("📊 CLI状态检查:")
|
|
898
|
-
for cli_name in system.cli_specs:
|
|
899
|
-
status = system.check_cli_availability(cli_name)
|
|
900
|
-
status_icon = "✅" if status['exists'] else "❌"
|
|
901
|
-
print(f" {status_icon} {cli_name}: {status.get('best_method', '未安装')} ({status['type']})")
|
|
902
|
-
if status.get('version_info'):
|
|
903
|
-
print(f" 📋 版本: {status['version_info']}")
|
|
904
|
-
|
|
905
|
-
# 测试文件上下文调用
|
|
906
|
-
available_clis = [name for name, spec in system.cli_specs.items() if system.check_cli_availability(name)['exists']]
|
|
907
|
-
|
|
908
|
-
if available_clis:
|
|
909
|
-
print(f"\n🚀 测试文件上下文调用:")
|
|
910
|
-
test_cli = available_clis[0]
|
|
911
|
-
|
|
912
|
-
# 创建测试文件
|
|
913
|
-
test_file = Path.cwd() / 'test_context.py'
|
|
914
|
-
test_content = '''
|
|
915
|
-
def hello_world():
|
|
916
|
-
"""这是一个测试函数"""
|
|
917
|
-
print("Hello, World!")
|
|
918
|
-
return "success"
|
|
919
|
-
|
|
920
|
-
if __name__ == "__main__":
|
|
921
|
-
result = hello_world()
|
|
922
|
-
print(f"Result: {result}")
|
|
923
|
-
'''
|
|
924
|
-
safe_file_write(str(test_file), test_content)
|
|
925
|
-
|
|
926
|
-
# 测试调用
|
|
927
|
-
result = system.call_cli_with_file_context(
|
|
928
|
-
source_cli='test',
|
|
929
|
-
target_cli=test_cli,
|
|
930
|
-
request='分析这个Python文件并改进代码质量',
|
|
931
|
-
context_files=[str(test_file)],
|
|
932
|
-
working_dir=str(Path.cwd()),
|
|
933
|
-
auto_mode=True,
|
|
934
|
-
timeout=60
|
|
935
|
-
)
|
|
936
|
-
|
|
937
|
-
print(f" 📊 调用结果: {'成功' if result['success'] else '失败'}")
|
|
938
|
-
print(f" ⏱️ 执行时间: {result.get('execution_time', 0):.2f}s")
|
|
939
|
-
print(f" 🔧 命令: {result.get('command_used', 'N/A')}")
|
|
940
|
-
print(f" 📁 上下文文件: {len(result.get('context_files_used', []))}")
|
|
941
|
-
|
|
942
|
-
if result.get('fallback_used'):
|
|
943
|
-
print(f" 🛡️ 降级级别: {result.get('fallback_level', 'unknown')}")
|
|
944
|
-
|
|
945
|
-
# 显示响应预览
|
|
946
|
-
response = result.get('response', '')
|
|
947
|
-
if response:
|
|
948
|
-
preview = response[:300] + '...' if len(response) > 300 else response
|
|
949
|
-
print(f" 📄 响应预览:\n{preview}")
|
|
950
|
-
|
|
951
|
-
# 清理测试文件
|
|
952
|
-
if test_file.exists():
|
|
953
|
-
test_file.unlink()
|
|
954
|
-
|
|
955
|
-
else:
|
|
956
|
-
print("\n⚠️ 没有可用的CLI进行测试")
|
|
957
|
-
print(" 请先安装至少一个CLI工具:")
|
|
958
|
-
for cli_name, spec in system.cli_specs.items():
|
|
959
|
-
print(f" - {spec.name}: {spec.install_command}")
|
|
960
|
-
|
|
961
|
-
print("\n✅ 验证完成!")
|