myagent-ai 1.47.10 → 1.47.12
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/aiskills/browser_stealth.py +71 -14
- package/main.py +19 -1
- package/package.json +1 -1
- package/start.js +5 -1
- package/tray_manager.py +20 -2
- package/web/api_server.py +15 -4
|
@@ -214,15 +214,21 @@ def _ensure_display() -> Optional[Dict[str, Any]]:
|
|
|
214
214
|
"""
|
|
215
215
|
确保有可用的 X11 显示,供浏览器有头模式使用。
|
|
216
216
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
2. 自动启动 VNC(含 Xvfb + x11vnc + websockify)
|
|
220
|
-
3. VNC 不可用时独立启动 Xvfb
|
|
217
|
+
Termux+Ubuntu 环境: 只支持 VNC,无其他 fallback
|
|
218
|
+
非 Termux 容器环境: VNC > 独立 Xvfb 降级
|
|
221
219
|
|
|
222
220
|
Returns:
|
|
223
221
|
{"display": ":99", "vnc": True/False, "xvfb_standalone": True/False}
|
|
224
222
|
失败返回 None
|
|
225
223
|
"""
|
|
224
|
+
# 检测是否为 Termux 环境
|
|
225
|
+
_is_termux = False
|
|
226
|
+
try:
|
|
227
|
+
from core.env_detect import is_termux
|
|
228
|
+
_is_termux = is_termux()
|
|
229
|
+
except ImportError:
|
|
230
|
+
pass
|
|
231
|
+
|
|
226
232
|
# 1. 尝试复用 VNC 远程桌面
|
|
227
233
|
try:
|
|
228
234
|
from core.vnc_manager import get_vnc_manager
|
|
@@ -240,8 +246,6 @@ def _ensure_display() -> Optional[Dict[str, Any]]:
|
|
|
240
246
|
import asyncio
|
|
241
247
|
loop = asyncio.get_event_loop()
|
|
242
248
|
if loop.is_running():
|
|
243
|
-
# 在已有事件循环中,用 run_until_complete 不行,
|
|
244
|
-
# 创建 task 等待完成
|
|
245
249
|
import concurrent.futures
|
|
246
250
|
with concurrent.futures.ThreadPoolExecutor() as pool:
|
|
247
251
|
result = pool.submit(asyncio.run, vnc.start()).result(timeout=30)
|
|
@@ -263,9 +267,15 @@ def _ensure_display() -> Optional[Dict[str, Any]]:
|
|
|
263
267
|
except Exception as e:
|
|
264
268
|
logger.warning(f"VNC 检测异常: {e}")
|
|
265
269
|
|
|
266
|
-
#
|
|
267
|
-
|
|
268
|
-
|
|
270
|
+
# ── Termux+Ubuntu: VNC 是唯一方式,不允许其他 fallback ──
|
|
271
|
+
if _is_termux:
|
|
272
|
+
logger.error(
|
|
273
|
+
"Termux+Ubuntu 环境仅支持通过 VNC 启动浏览器,"
|
|
274
|
+
"VNC 启动失败。请检查 VNC 配置或手动启动 VNC 远程桌面。"
|
|
275
|
+
)
|
|
276
|
+
return None
|
|
277
|
+
|
|
278
|
+
# 2. 非 Termux 容器环境 → 独立启动 Xvfb 作为 fallback
|
|
269
279
|
xvfb_display = _start_xvfb(display_num=100)
|
|
270
280
|
if xvfb_display:
|
|
271
281
|
return {"display": xvfb_display, "vnc": False, "xvfb_standalone": True}
|
|
@@ -561,17 +571,24 @@ class StealthBrowser:
|
|
|
561
571
|
logger.info("桌面环境,使用系统 Chrome 原生参数")
|
|
562
572
|
|
|
563
573
|
# ── 无显示环境处理 ──
|
|
564
|
-
#
|
|
565
|
-
#
|
|
566
|
-
#
|
|
574
|
+
# 桌面环境 (Windows/macOS/Linux有真实显示器): 直接用系统 Chrome
|
|
575
|
+
# Termux+Ubuntu: 仅支持 VNC,不降级到 headless
|
|
576
|
+
# 非 Termux 容器: VNC > Xvfb > headless 降级
|
|
577
|
+
_is_termux_env = False
|
|
578
|
+
try:
|
|
579
|
+
from core.env_detect import is_termux
|
|
580
|
+
_is_termux_env = is_termux()
|
|
581
|
+
except ImportError:
|
|
582
|
+
pass
|
|
583
|
+
|
|
567
584
|
if not self._headless:
|
|
568
585
|
try:
|
|
569
586
|
from core.env_detect import is_desktop
|
|
570
587
|
if is_desktop():
|
|
571
|
-
#
|
|
588
|
+
# 桌面环境: 直接用系统 Chrome
|
|
572
589
|
logger.info("桌面环境,直接使用系统浏览器,跳过 VNC/Xvfb")
|
|
573
590
|
else:
|
|
574
|
-
#
|
|
591
|
+
# 非桌面环境 (容器/Termux): 通过 _ensure_display() 获取显示
|
|
575
592
|
display = _ensure_display()
|
|
576
593
|
if display:
|
|
577
594
|
self._vnc_used = display.get("vnc", False)
|
|
@@ -579,6 +596,17 @@ class StealthBrowser:
|
|
|
579
596
|
if self._vnc_used:
|
|
580
597
|
logger.info(f"复用 VNC 远程桌面显示 ({display['display']}),可在 VNC 中查看浏览器操作")
|
|
581
598
|
else:
|
|
599
|
+
# ── Termux+Ubuntu: VNC 失败 → 直接报错,不降级 headless ──
|
|
600
|
+
if _is_termux_env:
|
|
601
|
+
return SkillResult(
|
|
602
|
+
success=False,
|
|
603
|
+
error=(
|
|
604
|
+
"Termux+Ubuntu 环境仅支持通过 VNC 启动浏览器,"
|
|
605
|
+
"VNC 启动失败。请先启动 VNC 远程桌面,"
|
|
606
|
+
"或通过 Web 管理面板打开 VNC 后再使用浏览器功能。"
|
|
607
|
+
),
|
|
608
|
+
)
|
|
609
|
+
# ── 非 Termux 容器: 降级到 headless ──
|
|
582
610
|
self._headless = True
|
|
583
611
|
logger.warning(
|
|
584
612
|
"无显示环境且 VNC/Xvfb 均不可用,自动降级为 headless 模式"
|
|
@@ -591,10 +619,39 @@ class StealthBrowser:
|
|
|
591
619
|
self._vnc_used = display.get("vnc", False)
|
|
592
620
|
self._xvfb_started_by_us = display.get("xvfb_standalone", False)
|
|
593
621
|
else:
|
|
622
|
+
if _is_termux_env:
|
|
623
|
+
return SkillResult(
|
|
624
|
+
success=False,
|
|
625
|
+
error=(
|
|
626
|
+
"Termux+Ubuntu 环境仅支持通过 VNC 启动浏览器,"
|
|
627
|
+
"VNC 启动失败。请先启动 VNC 远程桌面后再使用浏览器功能。"
|
|
628
|
+
),
|
|
629
|
+
)
|
|
594
630
|
self._headless = True
|
|
595
631
|
logger.warning(
|
|
596
632
|
"无 DISPLAY 环境且 VNC/Xvfb 均不可用,自动降级为 headless 模式"
|
|
597
633
|
)
|
|
634
|
+
else:
|
|
635
|
+
# headless=True 被显式请求,但 Termux 环境下仍强制使用 VNC
|
|
636
|
+
# 因为 headless Chromium 在 Termux 下容易被 OOM Kill
|
|
637
|
+
if _is_termux_env:
|
|
638
|
+
logger.info("Termux+Ubuntu 环境: 忽略 headless 请求,强制使用 VNC 模式")
|
|
639
|
+
self._headless = False
|
|
640
|
+
display = _ensure_display()
|
|
641
|
+
if display:
|
|
642
|
+
self._vnc_used = display.get("vnc", False)
|
|
643
|
+
self._xvfb_started_by_us = display.get("xvfb_standalone", False)
|
|
644
|
+
if self._vnc_used:
|
|
645
|
+
logger.info(f"Termux+Ubuntu: 已通过 VNC 获取显示 ({display['display']})")
|
|
646
|
+
else:
|
|
647
|
+
return SkillResult(
|
|
648
|
+
success=False,
|
|
649
|
+
error=(
|
|
650
|
+
"Termux+Ubuntu 环境仅支持通过 VNC 启动浏览器,"
|
|
651
|
+
"VNC 启动失败。headless 模式在此环境下不可用(容易被 OOM Kill)。"
|
|
652
|
+
"请先启动 VNC 远程桌面后再使用浏览器功能。"
|
|
653
|
+
),
|
|
654
|
+
)
|
|
598
655
|
|
|
599
656
|
# 无头模式(co.headless() 内部设置 --headless=new)
|
|
600
657
|
if self._headless:
|
package/main.py
CHANGED
|
@@ -83,11 +83,23 @@ def _open_browser_kiosk(url: str):
|
|
|
83
83
|
"""打开浏览器窗口,使用系统已安装的 Chrome 或默认浏览器。
|
|
84
84
|
|
|
85
85
|
[v1.34.0] 优先使用系统已安装的 Chrome/Edge,而非 DrissionPage 控制的浏览器。
|
|
86
|
+
[v1.47.12] Termux 环境: 优先使用 termux-open-url(调用 Android 系统浏览器)。
|
|
86
87
|
"""
|
|
87
88
|
import shutil
|
|
88
89
|
import subprocess
|
|
89
90
|
import platform
|
|
90
91
|
|
|
92
|
+
# [v1.47.12] Termux 环境: 优先使用 termux-open-url 打开 Android 系统浏览器
|
|
93
|
+
# 在 Termux proot 环境下,xdg-open 无法工作(Permission denied),
|
|
94
|
+
# 但 termux-open-url 可以跨 proot 边界调用 Android 系统浏览器
|
|
95
|
+
termux_open = shutil.which("termux-open-url")
|
|
96
|
+
if termux_open:
|
|
97
|
+
try:
|
|
98
|
+
subprocess.Popen([termux_open, url], start_new_session=True)
|
|
99
|
+
return
|
|
100
|
+
except Exception:
|
|
101
|
+
pass
|
|
102
|
+
|
|
91
103
|
chrome_path = None
|
|
92
104
|
system = platform.system()
|
|
93
105
|
|
|
@@ -1056,6 +1068,7 @@ def create_tray_icon(app: MyAgentApp, web_port: int = 8767):
|
|
|
1056
1068
|
app.logger.warning(f"无法打开不存在的路径: {path}")
|
|
1057
1069
|
return
|
|
1058
1070
|
import subprocess
|
|
1071
|
+
import shutil
|
|
1059
1072
|
import platform as pf
|
|
1060
1073
|
system = pf.system()
|
|
1061
1074
|
try:
|
|
@@ -1064,7 +1077,12 @@ def create_tray_icon(app: MyAgentApp, web_port: int = 8767):
|
|
|
1064
1077
|
elif system == "Darwin":
|
|
1065
1078
|
subprocess.Popen(["open", path])
|
|
1066
1079
|
else:
|
|
1067
|
-
|
|
1080
|
+
# [v1.47.12] Termux 环境: 优先使用 termux-open-url
|
|
1081
|
+
termux_open = shutil.which("termux-open-url")
|
|
1082
|
+
if termux_open:
|
|
1083
|
+
subprocess.Popen([termux_open, path], start_new_session=True)
|
|
1084
|
+
else:
|
|
1085
|
+
subprocess.Popen(["xdg-open", path])
|
|
1068
1086
|
except Exception as e:
|
|
1069
1087
|
app.logger.warning(f"无法打开路径 {path}: {e}")
|
|
1070
1088
|
|
package/package.json
CHANGED
package/start.js
CHANGED
|
@@ -754,7 +754,11 @@ function cmdRun(pkgDir, userArgs) {
|
|
|
754
754
|
try {
|
|
755
755
|
if (IS_WIN) execSync(`start "" "${url}"`);
|
|
756
756
|
else if (process.platform === "darwin") execSync(`open "${url}"`);
|
|
757
|
-
else
|
|
757
|
+
else {
|
|
758
|
+
// [v1.47.12] Termux 环境: 优先使用 termux-open-url(Android 系统浏览器)
|
|
759
|
+
try { execSync(`termux-open-url "${url}"`); }
|
|
760
|
+
catch (_) { execSync(`xdg-open "${url}"`); }
|
|
761
|
+
}
|
|
758
762
|
} catch (_) {}
|
|
759
763
|
}
|
|
760
764
|
});
|
package/tray_manager.py
CHANGED
|
@@ -347,19 +347,37 @@ def restart_server() -> bool:
|
|
|
347
347
|
|
|
348
348
|
def open_dashboard():
|
|
349
349
|
"""Open chat dashboard in default browser"""
|
|
350
|
-
import
|
|
350
|
+
import shutil, subprocess
|
|
351
351
|
port = _read_port_from_env()
|
|
352
352
|
url = f"http://localhost:{port}"
|
|
353
353
|
log(f"Opening dashboard: {url}")
|
|
354
|
+
# [v1.47.12] Termux 环境: 优先使用 termux-open-url
|
|
355
|
+
termux_open = shutil.which("termux-open-url")
|
|
356
|
+
if termux_open:
|
|
357
|
+
try:
|
|
358
|
+
subprocess.Popen([termux_open, url], start_new_session=True)
|
|
359
|
+
return
|
|
360
|
+
except Exception:
|
|
361
|
+
pass
|
|
362
|
+
import webbrowser
|
|
354
363
|
webbrowser.open(url)
|
|
355
364
|
|
|
356
365
|
|
|
357
366
|
def open_admin():
|
|
358
367
|
"""Open admin dashboard in default browser"""
|
|
359
|
-
import
|
|
368
|
+
import shutil, subprocess
|
|
360
369
|
port = _read_port_from_env()
|
|
361
370
|
url = f"http://localhost:{port}/admin"
|
|
362
371
|
log(f"Opening admin panel: {url}")
|
|
372
|
+
# [v1.47.12] Termux 环境: 优先使用 termux-open-url
|
|
373
|
+
termux_open = shutil.which("termux-open-url")
|
|
374
|
+
if termux_open:
|
|
375
|
+
try:
|
|
376
|
+
subprocess.Popen([termux_open, url], start_new_session=True)
|
|
377
|
+
return
|
|
378
|
+
except Exception:
|
|
379
|
+
pass
|
|
380
|
+
import webbrowser
|
|
363
381
|
webbrowser.open(url)
|
|
364
382
|
|
|
365
383
|
|
package/web/api_server.py
CHANGED
|
@@ -6424,10 +6424,21 @@ window.addEventListener('beforeunload', function() {{
|
|
|
6424
6424
|
"message": message,
|
|
6425
6425
|
})
|
|
6426
6426
|
else:
|
|
6427
|
-
# 找不到 Chrome
|
|
6428
|
-
import
|
|
6429
|
-
|
|
6430
|
-
|
|
6427
|
+
# 找不到 Chrome,降级使用系统浏览器
|
|
6428
|
+
import shutil, subprocess as _sp
|
|
6429
|
+
_opened = False
|
|
6430
|
+
# [v1.47.12] Termux 环境: 优先使用 termux-open-url
|
|
6431
|
+
termux_open = shutil.which("termux-open-url")
|
|
6432
|
+
if termux_open and login_url:
|
|
6433
|
+
try:
|
|
6434
|
+
_sp.Popen([termux_open, login_url], start_new_session=True)
|
|
6435
|
+
_opened = True
|
|
6436
|
+
except Exception:
|
|
6437
|
+
pass
|
|
6438
|
+
if not _opened:
|
|
6439
|
+
import webbrowser
|
|
6440
|
+
if login_url:
|
|
6441
|
+
webbrowser.open(login_url)
|
|
6431
6442
|
logger.info(f"桌面环境: 未找到 Chrome,使用系统默认浏览器打开 {login_url}")
|
|
6432
6443
|
|
|
6433
6444
|
display_name = site.get('display_name', name)
|