diff --git a/bridge.py b/bridge.py index c1fd237..ffa0056 100644 --- a/bridge.py +++ b/bridge.py @@ -380,11 +380,30 @@ def comment(state: dict, ledger_id: str, content: str, what: str, # ── Intake: Pulse posts -> ledger + kanban ─────────────────────────────────── +def kanban_cmd() -> list[str]: + """How to invoke hermes' kanban CLI, resolved fresh on every call. + + The shared checkout's venv is not stable: a release cutover can delete or + replace it mid-run (observed 2026-08-23 — every intake tick failed with + ENOENT on `/venv/bin/python`). The `~/.local/bin/hermes` shim is + repointed by the release recipe itself, so it is the durable entry point; + the checkout venv stays as a fallback for installs that have no shim. + """ + override = cfg("PULSE_BRIDGE_HERMES_PY", "") + if override: + return [override, "-m", "shiva_cli.main"] + shim = HOME / ".local/bin/hermes" + if os.access(shim, os.X_OK): + return [str(shim)] + return [f"{HERMES_DIR}/venv/bin/python", "-m", "shiva_cli.main"] + + def kanban(*args: str, timeout: int = 60) -> str: + cmd = kanban_cmd() + cwd = HERMES_DIR if os.path.isdir(HERMES_DIR) else str(HOME) out = subprocess.run( - [f"{HERMES_DIR}/venv/bin/python", "-m", "shiva_cli.main", - "kanban", *args], - capture_output=True, text=True, timeout=timeout, cwd=HERMES_DIR, + [*cmd, "kanban", *args], + capture_output=True, text=True, timeout=timeout, cwd=cwd, env={**os.environ, "HERMES_HOME": HERMES_HOME_DIR}) if out.returncode != 0: raise RuntimeError(f"kanban {args[0]} rc={out.returncode}: "