#!/bin/bash # # Purpose : Set up the things MiniServer installs that need your input: # mounting your Nextcloud files and signing in to the AI agents. # # Each file in configure.d/ is one item. It sets TITLE and DESCRIPTION and # defines is_configured and run_configure. It can also define is_installed; # the item is left out when that fails. To add an item, add a file there. # Wrapped in { ...; exit; } so bash reads the whole script up front; update # replaces this file while it runs. { MINISERVER="$HOME/.local/share/MiniServer" PATH="$HOME/.local/bin:$PATH" # Run an agent's real command rather than its sandboxed one in sandbox/bin: # setting an agent up writes outside its sandbox unsandboxed() { "$MINISERVER/sandbox/bin/unsandboxed" "$@" } # Ask a yes/no question; the default is no confirm() { local answer read -rp "$1 [y/N] " answer [[ "$answer" == [yY]* ]] } # Ask a yes/no question; the default is yes confirm_yes() { local answer read -rp "$1 [Y/n] " answer [[ "$answer" != [nN]* ]] } usage() { cat << EOF Usage: configure [item] configure Show what's set up and choose what to set up configure Set up one item configure --list Show what's set up, and the item names EOF } # configure.d/30-claude.sh -> claude item_name() { local name name="$(basename "$1" .sh)" echo "${name#[0-9][0-9]-}" } # Prints "||<description>"; state is done, todo or absent item_info() { ( source "$1" if declare -f is_installed > /dev/null && ! is_installed &> /dev/null; then echo "absent||" elif is_configured &> /dev/null; then echo "done|$TITLE|$DESCRIPTION" else echo "todo|$TITLE|$DESCRIPTION" fi ) } configure_item() { ( source "$1" echo echo -e "\e[1m$TITLE\e[0m" run_configure ) local status=$? if [ $status -ne 0 ]; then echo -e "\e[31m$(item_name "$1") was not set up.\e[0m" fi return $status } # Fill ITEMS, STATES, TITLES and DESCRIPTIONS with the installed items load_items() { local file state title description ITEMS=() STATES=() TITLES=() DESCRIPTIONS=() for file in "$MINISERVER"/configure.d/*.sh; do [ -f "$file" ] || continue IFS='|' read -r state title description < <(item_info "$file") [ "$state" = absent ] && continue ITEMS+=("$file") STATES+=("$state") TITLES+=("$title") DESCRIPTIONS+=("$description") done } show_items() { local i mark for i in "${!ITEMS[@]}"; do if [ "${STATES[$i]}" = done ]; then mark="\e[32mdone\e[0m " else mark="\e[33mto do\e[0m" fi printf " %2d) $mark %-22s %s\n" $((i + 1)) "${TITLES[$i]}" "${DESCRIPTIONS[$i]}" done } case "$1" in "") ;; -h|--help) usage exit 0 ;; -l|--list) load_items for i in "${!ITEMS[@]}"; do printf '%-6s %-14s %s\n' "${STATES[$i]/todo/to do}" "$(item_name "${ITEMS[$i]}")" "${TITLES[$i]}" done exit 0 ;; *) for file in "$MINISERVER"/configure.d/*.sh; do if [ "$(item_name "$file")" = "$1" ]; then configure_item "$file" exit fi done echo "No item named $1. These are: configure --list" exit 2 ;; esac while true; do load_items echo echo "MiniServer configuration" echo show_items echo echo " a) Set up everything still to do" echo " q) Quit" echo read -rp "Choose: " choice || exit 0 case "$choice" in q|Q|"") exit 0 ;; a|A) for i in "${!ITEMS[@]}"; do [ "${STATES[$i]}" = todo ] && configure_item "${ITEMS[$i]}" done ;; *) if [[ "$choice" =~ ^[0-9]+$ ]] && (( choice >= 1 && choice <= ${#ITEMS[@]} )); then configure_item "${ITEMS[$((choice - 1))]}" else echo "Choose a number from the list, a or q." fi ;; esac done }