#!/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 --account [arguments...]" echo " muse -a [arguments...]" echo "" echo "Required:" echo " -a, --account Target NetVM account / node identity" echo "" echo "Available accounts:" for acct in "${VALID_ACCOUNTS[@]}"; do echo " • $acct" done echo "" echo "Common commands:" echo " chat [--thread ] Launch interactive conversational shell / REPL" echo " status Check agent status, sessions, and unread" echo " threads List active threads and sidechats" echo " history --thread View message history" echo " send --thread msg Send message to an agent" echo " unread View unread counts" 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 "" } ACCOUNT="" POSITIONAL=() 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. Please specify an account with -a or --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 '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 # 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