myagent-ai 1.47.27 → 1.47.28
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/core/vnc_manager.py +117 -298
- package/package.json +1 -1
package/core/vnc_manager.py
CHANGED
|
@@ -357,7 +357,8 @@ class VNCManager:
|
|
|
357
357
|
# [v1.47.27] 策略B: 尝试 apt-get -f install 修复依赖
|
|
358
358
|
try:
|
|
359
359
|
result_fix = subprocess.run(
|
|
360
|
-
sudo + ["apt-get", "-f", "install", "-y"
|
|
360
|
+
sudo + ["apt-get", "-f", "install", "-y",
|
|
361
|
+
"-o", "Acquire::ForceIPv4=true"],
|
|
361
362
|
capture_output=True, text=True, timeout=30,
|
|
362
363
|
env=no_service_env,
|
|
363
364
|
start_new_session=True,
|
|
@@ -663,7 +664,7 @@ class VNCManager:
|
|
|
663
664
|
# [v1.36.0] 窗口管理器 — 总是安装 icewm(即使已有 fluxbox),因为 icewm 是目标 WM
|
|
664
665
|
_has_icewm = shutil.which("icewm-session") or shutil.which("icewm")
|
|
665
666
|
if not _has_icewm:
|
|
666
|
-
packages_to_install.
|
|
667
|
+
packages_to_install.append("icewm") # [v1.47.28] 移除 icewm-themes — ARM64 无安装候选
|
|
667
668
|
|
|
668
669
|
# [v1.36.0] 文件管理器 — 总是安装 thunar(即使已有 pcmanfm),thunar 在 proot 下更稳定
|
|
669
670
|
if not shutil.which("thunar"):
|
|
@@ -721,7 +722,8 @@ class VNCManager:
|
|
|
721
722
|
|
|
722
723
|
try:
|
|
723
724
|
result = subprocess.run(
|
|
724
|
-
sudo + ["apt-get", "install", "-y", "--fix-broken", "--no-install-recommends"
|
|
725
|
+
sudo + ["apt-get", "install", "-y", "--fix-broken", "--no-install-recommends",
|
|
726
|
+
"-o", "Acquire::ForceIPv4=true"] + packages_to_install,
|
|
725
727
|
capture_output=True, text=True, timeout=180,
|
|
726
728
|
start_new_session=True, # [v1.40.0] 进程隔离
|
|
727
729
|
)
|
|
@@ -733,7 +735,8 @@ class VNCManager:
|
|
|
733
735
|
self._fix_dpkg_interrupted(sudo)
|
|
734
736
|
try:
|
|
735
737
|
result2 = subprocess.run(
|
|
736
|
-
sudo + ["apt-get", "install", "-y", "--fix-broken", "--no-install-recommends"
|
|
738
|
+
sudo + ["apt-get", "install", "-y", "--fix-broken", "--no-install-recommends",
|
|
739
|
+
"-o", "Acquire::ForceIPv4=true"] + packages_to_install,
|
|
737
740
|
capture_output=True, text=True, timeout=180,
|
|
738
741
|
start_new_session=True,
|
|
739
742
|
)
|
|
@@ -797,7 +800,8 @@ class VNCManager:
|
|
|
797
800
|
logger.info(f"快速安装核心依赖: {packages}")
|
|
798
801
|
try:
|
|
799
802
|
result = subprocess.run(
|
|
800
|
-
sudo + ["apt-get", "install", "-y", "--fix-broken", "--no-install-recommends"
|
|
803
|
+
sudo + ["apt-get", "install", "-y", "--fix-broken", "--no-install-recommends",
|
|
804
|
+
"-o", "Acquire::ForceIPv4=true"] + packages,
|
|
801
805
|
capture_output=True, text=True, timeout=60,
|
|
802
806
|
start_new_session=True, # [v1.40.0] 进程隔离
|
|
803
807
|
)
|
|
@@ -809,7 +813,8 @@ class VNCManager:
|
|
|
809
813
|
self._fix_dpkg_interrupted(sudo)
|
|
810
814
|
try:
|
|
811
815
|
result2 = subprocess.run(
|
|
812
|
-
sudo + ["apt-get", "install", "-y", "--fix-broken", "--no-install-recommends"
|
|
816
|
+
sudo + ["apt-get", "install", "-y", "--fix-broken", "--no-install-recommends",
|
|
817
|
+
"-o", "Acquire::ForceIPv4=true"] + packages,
|
|
813
818
|
capture_output=True, text=True, timeout=60,
|
|
814
819
|
start_new_session=True,
|
|
815
820
|
)
|
|
@@ -877,7 +882,8 @@ class VNCManager:
|
|
|
877
882
|
try:
|
|
878
883
|
logger.info(f"尝试单独安装: {pkg}")
|
|
879
884
|
result = subprocess.run(
|
|
880
|
-
sudo + ["apt-get", "install", "-y", "--fix-broken", "--no-install-recommends",
|
|
885
|
+
sudo + ["apt-get", "install", "-y", "--fix-broken", "--no-install-recommends",
|
|
886
|
+
"-o", "Acquire::ForceIPv4=true", pkg],
|
|
881
887
|
capture_output=True, text=True, timeout=45,
|
|
882
888
|
start_new_session=True,
|
|
883
889
|
)
|
|
@@ -1088,14 +1094,19 @@ class VNCManager:
|
|
|
1088
1094
|
logger.info("=== 后台组件安装完成 ===")
|
|
1089
1095
|
|
|
1090
1096
|
def _install_browser_background(self) -> None:
|
|
1091
|
-
"""[v1.
|
|
1097
|
+
"""[v1.47.28] 后台安装浏览器 — 纯 apt 方式,不使用 FTP 下载。
|
|
1092
1098
|
|
|
1093
1099
|
策略(按优先级):
|
|
1094
|
-
1. apt install firefox —
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1100
|
+
1. apt update + apt install firefox — 标准方式
|
|
1101
|
+
强制 IPv4 避免 proot 环境下 IPv6 连接失败
|
|
1102
|
+
2. 手动添加 mozillateam PPA 源 + apt install firefox
|
|
1103
|
+
3. apt install firefox-esr
|
|
1104
|
+
4. apt install chromium
|
|
1105
|
+
|
|
1106
|
+
[v1.47.28] 关键变更:
|
|
1107
|
+
- 删除 FTP 下载 Firefox 回退代码,只用 apt 方式
|
|
1108
|
+
- 所有 apt 命令强制 IPv4(proot 下 IPv6 经常不可达)
|
|
1109
|
+
- 安装前先 apt update 确保包索引最新
|
|
1099
1110
|
|
|
1100
1111
|
安全措施:
|
|
1101
1112
|
- start_new_session=True 进程隔离,安装崩溃不影响 VNC
|
|
@@ -1120,13 +1131,27 @@ class VNCManager:
|
|
|
1120
1131
|
logger.info(f"已有浏览器 {existing_browser} 是 snap 包装器,尝试安装真正的浏览器")
|
|
1121
1132
|
|
|
1122
1133
|
sudo = [] if os.getuid() == 0 else ["sudo"]
|
|
1134
|
+
# [v1.47.28] proot 环境下 IPv6 经常不可达,强制 IPv4
|
|
1135
|
+
apt_ipv4_opts = ["-o", "Acquire::ForceIPv4=true"]
|
|
1136
|
+
|
|
1137
|
+
# ── 预备: apt update 确保包索引最新 ──
|
|
1138
|
+
try:
|
|
1139
|
+
logger.info("执行 apt update 确保包索引最新...")
|
|
1140
|
+
subprocess.run(
|
|
1141
|
+
sudo + ["apt-get", "update"] + apt_ipv4_opts,
|
|
1142
|
+
capture_output=True, text=True, timeout=120,
|
|
1143
|
+
env={**os.environ, "DEBIAN_FRONTEND": "noninteractive"},
|
|
1144
|
+
start_new_session=True,
|
|
1145
|
+
)
|
|
1146
|
+
except Exception as e:
|
|
1147
|
+
logger.debug(f"apt update 异常(继续): {e}")
|
|
1123
1148
|
|
|
1124
1149
|
# ── 方案1: apt install firefox ──
|
|
1125
1150
|
firefox_apt_ok = False
|
|
1126
1151
|
try:
|
|
1127
1152
|
logger.info("尝试 apt install firefox(约需 20 分钟)...")
|
|
1128
1153
|
result = subprocess.run(
|
|
1129
|
-
sudo + ["apt-get", "install", "-y", "--no-install-recommends"
|
|
1154
|
+
sudo + ["apt-get", "install", "-y", "--no-install-recommends"] + apt_ipv4_opts + ["firefox"],
|
|
1130
1155
|
capture_output=True, text=True, timeout=1500, # 25 分钟
|
|
1131
1156
|
env={**os.environ, "DEBIAN_FRONTEND": "noninteractive"},
|
|
1132
1157
|
start_new_session=True,
|
|
@@ -1146,13 +1171,13 @@ class VNCManager:
|
|
|
1146
1171
|
else:
|
|
1147
1172
|
stderr = (result.stderr or "")[-300:]
|
|
1148
1173
|
logger.warning(f"apt install firefox 失败: {stderr}")
|
|
1149
|
-
#
|
|
1174
|
+
# dpkg 中断时先修复再重试
|
|
1150
1175
|
if "dpkg was interrupted" in stderr:
|
|
1151
1176
|
logger.info("dpkg 中断,尝试修复后重试 firefox 安装...")
|
|
1152
1177
|
self._fix_dpkg_interrupted(sudo)
|
|
1153
1178
|
try:
|
|
1154
1179
|
result2 = subprocess.run(
|
|
1155
|
-
sudo + ["apt-get", "install", "-y", "--no-install-recommends"
|
|
1180
|
+
sudo + ["apt-get", "install", "-y", "--no-install-recommends"] + apt_ipv4_opts + ["firefox"],
|
|
1156
1181
|
capture_output=True, text=True, timeout=1500,
|
|
1157
1182
|
env={**os.environ, "DEBIAN_FRONTEND": "noninteractive"},
|
|
1158
1183
|
start_new_session=True,
|
|
@@ -1173,12 +1198,62 @@ class VNCManager:
|
|
|
1173
1198
|
if firefox_apt_ok:
|
|
1174
1199
|
return
|
|
1175
1200
|
|
|
1176
|
-
# ── 方案2: apt install
|
|
1201
|
+
# ── 方案2: 手动添加 mozillateam PPA 源 + apt install firefox ──
|
|
1202
|
+
# [v1.47.28] Ubuntu 默认源可能没有 firefox .deb,需要 PPA
|
|
1203
|
+
try:
|
|
1204
|
+
logger.info("尝试手动添加 mozillateam PPA 安装 Firefox...")
|
|
1205
|
+
ppa_installed = self._add_mozillateam_ppa_manual(sudo, "arm64")
|
|
1206
|
+
if ppa_installed:
|
|
1207
|
+
result = subprocess.run(
|
|
1208
|
+
sudo + ["apt-get", "install", "-y", "--fix-broken"] + apt_ipv4_opts + ["firefox"],
|
|
1209
|
+
capture_output=True, text=True, timeout=1500,
|
|
1210
|
+
env={**os.environ, "DEBIAN_FRONTEND": "noninteractive"},
|
|
1211
|
+
start_new_session=True,
|
|
1212
|
+
)
|
|
1213
|
+
firefox_path = shutil.which("firefox")
|
|
1214
|
+
if firefox_path and not self._is_snap_wrapper(firefox_path):
|
|
1215
|
+
logger.info(f"Firefox PPA 安装成功: {firefox_path}")
|
|
1216
|
+
self._create_browser_wrapper(firefox_path)
|
|
1217
|
+
return
|
|
1218
|
+
else:
|
|
1219
|
+
logger.warning("PPA 安装后 Firefox 仍是 snap 或未找到")
|
|
1220
|
+
except subprocess.TimeoutExpired:
|
|
1221
|
+
logger.warning("mozillateam PPA 安装超时")
|
|
1222
|
+
except Exception as e:
|
|
1223
|
+
logger.debug(f"mozillateam PPA 安装异常: {e}")
|
|
1224
|
+
|
|
1225
|
+
# ── 方案3: apt install firefox-esr ──
|
|
1226
|
+
try:
|
|
1227
|
+
logger.info("尝试 apt install firefox-esr...")
|
|
1228
|
+
result = subprocess.run(
|
|
1229
|
+
sudo + ["apt-get", "install", "-y", "--no-install-recommends"] + apt_ipv4_opts + ["firefox-esr"],
|
|
1230
|
+
capture_output=True, text=True, timeout=1500,
|
|
1231
|
+
env={**os.environ, "DEBIAN_FRONTEND": "noninteractive"},
|
|
1232
|
+
start_new_session=True,
|
|
1233
|
+
)
|
|
1234
|
+
if result.returncode == 0:
|
|
1235
|
+
firefox_path = shutil.which("firefox-esr") or shutil.which("firefox")
|
|
1236
|
+
if firefox_path and not self._is_snap_wrapper(firefox_path):
|
|
1237
|
+
logger.info(f"Firefox ESR 安装成功: {firefox_path}")
|
|
1238
|
+
self._create_browser_wrapper(firefox_path)
|
|
1239
|
+
return
|
|
1240
|
+
else:
|
|
1241
|
+
logger.warning("apt install firefox-esr 安装的是 snap 包装器,跳过")
|
|
1242
|
+
else:
|
|
1243
|
+
stderr = (result.stderr or "")[-200:]
|
|
1244
|
+
logger.warning(f"apt install firefox-esr 失败: {stderr}")
|
|
1245
|
+
except subprocess.TimeoutExpired:
|
|
1246
|
+
logger.warning("apt install firefox-esr 超时")
|
|
1247
|
+
except Exception as e:
|
|
1248
|
+
logger.warning(f"apt install firefox-esr 异常: {e}")
|
|
1249
|
+
|
|
1250
|
+
# ── 方案4: apt install chromium ──
|
|
1177
1251
|
try:
|
|
1178
1252
|
logger.info("尝试 apt install chromium...")
|
|
1179
1253
|
result = subprocess.run(
|
|
1180
|
-
sudo + ["apt-get", "install", "-y", "--no-install-recommends"
|
|
1254
|
+
sudo + ["apt-get", "install", "-y", "--no-install-recommends"] + apt_ipv4_opts + ["chromium"],
|
|
1181
1255
|
capture_output=True, text=True, timeout=600,
|
|
1256
|
+
env={**os.environ, "DEBIAN_FRONTEND": "noninteractive"},
|
|
1182
1257
|
start_new_session=True,
|
|
1183
1258
|
)
|
|
1184
1259
|
if result.returncode == 0:
|
|
@@ -1197,17 +1272,7 @@ class VNCManager:
|
|
|
1197
1272
|
except Exception as e:
|
|
1198
1273
|
logger.warning(f"apt install chromium 异常: {e}")
|
|
1199
1274
|
|
|
1200
|
-
|
|
1201
|
-
# 只在前两种方式都失败时尝试
|
|
1202
|
-
if not shutil.which("firefox") and not shutil.which("chromium"):
|
|
1203
|
-
logger.info("apt 安装浏览器均失败,尝试 proot 专用安装方式...")
|
|
1204
|
-
try:
|
|
1205
|
-
browser_binary = self._install_chromium_proot()
|
|
1206
|
-
if browser_binary:
|
|
1207
|
-
self._create_browser_wrapper(browser_binary)
|
|
1208
|
-
except Exception as e:
|
|
1209
|
-
logger.warning(f"proot 专用浏览器安装异常: {e}")
|
|
1210
|
-
|
|
1275
|
+
logger.warning("所有 apt 安装浏览器方式均失败,请手动运行: sudo apt install firefox")
|
|
1211
1276
|
logger.info("浏览器安装流程结束")
|
|
1212
1277
|
|
|
1213
1278
|
def _create_titlebar_button_pixmaps(self, theme_dir: str) -> None:
|
|
@@ -3841,7 +3906,7 @@ exec {backup_path} "${{args[@]}}"
|
|
|
3841
3906
|
return False
|
|
3842
3907
|
|
|
3843
3908
|
# 安装 icewm(Windows风格) + thunar(文件管理器) + xterm
|
|
3844
|
-
packages = ["icewm", "
|
|
3909
|
+
packages = ["icewm", "thunar", "xterm"] # [v1.47.28] 移除 icewm-themes — ARM64 无安装候选
|
|
3845
3910
|
_apt_cmd = ["apt-get", "install", "-y", "--fix-broken", "--no-install-recommends"] + packages
|
|
3846
3911
|
try:
|
|
3847
3912
|
# 尝试直接执行(root 环境)
|
|
@@ -4243,13 +4308,13 @@ exec {backup_path} "${{args[@]}}"
|
|
|
4243
4308
|
try:
|
|
4244
4309
|
if downloader == "curl":
|
|
4245
4310
|
result = subprocess.run(
|
|
4246
|
-
sudo + ["curl", "-fsSL", "-o", gpg_path, keyserver_url],
|
|
4311
|
+
sudo + ["curl", "-fsSL", "-4", "-o", gpg_path, keyserver_url],
|
|
4247
4312
|
capture_output=True, text=True, timeout=30,
|
|
4248
4313
|
start_new_session=True,
|
|
4249
4314
|
)
|
|
4250
4315
|
else:
|
|
4251
4316
|
result = subprocess.run(
|
|
4252
|
-
sudo + ["wget", "-q", "-O", gpg_path, keyserver_url],
|
|
4317
|
+
sudo + ["wget", "-q", "-4", "-O", gpg_path, keyserver_url],
|
|
4253
4318
|
capture_output=True, text=True, timeout=30,
|
|
4254
4319
|
start_new_session=True,
|
|
4255
4320
|
)
|
|
@@ -4268,7 +4333,7 @@ exec {backup_path} "${{args[@]}}"
|
|
|
4268
4333
|
continue
|
|
4269
4334
|
if downloader == "curl":
|
|
4270
4335
|
subprocess.run(
|
|
4271
|
-
["curl", "-fsSL", keyserver_url],
|
|
4336
|
+
["curl", "-fsSL", "-4", keyserver_url],
|
|
4272
4337
|
capture_output=True, text=True, timeout=30,
|
|
4273
4338
|
start_new_session=True,
|
|
4274
4339
|
)
|
|
@@ -4276,7 +4341,7 @@ exec {backup_path} "${{args[@]}}"
|
|
|
4276
4341
|
if shutil.which("apt-key"):
|
|
4277
4342
|
result = subprocess.run(
|
|
4278
4343
|
sudo + ["bash", "-c",
|
|
4279
|
-
f"curl -fsSL '{keyserver_url}' | apt-key add -"],
|
|
4344
|
+
f"curl -fsSL -4 '{keyserver_url}' | apt-key add -"],
|
|
4280
4345
|
capture_output=True, text=True, timeout=30,
|
|
4281
4346
|
start_new_session=True,
|
|
4282
4347
|
)
|
|
@@ -4346,10 +4411,10 @@ exec {backup_path} "${{args[@]}}"
|
|
|
4346
4411
|
except Exception:
|
|
4347
4412
|
pass
|
|
4348
4413
|
|
|
4349
|
-
# 5. apt-get update
|
|
4414
|
+
# 5. apt-get update(强制 IPv4)
|
|
4350
4415
|
logger.info("执行 apt-get update(更新 PPA 源)...")
|
|
4351
4416
|
result = subprocess.run(
|
|
4352
|
-
sudo + ["apt-get", "update"],
|
|
4417
|
+
sudo + ["apt-get", "update", "-o", "Acquire::ForceIPv4=true"],
|
|
4353
4418
|
capture_output=True, text=True, timeout=120,
|
|
4354
4419
|
env={**os.environ, "DEBIAN_FRONTEND": "noninteractive"},
|
|
4355
4420
|
start_new_session=True,
|
|
@@ -4450,6 +4515,7 @@ exec {backup_path} "${{args[@]}}"
|
|
|
4450
4515
|
# 先尝试 chromium 包(Debian 有真 .deb)
|
|
4451
4516
|
result = subprocess.run(
|
|
4452
4517
|
sudo + ["apt-get", "install", "-y", "--fix-broken", "--no-install-recommends",
|
|
4518
|
+
"-o", "Acquire::ForceIPv4=true",
|
|
4453
4519
|
"chromium", "chromium-common"],
|
|
4454
4520
|
capture_output=True, text=True, timeout=90,
|
|
4455
4521
|
start_new_session=True,
|
|
@@ -4608,20 +4674,16 @@ exec {backup_path} "${{args[@]}}"
|
|
|
4608
4674
|
return None
|
|
4609
4675
|
|
|
4610
4676
|
def _install_firefox_proot(self, sudo: list, arch: str = "arm64") -> Optional[str]:
|
|
4611
|
-
"""[v1.47.
|
|
4677
|
+
"""[v1.47.28] 在 proot/Termux 环境安装 Firefox — 纯 apt 方式。
|
|
4612
4678
|
|
|
4613
4679
|
策略优先级:
|
|
4614
4680
|
1. 检查已有非 snap 的 Firefox
|
|
4615
|
-
2. apt install firefox
|
|
4681
|
+
2. apt install firefox/firefox-esr(强制 IPv4,检测 snap 包装器)
|
|
4616
4682
|
3. mozillateam PPA 手动添加源文件(不走 add-apt-repository,proot 兼容)
|
|
4617
|
-
4. apt install firefox-esr
|
|
4618
|
-
5. [最后手段] 下载 Mozilla Firefox 二进制 tar.bz2
|
|
4619
4683
|
|
|
4620
|
-
[v1.47.
|
|
4621
|
-
-
|
|
4622
|
-
-
|
|
4623
|
-
绕过 add-apt-repository(proot 下 futex 崩溃)
|
|
4624
|
-
- FTP 下载降级为最后手段
|
|
4684
|
+
[v1.47.28] 关键变更:
|
|
4685
|
+
- 删除 FTP 下载回退代码,只用 apt 方式
|
|
4686
|
+
- 所有 apt 命令强制 IPv4(proot 下 IPv6 经常不可达)
|
|
4625
4687
|
|
|
4626
4688
|
Returns:
|
|
4627
4689
|
Firefox 二进制路径,失败返回 None
|
|
@@ -4633,14 +4695,16 @@ exec {backup_path} "${{args[@]}}"
|
|
|
4633
4695
|
logger.info(f"检测到已有非snap Firefox: {existing_path}")
|
|
4634
4696
|
return existing_path
|
|
4635
4697
|
|
|
4636
|
-
# ── 策略2: apt install firefox(proot
|
|
4698
|
+
# ── 策略2: apt install firefox(proot 下也尝试,强制 IPv4)──
|
|
4637
4699
|
# [v1.47.27] 不再无条件跳过 apt install,而是先尝试再检测 snap
|
|
4700
|
+
# [v1.47.28] 强制 IPv4,proot 环境下 IPv6 经常不可达
|
|
4701
|
+
apt_ipv4 = ["-o", "Acquire::ForceIPv4=true"]
|
|
4638
4702
|
# 如果 apt 的 Firefox 是 snap 包装器,才跳到下一策略
|
|
4639
4703
|
for pkg in ["firefox", "firefox-esr"]:
|
|
4640
4704
|
try:
|
|
4641
4705
|
logger.info(f"尝试 apt install {pkg}...")
|
|
4642
4706
|
result = subprocess.run(
|
|
4643
|
-
sudo + ["apt-get", "install", "-y", "--fix-broken", "--no-install-recommends"
|
|
4707
|
+
sudo + ["apt-get", "install", "-y", "--fix-broken", "--no-install-recommends"] + apt_ipv4 + [pkg],
|
|
4644
4708
|
capture_output=True, text=True, timeout=180,
|
|
4645
4709
|
env={**os.environ, "DEBIAN_FRONTEND": "noninteractive"},
|
|
4646
4710
|
start_new_session=True,
|
|
@@ -4663,7 +4727,7 @@ exec {backup_path} "${{args[@]}}"
|
|
|
4663
4727
|
self._fix_dpkg_interrupted(sudo)
|
|
4664
4728
|
# 修复后重试
|
|
4665
4729
|
result2 = subprocess.run(
|
|
4666
|
-
sudo + ["apt-get", "install", "-y", "--fix-broken", "--no-install-recommends"
|
|
4730
|
+
sudo + ["apt-get", "install", "-y", "--fix-broken", "--no-install-recommends"] + apt_ipv4 + [pkg],
|
|
4667
4731
|
capture_output=True, text=True, timeout=180,
|
|
4668
4732
|
env={**os.environ, "DEBIAN_FRONTEND": "noninteractive"},
|
|
4669
4733
|
start_new_session=True,
|
|
@@ -4687,7 +4751,7 @@ exec {backup_path} "${{args[@]}}"
|
|
|
4687
4751
|
ppa_installed = self._add_mozillateam_ppa_manual(sudo, arch)
|
|
4688
4752
|
if ppa_installed:
|
|
4689
4753
|
result = subprocess.run(
|
|
4690
|
-
sudo + ["apt-get", "install", "-y", "--fix-broken"
|
|
4754
|
+
sudo + ["apt-get", "install", "-y", "--fix-broken"] + apt_ipv4 + ["firefox"],
|
|
4691
4755
|
capture_output=True, text=True, timeout=300,
|
|
4692
4756
|
env={**os.environ, "DEBIAN_FRONTEND": "noninteractive"},
|
|
4693
4757
|
start_new_session=True,
|
|
@@ -4706,255 +4770,10 @@ exec {backup_path} "${{args[@]}}"
|
|
|
4706
4770
|
except Exception as e:
|
|
4707
4771
|
logger.debug(f"mozillateam PPA 安装异常: {e}")
|
|
4708
4772
|
|
|
4709
|
-
#
|
|
4710
|
-
#
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
firefox_bin = os.path.join(firefox_install_dir, "firefox")
|
|
4714
|
-
|
|
4715
|
-
# 如果已存在,直接使用
|
|
4716
|
-
if os.path.isfile(firefox_bin) and os.access(firefox_bin, os.X_OK):
|
|
4717
|
-
logger.info(f"Mozilla Firefox 二进制版已存在: {firefox_bin}")
|
|
4718
|
-
link_path = "/usr/local/bin/firefox"
|
|
4719
|
-
if not os.path.exists(link_path):
|
|
4720
|
-
try:
|
|
4721
|
-
os.symlink(firefox_bin, link_path)
|
|
4722
|
-
except Exception:
|
|
4723
|
-
pass
|
|
4724
|
-
return firefox_bin
|
|
4725
|
-
|
|
4726
|
-
import tempfile
|
|
4727
|
-
import re
|
|
4728
|
-
tar_path = os.path.join(tempfile.gettempdir(), "firefox.tar.bz2")
|
|
4729
|
-
|
|
4730
|
-
# [v1.40.0] 动态构建 URL 列表 — 改进版
|
|
4731
|
-
ftp_arch = "linux-aarch64" if arch in ("arm64", "aarch64") else "linux-x86_64"
|
|
4732
|
-
download_urls = []
|
|
4733
|
-
|
|
4734
|
-
# 方法A: 动态查询 Mozilla FTP 获取最新可用版本
|
|
4735
|
-
# 改进:先检查版本目录下是否真的有对应架构的文件
|
|
4736
|
-
try:
|
|
4737
|
-
logger.info("查询 Mozilla FTP 获取最新 Firefox 版本...")
|
|
4738
|
-
ftp_index_url = "https://ftp.mozilla.org/pub/firefox/releases/"
|
|
4739
|
-
ftp_index = ""
|
|
4740
|
-
for dl in ["curl", "wget"]:
|
|
4741
|
-
if not shutil.which(dl):
|
|
4742
|
-
continue
|
|
4743
|
-
try:
|
|
4744
|
-
if dl == "curl":
|
|
4745
|
-
idx_result = subprocess.run(
|
|
4746
|
-
["curl", "-sL", "--max-time", "15", ftp_index_url],
|
|
4747
|
-
capture_output=True, text=True, timeout=20,
|
|
4748
|
-
start_new_session=True,
|
|
4749
|
-
)
|
|
4750
|
-
else:
|
|
4751
|
-
idx_result = subprocess.run(
|
|
4752
|
-
["wget", "-q", "-O", "-", ftp_index_url],
|
|
4753
|
-
capture_output=True, text=True, timeout=20,
|
|
4754
|
-
start_new_session=True,
|
|
4755
|
-
)
|
|
4756
|
-
if idx_result.returncode == 0 and idx_result.stdout:
|
|
4757
|
-
ftp_index = idx_result.stdout
|
|
4758
|
-
break
|
|
4759
|
-
except Exception:
|
|
4760
|
-
pass
|
|
4761
|
-
|
|
4762
|
-
if ftp_index:
|
|
4763
|
-
# 从 HTML 中提取版本目录名
|
|
4764
|
-
# 格式: <a href="137.0.2/">137.0.2/</a>
|
|
4765
|
-
# 匹配 ESR 和正式版版本号
|
|
4766
|
-
versions = re.findall(r'href="(\d+\.\d+(?:\.\d+)?(?:esr)?)/"', ftp_index)
|
|
4767
|
-
# 过滤无效版本(0.x, 太旧的)并排序
|
|
4768
|
-
valid_versions = []
|
|
4769
|
-
for v in versions:
|
|
4770
|
-
try:
|
|
4771
|
-
major = int(v.replace("esr", "").split(".")[0])
|
|
4772
|
-
if major >= 115: # 115+ 是可用的
|
|
4773
|
-
valid_versions.append(v)
|
|
4774
|
-
except (ValueError, IndexError):
|
|
4775
|
-
pass
|
|
4776
|
-
|
|
4777
|
-
# 去重并倒序(最新版本优先)
|
|
4778
|
-
seen = set()
|
|
4779
|
-
unique_versions = []
|
|
4780
|
-
for v in reversed(valid_versions):
|
|
4781
|
-
if v not in seen:
|
|
4782
|
-
seen.add(v)
|
|
4783
|
-
unique_versions.append(v)
|
|
4784
|
-
|
|
4785
|
-
# 取最新的几个版本构建 URL(ESR 和正式版都尝试)
|
|
4786
|
-
esr_versions = [v for v in unique_versions if "esr" in v]
|
|
4787
|
-
regular_versions = [v for v in unique_versions if "esr" not in v]
|
|
4788
|
-
|
|
4789
|
-
# 优先 ESR(ARM64 上更稳定),然后正式版
|
|
4790
|
-
# [v1.40.0] 只取最新的几个,避免过多无效下载尝试
|
|
4791
|
-
for v in (esr_versions[:2] + regular_versions[:2]):
|
|
4792
|
-
url = f"https://ftp.mozilla.org/pub/firefox/releases/{v}/{ftp_arch}/en-US/firefox-{v}.tar.bz2"
|
|
4793
|
-
download_urls.append(url)
|
|
4794
|
-
|
|
4795
|
-
if download_urls:
|
|
4796
|
-
logger.info(f"FTP 发现 {len(unique_versions)} 个版本,尝试最新: "
|
|
4797
|
-
f"{[v for v in (esr_versions[:2] + regular_versions[:2])]}")
|
|
4798
|
-
except Exception as e:
|
|
4799
|
-
logger.debug(f"FTP 版本查询异常: {e}")
|
|
4800
|
-
|
|
4801
|
-
# 方法B: download.mozilla.org 重定向器
|
|
4802
|
-
# [v1.40.0] 注意:aarch64 重定向器有时返回 HTML 错误页而非 tar.bz2
|
|
4803
|
-
# 已有魔术字节验证,但优先级放在 FTP 直接链接之后
|
|
4804
|
-
if arch in ("arm64", "aarch64"):
|
|
4805
|
-
download_urls.extend([
|
|
4806
|
-
"https://download.mozilla.org/?product=firefox-esr-latest-ssl&os=linux64-aarch64&lang=en-US",
|
|
4807
|
-
"https://download.mozilla.org/?product=firefox-latest-ssl&os=linux64-aarch64&lang=en-US",
|
|
4808
|
-
])
|
|
4809
|
-
else:
|
|
4810
|
-
download_urls.extend([
|
|
4811
|
-
"https://download.mozilla.org/?product=firefox-latest-ssl&os=linux64&lang=en-US",
|
|
4812
|
-
"https://download.mozilla.org/?product=firefox-esr-latest-ssl&os=linux64&lang=en-US",
|
|
4813
|
-
])
|
|
4814
|
-
|
|
4815
|
-
# 方法C: 硬编码回退(以防动态查询和重定向器都失败)
|
|
4816
|
-
if arch in ("arm64", "aarch64"):
|
|
4817
|
-
hardcoded = [
|
|
4818
|
-
"https://ftp.mozilla.org/pub/firefox/releases/128.8.0esr/linux-aarch64/en-US/firefox-128.8.0esr.tar.bz2",
|
|
4819
|
-
"https://ftp.mozilla.org/pub/firefox/releases/115.24.0esr/linux-aarch64/en-US/firefox-115.24.0esr.tar.bz2",
|
|
4820
|
-
]
|
|
4821
|
-
else:
|
|
4822
|
-
hardcoded = [
|
|
4823
|
-
"https://ftp.mozilla.org/pub/firefox/releases/128.8.0esr/linux-x86_64/en-US/firefox-128.8.0esr.tar.bz2",
|
|
4824
|
-
]
|
|
4825
|
-
# 只添加尚未在列表中的 URL
|
|
4826
|
-
for url in hardcoded:
|
|
4827
|
-
if url not in download_urls:
|
|
4828
|
-
download_urls.append(url)
|
|
4829
|
-
|
|
4830
|
-
download_ok = False
|
|
4831
|
-
for url in download_urls:
|
|
4832
|
-
if download_ok:
|
|
4833
|
-
break
|
|
4834
|
-
# 清理之前的下载残留
|
|
4835
|
-
if os.path.exists(tar_path):
|
|
4836
|
-
try:
|
|
4837
|
-
os.remove(tar_path)
|
|
4838
|
-
except Exception:
|
|
4839
|
-
pass
|
|
4840
|
-
|
|
4841
|
-
logger.info(f"尝试下载 Firefox: {url[:80]}...")
|
|
4842
|
-
|
|
4843
|
-
for downloader in ["curl", "wget"]:
|
|
4844
|
-
if not shutil.which(downloader):
|
|
4845
|
-
continue
|
|
4846
|
-
try:
|
|
4847
|
-
if downloader == "wget":
|
|
4848
|
-
dl_result = subprocess.run(
|
|
4849
|
-
["wget", "-q", "-L", "--timeout=30", "--tries=2",
|
|
4850
|
-
"-O", tar_path, url],
|
|
4851
|
-
capture_output=True, text=True, timeout=180,
|
|
4852
|
-
start_new_session=True,
|
|
4853
|
-
)
|
|
4854
|
-
else:
|
|
4855
|
-
dl_result = subprocess.run(
|
|
4856
|
-
["curl", "-sL", "--max-time", "60", "--retry", "2",
|
|
4857
|
-
"-o", tar_path, url],
|
|
4858
|
-
capture_output=True, text=True, timeout=180,
|
|
4859
|
-
start_new_session=True,
|
|
4860
|
-
)
|
|
4861
|
-
if dl_result.returncode != 0 or not os.path.exists(tar_path):
|
|
4862
|
-
logger.debug(f"{downloader} 下载返回 rc={dl_result.returncode if os.path.exists(tar_path) else 'no file'}")
|
|
4863
|
-
continue
|
|
4864
|
-
|
|
4865
|
-
file_size = os.path.getsize(tar_path)
|
|
4866
|
-
# 验证文件是否为有效的 bzip2 格式
|
|
4867
|
-
# bzip2 文件以 'BZ' 魔术字节开头
|
|
4868
|
-
# download.mozilla.org 的 aarch64 重定向可能返回 HTML 错误页
|
|
4869
|
-
is_valid_bz2 = False
|
|
4870
|
-
try:
|
|
4871
|
-
with open(tar_path, "rb") as f:
|
|
4872
|
-
magic = f.read(3)
|
|
4873
|
-
is_valid_bz2 = (magic[:2] == b'BZ')
|
|
4874
|
-
except Exception:
|
|
4875
|
-
pass
|
|
4876
|
-
|
|
4877
|
-
if file_size > 5000000 and is_valid_bz2:
|
|
4878
|
-
download_ok = True
|
|
4879
|
-
break
|
|
4880
|
-
else:
|
|
4881
|
-
# [v1.40.0] 输出文件头部内容帮助调试
|
|
4882
|
-
head_info = ""
|
|
4883
|
-
try:
|
|
4884
|
-
with open(tar_path, "rb") as f:
|
|
4885
|
-
head_info = f.read(200).hex()[:100]
|
|
4886
|
-
except Exception:
|
|
4887
|
-
pass
|
|
4888
|
-
logger.info(
|
|
4889
|
-
f"下载的文件无效 (size={file_size}, "
|
|
4890
|
-
f"valid_bz2={is_valid_bz2}, head={head_info}, "
|
|
4891
|
-
f"url={url[:60]}...)"
|
|
4892
|
-
)
|
|
4893
|
-
try:
|
|
4894
|
-
os.remove(tar_path)
|
|
4895
|
-
except Exception:
|
|
4896
|
-
pass
|
|
4897
|
-
except subprocess.TimeoutExpired:
|
|
4898
|
-
logger.warning(f"{downloader} 下载超时")
|
|
4899
|
-
except Exception as e:
|
|
4900
|
-
logger.debug(f"{downloader} 下载异常: {e}")
|
|
4901
|
-
|
|
4902
|
-
if not download_ok:
|
|
4903
|
-
logger.warning("Mozilla Firefox 二进制版下载失败,所有 URL 均无效")
|
|
4904
|
-
return None
|
|
4905
|
-
|
|
4906
|
-
# 解压到 /opt
|
|
4907
|
-
logger.info("解压 Firefox 到 /opt/...")
|
|
4908
|
-
os.makedirs(firefox_install_dir, exist_ok=True)
|
|
4909
|
-
result = subprocess.run(
|
|
4910
|
-
["tar", "xjf", tar_path, "-C", "/opt/"],
|
|
4911
|
-
capture_output=True, text=True, timeout=60,
|
|
4912
|
-
start_new_session=True,
|
|
4913
|
-
)
|
|
4914
|
-
|
|
4915
|
-
# 清理
|
|
4916
|
-
try:
|
|
4917
|
-
os.remove(tar_path)
|
|
4918
|
-
except Exception:
|
|
4919
|
-
pass
|
|
4920
|
-
|
|
4921
|
-
if result.returncode != 0:
|
|
4922
|
-
logger.warning(f"Firefox 解压失败: {result.stderr[:200]}")
|
|
4923
|
-
return None
|
|
4924
|
-
|
|
4925
|
-
# 验证
|
|
4926
|
-
if os.path.isfile(firefox_bin) and os.access(firefox_bin, os.X_OK):
|
|
4927
|
-
# 创建符号链接
|
|
4928
|
-
link_path = "/usr/local/bin/firefox"
|
|
4929
|
-
try:
|
|
4930
|
-
if os.path.exists(link_path) or os.islink(link_path):
|
|
4931
|
-
os.remove(link_path)
|
|
4932
|
-
os.symlink(firefox_bin, link_path)
|
|
4933
|
-
except Exception:
|
|
4934
|
-
pass
|
|
4935
|
-
# 安装依赖库
|
|
4936
|
-
# [v1.40.0] 使用 start_new_session 防止崩溃传播
|
|
4937
|
-
try:
|
|
4938
|
-
subprocess.run(
|
|
4939
|
-
sudo + ["apt-get", "install", "-y", "--no-install-recommends",
|
|
4940
|
-
"libgtk-3-0", "libdbus-glib-1-2", "libxt6",
|
|
4941
|
-
"libasound2", "libatk1.0-0", "libatk-bridge2.0-0",
|
|
4942
|
-
"libcups2", "libxdamage1", "libxrandr2",
|
|
4943
|
-
"libxcomposite1", "libpango-1.0-0",
|
|
4944
|
-
"libcairo2", "libx11-xcb1"],
|
|
4945
|
-
capture_output=True, text=True, timeout=60,
|
|
4946
|
-
start_new_session=True,
|
|
4947
|
-
)
|
|
4948
|
-
except Exception:
|
|
4949
|
-
pass
|
|
4950
|
-
logger.info(f"Mozilla Firefox 二进制版安装成功: {firefox_bin}")
|
|
4951
|
-
return firefox_bin
|
|
4952
|
-
else:
|
|
4953
|
-
logger.warning("Firefox 解压后未找到可执行文件")
|
|
4954
|
-
|
|
4955
|
-
except Exception as e:
|
|
4956
|
-
logger.warning(f"Mozilla Firefox 二进制版安装异常: {e}")
|
|
4957
|
-
|
|
4773
|
+
# [v1.47.28] 已删除 FTP 下载 Firefox 回退代码
|
|
4774
|
+
# 用户要求只用 apt 方式安装,不使用 FTP 下载
|
|
4775
|
+
# 如果以上所有 apt 方式都失败,返回 None
|
|
4776
|
+
logger.warning("所有 apt 方式安装 Firefox 均失败,请手动运行: sudo apt install firefox")
|
|
4958
4777
|
return None
|
|
4959
4778
|
|
|
4960
4779
|
def _create_browser_wrapper(self, browser_binary: str) -> None:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "myagent-ai",
|
|
3
|
-
"version": "1.47.
|
|
3
|
+
"version": "1.47.28",
|
|
4
4
|
"description": "\u672c\u5730\u684c\u9762\u7aef\u6267\u884c\u578bAI\u52a9\u624b - Open Interpreter \u98ce\u683c | Local Desktop Execution-Oriented AI Assistant",
|
|
5
5
|
"main": "main.py",
|
|
6
6
|
"bin": {
|