#!/usr/bin/env bash # NetVM native interactive muse CLI wrapper # Enforces account/node selection, verifies/refreshes authentication cookies, # and executes commands in the dedicated network namespace. set -euo pipefail SCRIPT_SRC="${BASH_SOURCE[0]}" while [ -h "$SCRIPT_SRC" ]; do DIR="$(cd -P "$(dirname "$SCRIPT_SRC")" && pwd)" SCRIPT_SRC="$(readlink "$SCRIPT_SRC")" [[ $SCRIPT_SRC != /* ]] && SCRIPT_SRC="$DIR/$SCRIPT_SRC" done NETVM_BIN="$(cd -P "$(dirname "$SCRIPT_SRC")" && pwd)" VALID_ACCOUNTS=("muse" "pip" "646" "opm" "def" "dev") show_usage() { echo "Usage: muse [arguments...]" echo " muse -a [arguments...]" echo " muse [arguments...]" echo "" echo "Available accounts:" for acct in "${VALID_ACCOUNTS[@]}"; do echo " • $acct" done echo "" echo "Global lookups & tools:" echo " tui Interactive full-screen Muse TUI & Box fleet console" echo " tmux [args...] Manage shared Muse tmux sessions (new, send, capture, ls, kill, prune)" echo " status Fleet overview & node vitality" echo " threads List registered threads and sidechats across fleet" echo " unread View unread counts across all agents" echo " lookup [subcommand] Unified lookup (fleet, threads, unread, approvals, key)" echo " passkey (or key) View passkey location (VM-only), PIN, & agent approval protocol" echo "" echo "Per-account commands:" echo " tui Launch interactive TUI for this account" echo " chat [--thread ] Launch interactive conversational shell / REPL" echo " status Check account status, sessions, and unread" echo " threads List active threads and sidechats for account" echo " history --thread View message history" echo " send --thread msg Send message to an agent" echo " unread View unread counts for account" echo "" echo "Authentication & Cookie Management:" echo " Cookies are isolated per-node in ~/.config/muse-cli//" echo " If expired, the CLI attempts automated CDP cookie extraction." echo "" } # Direct top-level global actions that do not require an account if [[ $# -gt 0 ]]; then case "$1" in tui) shift exec python3 "$NETVM_BIN/muse-tui.py" --mode muse "$@" ;; tmux) shift exec python3 "$NETVM_BIN/muse-tmux.py" "$@" ;; passkey|key) shift exec python3 "$NETVM_BIN/super-cli.py" passkey "$@" ;; lookup|lookups) shift exec python3 "$NETVM_BIN/super-cli.py" lookup "$@" ;; fleet) shift exec python3 "$NETVM_BIN/super-cli.py" fleet "$@" ;; threads) shift exec python3 "$NETVM_BIN/super-cli.py" thread list "$@" ;; unread) shift exec python3 "$NETVM_BIN/super-cli.py" lookup unread "$@" ;; status) shift exec python3 "$NETVM_BIN/super-cli.py" fleet status "$@" ;; esac fi ACCOUNT="" POSITIONAL=() # If first argument does not start with '-', treat it as the account candidate if [[ $# -gt 0 && "$1" != -* ]]; then ACCOUNT="$1" shift fi while [[ $# -gt 0 ]]; do case "$1" in -a|--account) if [[ -z "${2:-}" ]]; then echo "Error: --account requires an argument." >&2 exit 1 fi ACCOUNT="$2" shift 2 ;; --account=*) ACCOUNT="${1#*=}" shift ;; -h|--help) if [[ -z "$ACCOUNT" && ${#POSITIONAL[@]} -eq 0 ]]; then show_usage exit 0 fi POSITIONAL+=("$1") shift ;; *) POSITIONAL+=("$1") shift ;; esac done if [[ -z "$ACCOUNT" ]]; then echo "Error: No account specified. Specify account as first argument or with -a/--account." >&2 echo "" show_usage exit 1 fi VALID=0 for acct in "${VALID_ACCOUNTS[@]}"; do if [[ "$ACCOUNT" == "$acct" ]]; then VALID=1 break fi done if [[ $VALID -eq 0 ]]; then echo "Error: Invalid account '$ACCOUNT'." >&2 echo "" show_usage exit 1 fi if [[ ${#POSITIONAL[@]} -eq 0 ]]; then POSITIONAL=("status") fi # If subcommand is 'tui', launch interactive Muse TUI if [[ "${POSITIONAL[0]}" == "tui" ]]; then shift_args=("${POSITIONAL[@]:1}") exec python3 "$NETVM_BIN/muse-tui.py" --mode muse --account "$ACCOUNT" "${shift_args[@]}" fi # If subcommand is 'chat', launch interactive chat REPL if [[ "${POSITIONAL[0]}" == "chat" ]]; then shift_args=("${POSITIONAL[@]:1}") exec python3 "$NETVM_BIN/muse-chat-repl.py" "$ACCOUNT" "${shift_args[@]}" fi # If subcommand is 'tmux', dispatch to shared muse-tmux manager if [[ "${POSITIONAL[0]}" == "tmux" ]]; then shift_args=("${POSITIONAL[@]:1}") exec python3 "$NETVM_BIN/muse-tmux.py" "${shift_args[@]}" fi # Execute command; if auth fails and auto-cdp fails, offer interactive OTP sign-in if running interactively set +e "$NETVM_BIN/muse-cli-node" "$ACCOUNT" "${POSITIONAL[@]}" RC=$? set -e if [[ $RC -ne 0 && -t 0 ]]; then # Check if failure is authentication related echo "" echo "Notice: muse-cli command failed with exit code $RC." echo "Would you like to initiate an interactive login for account '$ACCOUNT'? [y/N] " read -r response if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then # Determine email for account if available EMAIL=$(grep -E "^\|[[:space:]]*$ACCOUNT[[:space:]]*\|" "$NETVM_BIN/../ACCOUNTS.md" | awk -F '|' '{print $7}' | tr -d ' ' || true) if [[ -z "$EMAIL" || "$EMAIL" == "-" ]]; then echo -n "Enter email for account '$ACCOUNT': " read -r EMAIL fi echo "Starting sign-in for $EMAIL..." set +e "$NETVM_BIN/muse-signin.py" --email "$EMAIL" SIGNIN_RC=$? set -e if [[ $SIGNIN_RC -eq 2 ]]; then echo -n "Enter the OTP code received: " read -r OTP_CODE "$NETVM_BIN/muse-signin.py" --email "$EMAIL" --otp "$OTP_CODE" echo "Extracting cookies for $ACCOUNT..." "$NETVM_BIN/refresh-node-cookies.py" "$ACCOUNT" echo "Retrying command..." exec "$NETVM_BIN/muse-cli-node" "$ACCOUNT" "${POSITIONAL[@]}" fi fi fi exit $RC