refactor(tui_gateway): W4 wave2 pass 19 — readiness scope inlined, secret mirroring unified
This commit is contained in:
@@ -39,8 +39,8 @@ def _(rid, params: dict) -> dict:
|
|||||||
policy = _repo_discovery_policy()
|
policy = _repo_discovery_policy()
|
||||||
with pdb.connect_closing() as conn:
|
with pdb.connect_closing() as conn:
|
||||||
_reconcile_repo_discovery(pdb, conn, policy, _repo_discovery_policy_key(policy))
|
_reconcile_repo_discovery(pdb, conn, policy, _repo_discovery_policy_key(policy))
|
||||||
# `scan=true` (remote-gateway desktop): its native scan only sees its own
|
# `scan=true` (remote-gateway desktop): its native scan only sees its own filesystem,
|
||||||
# filesystem, so the host scans the policy roots so zero-session repos surface.
|
# so the host scans the policy roots so zero-session repos surface.
|
||||||
if params.get("scan") and policy["enabled"]:
|
if params.get("scan") and policy["enabled"]:
|
||||||
_scan_discovered_repos_remote(conn, policy)
|
_scan_discovered_repos_remote(conn, policy)
|
||||||
repos = _discover_repos_payload(db, conn=conn, include_cached=policy["enabled"])
|
repos = _discover_repos_payload(db, conn=conn, include_cached=policy["enabled"])
|
||||||
@@ -83,9 +83,9 @@ def _stamped_project_tree(db, params, **kwargs):
|
|||||||
|
|
||||||
@_projects_handler("projects.tree")
|
@_projects_handler("projects.tree")
|
||||||
def _(rid, params: dict) -> dict:
|
def _(rid, params: dict) -> dict:
|
||||||
"""Project -> repo -> lane overview with counts + a few preview sessions per project, plus
|
"""Project -> repo -> lane overview with counts + a few preview sessions per project, plus the
|
||||||
the flat set of session ids claimed by any project (excluded from flat Recents). Lanes carry
|
flat set of session ids claimed by any project (excluded from flat Recents). Lanes carry no
|
||||||
no session rows here; drill-in uses ``projects.project_sessions``."""
|
session rows; drill-in uses ``projects.project_sessions``."""
|
||||||
with _profile_db(params) as db:
|
with _profile_db(params) as db:
|
||||||
if db is None:
|
if db is None:
|
||||||
return _ok(rid, {"projects": [], "active_id": None, "scoped_session_ids": []})
|
return _ok(rid, {"projects": [], "active_id": None, "scoped_session_ids": []})
|
||||||
@@ -241,32 +241,23 @@ def _(rid, params: dict) -> dict:
|
|||||||
|
|
||||||
# ── setup readiness
|
# ── setup readiness
|
||||||
|
|
||||||
def _readiness_profile_scope(params: dict):
|
def _readiness_check(rid, params, probe):
|
||||||
"""``(profile, scope)`` for the readiness RPCs' optional ``profile``: ``scope`` binds that
|
"""Shared shell of setup.status / setup.runtime_check. ``probe(profile, scoped)`` runs inside the
|
||||||
profile's HERMES_HOME + ``.env`` secret scope (ContextVars: concurrent checks stay isolated);
|
optional ``profile`` param's HERMES_HOME + ``.env`` secret scope (ContextVars: concurrent checks
|
||||||
no param -> ``("", nullcontext())``. Unknown profile raises ``FileNotFoundError`` — never
|
stay isolated); ``scoped`` is the ``{"profile": ...}`` payload stamp (``{}`` for the launch
|
||||||
quietly answer for the launch profile instead."""
|
profile). An unknown profile answers ``ok=False`` (never a JSON-RPC error, never a quiet answer
|
||||||
|
for the launch profile instead)."""
|
||||||
import contextlib
|
import contextlib
|
||||||
profile = str(params.get("profile") or "").strip() if isinstance(params, dict) else ""
|
profile = str(params.get("profile") or "").strip() if isinstance(params, dict) else ""
|
||||||
if not profile:
|
scope = contextlib.nullcontext()
|
||||||
return "", contextlib.nullcontext()
|
if profile:
|
||||||
from hermes_cli import profiles as profiles_mod
|
from hermes_cli import profiles as profiles_mod
|
||||||
if not profiles_mod.profile_exists(profile):
|
if not profiles_mod.profile_exists(profile):
|
||||||
raise FileNotFoundError(f"Profile '{profile}' does not exist on this backend.")
|
return _ok(rid, {"ok": False, "profile": params.get("profile"),
|
||||||
home = _profile_home(profile)
|
"error": f"Profile '{profile}' does not exist on this backend."})
|
||||||
if home is None:
|
home = _profile_home(profile)
|
||||||
return profile, contextlib.nullcontext()
|
if home is not None:
|
||||||
return profile, _session_profile_runtime_scope({"profile_home": str(home)})
|
scope = _session_profile_runtime_scope({"profile_home": str(home)})
|
||||||
|
|
||||||
|
|
||||||
def _readiness_check(rid, params, probe):
|
|
||||||
"""Shared shell of setup.status / setup.runtime_check: ``probe(profile, scoped)`` runs inside
|
|
||||||
the profile scope (``scoped`` = the ``{"profile": ...}`` payload stamp, ``{}`` for the launch
|
|
||||||
profile); an unknown profile answers ``ok=False`` (never a JSON-RPC error)."""
|
|
||||||
try:
|
|
||||||
profile, scope = _readiness_profile_scope(params)
|
|
||||||
except FileNotFoundError as e:
|
|
||||||
return _ok(rid, {"ok": False, "profile": params.get("profile"), "error": str(e)})
|
|
||||||
with scope:
|
with scope:
|
||||||
payload = probe(profile, {"profile": profile} if profile else {})
|
payload = probe(profile, {"profile": profile} if profile else {})
|
||||||
return _ok(rid, payload)
|
return _ok(rid, payload)
|
||||||
|
|||||||
@@ -232,9 +232,10 @@ def _(rid, params: dict) -> dict:
|
|||||||
return _ok(rid, {"profiles": out, "bot_mode_protocol": True})
|
return _ok(rid, {"profiles": out, "bot_mode_protocol": True})
|
||||||
|
|
||||||
|
|
||||||
def _copy_secret_file(src, dst, wanted: bool) -> bool:
|
def _mirror_secret(path, launch_home, name: str, wanted) -> bool:
|
||||||
"""Copy ``src`` -> ``dst`` (0600) when ``src`` exists and ``wanted``; True if copied."""
|
"""Copy the launch ``name`` file into the profile (0600) when it exists and ``wanted(src, dst)``."""
|
||||||
if not (src.is_file() and wanted):
|
src, dst = launch_home / name, path / name
|
||||||
|
if not (src.is_file() and wanted(src, dst)):
|
||||||
return False
|
return False
|
||||||
import shutil
|
import shutil
|
||||||
shutil.copy2(src, dst)
|
shutil.copy2(src, dst)
|
||||||
@@ -243,25 +244,9 @@ def _copy_secret_file(src, dst, wanted: bool) -> bool:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _mirror_env(path, launch_home) -> bool:
|
def _env_has_content(env_path) -> bool:
|
||||||
"""Copy the launch .env only over the seeded comment-only stub (never a clone's secrets)."""
|
lines = env_path.read_text(encoding="utf-8", errors="replace").splitlines()
|
||||||
def has_content(env_path) -> bool:
|
return any(s and not s.startswith("#") for s in map(str.strip, lines))
|
||||||
lines = env_path.read_text(encoding="utf-8", errors="replace").splitlines()
|
|
||||||
return any(s and not s.startswith("#") for s in map(str.strip, lines))
|
|
||||||
src, dst = launch_home / ".env", path / ".env"
|
|
||||||
return _copy_secret_file(src, dst, has_content(src) and not _try(lambda: has_content(dst), False))
|
|
||||||
|
|
||||||
|
|
||||||
def _mirror_auth(path, launch_home) -> bool:
|
|
||||||
"""Copy the launch auth.json when absent (skipped under ``share_auth``: a copy forks token
|
|
||||||
state and the first refresh in either store strands the other)."""
|
|
||||||
src, dst = launch_home / "auth.json", path / "auth.json"
|
|
||||||
if not _copy_secret_file(src, dst, not dst.exists()):
|
|
||||||
return False
|
|
||||||
# Drop single-use OAuth grants (first refresh strands every sibling); they read from
|
|
||||||
# the root grant via the pool fallback. API keys stay.
|
|
||||||
_best_effort(lambda: _lazy("hermes_cli.auth", "strip_cloned_single_use_oauth_grants")(path))
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def _mirror_voice_sections(path) -> bool:
|
def _mirror_voice_sections(path) -> bool:
|
||||||
@@ -309,9 +294,16 @@ def _mirror_launch_credentials(path, params: dict) -> dict:
|
|||||||
if not is_truthy_value(params.get("mirror_credentials", True)):
|
if not is_truthy_value(params.get("mirror_credentials", True)):
|
||||||
return mirrored
|
return mirrored
|
||||||
launch_home = get_hermes_home()
|
launch_home = get_hermes_home()
|
||||||
mirrored["env"] = _try(lambda: _mirror_env(path, launch_home), False)
|
# .env: only over the seeded comment-only stub (never a clone's secrets).
|
||||||
if not share_auth:
|
mirrored["env"] = _try(lambda: _mirror_secret(path, launch_home, ".env", lambda src, dst: (
|
||||||
mirrored["auth"] = _try(lambda: _mirror_auth(path, launch_home), False)
|
_env_has_content(src) and not _try(lambda: _env_has_content(dst), False))), False)
|
||||||
|
if not share_auth: # a copy forks token state: the first refresh in either store strands the other
|
||||||
|
mirrored["auth"] = _try(lambda: _mirror_secret(path, launch_home, "auth.json",
|
||||||
|
lambda src, dst: not dst.exists()), False)
|
||||||
|
if mirrored["auth"]:
|
||||||
|
# Drop single-use OAuth grants (first refresh strands every sibling); they read from the
|
||||||
|
# root grant via the pool fallback. API keys stay.
|
||||||
|
_best_effort(lambda: _lazy("hermes_cli.auth", "strip_cloned_single_use_oauth_grants")(path))
|
||||||
mirrored["voice"] = _mirror_voice_sections(path)
|
mirrored["voice"] = _mirror_voice_sections(path)
|
||||||
return mirrored
|
return mirrored
|
||||||
|
|
||||||
@@ -465,9 +457,9 @@ def _configure_model(profile_dir, params, applied):
|
|||||||
"""Apply a ``model`` + ``provider`` pin, or return a confirm message and write NOTHING (client
|
"""Apply a ``model`` + ``provider`` pin, or return a confirm message and write NOTHING (client
|
||||||
resends with ``confirm_expensive_model``). A failing guard = no warning (as _apply_model_switch)."""
|
resends with ``confirm_expensive_model``). A failing guard = no warning (as _apply_model_switch)."""
|
||||||
model, provider = _model_provider_params(params)
|
model, provider = _model_provider_params(params)
|
||||||
confirm_message = None
|
|
||||||
if not (model and provider):
|
if not (model and provider):
|
||||||
return None
|
return None
|
||||||
|
confirm_message = None
|
||||||
if not is_truthy_value(params.get("confirm_expensive_model", False)):
|
if not is_truthy_value(params.get("confirm_expensive_model", False)):
|
||||||
warn = _lazy("hermes_cli.model_selection_guards", "combined_selection_warning")
|
warn = _lazy("hermes_cli.model_selection_guards", "combined_selection_warning")
|
||||||
confirm_message = _try(lambda: getattr(warn(model, provider=provider or None), "message", None), None)
|
confirm_message = _try(lambda: getattr(warn(model, provider=provider or None), "message", None), None)
|
||||||
|
|||||||
Reference in New Issue
Block a user