zerochat 7.4.0__tar.gz → 7.5.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.
- {zerochat-7.4.0/zerochat.egg-info → zerochat-7.5.0}/PKG-INFO +5 -3
- {zerochat-7.4.0 → zerochat-7.5.0}/README.md +4 -2
- {zerochat-7.4.0 → zerochat-7.5.0}/pyproject.toml +1 -1
- {zerochat-7.4.0 → zerochat-7.5.0/zerochat.egg-info}/PKG-INFO +5 -3
- {zerochat-7.4.0 → zerochat-7.5.0}/zerochat.py +60 -58
- {zerochat-7.4.0 → zerochat-7.5.0}/LICENSE +0 -0
- {zerochat-7.4.0 → zerochat-7.5.0}/setup.cfg +0 -0
- {zerochat-7.4.0 → zerochat-7.5.0}/zerochat.egg-info/SOURCES.txt +0 -0
- {zerochat-7.4.0 → zerochat-7.5.0}/zerochat.egg-info/dependency_links.txt +0 -0
- {zerochat-7.4.0 → zerochat-7.5.0}/zerochat.egg-info/entry_points.txt +0 -0
- {zerochat-7.4.0 → zerochat-7.5.0}/zerochat.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zerochat
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.5.0
|
|
4
4
|
Summary: Private local web client for AI models, tools and MCP services
|
|
5
5
|
Author: Alberto Balday
|
|
6
6
|
License-Expression: MIT
|
|
@@ -41,13 +41,15 @@ Funciona de forma estática en el navegador (servido por GitHub Pages o directam
|
|
|
41
41
|
```bash
|
|
42
42
|
python3 zerochat.py
|
|
43
43
|
```
|
|
44
|
-
Inicia el asistente local, crea
|
|
44
|
+
Inicia el asistente local, crea `./zerochat/.venv` para los MCP y abre la interfaz web en tu navegador.
|
|
45
45
|
- **Instalación con PyPI**:
|
|
46
46
|
```bash
|
|
47
47
|
pip install zerochat
|
|
48
48
|
zerochat
|
|
49
49
|
```
|
|
50
|
-
Es la vía recomendada para instalar el servidor local desde PyPI.
|
|
50
|
+
Es la vía recomendada para instalar el servidor local desde PyPI. Igual que con la descarga directa, crea `./zerochat/` para el estado y los MCP; la interfaz se carga desde GitHub Pages.
|
|
51
|
+
|
|
52
|
+
En ambos modos, `./zerochat/` contiene configuración, token, servicios MCP y sus dependencias Python en `.venv/`. Borrar ese directorio elimina el estado local y los MCP, sin desinstalar el ejecutable de PyPI ni el archivo descargado.
|
|
51
53
|
|
|
52
54
|
Las publicaciones se realizan desde el repositorio oficial mediante GitHub Actions y PyPI Trusted Publishing.
|
|
53
55
|
|
|
@@ -19,13 +19,15 @@ Funciona de forma estática en el navegador (servido por GitHub Pages o directam
|
|
|
19
19
|
```bash
|
|
20
20
|
python3 zerochat.py
|
|
21
21
|
```
|
|
22
|
-
Inicia el asistente local, crea
|
|
22
|
+
Inicia el asistente local, crea `./zerochat/.venv` para los MCP y abre la interfaz web en tu navegador.
|
|
23
23
|
- **Instalación con PyPI**:
|
|
24
24
|
```bash
|
|
25
25
|
pip install zerochat
|
|
26
26
|
zerochat
|
|
27
27
|
```
|
|
28
|
-
Es la vía recomendada para instalar el servidor local desde PyPI.
|
|
28
|
+
Es la vía recomendada para instalar el servidor local desde PyPI. Igual que con la descarga directa, crea `./zerochat/` para el estado y los MCP; la interfaz se carga desde GitHub Pages.
|
|
29
|
+
|
|
30
|
+
En ambos modos, `./zerochat/` contiene configuración, token, servicios MCP y sus dependencias Python en `.venv/`. Borrar ese directorio elimina el estado local y los MCP, sin desinstalar el ejecutable de PyPI ni el archivo descargado.
|
|
29
31
|
|
|
30
32
|
Las publicaciones se realizan desde el repositorio oficial mediante GitHub Actions y PyPI Trusted Publishing.
|
|
31
33
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zerochat
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.5.0
|
|
4
4
|
Summary: Private local web client for AI models, tools and MCP services
|
|
5
5
|
Author: Alberto Balday
|
|
6
6
|
License-Expression: MIT
|
|
@@ -41,13 +41,15 @@ Funciona de forma estática en el navegador (servido por GitHub Pages o directam
|
|
|
41
41
|
```bash
|
|
42
42
|
python3 zerochat.py
|
|
43
43
|
```
|
|
44
|
-
Inicia el asistente local, crea
|
|
44
|
+
Inicia el asistente local, crea `./zerochat/.venv` para los MCP y abre la interfaz web en tu navegador.
|
|
45
45
|
- **Instalación con PyPI**:
|
|
46
46
|
```bash
|
|
47
47
|
pip install zerochat
|
|
48
48
|
zerochat
|
|
49
49
|
```
|
|
50
|
-
Es la vía recomendada para instalar el servidor local desde PyPI.
|
|
50
|
+
Es la vía recomendada para instalar el servidor local desde PyPI. Igual que con la descarga directa, crea `./zerochat/` para el estado y los MCP; la interfaz se carga desde GitHub Pages.
|
|
51
|
+
|
|
52
|
+
En ambos modos, `./zerochat/` contiene configuración, token, servicios MCP y sus dependencias Python en `.venv/`. Borrar ese directorio elimina el estado local y los MCP, sin desinstalar el ejecutable de PyPI ni el archivo descargado.
|
|
51
53
|
|
|
52
54
|
Las publicaciones se realizan desde el repositorio oficial mediante GitHub Actions y PyPI Trusted Publishing.
|
|
53
55
|
|
|
@@ -37,6 +37,8 @@ import webbrowser
|
|
|
37
37
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
|
38
38
|
from pathlib import Path
|
|
39
39
|
|
|
40
|
+
SOURCE_BACKEND_VERSION = "7.5.0"
|
|
41
|
+
|
|
40
42
|
def _read_source_version(filename: str) -> str | None:
|
|
41
43
|
"""Lee la versión de un archivo del repositorio cuando se ejecuta desde fuentes."""
|
|
42
44
|
try:
|
|
@@ -53,10 +55,13 @@ def _read_source_version(filename: str) -> str | None:
|
|
|
53
55
|
|
|
54
56
|
def _read_backend_version() -> str:
|
|
55
57
|
"""Devuelve la versión publicada del backend, sin depender de package.json instalado."""
|
|
58
|
+
source_version = _read_source_version("pyproject.toml")
|
|
59
|
+
if source_version:
|
|
60
|
+
return source_version
|
|
56
61
|
try:
|
|
57
62
|
return importlib.metadata.version("zerochat")
|
|
58
63
|
except importlib.metadata.PackageNotFoundError:
|
|
59
|
-
return
|
|
64
|
+
return SOURCE_BACKEND_VERSION
|
|
60
65
|
|
|
61
66
|
|
|
62
67
|
def _read_ui_version() -> str:
|
|
@@ -84,6 +89,7 @@ DEFAULT_PORT = 6388
|
|
|
84
89
|
DEFAULT_HOST = "127.0.0.1"
|
|
85
90
|
DEFAULT_UI_URL = "https://albalday.github.io/zerochat/zerochat.html"
|
|
86
91
|
REMOTE_VERSION_URL = "https://raw.githubusercontent.com/albalday/zerochat/master/package.json"
|
|
92
|
+
PYPI_VERSION_URL = "https://pypi.org/pypi/zerochat/json"
|
|
87
93
|
REMOTE_SCRIPT_URL = "https://raw.githubusercontent.com/albalday/zerochat/master/zerochat.py"
|
|
88
94
|
CONSOLE_STATUS_IDLE_SECONDS = 8.0
|
|
89
95
|
CONSOLE_CONTROL = None
|
|
@@ -256,26 +262,22 @@ def is_installed_runtime() -> bool:
|
|
|
256
262
|
return False
|
|
257
263
|
|
|
258
264
|
|
|
259
|
-
def
|
|
260
|
-
"""Devuelve el
|
|
261
|
-
if get_dev_root() is not None:
|
|
262
|
-
return (Path.cwd() / "zerochat").resolve()
|
|
263
|
-
|
|
265
|
+
def get_data_dir() -> Path:
|
|
266
|
+
"""Devuelve el directorio local que concentra el estado y los MCP de ZeroChat."""
|
|
264
267
|
configured = os.environ.get("ZEROCHAT_DATA_DIR", "").strip()
|
|
265
268
|
if configured:
|
|
266
269
|
return Path(configured).expanduser().resolve()
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
return (base / "zerochat").resolve()
|
|
270
|
+
return (Path.cwd() / "zerochat").resolve()
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def get_venv_dir() -> Path:
|
|
274
|
+
"""Devuelve el entorno aislado usado exclusivamente por los MCP Python."""
|
|
275
|
+
return get_data_dir() / ".venv"
|
|
274
276
|
|
|
275
277
|
|
|
276
278
|
def get_daily_token() -> str:
|
|
277
279
|
"""Devuelve un token de sesión diario persistido en ./zerochat/config/token.json."""
|
|
278
|
-
config_dir =
|
|
280
|
+
config_dir = get_data_dir() / "config"
|
|
279
281
|
config_dir.mkdir(parents=True, exist_ok=True)
|
|
280
282
|
token_file = config_dir / "token.json"
|
|
281
283
|
today = datetime.date.today().isoformat()
|
|
@@ -313,12 +315,10 @@ def get_venv_python(venv_dir: Path) -> Path:
|
|
|
313
315
|
|
|
314
316
|
def ensure_virtual_environment():
|
|
315
317
|
"""
|
|
316
|
-
|
|
317
|
-
|
|
318
|
+
Crea ./zerochat/.venv para dependencias MCP en ambos modos de distribución.
|
|
319
|
+
El servidor conserva el intérprete con el que fue iniciado; el entorno se usa
|
|
320
|
+
exclusivamente al lanzar procesos MCP Python.
|
|
318
321
|
"""
|
|
319
|
-
if is_installed_runtime():
|
|
320
|
-
return
|
|
321
|
-
|
|
322
322
|
venv_dir = get_venv_dir()
|
|
323
323
|
venv_py = get_venv_python(venv_dir)
|
|
324
324
|
|
|
@@ -332,19 +332,6 @@ def ensure_virtual_environment():
|
|
|
332
332
|
console_log(f"[{time.strftime('%H:%M:%S')}] [zerochat] Advertencia al crear venv: {err}. Continuando con intérprete actual.", flush=True)
|
|
333
333
|
return
|
|
334
334
|
|
|
335
|
-
# 2. Comprobar si ya estamos ejecutándonos dentro del venv
|
|
336
|
-
try:
|
|
337
|
-
current_py = Path(sys.executable).resolve()
|
|
338
|
-
target_py = venv_py.resolve()
|
|
339
|
-
if current_py != target_py and target_py.exists():
|
|
340
|
-
console_log(f"[{time.strftime('%H:%M:%S')}] [zerochat] Re-ejecutando bajo {venv_py}...", flush=True)
|
|
341
|
-
# Re-ejecutar con los mismos argumentos
|
|
342
|
-
args = [str(target_py), str(Path(__file__).resolve())] + sys.argv[1:]
|
|
343
|
-
os.execv(str(target_py), args)
|
|
344
|
-
except Exception as err:
|
|
345
|
-
console_log(f"[{time.strftime('%H:%M:%S')}] [zerochat] Error en re-ejecución: {err}. Continuando.", flush=True)
|
|
346
|
-
|
|
347
|
-
|
|
348
335
|
def parse_version(ver: str) -> tuple[int, ...]:
|
|
349
336
|
"""Convierte una cadena de versión semántica en tupla de enteros para comparación."""
|
|
350
337
|
parts = []
|
|
@@ -355,29 +342,43 @@ def parse_version(ver: str) -> tuple[int, ...]:
|
|
|
355
342
|
return tuple(parts)
|
|
356
343
|
|
|
357
344
|
|
|
345
|
+
def _read_remote_version(url: str) -> str | None:
|
|
346
|
+
"""Obtiene una versión publicada desde package.json o la API JSON de PyPI."""
|
|
347
|
+
req = urllib.request.Request(url, headers={"User-Agent": f"ZeroChat/{VERSION}"})
|
|
348
|
+
with urllib.request.urlopen(req, timeout=3) as resp:
|
|
349
|
+
content = resp.read(4096).decode("utf-8", errors="ignore")
|
|
350
|
+
try:
|
|
351
|
+
data = json.loads(content)
|
|
352
|
+
if isinstance(data, dict):
|
|
353
|
+
candidate = data.get("version")
|
|
354
|
+
if not isinstance(candidate, str) and isinstance(data.get("info"), dict):
|
|
355
|
+
candidate = data["info"].get("version")
|
|
356
|
+
if isinstance(candidate, str):
|
|
357
|
+
return candidate.strip()
|
|
358
|
+
except (json.JSONDecodeError, TypeError):
|
|
359
|
+
pass
|
|
360
|
+
match = re.search(r'["\']?version["\']?\s*[:=]\s*["\'](\d+\.\d+\.\d+)["\']', content)
|
|
361
|
+
return match.group(1) if match else None
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def has_new_backend_version(remote_version: str, local_version: str = VERSION) -> bool:
|
|
365
|
+
"""Compara solo major.minor: los parches pertenecen a la interfaz web."""
|
|
366
|
+
return parse_version(compatibility_version(remote_version)) > parse_version(compatibility_version(local_version))
|
|
367
|
+
|
|
368
|
+
|
|
358
369
|
def check_version():
|
|
359
|
-
"""
|
|
360
|
-
if get_dev_root() is not None
|
|
370
|
+
"""Informa de actualizaciones del backend, sin avisar por parches web."""
|
|
371
|
+
if get_dev_root() is not None:
|
|
361
372
|
return
|
|
362
373
|
try:
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
remote_ver =
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
except Exception:
|
|
372
|
-
pass
|
|
373
|
-
if not remote_ver:
|
|
374
|
-
match = re.search(r'["\']?version["\']?\s*[:=]\s*["\'](\d+\.\d+\.\d+)["\']', content)
|
|
375
|
-
if match:
|
|
376
|
-
remote_ver = match.group(1)
|
|
377
|
-
if remote_ver and re.match(r"^\d+(\.\d+)+", remote_ver):
|
|
378
|
-
if parse_version(remote_ver) > parse_version(VERSION):
|
|
379
|
-
console_log(f"[{time.strftime('%H:%M:%S')}] [zerochat] ¡Nueva versión disponible! (Local: {VERSION}, Remota: {remote_ver})", flush=True)
|
|
380
|
-
console_log(f"[{time.strftime('%H:%M:%S')}] [zerochat] Actualiza con: curl -sSL {REMOTE_SCRIPT_URL} -o zerochat.py", flush=True)
|
|
374
|
+
installed = is_installed_runtime()
|
|
375
|
+
remote_ver = _read_remote_version(PYPI_VERSION_URL if installed else REMOTE_VERSION_URL)
|
|
376
|
+
if remote_ver and re.match(r"^\d+(\.\d+)+", remote_ver) and has_new_backend_version(remote_ver):
|
|
377
|
+
console_log(f"[{time.strftime('%H:%M:%S')}] [zerochat] Nueva versión del servidor disponible (Local: {VERSION}, Remota: {compatibility_version(remote_ver)})", flush=True)
|
|
378
|
+
if installed:
|
|
379
|
+
console_log(f"[{time.strftime('%H:%M:%S')}] [zerochat] Actualiza cuando quieras con: {sys.executable} -m pip install --upgrade zerochat", flush=True)
|
|
380
|
+
else:
|
|
381
|
+
console_log(f"[{time.strftime('%H:%M:%S')}] [zerochat] Actualiza con: curl -sSL {REMOTE_SCRIPT_URL} -o zerochat.py", flush=True)
|
|
381
382
|
except Exception:
|
|
382
383
|
# Modo offline o timeout ignorado de forma segura
|
|
383
384
|
pass
|
|
@@ -784,11 +785,11 @@ class McpServiceManager:
|
|
|
784
785
|
else:
|
|
785
786
|
candidates = [
|
|
786
787
|
Path.cwd() / "services",
|
|
787
|
-
|
|
788
|
+
get_data_dir() / "services"
|
|
788
789
|
]
|
|
789
790
|
self.services_root = candidates[0] if get_dev_root() is not None and candidates[0].is_dir() else candidates[1]
|
|
790
791
|
self.services_root.mkdir(parents=True, exist_ok=True)
|
|
791
|
-
self.config_file =
|
|
792
|
+
self.config_file = get_data_dir() / "config" / "services.json"
|
|
792
793
|
self.config_file.parent.mkdir(parents=True, exist_ok=True)
|
|
793
794
|
self.clients: dict[str, StdioMcpClient] = {}
|
|
794
795
|
self.states: dict[str, str] = {}
|
|
@@ -1110,7 +1111,7 @@ for raw in sys.stdin:
|
|
|
1110
1111
|
|
|
1111
1112
|
return {
|
|
1112
1113
|
"serviceDir": str(service_dir),
|
|
1113
|
-
"pythonExecutable": sys.executable,
|
|
1114
|
+
"pythonExecutable": str(get_venv_python(get_venv_dir())) if get_venv_python(get_venv_dir()).is_file() else sys.executable,
|
|
1114
1115
|
"nodeExecutable": node
|
|
1115
1116
|
}
|
|
1116
1117
|
|
|
@@ -1862,7 +1863,7 @@ def main():
|
|
|
1862
1863
|
parser.add_argument("--ui-url", default=None, help="URL de la interfaz web a abrir (por defecto: interfaz local en desarrollo o GitHub Pages)")
|
|
1863
1864
|
parser.add_argument("--no-browser", action="store_true", help="No abrir automáticamente el navegador")
|
|
1864
1865
|
parser.add_argument("--no-exit-on-close", action="store_true", help="No detener el servidor automáticamente al cerrar el navegador")
|
|
1865
|
-
parser.add_argument("--no-venv", action="store_true", help="Omitir la comprobación/creación
|
|
1866
|
+
parser.add_argument("--no-venv", action="store_true", help="Omitir la comprobación/creación de ./zerochat/.venv")
|
|
1866
1867
|
parser.add_argument("--test", action="store_true", help="Ejecutar autocomprobación interna de herramientas")
|
|
1867
1868
|
parser.add_argument("--version", action="version", version=f"ZeroChat {VERSION}")
|
|
1868
1869
|
args = parser.parse_args()
|
|
@@ -1874,7 +1875,7 @@ def main():
|
|
|
1874
1875
|
print(f"[{time.strftime('%H:%M:%S')}] TEST all local tools ready.")
|
|
1875
1876
|
return
|
|
1876
1877
|
|
|
1877
|
-
# 1. Asegurar entorno
|
|
1878
|
+
# 1. Asegurar el entorno MCP aislado en ambos modos de distribución.
|
|
1878
1879
|
if not args.no_venv:
|
|
1879
1880
|
ensure_virtual_environment()
|
|
1880
1881
|
|
|
@@ -1911,7 +1912,8 @@ def main():
|
|
|
1911
1912
|
print("=" * 64)
|
|
1912
1913
|
print(f" ZeroChat Local Server v{VERSION} (UI {UI_VERSION})")
|
|
1913
1914
|
print(f" Directorio de trabajo : {Path.cwd()}")
|
|
1914
|
-
print(f"
|
|
1915
|
+
print(f" Datos y MCP : {get_data_dir()}")
|
|
1916
|
+
print(f" Entorno MCP : {get_venv_dir()}")
|
|
1915
1917
|
if is_dev:
|
|
1916
1918
|
print(f" Modo de ejecución : Desarrollo local ({dev_root})")
|
|
1917
1919
|
elif is_installed:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|