26382a7ac6
CI / Clippy (push) Failing after 15m13s
CI / Test (ubuntu-latest) (push) Failing after 16m1s
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Build (no embeddings / no ORT) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Cookbook (Node) (push) Has been cancelled
CI / Pi Extension (Node) (push) Has been cancelled
CI / Rust SDK (lean-ctx-client) (push) Has been cancelled
CI / Embed SDK (lean-ctx-sdk) (push) Has been cancelled
CI / Python SDK (leanctx) (push) Has been cancelled
CI / Hermes Plugin (Python) (push) Has been cancelled
CI / SDK Conformance Matrix (push) Has been cancelled
CI / Coverage (push) Has been cancelled
CI / cargo-deny (push) Has been cancelled
CI / Adversarial Safety (push) Has been cancelled
CI / Benchmarks (push) Has been cancelled
CI / Output-Quality Gate (eval A/B) (push) Has been cancelled
CI / Documentation (push) Has been cancelled
CI / CI Green (push) Has been cancelled
JetBrains Plugin / Actionlint (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (rust) (push) Has been cancelled
JetBrains Plugin / Validation (push) Has been cancelled
JetBrains Plugin / Build (push) Has been cancelled
JetBrains Plugin / Test (push) Has been cancelled
Security Check / Security Scan (push) Has been cancelled
114 lines
3.5 KiB
Python
114 lines
3.5 KiB
Python
"""Zero-dependency discovery of the local lean-ctx proxy endpoint.
|
|
|
|
Mirrors the daemon's own resolution so ``compress()`` works out of the box once
|
|
``lean-ctx proxy enable`` has run, while every step stays overridable via the
|
|
same environment variables the CLI honours:
|
|
|
|
* URL — ``LEAN_CTX_PROXY_URL`` else ``http://127.0.0.1:<port>``
|
|
* Port — ``LEAN_CTX_PROXY_PORT`` → ``config.toml`` ``proxy_port`` → UID-derived
|
|
* Token — ``LEAN_CTX_PROXY_TOKEN`` → ``<data_dir>/session_token``
|
|
* Dirs — ``LEAN_CTX_DATA_DIR`` / XDG, matching the Rust ``data_dir`` rules
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from pathlib import Path
|
|
from typing import List, Optional
|
|
|
|
# Base port the daemon derives per-UID (see proxy_setup::uid_based_port).
|
|
_DEFAULT_PORT = 4444
|
|
|
|
|
|
def _candidate_dirs() -> List[Path]:
|
|
"""Ordered data/config directories the daemon may have written to."""
|
|
dirs: List[Path] = []
|
|
env = os.environ.get("LEAN_CTX_DATA_DIR", "").strip()
|
|
if env:
|
|
dirs.append(Path(env))
|
|
|
|
home = Path.home()
|
|
dirs.append(home / ".lean-ctx")
|
|
|
|
xdg_data = os.environ.get("XDG_DATA_HOME", "").strip()
|
|
dirs.append(Path(xdg_data) / "lean-ctx" if xdg_data else home / ".local" / "share" / "lean-ctx")
|
|
|
|
xdg_config = os.environ.get("XDG_CONFIG_HOME", "").strip()
|
|
dirs.append(Path(xdg_config) / "lean-ctx" if xdg_config else home / ".config" / "lean-ctx")
|
|
|
|
# De-duplicate while preserving order.
|
|
seen = set()
|
|
unique: List[Path] = []
|
|
for d in dirs:
|
|
if d not in seen:
|
|
seen.add(d)
|
|
unique.append(d)
|
|
return unique
|
|
|
|
|
|
def _uid_port() -> int:
|
|
"""Replicate proxy_setup::uid_based_port (UID 1000 → 4444, +offset, base for <1000)."""
|
|
getuid = getattr(os, "getuid", None)
|
|
if getuid is None: # Windows
|
|
return _DEFAULT_PORT
|
|
uid = getuid()
|
|
offset = (uid - 1000) % 1000 if uid >= 1000 else 0
|
|
return _DEFAULT_PORT + offset
|
|
|
|
|
|
def _config_port() -> Optional[int]:
|
|
"""Read a top-level ``proxy_port`` from the first config.toml found."""
|
|
for directory in _candidate_dirs():
|
|
try:
|
|
text = (directory / "config.toml").read_text(encoding="utf-8")
|
|
except OSError:
|
|
continue
|
|
for line in text.splitlines():
|
|
stripped = line.strip()
|
|
if not stripped.startswith("proxy_port"):
|
|
continue
|
|
try:
|
|
value = stripped.split("=", 1)[1].strip().strip("\"'")
|
|
return int(value)
|
|
except (IndexError, ValueError):
|
|
break
|
|
return None
|
|
|
|
|
|
def resolve_port() -> int:
|
|
env = os.environ.get("LEAN_CTX_PROXY_PORT", "").strip()
|
|
if env:
|
|
try:
|
|
return int(env)
|
|
except ValueError:
|
|
pass
|
|
cfg = _config_port()
|
|
if cfg is not None:
|
|
return cfg
|
|
return _uid_port()
|
|
|
|
|
|
def resolve_base_url(base_url: Optional[str] = None) -> str:
|
|
if base_url:
|
|
return base_url.rstrip("/")
|
|
env = os.environ.get("LEAN_CTX_PROXY_URL", "").strip()
|
|
if env:
|
|
return env.rstrip("/")
|
|
return f"http://127.0.0.1:{resolve_port()}"
|
|
|
|
|
|
def resolve_token(token: Optional[str] = None) -> Optional[str]:
|
|
if token:
|
|
return token
|
|
env = os.environ.get("LEAN_CTX_PROXY_TOKEN", "").strip()
|
|
if env:
|
|
return env
|
|
for directory in _candidate_dirs():
|
|
try:
|
|
value = (directory / "session_token").read_text(encoding="utf-8").strip()
|
|
except OSError:
|
|
continue
|
|
if value:
|
|
return value
|
|
return None
|