#!/usr/bin/env bash # Agent loop: poll for unread mails periodically and maintain a witness file. # Run from repo root. Use a fichier témoin (status) to know if the loop is active. # # Usage: # ./gitea-issues/agent-loop.sh [interval_seconds] # AGENT_LOOP_INTERVAL_SEC=120 ./gitea-issues/agent-loop.sh # # Witness file: projects//logs/gitea-issues/agent-loop.status (or AGENT_LOOP_STATUS_FILE) # Updated every iteration. If mtime is older than 2*interval, consider the loop stopped. # Pending file: projects//logs/gitea-issues/agent-loop.pending (or AGENT_LOOP_PENDING_FILE) # Written when unread mails exist; contains timestamp and mail list. Clear after agent run. # # Optional: set AGENT_LOOP_RUN_AGENT=1 to run the Cursor Agent CLI when mails are detected. # Requires Cursor Agent CLI (https://cursor.com/docs/cli/using). If "agent" is not in PATH, the loop only updates status/pending. # # Optional: AGENT_LOOP_MODEL= to force the model (e.g. sonnet-4.6, gpt-5.4-low). Default: sonnet-4.6 to avoid Opus usage limits when running unattended. # set -euo pipefail # Source user env so PATH includes ~/.local/bin (Cursor Agent CLI, etc.) if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then set +u # shellcheck source=/dev/null source "$HOME/.bashrc" 2>/dev/null || true set -u fi [ -n "${HOME:-}" ] && [ -d "$HOME/.local/bin" ] && export PATH="$HOME/.local/bin:$PATH" GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}" ROOT="$(cd "${GITEA_ISSUES_DIR}/../.." && pwd)" export GITEA_ISSUES_DIR export REPO_ROOT="${ROOT}" cd "$ROOT" # Per-project logs under projects//logs (lib.sh sets PROJECT_LOGS_DIR) # shellcheck source=lib.sh source "${GITEA_ISSUES_DIR}/lib.sh" 2>/dev/null || true LOGS_GITEA="${PROJECT_LOGS_DIR:-$ROOT/logs}/gitea-issues" # Load agent-loop parameters from .secrets (optional; .secrets under ia_dev) AGENT_LOOP_ENV="${GITEA_ISSUES_DIR}/../.secrets/gitea-issues/agent-loop.env" if [ -r "$AGENT_LOOP_ENV" ]; then set +u # shellcheck source=/dev/null source "$AGENT_LOOP_ENV" set -u fi INTERVAL="${1:-${AGENT_LOOP_INTERVAL_SEC:-60}}" STATUS_FILE="${AGENT_LOOP_STATUS_FILE:-$LOGS_GITEA/agent-loop.status}" PENDING_FILE="${AGENT_LOOP_PENDING_FILE:-$LOGS_GITEA/agent-loop.pending}" mkdir -p "$(dirname "$STATUS_FILE")" write_status() { local status="$1" local detail="${2:-}" printf "%s\n%s\n%s\n" "$(date -Iseconds)" "$status" "$detail" > "$STATUS_FILE" } while true; do write_status "running" "interval=${INTERVAL}s" out="" if out=$("${GITEA_ISSUES_DIR}/mail-list-unread.sh" 2>&1); then if echo "$out" | grep -q "UID="; then write_status "mails_pending" "Des mails non lus. Lancer l'agent gitea-issues-process dans Cursor." printf "%s\n%s\n%s\n%s\n" "$(date -Iseconds)" "mails_pending" "---" "$out" > "$PENDING_FILE" echo "[agent-loop] $(date -Iseconds) — Mails non lus détectés. Lancer l'agent gitea-issues-process dans Cursor." if [ "${AGENT_LOOP_RUN_AGENT:-0}" = "1" ] && command -v agent >/dev/null 2>&1; then write_status "running_agent" "Lancement de l'agent Cursor pour traiter les mails." echo "[agent-loop] $(date -Iseconds) — Lancement de l'agent Cursor (workflow gitea-issues-process mails)." AGENT_MODEL="${AGENT_LOOP_MODEL:-sonnet-4.6}" echo "[agent-loop] $(date -Iseconds) — Modèle: $AGENT_MODEL" AGENT_OPTS=(-p "Exécute le workflow mails entrants de l'agent gitea-issues-process : les mails non lus viennent d'être détectés. 1) Pour chaque mail listé (voir contenu dans logs/gitea-issues/agent-loop.pending) : exécuter ./gitea-issues/mail-get-thread.sh , puis ./gitea-issues/mail-thread-log.sh init --uid , conserver THREAD_ID. 2) Pour chaque mail : rédiger une réponse NOUVELLE (non technique, didactique, contexte LeCoffre.io ; pour bug demander l'environnement, pour évolution considérer test). IMPORTANT : le --body de mail-send-reply.sh doit être du texte COMPOSÉ PAR TOI, jamais une copie ou citation d'un message du fil. Ne jamais renvoyer le contenu d'un message précédent (ex. réponse antérieure de ai.support). Envoyer avec ./gitea-issues/mail-send-reply.sh --to --subject \"Re: ...\" --body \"\", puis ./gitea-issues/mail-thread-log.sh append-sent, puis ./gitea-issues/mail-mark-read.sh . 3) Uniquement branche test, ne pas modifier les agents ni scripts d'agents. Répondre à tous les mails avant de marquer comme lu." -f --model "$AGENT_MODEL") if agent "${AGENT_OPTS[@]}" 2>&1; then write_status "agent_done" "Agent terminé." else write_status "mails_pending" "Agent terminé avec erreur ou interruption. Relancer l'agent manuellement si besoin." fi fi else write_status "idle" "Aucun mail non lu." if [ -f "$PENDING_FILE" ]; then : > "$PENDING_FILE" fi fi else write_status "error" "mail-list-unread a échoué" echo "[agent-loop] $(date -Iseconds) — Erreur mail-list-unread" >&2 fi sleep "$INTERVAL" done