#!/usr/bin/env bash # box-relay.sh — Lightweight Box Relay Client for Fleet Agent Containers. # # Enables fleet agents (646, pip, muse, opm) to access muse-cli level tools, # spawn subagents, send sidechat DMs, and inspect threads over the secure # exec-constrained HTTPS relay endpoint. # # Supports Bearer Token (EXEC_TOKEN or ~/.exec-token) AND SSH signature auth. # Endpoint: https://exec.muse-dev.online/exec (or Tailscale https://100.123.153.75:8444/exec) set -euo pipefail EXEC_URL="${EXEC_URL:-https://exec.muse-dev.online/exec}" AGENT="${BOX_AGENT:-${AGENT_NAME:-}}" TOKEN="${EXEC_TOKEN:-}" if [ -z "$TOKEN" ] && [ -f "$HOME/.exec-token" ]; then TOKEN="$(cat "$HOME/.exec-token" | tr -d '[:space:]')" fi # Detect agent identity if not set if [ -z "$AGENT" ]; then if [ -f "$HOME/.agent-name" ]; then AGENT="$(cat "$HOME/.agent-name" | tr -d '[:space:]')" elif echo "$HOSTNAME" | grep -qi "646"; then AGENT="646" elif echo "$HOSTNAME" | grep -qi "pip"; then AGENT="pip" elif echo "$HOSTNAME" | grep -qi "muse"; then AGENT="muse" elif echo "$HOSTNAME" | grep -qi "opm"; then AGENT="opm" elif echo "$HOSTNAME" | grep -qi "dev"; then AGENT="dev" elif echo "$HOSTNAME" | grep -qi "def"; then AGENT="def" else AGENT="646" fi fi # Helper: POST to exec endpoint call_exec() { local op="$1" local args_json="$2" if [ -n "$TOKEN" ]; then # Bearer token auth local body body=$(python3 -c "import json, sys; print(json.dumps({'op': sys.argv[1], 'args': json.loads(sys.argv[2])}))" "$op" "$args_json") local res res=$(curl -sk -sS -X POST "$EXEC_URL" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) Box-Relay/1.0" \ --data "$body") echo "$res" | python3 -c " import json, sys try: d = json.load(sys.stdin) if 'stdout' in d: sys.stdout.write(d['stdout']) elif 'error' in d: sys.stderr.write('Error: ' + str(d['error']) + '\n') sys.exit(1) else: print(json.dumps(d, indent=2)) except Exception as e: print(sys.stdin.read()) " else # Signature auth fallback local key="${SSH_KEY:-$HOME/.ssh/id_frontdoor}" if [ ! -f "$key" ] && [ -f "$HOME/.ssh/id_ed25519" ]; then key="$HOME/.ssh/id_ed25519" fi local ident="operator-$AGENT" if [ "$AGENT" = "super" ]; then ident="super" fi local ts ts=$(date +%s) local nonce nonce=$(python3 -c "import secrets; print(secrets.token_hex(16))") local payload payload=$(python3 -c " import json, sys op, args_json, ts, nonce = sys.argv[1:5] args = json.loads(args_json) print(json.dumps({'op': op, 'args': args, 'ts': int(ts), 'nonce': nonce})) " "$op" "$args_json" "$ts" "$nonce") local sig sig=$(printf '%s' "$payload" | ssh-keygen -Y sign -f "$key" -n exec-constrained 2>/dev/null) local body body=$(python3 -c " import json, sys ident, payload, sig = sys.argv[1:4] print(json.dumps({'identity': ident, 'payload': payload, 'signature': sig})) " "$ident" "$payload" "$sig") local res res=$(curl -sk -sS -X POST "$EXEC_URL" \ -H "Content-Type: application/json" \ -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) Box-Relay/1.0" \ --data "$body") echo "$res" | python3 -c " import json, sys try: d = json.load(sys.stdin) if 'stdout' in d: sys.stdout.write(d['stdout']) elif 'error' in d: sys.stderr.write('Error: ' + str(d['error']) + '\n') sys.exit(1) else: print(json.dumps(d, indent=2)) except Exception as e: print(sys.stdin.read()) " fi } cmd="${1:-help}" shift || true case "$cmd" in subagent) sub="${1:-help}" shift || true case "$sub" in spawn) title="subagent" wait=0 while [ $# -gt 0 ]; do case "$1" in --title) title="$2"; shift 2 ;; --wait) wait="$2"; shift 2 ;; --agent) AGENT="$2"; shift 2 ;; *) break ;; esac done prompt="${1:?usage: box subagent spawn [--title