Stabilize Local Agent and workstation management v1.26.23

This commit is contained in:
A R R R Associates
2026-09-30 21:35:40 +05:30
parent 76e13aa379
commit 56098aaeb9
4 changed files with 71 additions and 12 deletions
@@ -252,14 +252,50 @@ class Supervisor:
pass
@staticmethod
def _validate_staged(staged: Path) -> None:
def _validate_staged(staged: Path, expected_version: str = "") -> None:
if not staged.exists() or not staged.is_dir():
raise RuntimeError(f"Staged update directory not found: {staged}")
if not (staged / "erp_local_agent" / "__init__.py").is_file():
package_dir = staged / "erp_local_agent"
init_path = package_dir / "__init__.py"
dashboard_path = package_dir / "dashboard.py"
main_path = package_dir / "main.py"
if not init_path.is_file():
raise RuntimeError("Staged update does not contain erp_local_agent/__init__.py.")
if not dashboard_path.is_file() or not main_path.is_file():
raise RuntimeError("Staged update is missing dashboard.py or main.py.")
if not (staged / "requirements.txt").is_file():
raise RuntimeError("Staged update does not contain requirements.txt.")
# Validate the candidate in-place BEFORE the working worker is stopped.
# This specifically protects the dashboard identity contract that caused
# older staged builds to fail on: from . import AGENT_NAME, __version__.
py = _python(console=True)
code = (
"import sys;"
f"sys.path.insert(0, {str(staged)!r});"
"import erp_local_agent;"
"assert getattr(erp_local_agent, 'AGENT_NAME', '') == 'ERP Local Agent', 'AGENT_NAME missing/invalid';"
"assert getattr(erp_local_agent, '__version__', ''), '__version__ missing';"
"from erp_local_agent import dashboard,main,commands,updater;"
"print(erp_local_agent.__version__)"
)
result = subprocess.run(
[str(py), "-c", code],
cwd=str(staged),
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
creationflags=_create_no_window(),
timeout=90,
)
if result.returncode != 0:
raise RuntimeError("Staged update preflight import validation failed:\n" + result.stdout[-4000:])
staged_version = (result.stdout or "").strip().splitlines()[-1].strip()
if expected_version and staged_version != expected_version:
raise RuntimeError(
f"Staged update version mismatch: requested={expected_version}, package={staged_version or 'missing'}."
)
@staticmethod
def _backup_runtime(version: str) -> Path:
backup = UPDATES_DIR / f"supervisor_backup_{time.strftime('%Y%m%d_%H%M%S')}_{version}"
@@ -345,7 +381,8 @@ class Supervisor:
raise RuntimeError("Dependency installation failed:\n" + result.stdout[-4000:])
code = (
"import erp_local_agent;"
"from erp_local_agent import accounting_store,commands,tally,updater;"
"assert getattr(erp_local_agent, 'AGENT_NAME', '') == 'ERP Local Agent', 'AGENT_NAME missing/invalid';"
"from erp_local_agent import accounting_store,commands,tally,updater,dashboard,main;"
"print(erp_local_agent.__version__)"
)
result = subprocess.run(
@@ -379,7 +416,7 @@ class Supervisor:
if not version or not staged_text:
raise RuntimeError("Supervisor update request is missing version/staged_dir.")
staged = Path(staged_text).resolve()
self._validate_staged(staged)
self._validate_staged(staged, expected_version=version)
_update_progress("preparing", 8, f"Preparing ERP Local Agent {version} update.", version=version)
_state("installing", f"Installing ERP Local Agent {version}.", target_version=version, progress_pct=8)