zerochat 9.8.0__tar.gz → 9.9.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.8.0/zerochat.egg-info → zerochat-9.9.0}/PKG-INFO +1 -1
- {zerochat-9.8.0 → zerochat-9.9.0}/pyproject.toml +1 -1
- {zerochat-9.8.0 → zerochat-9.9.0/zerochat.egg-info}/PKG-INFO +1 -1
- {zerochat-9.8.0 → zerochat-9.9.0}/zerochat.py +108 -11
- {zerochat-9.8.0 → zerochat-9.9.0}/LICENSE +0 -0
- {zerochat-9.8.0 → zerochat-9.9.0}/README.md +0 -0
- {zerochat-9.8.0 → zerochat-9.9.0}/setup.cfg +0 -0
- {zerochat-9.8.0 → zerochat-9.9.0}/zerochat.egg-info/SOURCES.txt +0 -0
- {zerochat-9.8.0 → zerochat-9.9.0}/zerochat.egg-info/dependency_links.txt +0 -0
- {zerochat-9.8.0 → zerochat-9.9.0}/zerochat.egg-info/entry_points.txt +0 -0
- {zerochat-9.8.0 → zerochat-9.9.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.9.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."""
|
|
@@ -1344,6 +1344,92 @@ def set_project_directory(path) -> dict:
|
|
|
1344
1344
|
return {"cwd": str(target), "previous_cwd": previous}
|
|
1345
1345
|
|
|
1346
1346
|
|
|
1347
|
+
# Visores gráficos que `git difftool` ya sabe lanzar, en orden de preferencia, con el ejecutable que los delata.
|
|
1348
|
+
GUI_DIFF_TOOLS = {"vscode": "code", "meld": "meld", "kdiff3": "kdiff3", "kompare": "kompare", "gvimdiff": "gvim"}
|
|
1349
|
+
# Respaldo cuando no hay ninguno: visor web que se instala en el entorno aislado de ZeroChat.
|
|
1350
|
+
WEBDIFF_REQUIREMENT = "webdiff==1.4.0"
|
|
1351
|
+
WEBDIFF_INSTALL_TIMEOUT_SECONDS = 120
|
|
1352
|
+
|
|
1353
|
+
|
|
1354
|
+
def _venv_webdiff() -> Path:
|
|
1355
|
+
"""Ruta de webdiff dentro de ~/zerochat/.venv, junto al intérprete del entorno."""
|
|
1356
|
+
venv_python = get_venv_python(get_venv_dir())
|
|
1357
|
+
return venv_python.with_name("webdiff" + venv_python.suffix)
|
|
1358
|
+
|
|
1359
|
+
|
|
1360
|
+
def _find_webdiff() -> str:
|
|
1361
|
+
"""webdiff del entorno de ZeroChat o, si no, del PATH; '' si no hay ninguno."""
|
|
1362
|
+
venv_webdiff = _venv_webdiff()
|
|
1363
|
+
if venv_webdiff.exists():
|
|
1364
|
+
return str(venv_webdiff)
|
|
1365
|
+
return shutil.which("webdiff") or ""
|
|
1366
|
+
|
|
1367
|
+
|
|
1368
|
+
def _diff_tool_settings(tool: str, webdiff_bin: str) -> list:
|
|
1369
|
+
"""Pares (clave, valor) de git config que deja `tool` como visor gráfico; webdiff no es un visor integrado de git."""
|
|
1370
|
+
settings = [("diff.guitool", tool)]
|
|
1371
|
+
if tool == "webdiff":
|
|
1372
|
+
settings.insert(0, ("difftool.webdiff.cmd", f'"{webdiff_bin}" "$LOCAL" "$REMOTE"'))
|
|
1373
|
+
return settings
|
|
1374
|
+
|
|
1375
|
+
|
|
1376
|
+
def detect_gui_diff_tool() -> dict:
|
|
1377
|
+
"""Visor que proponer cuando Git no tiene ninguno: el primero instalado o, si no hay, webdiff.
|
|
1378
|
+
|
|
1379
|
+
Incluye las órdenes exactas que aplicará configure_gui_diff_tool, para mostrarlas antes de confirmar.
|
|
1380
|
+
"""
|
|
1381
|
+
tool = next((name for name, binary in GUI_DIFF_TOOLS.items() if shutil.which(binary)), "webdiff")
|
|
1382
|
+
webdiff_bin = _find_webdiff()
|
|
1383
|
+
return {
|
|
1384
|
+
"tool": tool,
|
|
1385
|
+
"install": tool == "webdiff" and not webdiff_bin,
|
|
1386
|
+
"commands": [
|
|
1387
|
+
shlex.join(["git", "config", "--global", key, value])
|
|
1388
|
+
for key, value in _diff_tool_settings(tool, webdiff_bin or str(_venv_webdiff()))
|
|
1389
|
+
],
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
|
|
1393
|
+
def _install_webdiff() -> str:
|
|
1394
|
+
"""Instala webdiff en ~/zerochat/.venv y devuelve la ruta del ejecutable."""
|
|
1395
|
+
ensure_virtual_environment()
|
|
1396
|
+
venv_python = get_venv_python(get_venv_dir())
|
|
1397
|
+
if not venv_python.exists():
|
|
1398
|
+
raise RuntimeError(f"No se pudo preparar el entorno virtual de ZeroChat: falta {venv_python}")
|
|
1399
|
+
res = subprocess.run(
|
|
1400
|
+
[str(venv_python), "-m", "pip", "install", WEBDIFF_REQUIREMENT],
|
|
1401
|
+
capture_output=True,
|
|
1402
|
+
text=True,
|
|
1403
|
+
timeout=WEBDIFF_INSTALL_TIMEOUT_SECONDS,
|
|
1404
|
+
check=False
|
|
1405
|
+
)
|
|
1406
|
+
if res.returncode != 0:
|
|
1407
|
+
raise RuntimeError(f"Error instalando webdiff: {(res.stderr or res.stdout).strip()[-500:]}")
|
|
1408
|
+
webdiff = _venv_webdiff()
|
|
1409
|
+
if not webdiff.exists():
|
|
1410
|
+
raise RuntimeError(f"webdiff se instaló pero no aparece en {webdiff}")
|
|
1411
|
+
return str(webdiff)
|
|
1412
|
+
|
|
1413
|
+
|
|
1414
|
+
def configure_gui_diff_tool(tool) -> dict:
|
|
1415
|
+
"""Deja `tool` como visor gráfico global de Git, instalando antes webdiff si es el elegido y falta."""
|
|
1416
|
+
if not isinstance(tool, str) or (tool != "webdiff" and tool not in GUI_DIFF_TOOLS):
|
|
1417
|
+
raise ValueError(f"Visor de diffs '{tool}' no reconocido.")
|
|
1418
|
+
git_bin = shutil.which("git")
|
|
1419
|
+
if not git_bin:
|
|
1420
|
+
raise RuntimeError("Git no está instalado o no se encuentra en el PATH del sistema.")
|
|
1421
|
+
|
|
1422
|
+
webdiff_bin = ""
|
|
1423
|
+
if tool == "webdiff":
|
|
1424
|
+
webdiff_bin = _find_webdiff() or _install_webdiff()
|
|
1425
|
+
elif not shutil.which(GUI_DIFF_TOOLS[tool]):
|
|
1426
|
+
raise ValueError(f"'{GUI_DIFF_TOOLS[tool]}' no está en el PATH del sistema.")
|
|
1427
|
+
|
|
1428
|
+
for key, value in _diff_tool_settings(tool, webdiff_bin):
|
|
1429
|
+
subprocess.run([git_bin, "config", "--global", key, value], capture_output=True, timeout=5, check=True)
|
|
1430
|
+
return {"tool": tool}
|
|
1431
|
+
|
|
1432
|
+
|
|
1347
1433
|
def _configured_gui_diff_tool(git_bin: str, repo_root: Path) -> str:
|
|
1348
1434
|
"""Herramienta gráfica que usaría `git difftool --gui`, o '' si no hay ninguna configurada.
|
|
1349
1435
|
|
|
@@ -1365,7 +1451,10 @@ def _configured_gui_diff_tool(git_bin: str, repo_root: Path) -> str:
|
|
|
1365
1451
|
|
|
1366
1452
|
|
|
1367
1453
|
def open_file_diff(path: str, commit_fallback: bool = False) -> dict:
|
|
1368
|
-
"""Abre un visor externo de diffs (git difftool) para comparar el fichero actual frente a Git HEAD, su último commit o fichero vacío.
|
|
1454
|
+
"""Abre un visor externo de diffs (git difftool) para comparar el fichero actual frente a Git HEAD, su último commit o fichero vacío.
|
|
1455
|
+
|
|
1456
|
+
Sin visor gráfico configurado no lanza nada y devuelve en `setup` el que propone configurar.
|
|
1457
|
+
"""
|
|
1369
1458
|
if not isinstance(path, str) or not path.strip():
|
|
1370
1459
|
raise ValueError("La ruta del archivo está vacía.")
|
|
1371
1460
|
if len(path) > MAX_PATH_LENGTH:
|
|
@@ -1398,10 +1487,7 @@ def open_file_diff(path: str, commit_fallback: bool = False) -> dict:
|
|
|
1398
1487
|
|
|
1399
1488
|
repo_root = Path(res.stdout.strip()).resolve()
|
|
1400
1489
|
if not _configured_gui_diff_tool(git_bin, repo_root):
|
|
1401
|
-
|
|
1402
|
-
"No hay un visor gráfico de diffs configurado en Git. Configura uno, por ejemplo: "
|
|
1403
|
-
"git config --global diff.guitool meld"
|
|
1404
|
-
)
|
|
1490
|
+
return {"success": False, "setup": detect_gui_diff_tool()}
|
|
1405
1491
|
|
|
1406
1492
|
has_head = subprocess.run(
|
|
1407
1493
|
[git_bin, "rev-parse", "--verify", "HEAD"],
|
|
@@ -2218,18 +2304,22 @@ def playwright_launch_env(config: dict) -> dict[str, str]:
|
|
|
2218
2304
|
|
|
2219
2305
|
|
|
2220
2306
|
def validate_profile_browser(raw) -> dict:
|
|
2221
|
-
"""Navegador que exige un perfil: el propio con un motor
|
|
2222
|
-
|
|
2223
|
-
|
|
2307
|
+
"""Navegador que exige un perfil: el propio con un motor, y headless False si exige la ventana
|
|
2308
|
+
visible, o el del usuario con uno de sus navegadores."""
|
|
2309
|
+
if isinstance(raw, dict) and raw.get("mode") == "own" and raw.get("engine") in OWN_BROWSER_ENGINES:
|
|
2310
|
+
if set(raw) == {"mode", "engine"}:
|
|
2311
|
+
return {"mode": "own", "engine": raw["engine"]}
|
|
2312
|
+
if set(raw) == {"mode", "engine", "headless"} and raw["headless"] is False:
|
|
2313
|
+
return {"mode": "own", "engine": raw["engine"], "headless": False}
|
|
2224
2314
|
if isinstance(raw, dict) and raw.get("mode") == "user" and set(raw) == {"mode", "userBrowser"} and raw["userBrowser"] in USER_BROWSERS:
|
|
2225
2315
|
return {"mode": "user", "userBrowser": raw["userBrowser"]}
|
|
2226
|
-
raise ValueError("browser debe ser {mode: own, engine} o {mode: user, userBrowser} con un motor o navegador admitido")
|
|
2316
|
+
raise ValueError("browser debe ser {mode: own, engine[, headless: false]} o {mode: user, userBrowser} con un motor o navegador admitido")
|
|
2227
2317
|
|
|
2228
2318
|
|
|
2229
2319
|
def browser_choice(config: dict) -> dict:
|
|
2230
2320
|
"""Modo y navegador con los que arranca Playwright MCP, en la forma de validate_profile_browser."""
|
|
2231
2321
|
if config["mode"] == "own":
|
|
2232
|
-
return {"mode": "own", "engine": config["engine"]}
|
|
2322
|
+
return {"mode": "own", "engine": config["engine"], **({} if config["headless"] else {"headless": False})}
|
|
2233
2323
|
return {"mode": "user", "userBrowser": config["userBrowser"]}
|
|
2234
2324
|
|
|
2235
2325
|
|
|
@@ -3774,6 +3864,13 @@ class ZeroChatServerHandler(BaseHTTPRequestHandler):
|
|
|
3774
3864
|
return None, {"code": -32602, "message": str(exc)}, ""
|
|
3775
3865
|
except Exception as exc:
|
|
3776
3866
|
return None, {"code": -32603, "message": f"Error al abrir el visor de diffs: {exc}"}, str(exc)
|
|
3867
|
+
if method == "zerochat/diff/configure":
|
|
3868
|
+
try:
|
|
3869
|
+
return configure_gui_diff_tool(params.get("tool")), None, ""
|
|
3870
|
+
except (ValueError, RuntimeError) as exc:
|
|
3871
|
+
return None, {"code": -32602, "message": str(exc)}, ""
|
|
3872
|
+
except Exception as exc:
|
|
3873
|
+
return None, {"code": -32603, "message": f"Error configurando el visor de diffs: {exc}"}, str(exc)
|
|
3777
3874
|
if method == "zerochat/web/fetch":
|
|
3778
3875
|
try:
|
|
3779
3876
|
return fetch_web_resource(params), None, ""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|