zerochat 9.7.0__tar.gz → 9.8.0__tar.gz
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.
Potentially problematic release.
This version of zerochat might be problematic. Click here for more details.
- {zerochat-9.7.0/zerochat.egg-info → zerochat-9.8.0}/PKG-INFO +1 -1
- {zerochat-9.7.0 → zerochat-9.8.0}/pyproject.toml +1 -1
- {zerochat-9.7.0 → zerochat-9.8.0/zerochat.egg-info}/PKG-INFO +1 -1
- {zerochat-9.7.0 → zerochat-9.8.0}/zerochat.py +33 -39
- {zerochat-9.7.0 → zerochat-9.8.0}/LICENSE +0 -0
- {zerochat-9.7.0 → zerochat-9.8.0}/README.md +0 -0
- {zerochat-9.7.0 → zerochat-9.8.0}/setup.cfg +0 -0
- {zerochat-9.7.0 → zerochat-9.8.0}/zerochat.egg-info/SOURCES.txt +0 -0
- {zerochat-9.7.0 → zerochat-9.8.0}/zerochat.egg-info/dependency_links.txt +0 -0
- {zerochat-9.7.0 → zerochat-9.8.0}/zerochat.egg-info/entry_points.txt +0 -0
- {zerochat-9.7.0 → zerochat-9.8.0}/zerochat.egg-info/top_level.txt +0 -0
|
@@ -46,7 +46,7 @@ import zlib
|
|
|
46
46
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
|
47
47
|
from pathlib import Path
|
|
48
48
|
|
|
49
|
-
SOURCE_BACKEND_VERSION = "9.
|
|
49
|
+
SOURCE_BACKEND_VERSION = "9.8.0"
|
|
50
50
|
|
|
51
51
|
def _read_source_version(filename: str) -> str | None:
|
|
52
52
|
"""Lee la versión de un archivo del repositorio cuando se ejecuta desde fuentes."""
|
|
@@ -1727,17 +1727,13 @@ class PersistentBrowserSession:
|
|
|
1727
1727
|
const readline = require('readline');
|
|
1728
1728
|
let playwright;
|
|
1729
1729
|
try {
|
|
1730
|
-
playwright = require(
|
|
1731
|
-
} catch (
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
error: "Playwright is not available. Install it with 'npm install playwright' or enable the Playwright MCP service."
|
|
1738
|
-
}));
|
|
1739
|
-
process.exit(1);
|
|
1740
|
-
}
|
|
1730
|
+
playwright = require(process.env.ZEROCHAT_PLAYWRIGHT_MODULE);
|
|
1731
|
+
} catch (e) {
|
|
1732
|
+
console.log(JSON.stringify({
|
|
1733
|
+
success: false,
|
|
1734
|
+
error: "Playwright is not available. Start the Playwright service once in Settings > MCP to install it."
|
|
1735
|
+
}));
|
|
1736
|
+
process.exit(1);
|
|
1741
1737
|
}
|
|
1742
1738
|
|
|
1743
1739
|
(async () => {
|
|
@@ -1903,8 +1899,8 @@ def browser_action_availability() -> dict:
|
|
|
1903
1899
|
"""Comprueba requisitos locales sin lanzar Node.js ni Chromium."""
|
|
1904
1900
|
if not shutil.which("node"):
|
|
1905
1901
|
return {"available": False, "error": "Node.js is not installed or not found in system PATH."}
|
|
1906
|
-
|
|
1907
|
-
if not
|
|
1902
|
+
# Solo el Playwright del servicio, no el node_modules de la carpeta desde la que arranca el servidor.
|
|
1903
|
+
if not playwright_service_cli().is_file():
|
|
1908
1904
|
return {"available": False, "error": "Playwright is not available."}
|
|
1909
1905
|
# El runner prueba las entradas de Chromium de Playwright y los canales chrome y msedge.
|
|
1910
1906
|
browsers = system_browsers()
|
|
@@ -1913,6 +1909,11 @@ def browser_action_availability() -> dict:
|
|
|
1913
1909
|
return {"available": False, "error": "Playwright Chromium is not installed."}
|
|
1914
1910
|
|
|
1915
1911
|
|
|
1912
|
+
def playwright_status() -> dict:
|
|
1913
|
+
"""Playwright del servicio y browser_action tal como están ahora, para el latido del cliente."""
|
|
1914
|
+
return {"installed": playwright_service_cli().is_file(), "browserAction": browser_action_availability()}
|
|
1915
|
+
|
|
1916
|
+
|
|
1916
1917
|
def browser_action(action: str, url: str | None = None, selector: str | None = None, value: str | None = None) -> str:
|
|
1917
1918
|
"""Control a headless browser for UI testing and visual inspection."""
|
|
1918
1919
|
try:
|
|
@@ -2358,22 +2359,19 @@ class BrowserEngines:
|
|
|
2358
2359
|
return {name: (title, Path(location.strip())) for title, name, location in _DRY_RUN_ENTRY.findall(result.stdout)}
|
|
2359
2360
|
|
|
2360
2361
|
def list(self) -> dict:
|
|
2362
|
+
"""Navegadores del sistema y motores de Playwright; sin Playwright del servicio no hay motores."""
|
|
2361
2363
|
cli = playwright_service_cli()
|
|
2362
2364
|
result = {"systemBrowsers": system_browsers(), "extensions": user_browser_extensions(), "engines": []}
|
|
2363
2365
|
if not cli.is_file():
|
|
2364
|
-
return
|
|
2365
|
-
|
|
2366
|
-
version = json.loads((cli.parent / "package.json").read_text(encoding="utf-8")).get("version")
|
|
2367
|
-
locations = self._locations(cli)
|
|
2368
|
-
except (OSError, json.JSONDecodeError, RuntimeError, subprocess.SubprocessError) as err:
|
|
2369
|
-
return {**result, "available": False, "error": str(err)}
|
|
2366
|
+
return result
|
|
2367
|
+
locations = self._locations(cli)
|
|
2370
2368
|
with self._lock:
|
|
2371
2369
|
jobs = {engine: dict(job) for engine, job in self._jobs.items()}
|
|
2372
2370
|
for engine, entries in ENGINE_CACHE_ENTRIES.items():
|
|
2373
2371
|
title = locations.get(entries[0], (engine,))[0]
|
|
2374
2372
|
installed = all(name in locations and (locations[name][1] / "INSTALLATION_COMPLETE").is_file() for name in entries)
|
|
2375
2373
|
result["engines"].append({"id": engine, "title": title, "installed": installed, **jobs.get(engine, {})})
|
|
2376
|
-
return
|
|
2374
|
+
return result
|
|
2377
2375
|
|
|
2378
2376
|
def _check_engine(self, engine) -> Path:
|
|
2379
2377
|
if engine not in ENGINE_CACHE_ENTRIES:
|
|
@@ -2864,6 +2862,12 @@ class McpServiceManager:
|
|
|
2864
2862
|
client = self.clients.get(server_id)
|
|
2865
2863
|
state = self.states.get(server_id, "stopped")
|
|
2866
2864
|
running = bool(client and client.running() and state == "running")
|
|
2865
|
+
error = self.errors.get(server_id)
|
|
2866
|
+
# El proceso de un servicio en marcha puede morir sin que nadie lo detenga.
|
|
2867
|
+
if state == "running" and client and not running:
|
|
2868
|
+
code = client.process.poll() if client.process else None
|
|
2869
|
+
state = "error"
|
|
2870
|
+
error = f"MCP process exited with code {code}" if code is not None else "MCP process is not responding"
|
|
2867
2871
|
pref = self.preferences.get(server_id, {})
|
|
2868
2872
|
result.append({
|
|
2869
2873
|
"id": server_id,
|
|
@@ -2874,7 +2878,7 @@ class McpServiceManager:
|
|
|
2874
2878
|
"enabled": pref.get("enabled", server.get("enabledByDefault", False)),
|
|
2875
2879
|
"status": "running" if running else state,
|
|
2876
2880
|
"toolCount": len(client.tools) if running else 0,
|
|
2877
|
-
"error":
|
|
2881
|
+
"error": error,
|
|
2878
2882
|
"options": server.get("options", []),
|
|
2879
2883
|
"userOptions": pref.get("options", {}),
|
|
2880
2884
|
"oauthUrl": client.oauth_url if client else None,
|
|
@@ -3568,12 +3572,16 @@ class ZeroChatServerHandler(BaseHTTPRequestHandler):
|
|
|
3568
3572
|
if is_heartbeat:
|
|
3569
3573
|
mark_browser_active()
|
|
3570
3574
|
# cwd permite a cada pestaña notar que otra ha cambiado el directorio del proyecto;
|
|
3571
|
-
# jobs, mostrar los comandos que siguen en marcha y avisar antes de cerrar si se detendrían
|
|
3575
|
+
# jobs, mostrar los comandos que siguen en marcha y avisar antes de cerrar si se detendrían;
|
|
3576
|
+
# playwright, si se puede navegar aunque se haya instalado o quitado durante la sesión;
|
|
3577
|
+
# servers, los servicios MCP externos aunque otra pestaña los cambie o su proceso muera.
|
|
3572
3578
|
self._send_json_response(200, {
|
|
3573
3579
|
"ok": True,
|
|
3574
3580
|
"cwd": str(Path.cwd().resolve()),
|
|
3575
3581
|
"jobs": [job.summary() for job in JOBS.running()],
|
|
3576
|
-
"exit_on_close": EXIT_ON_CLOSE
|
|
3582
|
+
"exit_on_close": EXIT_ON_CLOSE,
|
|
3583
|
+
"playwright": playwright_status(),
|
|
3584
|
+
"servers": GLOBAL_MCP_MANAGER.list_servers()
|
|
3577
3585
|
})
|
|
3578
3586
|
return
|
|
3579
3587
|
|
|
@@ -3597,7 +3605,6 @@ class ZeroChatServerHandler(BaseHTTPRequestHandler):
|
|
|
3597
3605
|
"version": VERSION,
|
|
3598
3606
|
"cwd": str(Path.cwd().resolve()),
|
|
3599
3607
|
"tools_count": len(LOCAL_TOOLS_DEFINITIONS),
|
|
3600
|
-
"browser_action": browser_action_availability(),
|
|
3601
3608
|
"os": DETECTED_OS
|
|
3602
3609
|
})
|
|
3603
3610
|
self._log_res(200, safe_path, (time.monotonic() - t0) * 1000)
|
|
@@ -3731,18 +3738,7 @@ class ZeroChatServerHandler(BaseHTTPRequestHandler):
|
|
|
3731
3738
|
}
|
|
3732
3739
|
return self._initialize_result(server_info), None, ""
|
|
3733
3740
|
if method == "tools/list":
|
|
3734
|
-
|
|
3735
|
-
tools = []
|
|
3736
|
-
for definition in LOCAL_TOOLS_DEFINITIONS:
|
|
3737
|
-
item = dict(definition)
|
|
3738
|
-
if item.get("name") == "browser_action":
|
|
3739
|
-
item["availability"] = browser_availability
|
|
3740
|
-
tools.append(item)
|
|
3741
|
-
return {"tools": tools}, None, ""
|
|
3742
|
-
if method == "tools/availability":
|
|
3743
|
-
if params.get("name", "") != "browser_action":
|
|
3744
|
-
return None, {"code": -32602, "message": "Herramienta no compatible con comprobación de disponibilidad."}, ""
|
|
3745
|
-
return browser_action_availability(), None, ""
|
|
3741
|
+
return {"tools": [dict(definition) for definition in LOCAL_TOOLS_DEFINITIONS]}, None, ""
|
|
3746
3742
|
if method == "tools/call":
|
|
3747
3743
|
tool_name = params["name"]
|
|
3748
3744
|
handler = LOCAL_TOOL_HANDLERS.get(tool_name)
|
|
@@ -3789,8 +3785,6 @@ class ZeroChatServerHandler(BaseHTTPRequestHandler):
|
|
|
3789
3785
|
return self._dispatch_jobs(method, params)
|
|
3790
3786
|
if method.startswith("zerochat/run/"):
|
|
3791
3787
|
return dispatch_run(method, params)
|
|
3792
|
-
if method == "zerochat/external/status":
|
|
3793
|
-
return {"host": "running", "version": VERSION, "servers": GLOBAL_MCP_MANAGER.list_servers()}, None, ""
|
|
3794
3788
|
if method in ("zerochat/external/servers/start", "zerochat/external/servers/stop", "zerochat/external/servers/configure"):
|
|
3795
3789
|
return self._dispatch_server_control(method, params)
|
|
3796
3790
|
if method.startswith("zerochat/browser/"):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|