Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 29 additions & 14 deletions .agents/scripts/supervisor-helper.sh
Original file line number Diff line number Diff line change
Expand Up @@ -111,18 +111,20 @@ unset _p
# When `gh auth token` succeeds (interactive), cache it for cron to use later.
_gh_token_cache="$HOME/.aidevops/.agent-workspace/supervisor/.gh-token-cache"
if [[ -z "${GH_TOKEN:-}" ]]; then
# Try gh auth token (works interactively, fails in cron without keyring)
GH_TOKEN=$(gh auth token 2>/dev/null || echo "")
# Try cached token FIRST (most reliable for cron — written by interactive sessions)
if [[ -f "$_gh_token_cache" ]]; then
GH_TOKEN=$(cat "$_gh_token_cache" 2>/dev/null || echo "")
fi
# If no cache, try gh auth token (works interactively, may fail in cron)
if [[ -z "$GH_TOKEN" ]]; then
GH_TOKEN=$(gh auth token 2>/dev/null || echo "")
fi
# Cache the token if we got one (for future cron runs)
if [[ -n "$GH_TOKEN" ]]; then
# Cache for cron (600 permissions — owner-only read/write)
mkdir -p "$(dirname "$_gh_token_cache")"
printf '%s' "$GH_TOKEN" > "$_gh_token_cache" 2>/dev/null || true
chmod 600 "$_gh_token_cache" 2>/dev/null || true
fi
if [[ -z "$GH_TOKEN" && -f "$_gh_token_cache" ]]; then
# Read from cache (written by a previous interactive session)
GH_TOKEN=$(cat "$_gh_token_cache" 2>/dev/null || echo "")
fi
if [[ -z "$GH_TOKEN" ]]; then
# Try gopass (encrypted secret store)
GH_TOKEN=$(gopass show -o github/token 2>/dev/null || echo "")
Expand Down Expand Up @@ -218,6 +220,19 @@ log_warn() { echo -e "${YELLOW}[SUPERVISOR]${NC} $*"; }
log_error() { echo -e "${RED}[SUPERVISOR]${NC} $*" >&2; }
log_verbose() { [[ "${SUPERVISOR_VERBOSE:-}" == "true" ]] && echo -e "${BLUE}[SUPERVISOR]${NC} $*" || true; }

# Check GitHub authentication in a way that works with GH_TOKEN env var.
# gh auth status may fail in cron even when GH_TOKEN is valid (keyring issues).
# This function checks GH_TOKEN first, then falls back to gh auth status.
check_gh_auth() {
# If GH_TOKEN is set, verify it works with a lightweight API call
if [[ -n "${GH_TOKEN:-}" ]]; then
gh api user --jq '.login' >/dev/null 2>&1 && return 0
fi
# Fall back to gh auth status (works interactively with keyring)
gh auth status >/dev/null 2>&1 && return 0
return 1
}

# Supervisor stderr log file - captures stderr from commands that previously
# used 2>/dev/null, making errors debuggable without cluttering terminal output.
# See GH#441 (t144) for rationale.
Expand Down Expand Up @@ -2511,7 +2526,7 @@ sync_claim_to_github() {

# Skip if gh CLI not available or not authenticated
command -v gh &>/dev/null || return 0
gh auth status &>/dev/null 2>&1 || return 0
check_gh_auth || return 0

local issue_number
issue_number=$(find_task_issue_number "$task_id" "$project_root")
Expand Down Expand Up @@ -3461,9 +3476,9 @@ cmd_dispatch() {
# Pre-dispatch GitHub auth check — verify the worker can push before
# creating worktrees and burning compute. Workers spawned via nohup/cron
# may lack SSH keys; gh auth git-credential only works with HTTPS remotes.
if ! gh auth status >/dev/null 2>&1; then
log_error "GitHub auth unavailable for $task_id — gh auth status failed"
log_error "Workers need 'gh auth login' with HTTPS protocol. Skipping dispatch."
if ! check_gh_auth; then
log_error "GitHub auth unavailable for $task_id — check_gh_auth failed"
log_error "Workers need 'gh auth login' or GH_TOKEN set. Skipping dispatch."
return 3
fi

Expand Down Expand Up @@ -6388,7 +6403,7 @@ create_github_issue() {
return 0
fi

if ! gh auth status &>/dev/null 2>&1; then
if ! check_gh_auth; then
log_warn "gh CLI not authenticated, skipping GitHub issue creation"
return 0
fi
Expand Down Expand Up @@ -6644,7 +6659,7 @@ verify_task_deliverables() {
log_warn "gh CLI not found; cannot verify deliverables for $task_id"
return 1
fi
if ! gh auth status &>/dev/null 2>&1; then
if ! check_gh_auth; then
log_warn "gh CLI not authenticated; cannot verify deliverables for $task_id"
return 1
fi
Expand Down Expand Up @@ -7287,7 +7302,7 @@ generate_verify_entry() {
local files_list=""
local -a check_lines=()

if [[ -n "$pr_number" ]] && command -v gh &>/dev/null && gh auth status &>/dev/null 2>&1; then
if [[ -n "$pr_number" ]] && command -v gh &>/dev/null && check_gh_auth; then
local repo_slug=""
repo_slug=$(detect_repo_slug "$trepo" 2>/dev/null || echo "")
if [[ -n "$repo_slug" ]]; then
Expand Down
24 changes: 15 additions & 9 deletions setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2575,9 +2575,11 @@ deploy_aidevops_agents() {
if [[ "$CLEAN_MODE" == "true" ]]; then
# Build list of directories to preserve: custom, draft, plus plugin namespaces
local -a preserved_dirs=("custom" "draft")
for pns in "${plugin_namespaces[@]}"; do
preserved_dirs+=("$pns")
done
if [[ ${#plugin_namespaces[@]} -gt 0 ]]; then
for pns in "${plugin_namespaces[@]}"; do
preserved_dirs+=("$pns")
done
Comment on lines +2579 to +2581

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This for loop can be made more concise. Since you're inside the if guard, you can safely append the entire plugin_namespaces array to preserved_dirs in one go. This is a more idiomatic way to combine arrays in Bash.

Suggested change
for pns in "${plugin_namespaces[@]}"; do
preserved_dirs+=("$pns")
done
preserved_dirs+=("${plugin_namespaces[@]}")

fi
print_info "Clean mode: removing stale files from $target_dir (preserving ${preserved_dirs[*]})"
local tmp_preserve
tmp_preserve="$(mktemp -d)"
Expand Down Expand Up @@ -2617,18 +2619,22 @@ deploy_aidevops_agents() {
local deploy_ok=false
if command -v rsync &>/dev/null; then
local -a rsync_excludes=("--exclude=loop-state/" "--exclude=custom/" "--exclude=draft/")
for pns in "${plugin_namespaces[@]}"; do
rsync_excludes+=("--exclude=${pns}/")
done
if [[ ${#plugin_namespaces[@]} -gt 0 ]]; then
for pns in "${plugin_namespaces[@]}"; do
rsync_excludes+=("--exclude=${pns}/")
done
fi
if rsync -a "${rsync_excludes[@]}" "$source_dir/" "$target_dir/"; then
deploy_ok=true
fi
else
# Fallback: use tar with exclusions to match rsync behavior
local -a tar_excludes=("--exclude=loop-state" "--exclude=custom" "--exclude=draft")
for pns in "${plugin_namespaces[@]}"; do
tar_excludes+=("--exclude=$pns")
done
if [[ ${#plugin_namespaces[@]} -gt 0 ]]; then
for pns in "${plugin_namespaces[@]}"; do
tar_excludes+=("--exclude=$pns")
done
fi
if (cd "$source_dir" && tar cf - "${tar_excludes[@]}" .) | (cd "$target_dir" && tar xf -); then
deploy_ok=true
fi
Expand Down
Loading