- install-claude-profiles: distinguish broken symlink vs real dir vs free path via -L/-e, repoint existing links with ln -sfn, warn instead of silently skipping when target is a non-symlink dir. - profiles.sh: only set -euo pipefail when sourced non-interactively so sourcing in an interactive shell doesn't clobber session settings. Co-Authored-By: Claude <noreply@anthropic.com>
109 lines
2.5 KiB
Bash
Executable file
109 lines
2.5 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Only enforce strict mode when sourced non-interactively, so sourcing this
|
|
# file in an interactive shell doesn't clobber the user's session settings.
|
|
[[ $- == *i* ]] || set -euo pipefail
|
|
|
|
repo_root() {
|
|
local script_dir
|
|
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
printf '%s\n' "$script_dir"
|
|
}
|
|
|
|
config_file() {
|
|
printf '%s/config/profiles.yml\n' "$(repo_root)"
|
|
}
|
|
|
|
require_yq() {
|
|
command -v yq >/dev/null 2>&1 || {
|
|
echo "Error: yq is required but not installed." >&2
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
require_config() {
|
|
local cfg
|
|
cfg="$(config_file)"
|
|
[[ -f "$cfg" ]] || {
|
|
echo "Error: missing config file: $cfg" >&2
|
|
echo "Create it from config/profiles.example.yml" >&2
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
cfg_get() {
|
|
local expr="$1"
|
|
yq -r "$expr // \"\"" "$(config_file)"
|
|
}
|
|
|
|
profile_exists() {
|
|
local profile="$1"
|
|
[[ "$(cfg_get ".profiles.${profile}.mode")" != "" ]]
|
|
}
|
|
|
|
clear_claude_env() {
|
|
unset ANTHROPIC_BASE_URL
|
|
unset ANTHROPIC_AUTH_TOKEN
|
|
unset ANTHROPIC_API_KEY
|
|
unset ANTHROPIC_MODEL
|
|
unset ANTHROPIC_DEFAULT_OPUS_MODEL
|
|
unset ANTHROPIC_DEFAULT_SONNET_MODEL
|
|
unset ANTHROPIC_DEFAULT_HAIKU_MODEL
|
|
unset CLAUDE_CODE_SUBAGENT_MODEL
|
|
}
|
|
|
|
launch_profile() {
|
|
local profile="$1"
|
|
local mode claude_cmd base_url api_key model
|
|
|
|
require_yq
|
|
require_config
|
|
|
|
profile_exists "$profile" || {
|
|
echo "Error: profile '$profile' not found in $(config_file)" >&2
|
|
exit 1
|
|
}
|
|
|
|
claude_cmd="$(cfg_get '.defaults.claude_cmd')"
|
|
[[ -n "$claude_cmd" ]] || claude_cmd="claude"
|
|
|
|
mode="$(cfg_get ".profiles.${profile}.mode")"
|
|
|
|
clear_claude_env
|
|
|
|
case "$mode" in
|
|
pro)
|
|
echo "Claude Pro profile active"
|
|
exec "$claude_cmd"
|
|
;;
|
|
openrouter)
|
|
base_url="$(cfg_get '.defaults.openrouter_base_url')"
|
|
[[ -n "$base_url" ]] || base_url="https://openrouter.ai/api"
|
|
|
|
api_key="${OPENROUTER_API_KEY:-}"
|
|
model="$(cfg_get ".profiles.${profile}.model")"
|
|
|
|
[[ -n "$api_key" ]] || {
|
|
echo "Error: OPENROUTER_API_KEY is not set for profile '$profile'" >&2
|
|
exit 1
|
|
}
|
|
|
|
[[ -n "$model" ]] || {
|
|
echo "Error: model missing for profile '$profile'" >&2
|
|
exit 1
|
|
}
|
|
|
|
export ANTHROPIC_BASE_URL="$base_url"
|
|
export ANTHROPIC_AUTH_TOKEN="$api_key"
|
|
export ANTHROPIC_API_KEY=""
|
|
export ANTHROPIC_MODEL="$model"
|
|
|
|
echo "OpenRouter profile active: $profile -> $model"
|
|
exec "$claude_cmd"
|
|
;;
|
|
*)
|
|
echo "Error: unsupported mode '$mode' for profile '$profile'" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|