Files
socialmag/install.sh
T
juxtapoandClaude Opus 5 01fae3ca74 v0.7: one-click install — pyproject, console scripts, user units, hermes wiring
A clone + ./install.sh + ./launch-brave.sh + sign in once. Nothing else.

pyproject.toml declares the one real dependency (websockets) and maps the
repo-root-is-the-package layout, which retires the PYTHONPATH=<parent> line
every unit used to carry.

cli.py backs three console scripts. They exist because `python3 -m socialmag`
run from INSIDE a clone dies at `import asyncio`: the repo root is the package
dir, so it ships selectors.py and queue.py, and python puts the current
directory first on sys.path. `cd socialmag` is the first thing anyone does
after a clone, so the documented workaround failed at exactly the moment it
would be tried. A generated bin/ script never puts cwd on sys.path.

The same trap bit `python3 -m venv` inside install.sh — the installer was
broken by the thing it exists to fix. Every python3 call now runs from /.

deploy/user/*.in replaces root system units with systemd --user templates:
no User=, WantedBy=default.target, venv paths, @REPO@/@VENV@/@CDP_ENDPOINT@
substituted at install time. deploy/home/ is untouched and still live here.

launch-brave.sh carries --disable-background-timer-throttling. That is
load-bearing, not tidiness: five of six platforms are read in a hidden tab, and
a throttled background tab stops running the timers those pages use to fetch
their own data — the reads come back empty with no error.

install.sh checks the mcp package in hermes's own interpreter and refuses to
continue without it. Hermes treats mcp as optional and silently no-ops the
whole subsystem when it is missing, so a server that never loaded looks exactly
like one that loaded and did nothing.

It will not merge into an existing mcp_servers: key — it backs up config.yaml
and appends only when the key is absent, otherwise it prints the block. Blind
YAML merging is how someone's other servers disappear.

Verified end-to-end in a sandbox with a fake HOME and stubbed systemctl:
real MCP initialize handshake from inside the repo dir returns all 7 tools;
hermes's own yaml parser re-reads the written config with every pre-existing
key intact; a second run leaves the mcp_servers key count at 1; launch-brave.sh
exits 1 against a busy port; no unsubstituted @PLACEHOLDER@ in any rendered unit.

Not fixed, pre-existing: server.py reports SERVER_VERSION 0.1.0 while the repo
is at v0.7. The handshake shows 0.1.0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-13 02:10:58 +08:00

165 lines
6.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# socialmag installer — clone, run this, sign in, done.
#
# What it does not do: log you in. socialmag holds no passwords, which is the
# whole design. The last step is yours and it only happens once.
set -euo pipefail
REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
VENV="${SOCIALMAG_VENV:-$REPO/.venv}"
CDP_ENDPOINT="${SOCIALMAG_CDP_ENDPOINT:-http://127.0.0.1:9336}"
UNIT_DIR="$HOME/.config/systemd/user"
HERMES_CONFIG="${HERMES_CONFIG:-$HOME/.hermes/config.yaml}"
say() { printf '\n\033[1;36m==>\033[0m %s\n' "$*"; }
ok() { printf ' \033[32mok\033[0m %s\n' "$*"; }
warn() { printf ' \033[33m!!\033[0m %s\n' "$*"; }
die() { printf '\n\033[31merror:\033[0m %s\n' "$*" >&2; exit 1; }
# ---------------------------------------------------------------- python
say "Python"
command -v python3 >/dev/null 2>&1 || die "python3 not found on PATH"
# Every python3 call below runs from / rather than from here. The repo root is
# the package dir, so it ships selectors.py and queue.py — names the stdlib also
# uses. Python puts the current directory first on sys.path, so `python3 -m venv`
# run from inside a fresh clone dies at `import subprocess` with
# "module 'selectors' has no attribute 'SelectSelector'". Running from / is the
# whole fix. (This is the same trap cli.py exists to keep off users.)
(cd / && python3 - <<'PY') || die "socialmag needs Python 3.10 or newer"
import sys
sys.exit(0 if sys.version_info >= (3, 10) else 1)
PY
ok "$(cd / && python3 -V)"
# ---------------------------------------------------------------- venv
say "Virtualenv + package"
if [[ ! -x "$VENV/bin/python" ]]; then
(cd / && python3 -m venv "$VENV") || die "could not create a venv at $VENV
Two things cause this. Read the traceback above to tell them apart:
- 'No module named venv' -> the venv module is not installed.
Debian/Ubuntu: sudo apt install python3-venv
- anything else -> report it; the installer already runs python
from / to keep this repo off sys.path."
ok "created $VENV"
else
ok "reusing $VENV"
fi
# Editable on purpose. socialmag resolves socialmag.db, state.json and
# dashboard.json relative to its own __file__; a non-editable install would put
# all three inside site-packages, where nothing else looks for them.
(cd / && "$VENV/bin/pip" install --quiet --upgrade pip) >/dev/null
(cd / && "$VENV/bin/pip" install --quiet -e "$REPO") || die "pip install failed"
ok "socialmag installed (editable), websockets pulled in"
for script in socialmag socialmag-refresh socialmag-openbridge; do
[[ -x "$VENV/bin/$script" ]] || die "console script $script was not generated — pyproject.toml [project.scripts] did not take"
done
ok "console scripts: socialmag, socialmag-refresh, socialmag-openbridge"
# ---------------------------------------------------------------- systemd
say "systemd user units"
if ! command -v systemctl >/dev/null 2>&1; then
warn "systemctl not found — skipping units"
warn "run the three processes by hand: socialmag, socialmag-openbridge, and 'python -m http.server 8321' in $REPO"
else
mkdir -p "$UNIT_DIR"
for src in "$REPO"/deploy/user/*.in; do
dest="$UNIT_DIR/$(basename "${src%.in}")"
sed -e "s|@REPO@|$REPO|g" \
-e "s|@VENV@|$VENV|g" \
-e "s|@CDP_ENDPOINT@|$CDP_ENDPOINT|g" \
"$src" > "$dest"
ok "$(basename "$dest")"
done
cp "$REPO/deploy/user/socialmag-refresh.timer" "$UNIT_DIR/socialmag-refresh.timer"
ok "socialmag-refresh.timer"
systemctl --user daemon-reload
systemctl --user enable --now socialmag-dash.service socialmag-openbridge.service >/dev/null
systemctl --user enable --now socialmag-refresh.timer >/dev/null
ok "enabled: dash (:8321), openbridge (:8322), refresh timer (30min)"
# These die at logout unless lingering is on. Say so rather than let someone
# discover it when the dashboard is empty tomorrow.
if ! loginctl show-user "$USER" -p Linger 2>/dev/null | grep -q 'Linger=yes'; then
warn "user services stop when you log out. To keep them running:"
warn " sudo loginctl enable-linger $USER"
fi
fi
# ---------------------------------------------------------------- hermes
say "Hermes MCP registration"
HERMES_PY="/usr/local/lib/hermes-agent/venv/bin/python"
if ! command -v hermes >/dev/null 2>&1; then
warn "hermes not on PATH — skipping. Register manually later:"
printf '\n mcp_servers:\n socialmag:\n command: "%s/bin/socialmag"\n args: []\n env:\n SOCIALMAG_CDP_ENDPOINT: "%s"\n\n' "$VENV" "$CDP_ENDPOINT"
elif [[ ! -f "$HERMES_CONFIG" ]]; then
die "hermes is installed but $HERMES_CONFIG does not exist.
Start hermes once so it writes a config, then re-run this installer."
else
# Hermes treats the mcp python package as optional: without it the entire MCP
# subsystem is a no-op that logs at debug level. A server that never loaded
# looks exactly like one that loaded and did nothing, so check it here rather
# than let that be discovered later.
if [[ -x "$HERMES_PY" ]]; then
if "$HERMES_PY" -c "import importlib.util,sys; sys.exit(0 if importlib.util.find_spec('mcp') else 1)"; then
ok "hermes has the mcp package"
else
die "hermes cannot load MCP servers: the 'mcp' package is missing from
$HERMES_PY
Without it hermes silently ignores every mcp_servers entry — no error, only a
debug log line. Install it into that interpreter, then re-run:
$HERMES_PY -m pip install mcp"
fi
else
warn "could not find hermes's interpreter at $HERMES_PY — cannot check for the mcp package"
warn "if socialmag's tools never appear in hermes, that is the first thing to check"
fi
if grep -qE '^\s*mcp_servers\s*:' "$HERMES_CONFIG"; then
warn "$HERMES_CONFIG already has an mcp_servers: key — not touching it."
warn "Merging YAML blind is how someone's other servers disappear. Add this by hand:"
printf '\n socialmag:\n command: "%s/bin/socialmag"\n args: []\n env:\n SOCIALMAG_CDP_ENDPOINT: "%s"\n\n' "$VENV" "$CDP_ENDPOINT"
else
backup="$HERMES_CONFIG.bak-pre-socialmag-$(date +%Y%m%d%H%M%S)"
cp "$HERMES_CONFIG" "$backup"
cat >> "$HERMES_CONFIG" <<EOF
mcp_servers:
socialmag:
command: "$VENV/bin/socialmag"
args: []
env:
SOCIALMAG_CDP_ENDPOINT: "$CDP_ENDPOINT"
EOF
ok "registered in $HERMES_CONFIG (backup: $(basename "$backup"))"
fi
fi
# ---------------------------------------------------------------- done
cat <<EOF
$(printf '\033[1;32mInstalled.\033[0m') Two things left, both yours:
1. Start the browser socialmag drives:
$REPO/launch-brave.sh
2. Sign in to your platforms in that window — Threads, Facebook, Instagram,
YouTube, TikTok, X. Once. socialmag stores no passwords; it uses the
session that now belongs to that browser profile.
Then:
dashboard http://127.0.0.1:8321/dashboard.html
check $VENV/bin/socialmag-refresh
logs journalctl --user -u socialmag-refresh -f
EOF