#!/bin/bash set -euo pipefail KUGETSU_DIR="${KUGETSU_DIR:-$HOME/.kugetsu}" SESSIONS_DIR="$KUGETSU_DIR/sessions" WORKTREES_DIR="$KUGETSU_DIR/worktrees" REPOS_CONFIG="$KUGETSU_DIR/repos.json" INDEX_FILE="$KUGETSU_DIR/index.json" NOTIFICATIONS_FILE="$KUGETSU_DIR/notifications.json" LOGS_DIR="$KUGETSU_DIR/logs" ENV_DIR="${ENV_DIR:-$KUGETSU_DIR/env}" VERBOSITY_DIR="$KUGETSU_DIR/verbosity" MAX_CONCURRENT_AGENTS="${MAX_CONCURRENT_AGENTS:-3}" KUGETSU_VERBOSITY="${KUGETSU_VERBOSITY:-default}" CONTEXT_DIR="${CONTEXT_DIR:-$KUGETSU_DIR/context}" ENABLE_CONTEXT_DUMP="${ENABLE_CONTEXT_DUMP:-true}" WORKTREE_CHECK_PR_STATUS="${WORKTREE_CHECK_PR_STATUS:-true}" QUEUE_DIR="${QUEUE_DIR:-$KUGETSU_DIR/queue}" QUEUE_ITEMS_DIR="${QUEUE_ITEMS_DIR:-$QUEUE_DIR/items}" QUEUE_DAEMON_PID_FILE="${QUEUE_DAEMON_PID_FILE:-$QUEUE_DIR/daemon.pid}" QUEUE_DAEMON_LOCK_FILE="${QUEUE_DAEMON_LOCK_FILE:-$QUEUE_DIR/daemon.lock}" QUEUE_DAEMON_LOG_FILE="${QUEUE_DAEMON_LOG_FILE:-$QUEUE_DIR/daemon.log}" QUEUE_DAEMON_INTERVAL_MINUTES="${QUEUE_DAEMON_INTERVAL_MINUTES:-5}" QUEUE_CLEANUP_AGE_DAYS="${QUEUE_CLEANUP_AGE_DAYS:-7}" TASK_TIMEOUT_HOURS="${TASK_TIMEOUT_HOURS:-1}" NETWORK_RETRY_ATTEMPTS="${NETWORK_RETRY_ATTEMPTS:-3}" NETWORK_RETRY_DELAY_SECONDS="${NETWORK_RETRY_DELAY_SECONDS:-5}" KUGETSU_BASE_BRANCH="${KUGETSU_BASE_BRANCH:-origin/main}" # Load user config overrides (~/.kugetsu/config) if [ -f "$KUGETSU_DIR/config" ]; then source "$KUGETSU_DIR/config" fi mask_sensitive_vars() { local line="${1:-}" for var in GITEA_TOKEN GITHUB_TOKEN GITLAB_TOKEN API_KEY PASSWORD TOKEN SECRET; do if [[ "$line" =~ $var ]]; then line=$(echo "$line" | sed -E "s/=.*/=***MASKED***/") fi done echo "$line" } strip_ansi_codes() { local line="${1:-}" echo "$line" | sed 's/\x1b\[[0-9;]*m//g' | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' } load_agent_env() { local agent_type="${1:-base}" local env_file="$ENV_DIR/${agent_type}.env" if [ -f "$env_file" ]; then set -a source "$env_file" set +a elif [ -f "$ENV_DIR/default.env" ]; then set -a source "$ENV_DIR/default.env" set +a elif [ -f "$ENV_DIR/pm-agent.env" ]; then set -a source "$ENV_DIR/pm-agent.env" set +a fi } set_debug_mode() { local filtered_args=() local debug_mode=false for arg in "$@"; do case "$arg" in --debug) debug_mode=true ;; *) filtered_args+=("$arg") ;; esac done if [ "$debug_mode" = true ]; then export KUGETSU_VERBOSITY="debug" echo "[DEBUG] Debug mode enabled" >&2 fi echo "${filtered_args[@]}" } retry_with_backoff() { local max_attempts="${1:-$NETWORK_RETRY_ATTEMPTS}" local delay_seconds="${2:-$NETWORK_RETRY_DELAY_SECONDS}" local command="$3" local remaining_attempts=$max_attempts while [ $remaining_attempts -gt 0 ]; do if eval "$command"; then return 0 fi remaining_attempts=$((remaining_attempts - 1)) if [ $remaining_attempts -gt 0 ]; then log "warn" "retry_with_backoff" "Command failed, $remaining_attempts retries remaining. Waiting ${delay_seconds}s..." sleep "$delay_seconds" delay_seconds=$((delay_seconds * 2)) fi done log "error" "retry_with_backoff" "Command failed after $max_attempts attempts" return 1 }