@@ -166,6 +166,52 @@ update_telegram_dashboard() {
166166 fi
167167}
168168
169+ # ═══════════════════════════════════════════════════════════════════════════════
170+ # TELEGRAM LOG STREAMING — Batch streaming every 5 seconds to avoid rate limits
171+ # ═══════════════════════════════════════════════════════════════════════════════
172+
173+ TELEGRAM_BUFFER=" "
174+ TELEGRAM_LAST_SEND=0
175+ TELEGRAM_STREAM=" ${TELEGRAM_STREAM:- true} "
176+ TELEGRAM_BATCH_INTERVAL=" ${TELEGRAM_BATCH_INTERVAL:- 5} "
177+
178+ stream_to_telegram () {
179+ [ " $TELEGRAM_STREAM " != " true" ] && return
180+ local line=" $1 "
181+ TELEGRAM_BUFFER=" ${TELEGRAM_BUFFER}${line}
182+ "
183+
184+ local now=$( date +%s)
185+ local diff=$(( now - TELEGRAM_LAST_SEND))
186+
187+ if [ $diff -ge $TELEGRAM_BATCH_INTERVAL ] || [ ${# TELEGRAM_BUFFER} -gt 3000 ]; then
188+ if [ -n " $TELEGRAM_BUFFER " ] && [ -n " $TELEGRAM_BOT_TOKEN " ]; then
189+ local msg=$( echo -e " $TELEGRAM_BUFFER " | head -c 3900)
190+ curl -s -X POST " https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN} /sendMessage" \
191+ -d " chat_id=${TELEGRAM_CHAT_ID} " \
192+ -d " parse_mode=HTML" \
193+ -d " text=<pre>🤖 #${ISSUE} LOG
194+ ${msg} </pre>" \
195+ --max-time 5 || true
196+ TELEGRAM_BUFFER=" "
197+ TELEGRAM_LAST_SEND=$now
198+ fi
199+ fi
200+ }
201+
202+ flush_telegram () {
203+ if [ -n " $TELEGRAM_BUFFER " ] && [ -n " $TELEGRAM_BOT_TOKEN " ]; then
204+ local msg=$( echo -e " $TELEGRAM_BUFFER " | head -c 3900)
205+ curl -s -X POST " https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN} /sendMessage" \
206+ -d " chat_id=${TELEGRAM_CHAT_ID} " \
207+ -d " parse_mode=HTML" \
208+ -d " text=<pre>🤖 #${ISSUE} LOG
209+ ${msg} </pre>" \
210+ --max-time 5 || true
211+ TELEGRAM_BUFFER=" "
212+ fi
213+ }
214+
169215# ═══════════════════════════════════════════════════════════════════════════════
170216# EVENT STREAM (OpenHands-style structured events)
171217# ═══════════════════════════════════════════════════════════════════════════════
@@ -405,7 +451,19 @@ Comment on the issue at each major step."
405451
406452emit_event " status" ' {"status":"CODING","detail":"Claude Code starting"}'
407453CLAUDE_EXIT=0
408- timeout " ${AGENT_TIMEOUT} " claude -p " ${PROMPT} " --allowedTools " Bash,Read,Write,Edit,Glob,Grep" 2>&1 || CLAUDE_EXIT=$?
454+ timeout " ${AGENT_TIMEOUT} " claude -p " ${PROMPT} " --allowedTools " Bash,Read,Write,Edit,Glob,Grep" 2>&1 | \
455+ while IFS= read -r line; do
456+ echo " $line "
457+ stream_to_telegram " $line "
458+ echo " {\" type\" :\" log\" ,\" issue\" :${ISSUE} ,\" line\" :\" $( echo " $line " | sed ' s/"/\\"/g' | head -c 500) \" ,\" ts\" :\" $( date -u +%Y-%m-%dT%H:%M:%SZ) \" }" >> /tmp/agent_events.jsonl
459+ case " $line " in
460+ * " Read(" * |* " cat " * ) report_status " READING" " $line " ;;
461+ * " Write(" * |* " Edit(" * ) report_status " CODING" " $( echo $line | head -c 100) " ;;
462+ * " Bash(" * |* " zig build" * ) report_status " TESTING" " $( echo $line | head -c 100) " ;;
463+ * " error" * |* " Error" * ) report_status " ERROR" " $( echo $line | head -c 200) " ;;
464+ esac
465+ done || CLAUDE_EXIT=$?
466+ flush_telegram
409467emit_event " command" " {\" cmd\" :\" claude\" ,\" exit_code\" :${CLAUDE_EXIT} ,\" timeout\" :${AGENT_TIMEOUT} }"
410468
411469if [ " ${CLAUDE_EXIT} " -eq 124 ]; then
417475
418476# === 6b. Self-review (advisory only — never blocks push) ===
419477report_status " REVIEWING" " Self-review (advisory)"
478+ stream_to_telegram " Running self-review..."
420479REVIEW_WARNINGS=0
421480
422481# 7a. Format check — auto-fix silently
482+ stream_to_telegram " Checking zig fmt format..."
423483if ! zig fmt --check src/ 2> /dev/null; then
484+ stream_to_telegram " Running zig fmt to fix formatting..."
424485 zig fmt src/ 2> /dev/null || true
425486 git add -A
426487 git commit -m " style: zig fmt (#${ISSUE} )" 2> /dev/null || true
488+ stream_to_telegram " Formatting fixed and committed."
489+ else
490+ stream_to_telegram " Format check passed."
427491fi
428492
429493# 7b. Generated files check (only real blocker)
494+ stream_to_telegram " Checking for generated files..."
430495if git diff --name-only main..HEAD 2> /dev/null | grep -qE ' trinity/output/|generated/' ; then
431496 emit_event " error" ' {"msg":"Modified generated files"}'
432497 REVIEW_WARNINGS=$(( REVIEW_WARNINGS + 1 ))
498+ stream_to_telegram " Warning: Generated files modified."
433499fi
434500
435501# 7c. Diff size warning (advisory)
502+ stream_to_telegram " Checking diff size..."
436503DIFF_LINES=$( git diff --stat main..HEAD 2> /dev/null | tail -1 | grep -oE ' [0-9]+ insertion' | grep -oE ' [0-9]+' || echo " 0" )
437504if [ " ${DIFF_LINES:- 0} " -gt 500 ]; then
438505 emit_event " error" " {\" msg\" :\" Diff large: ${DIFF_LINES} lines\" }"
439506 REVIEW_WARNINGS=$(( REVIEW_WARNINGS + 1 ))
507+ stream_to_telegram " Warning: Large diff (${DIFF_LINES} lines)."
508+ else
509+ stream_to_telegram " Diff size OK: ${DIFF_LINES} lines."
440510fi
441511
442512# NOTE: zig build skipped — too heavy for Railway containers, always fails
443513# Tests run by CI after PR is created
444514if [ $REVIEW_WARNINGS -gt 0 ]; then
515+ stream_to_telegram " Self-review: ${REVIEW_WARNINGS} warning(s) (advisory, not blocking)."
445516 log " Self-review: ${REVIEW_WARNINGS} warning(s) (advisory, not blocking)"
517+ else
518+ stream_to_telegram " Self-review: All checks passed."
446519fi
447520
448521# === 8. Push and create PR if not already done ===
449522report_status " TESTING" " Checking/creating PR"
523+ stream_to_telegram " Checking for existing PR..."
450524EXISTING_PR=$( gh pr list --head " feat/issue-${ISSUE} " --json number --jq ' .[0].number' 2> /dev/null || echo " " )
451525
452526if [ -z " ${EXISTING_PR} " ]; then
453527 # Check if there are actually commits to push
454528 COMMIT_COUNT=$( git log --oneline main..HEAD 2> /dev/null | wc -l | tr -d ' ' )
529+ stream_to_telegram " Commit count: ${COMMIT_COUNT} "
455530 if [ " ${COMMIT_COUNT} " -gt 0 ]; then
456531 log " Pushing ${COMMIT_COUNT} commit(s)..."
532+ stream_to_telegram " Pushing ${COMMIT_COUNT} commit(s) to origin..."
457533 retry " git push -u origin 'feat/issue-${ISSUE} ' 2>/dev/null" || true
534+ stream_to_telegram " Push completed."
458535
459536 log " Creating PR..."
537+ stream_to_telegram " Creating pull request..."
460538 PR_URL=$( gh pr create \
461539 --title " feat: solve issue #${ISSUE} " \
462540 --body " Closes #${ISSUE}
@@ -466,13 +544,15 @@ Commits: ${COMMIT_COUNT}" \
466544 --head " feat/issue-${ISSUE} " 2> /dev/null || true)
467545
468546 if [ -n " ${PR_URL} " ]; then
547+ stream_to_telegram " PR created: ${PR_URL} "
469548 emit_event " pr" " {\" url\" :\" ${PR_URL} \" ,\" commits\" :${COMMIT_COUNT} }"
470549 report_status " PR_CREATED" " PR: ${PR_URL} "
471550 # Send metrics to monitor
472551 report_metrics
473552 # Post final summary comment
474553 DIFF_STAT=$( git diff --stat main..HEAD 2> /dev/null || echo " N/A" )
475554 FINAL_ELAPSED=$(( $(date +% s) - START_TIME ))
555+ stream_to_telegram " Posting final summary..."
476556 gh issue comment " ${ISSUE} " --body " 🚀 **Trinity Agent — Summary**
477557
478558| Field | Value |
@@ -485,17 +565,25 @@ Commits: ${COMMIT_COUNT}" \
485565\`\`\`
486566${DIFF_STAT}
487567\`\`\` " 2> /dev/null || true
568+ stream_to_telegram " Summary posted."
488569
489570 # Cleanup worktree after PR creation (keeps shared bare repo intact)
490571 log " Cleaning up worktree..."
572+ stream_to_telegram " Cleaning up worktree..."
491573 cd /bare-repo.git
492574 git worktree remove " ${WORKTREE_PATH} " --force 2> /dev/null || true
493575 log " Worktree removed: ${WORKTREE_PATH} "
576+ stream_to_telegram " Worktree removed."
577+ else
578+ stream_to_telegram " Failed to create PR."
494579 fi
495580 else
581+ stream_to_telegram " No commits produced — agent could not solve issue."
496582 report_status " FAILED" " No commits produced — agent could not solve issue"
497583 gh issue comment " ${ISSUE} " --body " ❌ **Trinity Agent**: No solution produced. Issue may need manual attention." 2> /dev/null || true
498584 fi
585+ else
586+ stream_to_telegram " PR already exists: #${EXISTING_PR} "
499587fi
500588
501589# === 8. Report final status ===
0 commit comments