-
-
Save khadorkin/e76521452f8a9a5b43ecf9aea7fda115 to your computer and use it in GitHub Desktop.
OpenCode Profile Switcher
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| # Switch between different opencode auth profiles under ~/.local/share/opencode/auth.json | |
| # Profiles are saved as auth-<profile_name>.json | |
| # Current profile saved in current_profile.txt | |
| die() { | |
| printf '%s\n' "$1" >&2 | |
| exit 1 | |
| } | |
| info() { | |
| printf '%s\n' "$1" | |
| } | |
| get_paths() { | |
| BASE_DIR=${OPENCODE_PROFILE_BASE_DIR:-"$HOME/.local/share/opencode"} | |
| AUTH_FILE="$BASE_DIR/auth.json" | |
| CURRENT_PROFILE_FILE="$BASE_DIR/current_profile.txt" | |
| PROFILES= | |
| PROFILE_COUNT=0 | |
| CURRENT_RECORDED_PROFILE= | |
| VALID_CURRENT_PROFILE= | |
| CURRENT_STATUS= | |
| } | |
| ensure_base_dir() { | |
| if [ ! -d "$BASE_DIR" ]; then | |
| mkdir -p "$BASE_DIR" || die "Failed to create base directory: $BASE_DIR" | |
| fi | |
| } | |
| load_profiles() { | |
| PROFILES= | |
| PROFILE_COUNT=0 | |
| for path in "$BASE_DIR"/auth-*.json; do | |
| [ -f "$path" ] || continue | |
| name=$(basename "$path") | |
| name=${name#auth-} | |
| name=${name%.json} | |
| if [ -z "$PROFILES" ]; then | |
| PROFILES=$name | |
| else | |
| PROFILES=$(printf '%s\n%s\n' "$PROFILES" "$name") | |
| fi | |
| done | |
| if [ -n "$PROFILES" ]; then | |
| PROFILES=$(printf '%s\n' "$PROFILES" | sort) | |
| set -- $PROFILES | |
| PROFILE_COUNT=$# | |
| fi | |
| } | |
| get_current_status() { | |
| CURRENT_RECORDED_PROFILE= | |
| VALID_CURRENT_PROFILE= | |
| if [ -f "$CURRENT_PROFILE_FILE" ]; then | |
| IFS= read -r CURRENT_RECORDED_PROFILE < "$CURRENT_PROFILE_FILE" || CURRENT_RECORDED_PROFILE= | |
| if [ -f "$BASE_DIR/auth-$CURRENT_RECORDED_PROFILE.json" ]; then | |
| VALID_CURRENT_PROFILE=$CURRENT_RECORDED_PROFILE | |
| CURRENT_STATUS=$CURRENT_RECORDED_PROFILE | |
| else | |
| CURRENT_STATUS="$CURRENT_RECORDED_PROFILE (missing profile file)" | |
| fi | |
| elif [ -f "$AUTH_FILE" ]; then | |
| CURRENT_STATUS='unknown profile' | |
| else | |
| CURRENT_STATUS='unset' | |
| fi | |
| } | |
| print_header() { | |
| printf '=== OpenCode Profile Utility ===\n' | |
| printf 'Current profile: %s\n\n' "$CURRENT_STATUS" | |
| } | |
| prompt_main_action() { | |
| while :; do | |
| printf '1) Switch to a profile\n' | |
| printf '2) Save current auth.json to a profile\n' | |
| printf 'q) Quit\n' | |
| printf 'Choose an action [1-2, q]: ' | |
| IFS= read -r action || action=q | |
| case $action in | |
| 1|2|q|quit) | |
| MAIN_ACTION=$action | |
| return 0 | |
| ;; | |
| *) | |
| info 'Invalid input. Please enter 1, 2, or q.' | |
| printf '\n' | |
| ;; | |
| esac | |
| done | |
| } | |
| print_profile_list() { | |
| if [ "$PROFILE_COUNT" -eq 0 ]; then | |
| return 0 | |
| fi | |
| index=1 | |
| set -- $PROFILES | |
| for profile_name do | |
| printf '%s) %s\n' "$index" "$profile_name" | |
| index=$((index + 1)) | |
| done | |
| } | |
| prompt_profile_selection() { | |
| if [ "$PROFILE_COUNT" -eq 0 ]; then | |
| info 'No saved profiles found.' | |
| return 1 | |
| fi | |
| print_profile_list | |
| while :; do | |
| printf 'Select a profile number [1-%s, q]: ' "$PROFILE_COUNT" | |
| IFS= read -r selection || return 1 | |
| case $selection in | |
| q|quit) | |
| return 1 | |
| ;; | |
| ''|*[!0-9]*) | |
| info 'Invalid input. Please enter a profile number or q.' | |
| ;; | |
| *) | |
| if [ "$selection" -lt 1 ] || [ "$selection" -gt "$PROFILE_COUNT" ]; then | |
| info "Invalid input. Please enter a number from 1 to $PROFILE_COUNT." | |
| else | |
| set -- $PROFILES | |
| index=1 | |
| for profile_name do | |
| if [ "$index" -eq "$selection" ]; then | |
| switch_to_profile "$profile_name" | |
| fi | |
| index=$((index + 1)) | |
| done | |
| fi | |
| ;; | |
| esac | |
| done | |
| } | |
| validate_profile_name() { | |
| profile_name=$1 | |
| case $profile_name in | |
| '') | |
| info 'Profile name cannot be empty.' | |
| return 1 | |
| ;; | |
| *[!A-Za-z0-9_-]*) | |
| info 'Profile name may contain only letters, numbers, underscores, and hyphens.' | |
| return 1 | |
| ;; | |
| *) | |
| return 0 | |
| ;; | |
| esac | |
| } | |
| confirm_overwrite() { | |
| profile_name=$1 | |
| printf "Profile '%s' already exists. Overwrite? [y/N]: " "$profile_name" | |
| IFS= read -r answer || return 1 | |
| case $answer in | |
| y|yes) | |
| return 0 | |
| ;; | |
| q|quit) | |
| return 1 | |
| ;; | |
| *) | |
| return 1 | |
| ;; | |
| esac | |
| } | |
| prompt_save_profile_name() { | |
| while :; do | |
| if [ -n "$VALID_CURRENT_PROFILE" ]; then | |
| printf 'Profile name [%s]: ' "$VALID_CURRENT_PROFILE" | |
| else | |
| printf 'Profile name: ' | |
| fi | |
| IFS= read -r profile_name || return 1 | |
| case $profile_name in | |
| q|quit) | |
| return 1 | |
| ;; | |
| esac | |
| if [ -z "$profile_name" ] && [ -n "$VALID_CURRENT_PROFILE" ]; then | |
| profile_name=$VALID_CURRENT_PROFILE | |
| fi | |
| if ! validate_profile_name "$profile_name"; then | |
| continue | |
| fi | |
| target_file="$BASE_DIR/auth-$profile_name.json" | |
| if [ -f "$target_file" ] && ! confirm_overwrite "$profile_name"; then | |
| continue | |
| fi | |
| save_current_to_profile "$profile_name" | |
| done | |
| } | |
| write_current_profile() { | |
| printf '%s\n' "$1" > "$CURRENT_PROFILE_FILE" || die 'Failed to update current_profile.txt' | |
| } | |
| switch_to_profile() { | |
| profile_name=$1 | |
| source_file="$BASE_DIR/auth-$profile_name.json" | |
| [ -f "$source_file" ] || die "Profile file not found: $source_file" | |
| cp "$source_file" "$AUTH_FILE" || die 'Failed to update auth.json' | |
| write_current_profile "$profile_name" | |
| info "Switched to profile '$profile_name'." | |
| exit 0 | |
| } | |
| save_current_to_profile() { | |
| profile_name=$1 | |
| target_file="$BASE_DIR/auth-$profile_name.json" | |
| [ -f "$AUTH_FILE" ] || die 'No auth.json found. Cannot save a profile.' | |
| cp "$AUTH_FILE" "$target_file" || die "Failed to save profile '$profile_name'" | |
| write_current_profile "$profile_name" | |
| info "Saved current auth to profile '$profile_name'." | |
| exit 0 | |
| } | |
| main() { | |
| get_paths | |
| ensure_base_dir | |
| while :; do | |
| load_profiles | |
| get_current_status | |
| print_header | |
| prompt_main_action | |
| case $MAIN_ACTION in | |
| 1) | |
| if prompt_profile_selection; then | |
| : | |
| fi | |
| ;; | |
| 2) | |
| if [ ! -f "$AUTH_FILE" ]; then | |
| info 'No auth.json found. Nothing to save.' | |
| else | |
| prompt_save_profile_name || : | |
| fi | |
| ;; | |
| q|quit) | |
| exit 0 | |
| ;; | |
| esac | |
| printf '\n' | |
| done | |
| } | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment