#!/usr/bin/env bash
# One-step ephemnet-agent installer for power users:
#
#   curl -fsSL https://eph.network/agent/install.sh | bash
#
# Fetches downloads/manifest.json (see scripts/release-agent.sh),
# picks this machine's own OS/arch, downloads that platform's tarball,
# verifies its SHA-256 against the manifest's own checksum (computed
# server-side from the real uploaded file, never trusted from the
# local build that produced it — see that script's own comment), and
# installs the binary. No self-update beyond that — this script is
# itself the update mechanism, meant to be re-run by hand whenever
# agentadminweb's own update-check banner (or just habit) says a newer
# version exists. See internal/agentupdate for that banner's own
# read-only check — this script is the only thing that ever actually
# fetches/replaces a binary, and only when a human runs it.
#
# Interactive, but safely so when piped (every question reads from
# /dev/tty specifically, never stdin — this script's own source
# already consumes stdin when run via `curl ... | bash` — and every
# question silently takes its default wherever no /dev/tty exists at
# all, e.g. CI):
#
#   - Where to install (prefilled with /usr/local/bin if writable,
#     else $HOME/.local/bin). Asked rather than silently decided: a
#     real deployment can already live somewhere else entirely (e.g.
#     /opt/ephemnet-agent, managed by deploy/deploy-agent.sh), and an
#     unasked-for second copy next to it is just confusing.
#   - Whether to start it on boot (default: no). If yes, writes a real
#     systemd unit (Linux, system-wide if run as root else
#     `systemctl --user`) or launchd agent (macOS) pointing at the
#     installed binary, then asks for a `-config <path>` (blank skips
#     this entirely — configure everything by hand instead). A given
#     path that doesn't exist yet gets a real default config.json
#     created there (-relay-addr pointed at the real production relay,
#     plus -status-addr so the local admin page is reachable to add
#     real domains/routes afterward) — without that, the unit/plist
#     would just crash-loop: this script has no way to know an
#     operator's own real -domain/-token/-local-addr secrets, but
#     ephemnet-agent itself refuses to even start with nothing
#     configured and no -status-addr to add anything later either. A
#     path that already points at a real config is used as-is, never
#     touched. Enabled+started immediately either way (once a config
#     exists); left unstarted only when the path was left blank.
#
# Overrides, all optional env vars:
#   EPHEMNET_AGENT_BASE_URL   default https://eph.network/agent — point
#                             at a dev site (e.g. https://dev4637.eph.network/agent)
#                             to install a build from there instead.
#   EPHEMNET_AGENT_VERSION    default: whatever manifest.json's own
#                             "latest" says — set to pin an exact
#                             version (e.g. v0.1.0) instead.
#   EPHEMNET_AGENT_INSTALL_DIR skips the prompt entirely — e.g. for a
#                             non-interactive/scripted install.
#
# Needs curl, tar, sha256sum (or shasum on macOS, which has no
# sha256sum by default), and either python3 or jq to read the JSON
# manifest — every one of these ships on a stock Linux/macOS install
# except jq, which is why python3 (present on both by default) is
# tried first.
set -euo pipefail

BASE_URL="${EPHEMNET_AGENT_BASE_URL:-https://eph.network/agent}"
PINNED_VERSION="${EPHEMNET_AGENT_VERSION:-}"

# The -status-addr this installer's own ensure_default_config writes,
# and the one offer_admin_shortcut below points a desktop shortcut at
# by default — one constant so the two can never drift apart.
DEFAULT_STATUS_ADDR="127.0.0.1:8093"

json_get() {
	# json_get <json-string> <python-expr-suffix-after-"data">
	# e.g. json_get "$manifest" '["latest"]'
	if command -v python3 >/dev/null 2>&1; then
		python3 -c "import json,sys; data=json.load(sys.stdin); print(data$2)" <<<"$1"
	elif command -v jq >/dev/null 2>&1; then
		# Only the two specific lookups this script actually needs are
		# supported here — this is not a general json_get, just enough
		# to avoid a hard python3 dependency when jq is what's on hand.
		case "$2" in
		'["latest"]') jq -r '.latest' <<<"$1" ;;
		*) echo "jq fallback does not support lookup: $2" >&2; exit 1 ;;
		esac
	else
		echo "ERROR: need python3 or jq to read the release manifest — install one and retry." >&2
		exit 1
	fi
}

manifest_lookup() {
	# manifest_lookup <manifest-json> <version> <platform> <field: path|sha256>
	python3 -c '
import json, sys
data, version, platform, field = json.loads(sys.argv[1]), sys.argv[2], sys.argv[3], sys.argv[4]
entry = next((v for v in data["versions"] if v["version"] == version), None)
if entry is None:
    sys.exit("version " + version + " not found in manifest")
if field == "path":
    print(entry["platforms"].get(platform, ""))
else:
    print(entry.get("sha256", {}).get(platform, ""))
' "$1" "$2" "$3" "$4"
}

# prompt_tty/prompt_yn read from /dev/tty specifically, never stdin —
# this script's own source already consumes stdin when run via
# `curl ... | bash`, so prompting against it would just read past
# whatever's left of the script and break. Wherever /dev/tty can't
# actually be opened (CI, a non-interactive invocation, any process
# with no controlling terminal at all — a permission-bit test like
# `[ -w /dev/tty ]` says nothing about this; the device node can be rw
# for everyone and opening it still fail with ENXIO), both silently
# take their default, same as every env-var override already does.
# `exec {fd}<>/dev/tty` is the actual open attempt, guarded so a
# failure never trips `set -e`.

# prompt_tty <question> <default> -> sets REPLY
prompt_tty() {
	REPLY="$2"
	local fd=0
	if { exec {fd}<>/dev/tty; } 2>/dev/null; then
		printf '%s [%s]: ' "$1" "$2" >&"$fd"
		local answer=""
		IFS= read -r answer <&"$fd" || answer=""
		exec {fd}>&-
		if [ -n "$answer" ]; then
			REPLY="$answer"
		fi
	fi
}

# prompt_yn <question> <default: y|n> -> sets REPLY_YN to 0 (yes) or 1 (no)
prompt_yn() {
	local shown fd=0
	if [ "$2" = "y" ]; then
		shown="Y/n"
		REPLY_YN=0
	else
		shown="y/N"
		REPLY_YN=1
	fi
	if { exec {fd}<>/dev/tty; } 2>/dev/null; then
		printf '%s [%s]: ' "$1" "$shown" >&"$fd"
		local answer=""
		IFS= read -r answer <&"$fd" || answer=""
		exec {fd}>&-
		case "$answer" in
		[Yy]*) REPLY_YN=0 ;;
		[Nn]*) REPLY_YN=1 ;;
		esac
	fi
}

os="$(uname -s)"
case "$os" in
Linux) os_name=linux ;;
Darwin) os_name=darwin ;;
*)
	echo "ERROR: unsupported OS '$os' — download manually from $BASE_URL/" >&2
	exit 1
	;;
esac

arch="$(uname -m)"
case "$arch" in
x86_64 | amd64) arch_name=amd64 ;;
aarch64 | arm64) arch_name=arm64 ;;
i386 | i686) arch_name=386 ;;
*)
	echo "ERROR: unsupported architecture '$arch' — download manually from $BASE_URL/" >&2
	exit 1
	;;
esac
platform="${os_name}-${arch_name}"

# Default install dir: /usr/local/bin if writable, else ~/.local/bin
# (created if missing) — same fallback EPHEMNET_AGENT_INSTALL_DIR
# itself overrides below. Computed before any network call so the
# prompt (and EPHEMNET_AGENT_INSTALL_DIR, if set) can short-circuit
# without wasting a fetch first.
if [ -w /usr/local/bin ]; then
	default_install_dir="/usr/local/bin"
else
	default_install_dir="$HOME/.local/bin"
fi

install_dir="${EPHEMNET_AGENT_INSTALL_DIR:-}"
if [ -z "$install_dir" ]; then
	# Ask, rather than silently picking the default — found the hard
	# way: a real existing deployment can live somewhere else entirely
	# (e.g. /opt/ephemnet-agent, managed by deploy/deploy-agent.sh),
	# and a silent ~/.local/bin install next to it is just a confusing,
	# unused extra copy nobody asked for.
	prompt_tty "Install directory" "$default_install_dir"
	install_dir="$REPLY"
fi

echo "==> Fetching ${BASE_URL}/downloads/manifest.json ..."
manifest="$(curl -fsSL "${BASE_URL}/downloads/manifest.json")"

version="$PINNED_VERSION"
if [ -z "$version" ]; then
	version="$(json_get "$manifest" '["latest"]')"
fi
echo "==> Installing ephemnet-agent ${version} for ${platform}..."

rel_path="$(manifest_lookup "$manifest" "$version" "$platform" path)"
if [ -z "$rel_path" ]; then
	echo "ERROR: no ${platform} build for version ${version} — see ${BASE_URL}/ for what's actually available." >&2
	exit 1
fi
expected_sha="$(manifest_lookup "$manifest" "$version" "$platform" sha256)"

tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
archive="$tmp/$(basename "$rel_path")"

echo "==> Downloading ${rel_path}..."
curl -fsSL "${BASE_URL}/downloads/${rel_path}" -o "$archive"

if [ -n "$expected_sha" ]; then
	echo "==> Verifying SHA-256..."
	if command -v sha256sum >/dev/null 2>&1; then
		actual_sha="$(sha256sum "$archive" | cut -d' ' -f1)"
	elif command -v shasum >/dev/null 2>&1; then
		actual_sha="$(shasum -a 256 "$archive" | cut -d' ' -f1)"
	else
		echo "ERROR: need sha256sum or shasum to verify the download — refusing to install unverified." >&2
		exit 1
	fi
	if [ "$actual_sha" != "$expected_sha" ]; then
		echo "ERROR: checksum mismatch — expected ${expected_sha}, got ${actual_sha}. Not installing." >&2
		exit 1
	fi
	echo "    OK (${actual_sha})"
else
	echo "WARNING: manifest has no checksum for this platform/version — installing unverified." >&2
fi

tar -xzf "$archive" -C "$tmp"

mkdir -p "$install_dir"
install -m 0755 "$tmp/ephemnet-agent" "$install_dir/ephemnet-agent"

echo "==> Installed ${version} to ${install_dir}/ephemnet-agent"
case ":$PATH:" in
*":$install_dir:"*) ;;
*) echo "    NOTE: ${install_dir} isn't on your PATH — add it, or run the binary by its full path." ;;
esac

# ensure_default_config creates a bare-minimum, real config.json at
# path (-relay-addr/-acme-api pointed at the real production relay,
# plus -status-addr so the admin UI is reachable to add real routes
# afterward) if nothing exists there yet — without -status-addr (or a
# -domain/-route), ephemnet-agent's own startup validation refuses to
# run at all ("this agent would serve nothing and have no way to add
# anything later"), so a freshly enabled boot-start service with no
# pre-existing config would otherwise just crash-loop forever instead
# of actually being usable. relay-addr is :443 (Caddy's own layer4 SNI
# route, A013), not :7000 directly — a real cert now, so no
# -insecure-skip-verify needed either. "#status-auth-token" is a
# documented-but-unset placeholder, not a real value — a "#"-prefixed
# key is agentconfig.Apply's own escape hatch for exactly this (plain
# JSON has no comment syntax, and that loader otherwise fails loud on
# any unrecognized key on purpose). Never touches a file that already
# exists — this is a bootstrap default, not a reset.
ensure_default_config() {
	local path="$1"
	if [ -f "$path" ]; then
		return
	fi
	mkdir -p "$(dirname "$path")"
	cat >"$path" <<CONFIGJSON
{
  "relay-addr": "mera.network:443",
  "status-addr": "${DEFAULT_STATUS_ADDR}",
  "acme-api": "https://api.mera.network",
  "#status-auth-token": "set this to require HTTP Basic Auth on the local admin page above once it's reachable beyond a single trusted operator — see that page's own API reference tab"
}
CONFIGJSON
	echo "    Created default config at $path (relay-addr=mera.network:443, status-addr=${DEFAULT_STATUS_ADDR}, acme-api=https://api.mera.network) — add real domains/routes via that local admin page (http://${DEFAULT_STATUS_ADDR}/) once it's running, or edit this file directly first."
}

# offer_admin_shortcut creates a real, clickable desktop shortcut to
# the local admin page (-status-addr) — found worth doing directly
# per user request: an operator who just wants to glance at connection
# status/routes shouldn't have to remember a port number or type a
# curl command first. Only offered when a config file is actually in
# play (config_path non-empty, same gate setup_systemd/setup_launchd
# already use to decide whether to enable+start the service itself) —
# with no config at all, there's no reason to believe -status-addr
# will even be set once the operator configures things by hand.
# Windows deliberately not covered yet (no boot-start/installer
# support there at all today — see setup_systemd/setup_launchd's own
# os_name case) — a .url Internet Shortcut is the natural equivalent
# whenever that lands.
offer_admin_shortcut() {
	local config_path="$1"
	if [ -z "$config_path" ]; then
		return 0
	fi
	prompt_tty "Admin page address for a desktop shortcut (blank to skip)" "$DEFAULT_STATUS_ADDR"
	local addr="$REPLY"
	if [ -z "$addr" ]; then
		return 0
	fi
	local url="http://${addr}/"
	case "$os_name" in
	linux) create_linux_shortcut "$url" ;;
	darwin) create_darwin_shortcut "$url" ;;
	esac
}

# create_linux_shortcut writes a .desktop launcher (freedesktop.org
# Desktop Entry spec) that just shells out to xdg-open — no GUI
# toolkit, no icon asset to ship, every desktop environment that
# implements the spec (GNOME, KDE, XFCE, ...) already knows how to
# render and launch this. xdg-open itself ships with essentially every
# desktop Linux distro (part of xdg-utils) but not a minimal/headless
# one — missing is a warning, not a hard failure, since the shortcut
# file itself is still harmless to have written.
create_linux_shortcut() {
	local url="$1"
	local apps_dir="$HOME/.local/share/applications"
	mkdir -p "$apps_dir"
	local desktop_path="$apps_dir/ephemnet-agent-admin.desktop"
	cat >"$desktop_path" <<DESKTOPENTRY
[Desktop Entry]
Type=Application
Name=EphemNet Agent Admin
Comment=Open the local ephemnet-agent admin page
Exec=xdg-open ${url}
Terminal=false
Categories=Network;
DESKTOPENTRY
	chmod +x "$desktop_path"
	echo "    Wrote $desktop_path — find \"EphemNet Agent Admin\" in your application launcher, or double-click the file."
	if ! command -v xdg-open >/dev/null 2>&1; then
		echo "    NOTE: xdg-open not found — install xdg-utils, or this shortcut won't open a browser when launched."
	fi
}

# create_darwin_shortcut builds the smallest possible real .app bundle
# — three files (Info.plist, a launcher script as CFBundleExecutable,
# no icon), placed in ~/Applications so Spotlight/Launchpad pick it up
# the same as any other installed app. The launcher script is just
# `open <url>`, which hands off to the user's own default browser —
# same mechanism a real double-click-to-open-URL app would use.
create_darwin_shortcut() {
	local url="$1"
	local app_dir="$HOME/Applications/EphemNet Agent Admin.app"
	local contents="$app_dir/Contents"
	mkdir -p "$contents/MacOS"
	cat >"$contents/Info.plist" <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleName</key>
	<string>EphemNet Agent Admin</string>
	<key>CFBundleIdentifier</key>
	<string>network.eph.ephemnet-agent-admin</string>
	<key>CFBundleExecutable</key>
	<string>open-admin</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
</dict>
</plist>
PLIST
	cat >"$contents/MacOS/open-admin" <<LAUNCHER
#!/bin/sh
open "${url}"
LAUNCHER
	chmod +x "$contents/MacOS/open-admin"
	echo "    Wrote $app_dir — find \"EphemNet Agent Admin\" in Launchpad/Spotlight, or double-click it."
}

# resolve_relative_to_install_dir rewrites a relative path (as typed at
# the config-file prompt) to be relative to install_dir specifically —
# never the directory this installer script itself happened to be
# invoked from, and never implicitly "wherever the systemd/launchd
# unit's own WorkingDirectory is" either, even though install_dir IS
# what that gets set to below: made explicit here, rather than relying
# on that coincidence, so ensure_default_config (which runs in THIS
# script's own process, with no WorkingDirectory of its own at all)
# and the unit it configures always agree on what the path means. Real
# bug found live: without this, a relative "config.json" answer
# created the file wherever the installer was run from, which can
# differ from install_dir — the unit then crash-loops looking for it
# in the one place it was never written.
resolve_relative_to_install_dir() {
	case "$1" in
	/* | "") printf '%s' "$1" ;;
	*) printf '%s' "$install_dir/$1" ;;
	esac
}

# compute_systemd_unit_vars sets UNIT_DIR/UNIT_CMD/WANTED_BY/USER_LINE
# for the current privilege level (root vs. not) — shared by
# setup_systemd and offer_restart_if_already_set_up below, so the two
# can never disagree about where the unit actually lives.
compute_systemd_unit_vars() {
	if [ "$(id -u)" -eq 0 ]; then
		UNIT_DIR="/etc/systemd/system"
		UNIT_CMD="systemctl"
		WANTED_BY="multi-user.target"
		USER_LINE="User=${SUDO_USER:-root}"
	else
		UNIT_DIR="$HOME/.config/systemd/user"
		UNIT_CMD="systemctl --user"
		WANTED_BY="default.target"
		USER_LINE=""
	fi
}

# setup_systemd/setup_launchd write a real, loadable unit either way,
# but only actually enable+start it when a -config file exists at the
# path given (creating one with ensure_default_config above if it
# doesn't yet) — leaving the -config flag off entirely (an empty
# answer to the prompt) is still how to opt out and configure
# everything by hand instead. Only ever reached on a genuinely fresh
# setup — see offer_restart_if_already_set_up below for what happens
# on a re-run against an install that already has one.
setup_systemd() {
	if ! command -v systemctl >/dev/null 2>&1; then
		echo "WARNING: systemctl not found — skipping boot-start setup; see deploy/deploy-agent.sh for a worked systemd example, or set one up by hand." >&2
		return
	fi
	prompt_tty "Config file for ephemnet-agent's own -config flag (blank to skip and configure everything by hand)" ""
	local config_path
	config_path="$(resolve_relative_to_install_dir "$REPLY")"
	local exec_start="$install_dir/ephemnet-agent"
	if [ -n "$config_path" ]; then
		ensure_default_config "$config_path"
		exec_start="$exec_start -config $config_path"
	fi

	compute_systemd_unit_vars
	local unit_dir="$UNIT_DIR" unit_cmd="$UNIT_CMD" wanted_by="$WANTED_BY" user_line="$USER_LINE"
	mkdir -p "$unit_dir"
	local unit_path="$unit_dir/ephemnet-agent.service"
	{
		echo "[Unit]"
		echo "Description=EphemNet reverse-tunnel agent"
		echo "After=network-online.target"
		echo "Wants=network-online.target"
		echo
		echo "[Service]"
		# Real bug found live: -config (or any other relative path
		# someone passes via ExecStart) resolves against systemd's own
		# default working directory (/), not wherever this binary and
		# its config actually live — a bare "-config config.json"
		# crash-loops forever (exit 2, "no such file") the instant a
		# relative path is given, which is the natural thing to type
		# when the config already lives next to the binary. Pinning
		# this to install_dir makes that just work, the same way
		# running the binary by hand from that same directory would.
		echo "WorkingDirectory=$install_dir"
		echo "ExecStart=$exec_start"
		echo "Restart=on-failure"
		echo "RestartSec=5"
		if [ -n "$user_line" ]; then
			echo "$user_line"
		fi
		echo
		echo "[Install]"
		echo "WantedBy=$wanted_by"
	} >"$unit_path"
	echo "==> Wrote $unit_path"

	$unit_cmd daemon-reload
	$unit_cmd enable ephemnet-agent.service
	if [ "$unit_cmd" = "systemctl --user" ]; then
		# A user service is otherwise killed the moment the last
		# session for this user ends (no active login left to hold the
		# user systemd instance up) — real bug found live: "enabled and
		# started" looked complete, but the tunnel actually dropped the
		# next time the operator's own SSH session closed. Attempted,
		# not just suggested: plain (no sudo) succeeds on systems where
		# polkit already permits self-linger; the sudo fallback covers
		# most others. Only silently falls back to the instruction
		# below if neither works non-interactively (sudo would prompt).
		if loginctl enable-linger "$(id -un)" 2>/dev/null || sudo -n loginctl enable-linger "$(id -un)" 2>/dev/null; then
			echo "    Enabled linger for $(id -un) — this service now survives logout/reboot with no active session needed."
		else
			echo "    NOTE: a user service needs 'sudo loginctl enable-linger $(id -un)' to start without an active login session — couldn't do this non-interactively (needs a password), run it yourself."
		fi
	fi
	if [ -n "$config_path" ]; then
		$unit_cmd start ephemnet-agent.service
		echo "    Enabled and started."
	else
		echo "    Enabled but not started — add real flags (or a -config file) to $unit_path, then run: $unit_cmd start ephemnet-agent.service"
	fi
	offer_admin_shortcut "$config_path"
}

setup_launchd() {
	prompt_tty "Config file for ephemnet-agent's own -config flag (blank to skip and configure everything by hand)" ""
	local config_path
	config_path="$(resolve_relative_to_install_dir "$REPLY")"
	local plist_dir="$HOME/Library/LaunchAgents"
	local plist_path="$plist_dir/network.eph.ephemnet-agent.plist"
	mkdir -p "$plist_dir"

	local extra_args=""
	if [ -n "$config_path" ]; then
		ensure_default_config "$config_path"
		extra_args="
		<string>-config</string>
		<string>${config_path}</string>"
	fi
	cat >"$plist_path" <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>network.eph.ephemnet-agent</string>
	<key>ProgramArguments</key>
	<array>
		<string>${install_dir}/ephemnet-agent</string>${extra_args}
	</array>
	<key>WorkingDirectory</key>
	<string>${install_dir}</string>
	<key>RunAtLoad</key>
	<true/>
	<key>KeepAlive</key>
	<true/>
</dict>
</plist>
PLIST
	echo "==> Wrote $plist_path"
	if [ -n "$config_path" ]; then
		launchctl load "$plist_path"
		echo "    Loaded."
	else
		echo "    Not loaded yet — add real flags (or a -config file) to $plist_path, then run: launchctl load $plist_path"
	fi
	offer_admin_shortcut "$config_path"
}

# offer_restart_if_already_set_up handles re-running this script
# against a host that already has a boot-start service from a
# previous run — real gap found live: install.sh only ever downloads
# and installs the binary, it never stops or restarts anything, so an
# already-running service just kept executing its old in-memory code
# after an "update" until someone remembered to restart it by hand.
# Sets SKIP_BOOT_START_PROMPT=1 when a service already exists (whether
# or not the operator chooses to restart it now) — the fresh-setup
# prompt below only ever makes sense when nothing is set up yet.
offer_restart_if_already_set_up() {
	local unit_path restart_cmd
	case "$os_name" in
	linux)
		# Bare `cmd || return` would exit the function carrying that
		# failed test's own nonzero status — fatal under this script's
		# own `set -e` the instant the condition is false, which is the
		# COMMON case here (no existing unit yet, a fresh install) —
		# same bug class already fixed once elsewhere in this file.
		# `return 0` always, explicitly: "nothing to do" is not a
		# failure.
		if ! command -v systemctl >/dev/null 2>&1; then
			return 0
		fi
		compute_systemd_unit_vars
		unit_path="$UNIT_DIR/ephemnet-agent.service"
		if [ ! -f "$unit_path" ]; then
			return 0
		fi
		restart_cmd="$UNIT_CMD restart ephemnet-agent.service"
		;;
	darwin)
		unit_path="$HOME/Library/LaunchAgents/network.eph.ephemnet-agent.plist"
		if [ ! -f "$unit_path" ]; then
			return 0
		fi
		restart_cmd="launchctl unload '$unit_path' && launchctl load '$unit_path'"
		;;
	*)
		return 0
		;;
	esac

	SKIP_BOOT_START_PROMPT=1
	prompt_yn "An ephemnet-agent service is already set up ($unit_path) — restart it now to use the just-installed $version" n
	if [ "$REPLY_YN" -ne 0 ]; then
		echo "    Not restarted — it'll keep running the previous version until you do: $restart_cmd"
		return 0
	fi
	if [ "$os_name" = "linux" ]; then
		$UNIT_CMD daemon-reload
		$UNIT_CMD restart ephemnet-agent.service
	else
		launchctl unload "$unit_path" 2>/dev/null
		launchctl load "$unit_path"
	fi
	echo "    Restarted."
}

echo
SKIP_BOOT_START_PROMPT=
offer_restart_if_already_set_up
if [ -z "$SKIP_BOOT_START_PROMPT" ]; then
	prompt_yn "Start ephemnet-agent automatically on boot?" n
	if [ "$REPLY_YN" -eq 0 ]; then
		case "$os_name" in
		linux) setup_systemd ;;
		darwin) setup_launchd ;;
		esac
	fi
fi

echo "Run 'ephemnet-agent -h' to get started. Re-run this script any time to update."
