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
2 changes: 2 additions & 0 deletions .agents/scripts/supervisor-helper.sh
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,8 @@ Environment:
SUPERVISOR_SKIP_STALENESS Skip pre-dispatch staleness check (default: false)
SUPERVISOR_WORKER_TIMEOUT Seconds before a hung worker is killed (default: 3600)
SUPERVISOR_SELF_MEM_LIMIT MB before supervisor respawns after batch (default: 8192)
SUPERVISOR_SKILL_UPDATE_PR Enable skill update PR pipeline in pulse (default: false)
SUPERVISOR_SKILL_UPDATE_INTERVAL Seconds between skill update PR runs (default: 86400)
AIDEVOPS_SUPERVISOR_DIR Override supervisor data directory

Database: ~/.aidevops/.agent-workspace/supervisor/supervisor.db
Expand Down
57 changes: 57 additions & 0 deletions .agents/scripts/supervisor/pulse.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1801,6 +1801,63 @@ RULES:
log_verbose " Phase 12: MODELS.md regen skipped (${models_md_remaining}s until next run)"
fi

# Phase 13: Skill update PR pipeline (t1082.2)
# Optional phase — disabled by default. Enable via SUPERVISOR_SKILL_UPDATE_PR=true.
# Runs skill-update-helper.sh pr on a configurable schedule (default: daily).
# Only runs for repos where the authenticated user has write/admin permission,
# ensuring PRs are only created where the user is a maintainer.
local skill_update_pr_enabled="${SUPERVISOR_SKILL_UPDATE_PR:-false}"
if [[ "$skill_update_pr_enabled" == "true" ]]; then
local skill_update_interval="${SUPERVISOR_SKILL_UPDATE_INTERVAL:-86400}" # seconds (24h default)
local skill_update_stamp="$SUPERVISOR_DIR/skill-update-pr-last-run"
local skill_update_now
skill_update_now=$(date +%s)
local skill_update_last=0
if [[ -f "$skill_update_stamp" ]]; then
skill_update_last=$(cat "$skill_update_stamp" 2>/dev/null || echo 0)
fi
local skill_update_elapsed=$((skill_update_now - skill_update_last))
if [[ "$skill_update_elapsed" -ge "$skill_update_interval" ]]; then
local skill_update_script="${SCRIPT_DIR}/skill-update-helper.sh"
if [[ -x "$skill_update_script" ]]; then
# Determine the repo root to check maintainer permission
local skill_update_repo=""
skill_update_repo=$(db "$SUPERVISOR_DB" "SELECT DISTINCT repo FROM tasks LIMIT 1;" 2>/dev/null || echo "")
if [[ -z "$skill_update_repo" ]]; then
skill_update_repo="$(pwd)"
fi
local skill_update_repo_root=""
skill_update_repo_root=$(git -C "$skill_update_repo" rev-parse --show-toplevel 2>/dev/null) || true
# Check viewer permission — only run if user is a maintainer (WRITE or ADMIN)
local viewer_permission=""
if [[ -n "$skill_update_repo_root" ]] && command -v gh &>/dev/null; then
viewer_permission=$(gh repo view --json viewerPermission --jq '.viewerPermission' \
-R "$(git -C "$skill_update_repo_root" remote get-url origin 2>/dev/null |
sed 's|.*github\.com[:/]\([^/]*/[^/]*\)\.git|\1|; s|.*github\.com[:/]\([^/]*/[^/]*\)$|\1|')" \
Comment on lines +1835 to +1836
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The sed command used to extract the repository owner/repo from the remote URL is complex and unnecessary. The gh CLI is capable of parsing the full remote URL directly when it's passed to the -R flag. Relying on gh's built-in parsing is more robust and readable than using a custom sed command.

Suggested change
-R "$(git -C "$skill_update_repo_root" remote get-url origin 2>/dev/null |
sed 's|.*github\.com[:/]\([^/]*/[^/]*\)\.git|\1|; s|.*github\.com[:/]\([^/]*/[^/]*\)$|\1|')" \
-R "$(git -C "$skill_update_repo_root" remote get-url origin 2>/dev/null)" \

2>/dev/null || echo "")
fi
Comment on lines +1833 to +1838
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Prefer detect_repo_slug over inline sed extraction.

detect_repo_slug is already used throughout this file (lines 759, 1449, 1506) for the same purpose — extracting owner/repo from a git remote URL. The inline sed here duplicates that logic and may not handle the same edge cases.

♻️ Suggested simplification
 			local viewer_permission=""
-			if [[ -n "$skill_update_repo_root" ]] && command -v gh &>/dev/null; then
-				viewer_permission=$(gh repo view --json viewerPermission --jq '.viewerPermission' \
-					-R "$(git -C "$skill_update_repo_root" remote get-url origin 2>/dev/null |
-						sed 's|.*github\.com[:/]\([^/]*/[^/]*\)\.git|\1|; s|.*github\.com[:/]\([^/]*/[^/]*\)$|\1|')" \
-					2>/dev/null || echo "")
-			fi
+			local skill_repo_slug=""
+			if [[ -n "$skill_update_repo_root" ]]; then
+				skill_repo_slug=$(detect_repo_slug "$skill_update_repo_root" 2>/dev/null || echo "")
+			fi
+			if [[ -n "$skill_repo_slug" ]] && command -v gh &>/dev/null; then
+				viewer_permission=$(gh repo view --json viewerPermission --jq '.viewerPermission' \
+					-R "$skill_repo_slug" 2>/dev/null || echo "")
+			fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/supervisor/pulse.sh around lines 1833 - 1838, Replace the
inline sed extraction used to build the owner/repo slug with the existing
detect_repo_slug helper: call detect_repo_slug passing skill_update_repo_root,
capture its output into a variable (e.g., repo_slug), and use that variable in
the gh repo view -R argument when setting viewer_permission; keep the same
fallback to an empty string if detect_repo_slug returns nothing and preserve the
surrounding command structure and error redirection.

if [[ "$viewer_permission" == "ADMIN" || "$viewer_permission" == "WRITE" ]]; then
log_info " Phase 13: Running skill update PR pipeline (permission: $viewer_permission)"
if "$skill_update_script" pr --quiet 2>>"$SUPERVISOR_LOG"; then
log_success " Phase 13: Skill update PR pipeline complete"
else
log_warn " Phase 13: Skill update PR pipeline finished with errors (see $SUPERVISOR_LOG)"
fi
elif [[ -z "$viewer_permission" ]]; then
log_verbose " Phase 13: Skipped (could not determine repo permission — gh CLI unavailable or not a GitHub repo)"
else
log_verbose " Phase 13: Skipped (viewer permission '$viewer_permission' — write/admin required)"
fi
else
log_verbose " Phase 13: Skipped (skill-update-helper.sh not found)"
fi
echo "$skill_update_now" >"$skill_update_stamp" 2>/dev/null || true
else
local skill_update_remaining=$((skill_update_interval - skill_update_elapsed))
log_verbose " Phase 13: Skill update PR skipped (${skill_update_remaining}s until next run)"
fi
fi

# t1052: Clear deferred batch completion flag to avoid leaking state
# if the supervisor process is reused for non-pulse commands
_PULSE_DEFER_BATCH_COMPLETION=""
Expand Down
Loading