Files
45060f4492 feat(agents): add manifest-driven gator agent (#1826)
* chore(gator): add gator gate skill

* chore(gator): add sandbox launcher scaffold

* chore(gator): add codex image and docs checks

* chore(gator): fold approved provider policy rules

* chore(gator): add deterministic reviewer runner

* chore(gator): clarify ok-to-test comments

* chore(gator): structure launcher harnesses

* chore(gator): require e2e for dependabot

* chore(gator): add codex refresh profile

* chore(gator): wip manifest agent launcher

* feat(agents): supervise watch cycles in sandbox

* fix(agents): preserve gateway refresh state

* fix(gator): continue human response threads

* fix(agents): keep watch supervisor retrying

* fix(agents): use refreshed Codex credential aliases

* fix(gator): avoid misleading gh auth checks

* docs(agents): remove architecture build update

* fix(gator): use REST-backed GitHub writes

* fix(agents): bake immutable agent payloads

* fix(agents): upload writable agent workspace

* fix(agents): surface gator watch progress

* fix(agents): prevent codex stdin hang

* fix(agents): align codex subagent input

* fix(agents): heartbeat during active cycles

* fix(agents): clean up heartbeat sleep

* fix(agents): disable gh telemetry in codex harness

* fix(agents): reconcile closed gator PRs

* fix(agents): query closed gator PR labels separately

* fix(agents): tolerate rotated credential placeholders

* fix(agents): enforce gator same-sha comment guard

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* docs(agents): scope gator trusted commentary

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* fix(gator): treat reviewer failures as transient

Signed-off-by: Evan Lezar <elezar@nvidia.com>

* feat(agents): refine gator supervised workflow

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* fix(agents): stream codex prompts via stdin

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* docs(agents): clarify trusted gator responses

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* refactor(agents): scope gator PR to scripts

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

---------

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>
Signed-off-by: Evan Lezar <elezar@nvidia.com>
Co-authored-by: John Myers <johntmyers@users.noreply.github.com>
Co-authored-by: Evan Lezar <elezar@nvidia.com>
2026-07-01 10:22:40 -07:00

150 lines
4.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail
REAL_GH="${OPENSHELL_REAL_GH:-/usr/bin/gh}"
GATOR_MARKER='> **gator-agent**'
if [[ $# -lt 1 || "$1" != "api" ]]; then
exec "$REAL_GH" "$@"
fi
method="GET"
input_file=""
body_field=""
endpoint=""
args=("$@")
consume_next=false
for ((i = 1; i < ${#args[@]}; i++)); do
arg="${args[$i]}"
if [[ "$consume_next" == "true" ]]; then
consume_next=false
continue
fi
case "$arg" in
--method|-X)
if (( i + 1 < ${#args[@]} )); then
method="${args[$((i + 1))]}"
consume_next=true
fi
;;
--method=*)
method="${arg#--method=}"
;;
--input)
if (( i + 1 < ${#args[@]} )); then
input_file="${args[$((i + 1))]}"
consume_next=true
fi
;;
--input=*)
input_file="${arg#--input=}"
;;
-f|--field|-F|--raw-field)
if (( i + 1 < ${#args[@]} )); then
field="${args[$((i + 1))]}"
if [[ "$field" == body=* ]]; then
body_field="${field#body=}"
fi
consume_next=true
fi
;;
-fbody=*|--field=body=*|-Fbody=*|--raw-field=body=*)
body_field="${arg#*=body=}"
;;
--*)
;;
*)
if [[ -z "$endpoint" ]]; then
endpoint="${arg#/}"
fi
;;
esac
done
read_body() {
if [[ -n "$input_file" && -f "$input_file" ]]; then
jq -r '.body // empty' "$input_file" 2>/dev/null || true
return
fi
printf '%s' "$body_field"
}
is_legacy_reviewer_failure_disposition() {
local existing_body="$1"
local head_sha="$2"
[[ "$existing_body" == *"$GATOR_MARKER"* ]] || return 1
[[ "$existing_body" == *"$head_sha"* ]] || return 1
[[ "$existing_body" == *"principal-engineer-reviewer"* ]] || return 1
[[ "$existing_body" == *"failed before producing"* ]] || return 1
}
has_blocking_same_sha_disposition() {
local head_sha="$1"
local encoded_bodies="$2"
local encoded_body existing_body
while IFS= read -r encoded_body; do
[[ -n "$encoded_body" ]] || continue
existing_body="$(printf '%s' "$encoded_body" | jq -r . 2>/dev/null || printf '%s' "$encoded_body")"
[[ "$existing_body" == *"$head_sha"* ]] || continue
if is_legacy_reviewer_failure_disposition "$existing_body" "$head_sha"; then
continue
fi
return 0
done <<< "$encoded_bodies"
return 1
}
guard_duplicate_gator_disposition() {
local owner="$1"
local repo="$2"
local number="$3"
local body="$4"
[[ "$body" == *"$GATOR_MARKER"* ]] || return 0
[[ "$body" != *"## Monitoring Complete"* ]] || return 0
local head_sha
head_sha="$($REAL_GH api "repos/$owner/$repo/pulls/$number" --jq '.head.sha // empty' 2>/dev/null || true)"
[[ -n "$head_sha" ]] || return 0
if is_legacy_reviewer_failure_disposition "$body" "$head_sha"; then
echo "openshell-agent: blocked public reviewer sub-agent failure disposition for $owner/$repo#$number ($head_sha)" >&2
echo "openshell-agent: return OPENSHELL_AGENT_RESULT status=transient_failure with reason=reviewer_subagent_failed instead" >&2
return 20
fi
local existing_comments existing_reviews
existing_comments="$($REAL_GH api "repos/$owner/$repo/issues/$number/comments" --paginate --jq '.[] | select(.body | contains("> **gator-agent**")) | .body | @json' 2>/dev/null || true)"
existing_reviews="$($REAL_GH api "repos/$owner/$repo/pulls/$number/reviews" --paginate --jq '.[] | select(.body | contains("> **gator-agent**")) | .body | @json' 2>/dev/null || true)"
if has_blocking_same_sha_disposition "$head_sha" "$(printf '%s\n%s\n' "$existing_comments" "$existing_reviews")"; then
echo "openshell-agent: blocked duplicate gator same-SHA disposition for $owner/$repo#$number ($head_sha)" >&2
echo "openshell-agent: push a new commit, remove the old disposition, or set OPENSHELL_GATOR_ALLOW_SAME_SHA_COMMENT=1 for an explicit maintainer-requested same-SHA action" >&2
return 20
fi
}
if [[ "${OPENSHELL_GATOR_ALLOW_SAME_SHA_COMMENT:-}" != "1" && "${method^^}" == "POST" ]]; then
request_body="$(read_body)"
if [[ "$endpoint" =~ ^repos/([^/]+)/([^/]+)/issues/([0-9]+)/comments$ ]]; then
guard_duplicate_gator_disposition "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}" "$request_body"
elif [[ "$endpoint" =~ ^repos/([^/]+)/([^/]+)/pulls/([0-9]+)/reviews$ ]]; then
guard_duplicate_gator_disposition "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}" "$request_body"
fi
fi
exec "$REAL_GH" "$@"