#!/usr/bin/env bash # Setup wizard for Actual Budget skill set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" CONFIG_DIR="${HOME}/.config/actual-budget" CONFIG_FILE="${CONFIG_DIR}/config" PASSWORD_FILE="${CONFIG_DIR}/password" echo "=== Actual Budget Skill Setup ===" echo "" # Create config directory mkdir -p "${CONFIG_DIR}" # Server URL read -rp "Actual Budget server URL [https://budget.prettyhefty.com]: " server_url server_url="${server_url:-https://budget.prettyhefty.com}" # Password read -rsp "Server password: " password echo "" if [[ -z "${password}" ]]; then echo "ERROR: Password is required" exit 1 fi # Save config cat > "${CONFIG_FILE}" < "${PASSWORD_FILE}" chmod 600 "${PASSWORD_FILE}" echo "" echo "Config saved to ${CONFIG_FILE}" echo "Password saved to ${PASSWORD_FILE}" # Install @actual-app/api locally echo "" echo "Installing @actual-app/api..." cd "${SCRIPT_DIR}" if [[ ! -f "${SCRIPT_DIR}/package.json" ]]; then npm init -y --silent > /dev/null 2>&1 fi npm install @actual-app/api --silent 2>&1 | tail -1 # List available budgets and let user pick echo "" echo "Connecting to server and listing budgets..." budgets_json=$(node "${SCRIPT_DIR}/actual-query.mjs" budgets 2>/dev/null) || { echo "ERROR: Failed to connect to server" echo "${budgets_json}" exit 1 } echo "" echo "Available budgets:" echo "${budgets_json}" | node -e " const data = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf-8')); if (Array.isArray(data)) { data.forEach((b, i) => console.log(' ' + (i+1) + ') ' + (b.name || b.groupId || b.id || 'unnamed') + ' [groupId: ' + (b.groupId || b.id || 'unknown') + ']')); } else { console.log(' (unexpected format)'); console.log(JSON.stringify(data, null, 2)); } " echo "" read -rp "Enter budget sync ID (or number from list above): " sync_id # If user entered a number, resolve it if [[ "${sync_id}" =~ ^[0-9]+$ ]]; then sync_id=$(echo "${budgets_json}" | node -e " const data = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf-8')); const idx = ${sync_id} - 1; if (data[idx]) console.log(data[idx].groupId || data[idx].id || ''); else console.log(''); ") fi if [[ -z "${sync_id}" ]]; then echo "ERROR: Sync ID is required" exit 1 fi # Append sync ID to config echo "ACTUAL_SYNC_ID=\"${sync_id}\"" >> "${CONFIG_FILE}" echo "" echo "Testing connection..." test_result=$(node "${SCRIPT_DIR}/actual-query.mjs" accounts 2>/dev/null) || { echo "ERROR: Failed to load budget" echo "${test_result}" exit 1 } account_count=$(echo "${test_result}" | node -e " const data = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf-8')); console.log(Array.isArray(data) ? data.length : 0); ") echo "Success! Found ${account_count} account(s)." echo "" echo "Setup complete. Source the helper to get started:" echo " source ${SCRIPT_DIR}/actual-helper.sh" echo " actual_accounts"