Files
hermes-agent/activate

104 lines
4.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# ============================================================================
# venv-style activation for the Hermes dev environment (pm-managed tools).
#
# source ./activate (bash / zsh, repo root)
# .\activate.ps1 (PowerShell)
#
# Emits the composed pm env (PATH + tool vars) into the CURRENT shell, with
# save/restore: `deactivate` undoes exactly what activation changed.
#
# Sync through setup before selecting the environment. PM owns freshness;
# activation does not maintain a second dependency stamp.
# ============================================================================
_HERMES_REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Setup runs in a child: failures must not exit or partially activate the
# caller's shell, and activation must not republish launchers or shell config.
if ! (
unset PYTHONHOME PYTHONPATH VIRTUAL_ENV
bash "$_HERMES_REPO/setup-hermes.sh" --runtime-only
) >&2; then
printf '%s\n' 'activate: setup failed; shell environment unchanged' >&2
return 1 2>/dev/null || exit 1
fi
# Guard against double-sourcing: venv activate precedent (re-activating is a
# no-op re-save; we keep it idempotent by deactivating first).
if [ -n "${__HERMES_ACTIVATED:-}" ]; then
deactivate
fi
# Bootstrap Python only emits the environment; it does not install anything.
_hermes_repo="$_HERMES_REPO"
_hermes_py=""
for _hermes_candidate in "$_hermes_repo/.venv/bin/python" "$_hermes_repo/.venv/Scripts/python.exe" \
"$_hermes_repo/venv/bin/python" "$_hermes_repo/venv/Scripts/python.exe"; do
[ -x "$_hermes_candidate" ] && { _hermes_py="$_hermes_candidate"; break; }
done
if [ -z "$_hermes_py" ]; then
for _hermes_store in "${HERMES_RUNTIME_DIR:-}" "$_hermes_repo/../tools" "${HERMES_HOME:-$HOME/.hermes}/tools"; do
[ -n "$_hermes_store" ] || continue
for _hermes_candidate in "$_hermes_store"/python-*/bin/python3 "$_hermes_store"/python-*/python.exe "$_hermes_store"/python-*/bin/python "$_hermes_store"/python-*/bin/python.exe; do
[ -x "$_hermes_candidate" ] && { _hermes_py="$_hermes_candidate"; break; }
done
[ -n "$_hermes_py" ] && break
done
fi
if [ -z "$_hermes_py" ]; then
echo "activate: no bootstrap Python found; run setup-hermes.sh" >&2
return 1 2>/dev/null || exit 1
fi
# --- emit export lines from `pm env` ---
_hermes_json="$(PYTHONHOME= PYTHONPATH="$_hermes_repo" "$_hermes_py" -m hermes_cli.runtime_paths)"
if [ -z "$_hermes_json" ] || [ "${_hermes_json#*{}" = "$_hermes_json" ]; then
echo "activate: could not read pm env (run ./setup-hermes.sh first)" >&2
unset _hermes_repo _hermes_os _hermes_arch _hermes_target _hermes_store _hermes_py _hermes_json
return 1 2>/dev/null || exit 1
fi
_hermes_keys="$(printf '%s' "$_hermes_json" | "$_hermes_py" -c 'import json,sys; print(" ".join(json.load(sys.stdin)))' \
| tr ' ' '\n' | grep -E '^[A-Za-z_][A-Za-z0-9_]*$' | tr '\n' ' ')"
[ -n "$_hermes_keys" ] || _hermes_keys="PATH"
# --- snapshot what we are about to change (deactivate restores this) ---
__HERMES_ACTIVATED=1
__HERMES_SAVED_PATH="$PATH"
for _hermes_k in $_hermes_keys; do
eval "__HERMES_SAVED_$_hermes_k=\"\${$_hermes_k+set}\""
eval "__HERMES_PRIOR_$_hermes_k=\${$_hermes_k-__HERMES_UNSET__}"
done
eval "$(printf '%s' "$_hermes_json" | "$_hermes_py" -c '
import json, sys, shlex, re
for k, v in json.load(sys.stdin).items():
# Windows carries names like ProgramFiles(ARM) that are not valid
# bash identifiers — skip them (they pass through untouched).
if not re.fullmatch(r"[A-Za-z_][A-Za-z0-9_]*", k):
continue
print("export %s=%s" % (k, shlex.quote(str(v))))')"
deactivate() {
export PATH="$__HERMES_SAVED_PATH"
for _hermes_k in $__HERMES_KEY_LIST; do
eval "_hermes_was=\"\$__HERMES_SAVED_$_hermes_k\""
eval "_hermes_old=\"\$__HERMES_PRIOR_$_hermes_k\""
if [ "$_hermes_was" != "set" ]; then
unset "$_hermes_k"
else
export "$_hermes_k=$_hermes_old"
fi
unset "__HERMES_SAVED_$_hermes_k" "__HERMES_PRIOR_$_hermes_k"
done
unset __HERMES_SAVED_PATH __HERMES_KEY_LIST __HERMES_ACTIVATED
unset -f deactivate
unset _hermes_k _hermes_was _hermes_old
}
# remember the key list for deactivate (kept out of the loop vars above)
__HERMES_KEY_LIST="$_hermes_keys"
unset _hermes_repo _hermes_os _hermes_arch _hermes_target _hermes_store \
_hermes_py _hermes_json _hermes_keys _hermes_k _hermes_entry _hermes_venvpy \
_hermes_winarch