sophhub 0.4.2 → 0.4.3
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/agents/ai-cs-admin/.config.json +6 -1
- package/agents/ai-cs-qa/.config.json +1 -1
- package/agents/ai-cs-qa/AGENTS.md +43 -15
- package/package.json +1 -1
- package/skills/agent-install/skill.json +27 -0
- package/skills/agent-install/src/SKILL.md +238 -0
- package/skills/agent-install/src/pyproject.toml +6 -0
- package/skills/agent-install/src/scripts/backup_agent.py +120 -0
- package/skills/agent-install/src/scripts/check_installed.py +479 -0
- package/skills/agent-install/src/scripts/common.py +487 -0
- package/skills/agent-install/src/scripts/copy_agent_files.py +59 -0
- package/skills/agent-install/src/scripts/list_agents.py +285 -0
- package/skills/agent-install/src/scripts/resolve_install_params.py +90 -0
- package/skills/agent-install/src/scripts/update_agent_md.py +76 -0
- package/skills/agent-install/src/scripts/update_openclaw.py +183 -0
- package/skills/agent-install/src/scripts/verify_download.py +148 -0
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from common import (
|
|
10
|
+
build_agent_entry,
|
|
11
|
+
default_openclaw_config_path,
|
|
12
|
+
detect_installed_version,
|
|
13
|
+
find_agent_entry,
|
|
14
|
+
find_agent_by_workspace,
|
|
15
|
+
get_agent_dependencies,
|
|
16
|
+
is_agent_installed,
|
|
17
|
+
load_agent_definition,
|
|
18
|
+
load_openclaw_config,
|
|
19
|
+
parse_version,
|
|
20
|
+
resolve_existing_agent_entry,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def workspace_exists(path_value: object) -> bool:
|
|
25
|
+
return isinstance(path_value, str) and bool(path_value) and Path(path_value).exists()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def normalized_name(value: object) -> str | None:
|
|
29
|
+
if isinstance(value, str):
|
|
30
|
+
stripped = value.strip()
|
|
31
|
+
if stripped:
|
|
32
|
+
return stripped
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def current_agent_names(current_entry: dict[str, object]) -> tuple[str | None, str | None]:
|
|
37
|
+
current_name = normalized_name(current_entry.get("name"))
|
|
38
|
+
identity = current_entry.get("identity")
|
|
39
|
+
identity_name = None
|
|
40
|
+
if isinstance(identity, dict):
|
|
41
|
+
identity_name = normalized_name(identity.get("name"))
|
|
42
|
+
return current_name, identity_name
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def build_user_prompt(result: dict[str, object]) -> str:
|
|
46
|
+
status = result["status"]
|
|
47
|
+
agent_id = str(result["agent_id"])
|
|
48
|
+
target_version = str(result.get("target_version") or "")
|
|
49
|
+
installed_version = str(result.get("installed_version") or "")
|
|
50
|
+
missing_dependencies = result.get("missing_dependencies", [])
|
|
51
|
+
|
|
52
|
+
if status == "DEPENDENCY_MISSING":
|
|
53
|
+
deps = "、".join(missing_dependencies) if isinstance(missing_dependencies, list) else str(missing_dependencies)
|
|
54
|
+
return f"检测到依赖 Agent 未安装:{deps}。\n\n请先安装依赖 Agent,再继续安装 `{agent_id}`。\n建议回复:先安装 {deps}"
|
|
55
|
+
|
|
56
|
+
if status == "UPDATABLE":
|
|
57
|
+
return (
|
|
58
|
+
f"检测到 `{agent_id}` 有可用更新({installed_version} -> {target_version})。\n\n"
|
|
59
|
+
"⚠️ 更新说明:\n"
|
|
60
|
+
"• 更新前会先备份当前 Agent 配置\n"
|
|
61
|
+
"• 更新后如果你之前手动修改过 Agent 配置,需要自行同步这些修改\n\n"
|
|
62
|
+
"是否确认更新?请回复「确认更新」或「取消」。"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
if status == "SAME_VERSION_REINSTALL":
|
|
66
|
+
return (
|
|
67
|
+
f"`{agent_id}` 当前已安装版本与下载版本一致({target_version})。\n\n"
|
|
68
|
+
"⚠️ 本次操作不是升级,而是重置 Agent 配置:\n"
|
|
69
|
+
"• 重置前会先备份当前 Agent 配置\n"
|
|
70
|
+
"• 重置后如果你之前手动修改过 Agent 配置,需要自行同步这些修改\n\n"
|
|
71
|
+
"是否确认继续重置?请回复「确认重置」或「取消」。"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
if status == "NOT_INSTALLED":
|
|
75
|
+
return f"`{agent_id}` 尚未安装,可以开始安装。"
|
|
76
|
+
|
|
77
|
+
return str(result.get("message") or "当前配置存在异常,请先人工检查。")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def detect_status(
|
|
81
|
+
agent_id: str,
|
|
82
|
+
config_path: Path,
|
|
83
|
+
*,
|
|
84
|
+
source_path: Path | None = None,
|
|
85
|
+
openclaw_id_override: str | None = None,
|
|
86
|
+
workspace_override: str | None = None,
|
|
87
|
+
name_override: str | None = None,
|
|
88
|
+
) -> dict[str, object]:
|
|
89
|
+
agent_def = load_agent_definition(agent_id, source_path)
|
|
90
|
+
desired_entry = build_agent_entry(
|
|
91
|
+
agent_def,
|
|
92
|
+
workspace_override=workspace_override,
|
|
93
|
+
name_override=name_override,
|
|
94
|
+
)
|
|
95
|
+
desired_workspace = desired_entry["workspace"]
|
|
96
|
+
desired_openclaw_id = (
|
|
97
|
+
openclaw_id_override.strip()
|
|
98
|
+
if isinstance(openclaw_id_override, str) and openclaw_id_override.strip()
|
|
99
|
+
else agent_id
|
|
100
|
+
)
|
|
101
|
+
desired_name = normalized_name(desired_entry.get("name")) or normalized_name(
|
|
102
|
+
desired_entry.get("identity", {}).get("name") if isinstance(desired_entry.get("identity"), dict) else None
|
|
103
|
+
)
|
|
104
|
+
dependencies = get_agent_dependencies(agent_def)
|
|
105
|
+
|
|
106
|
+
try:
|
|
107
|
+
openclaw = load_openclaw_config(config_path)
|
|
108
|
+
except FileNotFoundError:
|
|
109
|
+
result = {
|
|
110
|
+
"agent_id": agent_id,
|
|
111
|
+
"target_version": agent_def["version"],
|
|
112
|
+
"status": "CONFIG_ERROR",
|
|
113
|
+
"installed": False,
|
|
114
|
+
"workspace": desired_workspace,
|
|
115
|
+
"desired_workspace": desired_workspace,
|
|
116
|
+
"desired_name": desired_name,
|
|
117
|
+
"desired_openclaw_id": desired_openclaw_id,
|
|
118
|
+
"dependencies": dependencies,
|
|
119
|
+
"missing_dependencies": dependencies,
|
|
120
|
+
"reason": "openclaw_config_missing",
|
|
121
|
+
"message": "openclaw.json 不存在,请先初始化 OpenClaw 环境。",
|
|
122
|
+
}
|
|
123
|
+
result["user_prompt"] = build_user_prompt(result)
|
|
124
|
+
return result
|
|
125
|
+
|
|
126
|
+
current_entry_by_id = find_agent_entry(openclaw, agent_id)
|
|
127
|
+
desired_entry_by_openclaw_id = find_agent_entry(openclaw, desired_openclaw_id)
|
|
128
|
+
workspace_owner = find_agent_by_workspace(openclaw, desired_workspace)
|
|
129
|
+
current_entry = resolve_existing_agent_entry(config_path, openclaw, agent_id, desired_workspace)
|
|
130
|
+
installed_by_id = current_entry_by_id is not None
|
|
131
|
+
installed_by_workspace = workspace_owner is not None
|
|
132
|
+
desired_workspace_exists = workspace_exists(desired_workspace)
|
|
133
|
+
missing_dependencies = [dep for dep in dependencies if not is_agent_installed(config_path, openclaw, dep)]
|
|
134
|
+
|
|
135
|
+
if missing_dependencies:
|
|
136
|
+
result = {
|
|
137
|
+
"agent_id": agent_id,
|
|
138
|
+
"target_version": agent_def["version"],
|
|
139
|
+
"status": "DEPENDENCY_MISSING",
|
|
140
|
+
"installed": current_entry is not None,
|
|
141
|
+
"installed_by_id": installed_by_id,
|
|
142
|
+
"installed_by_workspace": installed_by_workspace,
|
|
143
|
+
"workspace": current_entry.get("workspace", desired_workspace) if current_entry else desired_workspace,
|
|
144
|
+
"desired_workspace": desired_workspace,
|
|
145
|
+
"workspace_exists": desired_workspace_exists,
|
|
146
|
+
"desired_name": desired_name,
|
|
147
|
+
"desired_openclaw_id": desired_openclaw_id,
|
|
148
|
+
"dependencies": dependencies,
|
|
149
|
+
"missing_dependencies": missing_dependencies,
|
|
150
|
+
"message": f"依赖 Agent 未安装:{', '.join(missing_dependencies)}。请先安装依赖 Agent。",
|
|
151
|
+
"suggested_action": f"先安装 {'、'.join(missing_dependencies)}",
|
|
152
|
+
}
|
|
153
|
+
result["user_prompt"] = build_user_prompt(result)
|
|
154
|
+
return result
|
|
155
|
+
|
|
156
|
+
if desired_entry_by_openclaw_id is not None and current_entry is None:
|
|
157
|
+
result = {
|
|
158
|
+
"agent_id": agent_id,
|
|
159
|
+
"target_version": agent_def["version"],
|
|
160
|
+
"status": "CONFIG_ERROR",
|
|
161
|
+
"installed": False,
|
|
162
|
+
"installed_by_id": installed_by_id,
|
|
163
|
+
"installed_by_workspace": installed_by_workspace,
|
|
164
|
+
"current_openclaw_id": desired_entry_by_openclaw_id.get("id"),
|
|
165
|
+
"workspace": desired_workspace,
|
|
166
|
+
"desired_workspace": desired_workspace,
|
|
167
|
+
"workspace_exists": desired_workspace_exists,
|
|
168
|
+
"desired_name": desired_name,
|
|
169
|
+
"desired_openclaw_id": desired_openclaw_id,
|
|
170
|
+
"dependencies": dependencies,
|
|
171
|
+
"missing_dependencies": missing_dependencies,
|
|
172
|
+
"reason": "openclaw_id_conflict",
|
|
173
|
+
"message": f"目标 openclaw id `{desired_openclaw_id}` 已存在,但不属于当前 Agent,请先人工检查。",
|
|
174
|
+
}
|
|
175
|
+
result["user_prompt"] = build_user_prompt(result)
|
|
176
|
+
return result
|
|
177
|
+
|
|
178
|
+
if (
|
|
179
|
+
desired_entry_by_openclaw_id is not None
|
|
180
|
+
and current_entry is not None
|
|
181
|
+
and desired_entry_by_openclaw_id is not current_entry
|
|
182
|
+
):
|
|
183
|
+
result = {
|
|
184
|
+
"agent_id": agent_id,
|
|
185
|
+
"target_version": agent_def["version"],
|
|
186
|
+
"status": "CONFIG_ERROR",
|
|
187
|
+
"installed": True,
|
|
188
|
+
"installed_by_id": installed_by_id,
|
|
189
|
+
"installed_by_workspace": installed_by_workspace,
|
|
190
|
+
"current_openclaw_id": current_entry.get("id"),
|
|
191
|
+
"workspace": desired_workspace,
|
|
192
|
+
"desired_workspace": desired_workspace,
|
|
193
|
+
"workspace_exists": desired_workspace_exists,
|
|
194
|
+
"desired_name": desired_name,
|
|
195
|
+
"desired_openclaw_id": desired_openclaw_id,
|
|
196
|
+
"dependencies": dependencies,
|
|
197
|
+
"missing_dependencies": missing_dependencies,
|
|
198
|
+
"reason": "openclaw_id_conflict",
|
|
199
|
+
"message": f"目标 openclaw id `{desired_openclaw_id}` 已被其他条目占用,请先人工检查。",
|
|
200
|
+
}
|
|
201
|
+
result["user_prompt"] = build_user_prompt(result)
|
|
202
|
+
return result
|
|
203
|
+
|
|
204
|
+
if current_entry is None and workspace_owner and workspace_owner.get("id") != agent_id:
|
|
205
|
+
result = {
|
|
206
|
+
"agent_id": agent_id,
|
|
207
|
+
"target_version": agent_def["version"],
|
|
208
|
+
"status": "CONFIG_ERROR",
|
|
209
|
+
"installed": False,
|
|
210
|
+
"installed_by_id": False,
|
|
211
|
+
"installed_by_workspace": True,
|
|
212
|
+
"workspace": desired_workspace,
|
|
213
|
+
"desired_workspace": desired_workspace,
|
|
214
|
+
"workspace_exists": desired_workspace_exists,
|
|
215
|
+
"desired_name": desired_name,
|
|
216
|
+
"desired_openclaw_id": desired_openclaw_id,
|
|
217
|
+
"workspace_owner_id": workspace_owner.get("id"),
|
|
218
|
+
"dependencies": dependencies,
|
|
219
|
+
"missing_dependencies": missing_dependencies,
|
|
220
|
+
"reason": "workspace_conflict",
|
|
221
|
+
"message": f"目标 workspace 已被 Agent {workspace_owner.get('id')} 占用,请先人工检查配置。",
|
|
222
|
+
}
|
|
223
|
+
result["user_prompt"] = build_user_prompt(result)
|
|
224
|
+
return result
|
|
225
|
+
|
|
226
|
+
if current_entry is None:
|
|
227
|
+
if desired_workspace_exists:
|
|
228
|
+
result = {
|
|
229
|
+
"agent_id": agent_id,
|
|
230
|
+
"target_version": agent_def["version"],
|
|
231
|
+
"status": "CONFIG_ERROR",
|
|
232
|
+
"installed": False,
|
|
233
|
+
"installed_by_id": False,
|
|
234
|
+
"installed_by_workspace": False,
|
|
235
|
+
"workspace": desired_workspace,
|
|
236
|
+
"desired_workspace": desired_workspace,
|
|
237
|
+
"workspace_exists": True,
|
|
238
|
+
"desired_name": desired_name,
|
|
239
|
+
"desired_openclaw_id": desired_openclaw_id,
|
|
240
|
+
"dependencies": dependencies,
|
|
241
|
+
"missing_dependencies": missing_dependencies,
|
|
242
|
+
"reason": "workspace_dir_exists_without_agent",
|
|
243
|
+
"message": "目标 workspace 目录已存在,但 openclaw.json 中没有当前 Agent,无法确认目录归属,请先人工检查。",
|
|
244
|
+
}
|
|
245
|
+
result["user_prompt"] = build_user_prompt(result)
|
|
246
|
+
return result
|
|
247
|
+
|
|
248
|
+
result = {
|
|
249
|
+
"agent_id": agent_id,
|
|
250
|
+
"target_version": agent_def["version"],
|
|
251
|
+
"status": "NOT_INSTALLED",
|
|
252
|
+
"installed": False,
|
|
253
|
+
"installed_by_id": False,
|
|
254
|
+
"installed_by_workspace": False,
|
|
255
|
+
"workspace": desired_workspace,
|
|
256
|
+
"desired_workspace": desired_workspace,
|
|
257
|
+
"workspace_exists": False,
|
|
258
|
+
"desired_name": desired_name,
|
|
259
|
+
"desired_openclaw_id": desired_openclaw_id,
|
|
260
|
+
"dependencies": dependencies,
|
|
261
|
+
"missing_dependencies": missing_dependencies,
|
|
262
|
+
"message": "Agent 尚未安装,可以开始安装。",
|
|
263
|
+
}
|
|
264
|
+
result["user_prompt"] = build_user_prompt(result)
|
|
265
|
+
return result
|
|
266
|
+
|
|
267
|
+
current_workspace = current_entry.get("workspace", desired_workspace)
|
|
268
|
+
current_workspace_exists = workspace_exists(current_workspace)
|
|
269
|
+
current_openclaw_id = current_entry.get("id")
|
|
270
|
+
if desired_openclaw_id != current_openclaw_id:
|
|
271
|
+
result = {
|
|
272
|
+
"agent_id": agent_id,
|
|
273
|
+
"target_version": agent_def["version"],
|
|
274
|
+
"status": "CONFIG_ERROR",
|
|
275
|
+
"installed": True,
|
|
276
|
+
"installed_by_id": installed_by_id,
|
|
277
|
+
"installed_by_workspace": installed_by_workspace,
|
|
278
|
+
"current_openclaw_id": current_openclaw_id,
|
|
279
|
+
"workspace": current_workspace,
|
|
280
|
+
"desired_workspace": desired_workspace,
|
|
281
|
+
"workspace_exists": current_workspace_exists,
|
|
282
|
+
"desired_name": desired_name,
|
|
283
|
+
"desired_openclaw_id": desired_openclaw_id,
|
|
284
|
+
"agent_dir": current_entry.get("agentDir"),
|
|
285
|
+
"dependencies": dependencies,
|
|
286
|
+
"missing_dependencies": missing_dependencies,
|
|
287
|
+
"reason": "openclaw_id_mismatch",
|
|
288
|
+
"message": "当前已安装 Agent 的 openclaw id 与本次确认值不一致,请先人工检查配置。",
|
|
289
|
+
}
|
|
290
|
+
result["user_prompt"] = build_user_prompt(result)
|
|
291
|
+
return result
|
|
292
|
+
|
|
293
|
+
if current_workspace != desired_workspace:
|
|
294
|
+
result = {
|
|
295
|
+
"agent_id": agent_id,
|
|
296
|
+
"target_version": agent_def["version"],
|
|
297
|
+
"status": "CONFIG_ERROR",
|
|
298
|
+
"installed": True,
|
|
299
|
+
"installed_by_id": installed_by_id,
|
|
300
|
+
"installed_by_workspace": installed_by_workspace,
|
|
301
|
+
"current_openclaw_id": current_openclaw_id,
|
|
302
|
+
"workspace": current_workspace,
|
|
303
|
+
"desired_workspace": desired_workspace,
|
|
304
|
+
"workspace_exists": current_workspace_exists,
|
|
305
|
+
"desired_name": desired_name,
|
|
306
|
+
"desired_openclaw_id": desired_openclaw_id,
|
|
307
|
+
"agent_dir": current_entry.get("agentDir"),
|
|
308
|
+
"dependencies": dependencies,
|
|
309
|
+
"missing_dependencies": missing_dependencies,
|
|
310
|
+
"reason": "workspace_mismatch",
|
|
311
|
+
"message": "当前 Agent 的 workspace 与配置文件不一致,请先人工检查配置。",
|
|
312
|
+
}
|
|
313
|
+
result["user_prompt"] = build_user_prompt(result)
|
|
314
|
+
return result
|
|
315
|
+
|
|
316
|
+
if not current_workspace_exists:
|
|
317
|
+
result = {
|
|
318
|
+
"agent_id": agent_id,
|
|
319
|
+
"target_version": agent_def["version"],
|
|
320
|
+
"status": "CONFIG_ERROR",
|
|
321
|
+
"installed": True,
|
|
322
|
+
"installed_by_id": installed_by_id,
|
|
323
|
+
"installed_by_workspace": installed_by_workspace,
|
|
324
|
+
"current_openclaw_id": current_openclaw_id,
|
|
325
|
+
"workspace": current_workspace,
|
|
326
|
+
"desired_workspace": desired_workspace,
|
|
327
|
+
"workspace_exists": False,
|
|
328
|
+
"desired_name": desired_name,
|
|
329
|
+
"desired_openclaw_id": desired_openclaw_id,
|
|
330
|
+
"agent_dir": current_entry.get("agentDir"),
|
|
331
|
+
"dependencies": dependencies,
|
|
332
|
+
"missing_dependencies": missing_dependencies,
|
|
333
|
+
"reason": "workspace_missing",
|
|
334
|
+
"message": "当前 Agent 的 workspace 目录不存在,请先人工检查配置。",
|
|
335
|
+
}
|
|
336
|
+
result["user_prompt"] = build_user_prompt(result)
|
|
337
|
+
return result
|
|
338
|
+
|
|
339
|
+
current_name, current_identity_name = current_agent_names(current_entry)
|
|
340
|
+
if desired_name and current_identity_name and current_identity_name != desired_name:
|
|
341
|
+
result = {
|
|
342
|
+
"agent_id": agent_id,
|
|
343
|
+
"target_version": agent_def["version"],
|
|
344
|
+
"status": "CONFIG_ERROR",
|
|
345
|
+
"installed": True,
|
|
346
|
+
"installed_by_id": installed_by_id,
|
|
347
|
+
"installed_by_workspace": installed_by_workspace,
|
|
348
|
+
"current_openclaw_id": current_openclaw_id,
|
|
349
|
+
"workspace": current_workspace,
|
|
350
|
+
"desired_workspace": desired_workspace,
|
|
351
|
+
"workspace_exists": True,
|
|
352
|
+
"desired_name": desired_name,
|
|
353
|
+
"desired_openclaw_id": desired_openclaw_id,
|
|
354
|
+
"current_name": current_name,
|
|
355
|
+
"current_identity_name": current_identity_name,
|
|
356
|
+
"agent_dir": current_entry.get("agentDir"),
|
|
357
|
+
"dependencies": dependencies,
|
|
358
|
+
"missing_dependencies": missing_dependencies,
|
|
359
|
+
"reason": "identity_name_mismatch",
|
|
360
|
+
"message": "当前 Agent 的 identity.name 与本次确认名称不一致,请先人工检查配置。",
|
|
361
|
+
}
|
|
362
|
+
result["user_prompt"] = build_user_prompt(result)
|
|
363
|
+
return result
|
|
364
|
+
|
|
365
|
+
desired_top_level_name = normalized_name(desired_entry.get("name"))
|
|
366
|
+
if desired_top_level_name and current_name and current_name != desired_top_level_name:
|
|
367
|
+
result = {
|
|
368
|
+
"agent_id": agent_id,
|
|
369
|
+
"target_version": agent_def["version"],
|
|
370
|
+
"status": "CONFIG_ERROR",
|
|
371
|
+
"installed": True,
|
|
372
|
+
"installed_by_id": installed_by_id,
|
|
373
|
+
"installed_by_workspace": installed_by_workspace,
|
|
374
|
+
"current_openclaw_id": current_openclaw_id,
|
|
375
|
+
"workspace": current_workspace,
|
|
376
|
+
"desired_workspace": desired_workspace,
|
|
377
|
+
"workspace_exists": True,
|
|
378
|
+
"desired_name": desired_name,
|
|
379
|
+
"desired_openclaw_id": desired_openclaw_id,
|
|
380
|
+
"current_name": current_name,
|
|
381
|
+
"current_identity_name": current_identity_name,
|
|
382
|
+
"agent_dir": current_entry.get("agentDir"),
|
|
383
|
+
"dependencies": dependencies,
|
|
384
|
+
"missing_dependencies": missing_dependencies,
|
|
385
|
+
"reason": "name_mismatch",
|
|
386
|
+
"message": "当前 Agent 的 name 与本次确认名称不一致,请先人工检查配置。",
|
|
387
|
+
}
|
|
388
|
+
result["user_prompt"] = build_user_prompt(result)
|
|
389
|
+
return result
|
|
390
|
+
|
|
391
|
+
installed_version, version_source = detect_installed_version(config_path, agent_id, current_entry)
|
|
392
|
+
target_version = agent_def["version"]
|
|
393
|
+
|
|
394
|
+
if not installed_version:
|
|
395
|
+
status = "CONFIG_ERROR"
|
|
396
|
+
message = "无法判断当前已安装 Agent 的版本,请先人工检查配置。"
|
|
397
|
+
reason = "installed_version_unknown"
|
|
398
|
+
else:
|
|
399
|
+
current_parsed = parse_version(str(installed_version))
|
|
400
|
+
target_parsed = parse_version(str(target_version))
|
|
401
|
+
if current_parsed and target_parsed:
|
|
402
|
+
if current_parsed < target_parsed:
|
|
403
|
+
status = "UPDATABLE"
|
|
404
|
+
message = "检测到可用更新。更新前会先备份当前 Agent 配置,再执行更新;如果你对原 Agent 做过修改,需要手动同步相关配置。"
|
|
405
|
+
reason = None
|
|
406
|
+
elif current_parsed == target_parsed:
|
|
407
|
+
status = "SAME_VERSION_REINSTALL"
|
|
408
|
+
message = "当前已安装版本与下载版本一致,本次操作将重置 Agent 配置。继续前必须强提醒并先备份。"
|
|
409
|
+
reason = None
|
|
410
|
+
else:
|
|
411
|
+
status = "CONFIG_ERROR"
|
|
412
|
+
message = "当前已安装版本高于下载版本,请先人工确认是否允许回退。"
|
|
413
|
+
reason = "installed_version_newer_than_target"
|
|
414
|
+
elif str(installed_version) == str(target_version):
|
|
415
|
+
status = "SAME_VERSION_REINSTALL"
|
|
416
|
+
message = "当前已安装版本与下载版本一致,本次操作将重置 Agent 配置。继续前必须强提醒并先备份。"
|
|
417
|
+
reason = None
|
|
418
|
+
else:
|
|
419
|
+
status = "CONFIG_ERROR"
|
|
420
|
+
message = "无法可靠比较当前版本与目标版本,请先人工检查配置。"
|
|
421
|
+
reason = "installed_version_compare_failed"
|
|
422
|
+
|
|
423
|
+
result = {
|
|
424
|
+
"agent_id": agent_id,
|
|
425
|
+
"target_version": target_version,
|
|
426
|
+
"installed_version": installed_version,
|
|
427
|
+
"status": status,
|
|
428
|
+
"installed": True,
|
|
429
|
+
"installed_by_id": installed_by_id,
|
|
430
|
+
"installed_by_workspace": installed_by_workspace,
|
|
431
|
+
"current_openclaw_id": current_openclaw_id,
|
|
432
|
+
"workspace": current_workspace,
|
|
433
|
+
"desired_workspace": desired_workspace,
|
|
434
|
+
"workspace_exists": True,
|
|
435
|
+
"desired_name": desired_name,
|
|
436
|
+
"desired_openclaw_id": desired_openclaw_id,
|
|
437
|
+
"current_name": current_name,
|
|
438
|
+
"current_identity_name": current_identity_name,
|
|
439
|
+
"agent_dir": current_entry.get("agentDir"),
|
|
440
|
+
"version_source": version_source,
|
|
441
|
+
"dependencies": dependencies,
|
|
442
|
+
"missing_dependencies": missing_dependencies,
|
|
443
|
+
"message": message,
|
|
444
|
+
}
|
|
445
|
+
if reason:
|
|
446
|
+
result["reason"] = reason
|
|
447
|
+
result["user_prompt"] = build_user_prompt(result)
|
|
448
|
+
return result
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def main() -> int:
|
|
452
|
+
parser = argparse.ArgumentParser(description="检测 Agent 安装状态")
|
|
453
|
+
parser.add_argument("--agent-id", required=True, help="Agent ID")
|
|
454
|
+
parser.add_argument("--source-path", help="Agent 下载目录(sophhub agent download 的 --path)")
|
|
455
|
+
parser.add_argument("--openclaw-id", help="目标 openclaw id(resolve_install_params 与流程确认结果)")
|
|
456
|
+
parser.add_argument("--workspace", help="目标 workspace(流程确认结果)")
|
|
457
|
+
parser.add_argument("--name", help="显示名称 agent_name(流程确认结果)")
|
|
458
|
+
parser.add_argument(
|
|
459
|
+
"--config",
|
|
460
|
+
default=str(default_openclaw_config_path()),
|
|
461
|
+
help="openclaw.json 路径",
|
|
462
|
+
)
|
|
463
|
+
args = parser.parse_args()
|
|
464
|
+
|
|
465
|
+
result = detect_status(
|
|
466
|
+
args.agent_id,
|
|
467
|
+
Path(args.config).expanduser().resolve(),
|
|
468
|
+
source_path=Path(args.source_path).expanduser().resolve() if args.source_path else None,
|
|
469
|
+
openclaw_id_override=args.openclaw_id,
|
|
470
|
+
workspace_override=args.workspace,
|
|
471
|
+
name_override=args.name,
|
|
472
|
+
)
|
|
473
|
+
json.dump(result, sys.stdout, indent=2, ensure_ascii=False)
|
|
474
|
+
sys.stdout.write("\n")
|
|
475
|
+
return 0
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
if __name__ == "__main__":
|
|
479
|
+
raise SystemExit(main())
|