1- #! /bin/sh
1+ #! /bin/bash
22# Trinity Cloud Agent Entrypoint
33# Solves a single GitHub issue using Claude Code
44# Required env: ISSUE_NUMBER, GITHUB_TOKEN, ANTHROPIC_API_KEY
55#
66# P0 hardened: timeout, SIGTERM handler, heartbeat loop, retry wrapper
77
88set -e
9+ set -o pipefail
910
1011REPO_URL=" ${REPO_URL:- https:// github.com/ gHashTag/ trinity.git} "
1112ISSUE=" ${ISSUE_NUMBER:? ISSUE_NUMBER is required} "
@@ -14,6 +15,7 @@ HEARTBEAT_INTERVAL="${HEARTBEAT_INTERVAL:-30}"
1415CURRENT_STATUS=" STARTING"
1516CURRENT_DETAIL=" Initializing"
1617HEARTBEAT_PID=" "
18+ LAST_TELEGRAM_SEND=0
1719
1820log () { echo " [agent-${ISSUE} ] $1 " ; }
1921
@@ -104,11 +106,41 @@ report_status() {
104106
105107send_telegram () {
106108 if [ -n " ${TELEGRAM_BOT_TOKEN} " ] && [ -n " ${TELEGRAM_CHAT_ID} " ]; then
109+ # HTML escape for Telegram
110+ local escaped=$( echo -e " $1 " | sed ' s/&/\&/g; s/</\</g; s/>/\>/g' )
111+ # Rate limit protection: minimum 3 seconds between sends
112+ local now=$( date +%s)
113+ local diff=$(( now - LAST_TELEGRAM_SEND))
114+ if [ $diff -lt 3 ]; then
115+ log " Skipping telegram send (rate limited, ${diff} s since last send)"
116+ return
117+ fi
107118 curl -s -X POST " https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN} /sendMessage" \
108119 -H " Content-Type: application/json" \
109- -d " {\" chat_id\" :\" ${TELEGRAM_CHAT_ID} \" ,\" text\" :\" $1 \" ,\" parse_mode\" :\" HTML\" }" \
120+ -d " {\" chat_id\" :\" ${TELEGRAM_CHAT_ID} \" ,\" text\" :\" ${escaped} \" ,\" parse_mode\" :\" HTML\" }" \
110121 --connect-timeout 5 --max-time 10 \
111122 2> /dev/null || log " Warning: Telegram send failed"
123+ LAST_TELEGRAM_SEND=$now
124+ fi
125+ }
126+
127+ stream_to_telegram () {
128+ local line=" $1 "
129+ # Stream line to telegram with HTML escaping
130+ if [ -n " ${TELEGRAM_BOT_TOKEN} " ] && [ -n " ${TELEGRAM_CHAT_ID} " ]; then
131+ local escaped=$( echo -e " ${line} " | sed ' s/&/\&/g; s/</\</g; s/>/\>/g' | head -c 3900)
132+ # Rate limit protection
133+ local now=$( date +%s)
134+ local diff=$(( now - LAST_TELEGRAM_SEND))
135+ if [ $diff -lt 3 ]; then
136+ return
137+ fi
138+ curl -s -X POST " https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN} /sendMessage" \
139+ -H " Content-Type: application/json" \
140+ -d " {\" chat_id\" :\" ${TELEGRAM_CHAT_ID} \" ,\" text\" :\" ${escaped} \" }" \
141+ --connect-timeout 2 --max-time 5 \
142+ 2> /dev/null || true
143+ LAST_TELEGRAM_SEND=$now
112144 fi
113145}
114146
@@ -294,8 +326,13 @@ Instructions:
294326Comment on the issue at each major step."
295327
296328emit_event " status" ' {"status":"CODING","detail":"Claude Code starting"}'
297- CLAUDE_EXIT=0
298- timeout " ${AGENT_TIMEOUT} " claude -p " ${PROMPT} " --allowedTools " Bash,Read,Write,Edit,Glob,Grep" 2>&1 || CLAUDE_EXIT=$?
329+ CLAUDE_LOG=" /tmp/claude_output_${ISSUE} .log"
330+ timeout " ${AGENT_TIMEOUT} " claude -p " ${PROMPT} " --allowedTools " Bash,Read,Write,Edit,Glob,Grep" 2>&1 | \
331+ tee " ${CLAUDE_LOG} " | \
332+ while IFS= read -r line; do
333+ stream_to_telegram " ${line} "
334+ done
335+ CLAUDE_EXIT=${PIPESTATUS[0]:- $? }
299336emit_event " command" " {\" cmd\" :\" claude\" ,\" exit_code\" :${CLAUDE_EXIT} ,\" timeout\" :${AGENT_TIMEOUT} }"
300337
301338if [ " ${CLAUDE_EXIT} " -eq 124 ]; then
307344
308345# === 6b. Run tests and capture results ===
309346report_status " TESTING" " Running zig build test"
310- TEST_OUTPUT=$( zig build test 2>&1 ) && TEST_EXIT=0 || TEST_EXIT=$?
347+ TEST_LOG=" /tmp/test_output_${ISSUE} .log"
348+ zig build test 2>&1 | tee " ${TEST_LOG} " | \
349+ while IFS= read -r line; do
350+ stream_to_telegram " ${line} "
351+ done
352+ TEST_EXIT=${PIPESTATUS[0]:- $? }
353+ TEST_OUTPUT=$( cat " ${TEST_LOG} " )
311354TESTS_PASSED=$( echo " ${TEST_OUTPUT} " | grep -c " OK" || echo " 0" )
312355TESTS_TOTAL=$( echo " ${TEST_OUTPUT} " | grep -cE " OK|FAIL" || echo " 0" )
313356if [ " ${TEST_EXIT} " -ne 0 ]; then
0 commit comments