2026-07-18 17:40:05 +00:00
#!/usr/bin/env bash
# Single headless poll via Grok for the heavy-duty org watcher.
set -euo pipefail
2026-07-22 23:23:33 +00:00
SCRIPT_DIR = " $( cd " $( dirname " $0 " ) " && pwd ) "
# shellcheck source=lib/common.sh
source " ${ SCRIPT_DIR } /lib/common.sh "
2026-07-18 17:40:05 +00:00
mkdir -p " ${ LOG_DIR } "
2026-07-22 23:23:33 +00:00
TS = " $( utc_now) "
2026-07-18 17:40:05 +00:00
PROMPT_FILE = " ${ WATCHER_DIR } /.poll-prompt.txt "
2026-07-22 23:23:33 +00:00
case " ${ FORGE_BACKEND } " in
github)
DISCOVERY_HINT = " gh search prs/issues --owner ${ ORG } (review-requested=@me / assignee=@me) "
POST_HINT = "Prefer gh pr review / gh issue comment"
BACKEND_LABEL = "GitHub"
; ;
forgejo)
DISCOVERY_HINT = " bash ${ WATCHER_DIR } /scripts/discover.sh # FORGE_BACKEND=forgejo "
POST_HINT = " Prefer stoke pr review / stoke pr comment (Forgejo at ${ FORGEJO_URL } ) "
BACKEND_LABEL = "Forgejo"
; ;
*)
echo " error: unknown FORGE_BACKEND= ${ FORGE_BACKEND } " >& 2
exit 2
; ;
esac
2026-07-18 17:40:05 +00:00
cat > " ${ PROMPT_FILE } " <<EOF
2026-07-22 23:23:33 +00:00
Execute ONE full poll cycle for the heavy-duty org ${ BACKEND_LABEL } watcher.
2026-07-18 17:40:05 +00:00
1. Read ${ WATCHER_DIR } /POLL_INSTRUCTIONS.md and ${ WATCHER_DIR } /state.json
2026-07-22 23:23:33 +00:00
2. Bot: ${ BOT_LOGIN } . Scope: ALL repos under org ${ ORG } ( not a single repo) . Backend: ${ FORGE_BACKEND } .
2026-07-18 17:40:05 +00:00
3. Discover open Issues/PRs where bot is assignee OR review-requested:
2026-07-22 23:23:33 +00:00
${ DISCOVERY_HINT }
Or run: FORGE_BACKEND = ${ FORGE_BACKEND } bash ${ WATCHER_DIR } /scripts/discover.sh
4. For each match: read ALL comments/reviews/inline threads/diff/checks first; never repeat prior ${ BOT_LOGIN } comments.
2026-07-18 17:40:05 +00:00
5. Comment/review only if first assignment, new commits ( head SHA change vs state) , new human comments needing reply, material CI change, or explicit re-request. Else silent.
2026-07-22 23:23:33 +00:00
6. Style: clear Verdict ( Approve/Comment/Request changes) or Status ( Aligned/Feedback/Need info) . Specific, non-redundant, actionable. Blockers vs nits. ${ POST_HINT } . Keep reviewing across updates until you fully agree ( then Approve) .
2026-07-18 17:40:05 +00:00
7. Never merge/close/reassign/drive-by on unassigned items.
2026-07-22 23:23:33 +00:00
8. Update ${ WATCHER_DIR } /state.json ( keys like ${ ORG } /repo#pr:N) + append one line to ${ WATCHER_DIR } /logs/poll.log
2026-07-18 17:40:05 +00:00
9. Brief report only. If zero assignments, log and exit.
EOF
2026-07-22 23:23:33 +00:00
watcher_log " ${ LOG_DIR } /poll.log " " poll-once.sh starting headless grok (org: ${ ORG } backend: ${ FORGE_BACKEND } ) "
if ! command -v grok >/dev/null 2>& 1; then
watcher_log " ${ LOG_DIR } /poll.log " "poll-once.sh failed: grok CLI not found"
echo "error: grok CLI not found on PATH" >& 2
exit 127
fi
2026-07-18 17:40:05 +00:00
if grok --always-approve --cwd " ${ HOME } " --max-turns 80 \
--single " $( cat " ${ PROMPT_FILE } " ) " \
>> " ${ LOG_DIR } /poll-headless.log " 2>& 1; then
2026-07-22 23:23:33 +00:00
watcher_log " ${ LOG_DIR } /poll.log " "poll-once.sh finished ok"
2026-07-18 17:40:05 +00:00
else
rc = $?
2026-07-22 23:23:33 +00:00
watcher_log " ${ LOG_DIR } /poll.log " " poll-once.sh failed rc= ${ rc } "
2026-07-18 17:40:05 +00:00
exit " ${ rc } "
fi