Gitea issues – scripts et agents
Dossier dédié au traitement des tickets (issues) Gitea du dépôt 4nk/lecoffre_ng (https://git.4nkweb.com/4nk/lecoffre_ng/issues). Toute la logique d'appel API et Git est dans les scripts ; les agents orchestrent et appellent /fix ou /evol.
Agents (.cursor/agents/)
| Agent | Fichier | Rôle |
|---|---|---|
| agent-loop | agent-loop.md |
Orchestre la boucle de récupération des mails et le traitement : lance les 2 boucles en arrière-plan (récupération + traitement, pas de timeout) ou exécute x fois (récupération 1 fois puis traitement 1 fois via gitea-issues-process). |
| gitea-issues-process | gitea-issues-process.md |
Traite les issues Gitea et les mails en attente : liste les issues/mails, crée des branches, lance /fix ou /evol, /push-by-script ; workflow mails (fil, réponse réelle, marquage lu). |
Spooler tickets (nouveau) : mails dans projects//data/issues/ (filtre par tickets.authorized_emails dans conf.json), pas de « non lu », aucun enregistrement supprimé. Format : gitea-issues/TICKETS_SPOOL_FORMAT.md. Récupération : ./ia_dev/gitea-issues/tickets-fetch-inbox.sh. Référence boucle mails (legacy) : gitea-issues/AGENT_LOOP.md. Hook Cursor : sessionStart → .cursor/hooks/remonter-mails.sh (lit projects/<id>/data/issues/*.pending).
Contexte d'exécution
- Emplacement :
gitea-issues/est dans le sous-module ia_dev du dépôt projet. Chemin typique :<racine_projet>/ia_dev/gitea-issues/. Fonctionne pour tout projet utilisant ia_dev de la même manière. - Projet cible : le projet est identifié dynamiquement par le fichier
../ai_project_id(à la racine du dépôt projet, parent deia_dev). Son contenu (slug) sert à charger la config dansia_dev/projects/<id>/. Changer de projet = changer le dépôt (ou le contenu deai_project_id) ; aucun chemin à hardcoder. - Lancement : le chat Cursor et les scripts sont lancés depuis ia_dev (
<racine_projet>/ia_dev/), mais les opérations (issues, mails, déploiement) concernent le dépôt parent (../= racine projet). Invoquer les scripts depuis la racine du dépôt projet :cd <racine_projet> && ./ia_dev/gitea-issues/<script>.sh. Depuis le workspace ia_dev, racine projet =... - Secrets et logs :
.secretsest sous ia_dev (ia_dev/.secrets, soit./.secretsdepuis ia_dev), et ne dépend pas du projet parent. Les scripts résolvent la racine pour.secretsetlogsvia le répertoire contenantgitea-issues(ia_dev), afin que la config IMAP/SMTP et les logs soient les mêmes quel que soit le projet ; un même clone ia_dev peut servir plusieurs projets configurés par../ai_project_id.
Prérequis
- jq :
apt install jqoubrew install jq - Token Gitea : variable d’environnement
GITEA_TOKENou fichier.secrets/gitea-issues/token(contenu = le token, non versionné). Créer le token dans Gitea : Settings → Applications → Generate New Token (scopesread:issue,write:issuesi commentaires).
Scripts (depuis la racine du dépôt)
| Script | Usage | Description |
|---|---|---|
list-open-issues.sh |
./gitea-issues/list-open-issues.sh [--lines] [--limit N] |
Liste les issues ouvertes (JSON ou lignes number|title|state). |
get-issue.sh |
./gitea-issues/get-issue.sh <num> [--summary] |
Détail d’une issue (JSON ou résumé texte). |
print-issue-prompt.sh |
./gitea-issues/print-issue-prompt.sh <num> |
Affiche titre + corps pour fournir la consigne à l’agent. |
create-branch-for-issue.sh |
./gitea-issues/create-branch-for-issue.sh <num> [base] |
Crée et checkout la branche issue/<num> depuis base (défaut test). |
comment-issue.sh |
./gitea-issues/comment-issue.sh <num> <message> ou echo "msg" | ./gitea-issues/comment-issue.sh <num> - |
Ajoute un commentaire à l’issue. |
mail-list-unread.sh |
./gitea-issues/mail-list-unread.sh |
Liste les mails non lus envoyés à l'alias (MAIL_FILTER_TO, défaut ai.support.lecoffreio@4nkweb.com) ; lecture seule ; sortie : UID, Message-ID, From, To, Subject, Date, Body. Aucun autre mail n'est listé. |
mail-get-thread.sh |
./gitea-issues/mail-get-thread.sh <uid> |
Récupère tout le fil (conversation) du mail donné : tous les messages liés par References/In-Reply-To, tri chronologique (ancien → récent). Même format de sortie que mail-list-unread. À utiliser avant de décider ou répondre sur un mail. |
mail-send-reply.sh |
./gitea-issues/mail-send-reply.sh --to <addr> --subject "..." [--body "..." | stdin] [--in-reply-to "<msg-id>" [--references "..."]] |
Envoie une réponse par mail via le Bridge (SMTP) ; signature « Support IA du projet Lecoffre.io » / ai.support.lecoffreio@4nkweb.com ajoutée automatiquement. |
mail-create-issue-from-email.sh |
./gitea-issues/mail-create-issue-from-email.sh --uid <uid> [--title "..." ] [--body "..."] |
Crée une issue à partir d’un mail (UID), optionnel titre/corps formalisés ; marque le mail lu. |
mail-mark-read.sh |
./gitea-issues/mail-mark-read.sh <uid> |
Marque un mail comme lu. |
mail-thread-log.sh |
./gitea-issues/mail-thread-log.sh get-id | init | append-sent | append-issue | append-commit ... |
Log par fil : un fichier par conversation dans projects/<id>/logs/gitea-issues/threads/ (échanges reçus/envoyés, tickets, commits). get-id --uid <uid> affiche THREAD_ID=... ; init --uid <uid> crée/met à jour le fichier ; append-sent/issue/commit enregistrent une réponse, une issue ou un commit. |
mail-to-issue.sh |
./gitea-issues/mail-to-issue.sh |
Batch : crée une issue par mail non lu (titre = sujet, corps = texte + From), marque lus. À éviter si on suit le workflow agent (voir ci‑dessous). |
agent-loop.sh |
./ia_dev/gitea-issues/agent-loop.sh [interval_sec] |
Boucle de surveillance : exécute périodiquement mail-list-unread.sh, met à jour un fichier témoin (projects/<id>/logs/gitea-issues/agent-loop.status) et écrit les mails en attente dans agent-loop.pending. Voir gitea-issues/AGENT_LOOP.md. |
agent-loop-treatment.sh |
./ia_dev/gitea-issues/agent-loop-treatment.sh |
Boucle traitement : vérifie périodiquement agent-loop.pending ; si non vide, lance l'agent Cursor (workflow gitea-issues-process) pour traiter les mails. À lancer en arrière-plan (pas de timeout). |
agent-loop-retrieval-once.sh |
./ia_dev/gitea-issues/agent-loop-retrieval-once.sh |
Récupération une fois (legacy, basé non lu) : exécute mail-list-unread.sh et écrit dans agent-loop.pending. Utilisé par l'agent agent-loop pour les cycles « x fois ». |
tickets-fetch-inbox.sh |
./ia_dev/gitea-issues/tickets-fetch-inbox.sh |
Récupération par expéditeurs autorisés : filtre tickets.authorized_emails (conf.json), pas de marquage lu/non lu. Écrit les nouveaux mails dans projects/<id>/data/issues/<date>_<from>_<uid>.pending (JSON). Voir TICKETS_SPOOL_FORMAT.md. |
Variables optionnelles : GITEA_API_URL, GITEA_REPO_OWNER, GITEA_REPO_NAME, GITEA_ISSUES_DIR.
Création d’issues depuis les mails (IMAP) – workflow agent
Ne pas enchaîner directement : l’agent doit d’abord lire les non lus, formaliser l’issue ou répondre par mail, et ne créer/traiter qu’au moment où la demande est prête.
- Lire les non lus :
./gitea-issues/mail-list-unread.sh(ne marque pas les mails comme lus). - Pour chaque mail : consulter tout l'historique du fil avec
./gitea-issues/mail-get-thread.sh <uid>, créer/mettre à jour le log du fil avec./gitea-issues/mail-thread-log.sh init --uid <uid>(sortieTHREAD_ID=...à conserver), puis décider soit d’envoyer une réponse directe (demande d’infos) viamail-send-reply.sh, soit de formaliser et créer l’issue avecmail-create-issue-from-email.sh(optionnel--title/--bodyformalisés). Si la demande est une correction/évolution prête : créer l’issue, traiter (fix/evol), commenter l’issue, répondre au mail viamail-send-reply.sh(avec--in-reply-topour le fil). Le corps de la réponse doit contenir la réponse réelle à la question (ex. si le mail demande « Décrit les rôles », le body = une description des rôles), jamais le sujet du mail ni la question reçue. - Réponses aux mails : toujours via le Bridge avec
mail-send-reply.sh. Le--bodydoit être la réponse réelle rédigée par l'agent (contenu de la réponse à la demande), pas le sujet du mail, pas la question reçue, pas un message précédent du fil. Chaque envoi est enregistré dans le log du fil avecmail-thread-log.sh append-sent --thread-id <id> --to <addr> --subject "..." --body "..."pour tracer l'expéditeur, le titre et le corps de la réponse envoyée.
Prérequis :
- Python 3 (stdlib : imaplib, email, smtplib, json, urllib).
- Token Gitea : comme les autres scripts (
GITEA_TOKENou.secrets/gitea-issues/token). - Config IMAP/SMTP : copier
gitea-issues/imap-bridge.env.examplevers.secrets/gitea-issues/imap-bridge.env. Pour la boucle agent (optionnel) :agent-loop.env.examplevers.secrets/gitea-issues/agent-loop.env(voir AGENT_LOOP.md). RenseignerIMAP_USER,IMAP_PASSWORD(et optionnellementSMTP_*pour l’envoi ; par défaut SMTP reprend les mêmes host/port Bridge 1025). Optionnel :MAIL_FILTER_TO=ai.support.lecoffreio@4nkweb.com(seuls les mails envoyés à cette adresse sont listés). - Proton Mail Bridge (ou serveur IMAP/SMTP) en cours d’exécution.
Scripts : mail-list-unread.sh, mail-get-thread.sh, mail-thread-log.sh, mail-send-reply.sh, mail-create-issue-from-email.sh, mail-mark-read.sh. Le script batch mail-to-issue.sh reste disponible mais ne doit pas être utilisé dans le cadre du workflow agent (liste → lecture du fil → log du fil → décision → création/ réponse). Le script agent-loop.sh permet de lancer une boucle de surveillance des mails avec fichier témoin ; voir gitea-issues/AGENT_LOOP.md.
API Wiki (tests préalables)
Script de test de l’API Wiki Gitea pour le même dépôt (prérequis à une éventuelle migration de docs/ vers le wiki) :
| Script | Usage | Description |
|---|---|---|
wiki-api-test.sh |
./gitea-issues/wiki-api-test.sh [--create] |
Teste GET list pages, GET page Home ; avec --create : POST une page test puis DELETE. |
Prérequis : même token que les issues (GITEA_TOKEN ou .secrets/gitea-issues/token). Pour l’écriture (création / suppression de pages), le token doit avoir les droits d’écriture sur le dépôt.
Endpoints utilisés (référence Gitea API 1.25) :
GET /repos/{owner}/{repo}/wiki/pages— liste des pagesGET /repos/{owner}/{repo}/wiki/page/{pageName}— contenu d’une page (ex.Home)POST /repos/{owner}/{repo}/wiki/new— créer une page (body :title,content_base64,message)PATCH /repos/{owner}/{repo}/wiki/page/{pageName}— modifier une pageDELETE /repos/{owner}/{repo}/wiki/page/{pageName}— supprimer une page
Si le wiki n’a jamais été initialisé (aucune page créée via l’interface), les GET peuvent renvoyer 404 ou une liste vide. Initialiser le wiki : aller sur https://git.4nkweb.com/4nk/lecoffre_ng/wiki et créer au moins une page (ex. « Home ») via l’interface, puis relancer le script avec un token valide.
Branche par défaut du wiki : si l’API renvoie object does not exist [id: refs/heads/master] alors que la branche par défaut du dépôt wiki est autre (ex. prod), c’est un bug connu de certaines versions de Gitea (l’API suppose master). Contournements possibles : (1) mettre à jour Gitea (correctif dans les versions récentes, ex. PR #34244) ; (2) changer la branche par défaut du wiki en master dans les réglages du dépôt (Settings → Branches). Variable optionnelle GITEA_WIKI_REF=master (défaut si wiki configuré sur master).
Migration docs/ → wiki
Décision : tout le contenu de docs/ (racine du dépôt) est migré vers le wiki ; pas de CI sur le wiki.
Script de migration :
| Script | Usage | Description |
|---|---|---|
wiki-migrate-docs.sh |
./gitea-issues/wiki-migrate-docs.sh [--dry-run] [fichier.md ...] |
Migre docs/*.md vers le wiki. --dry-run affiche le mapping sans appel API. Si des fichiers sont passés en argument, migre uniquement ceux-là. |
wiki-put-page.sh |
./gitea-issues/wiki-put-page.sh <page_name> <file_path> |
Met à jour ou crée une page wiki à partir d’un fichier local (ex. Home docs/README.md). |
wiki-get-page.sh |
./gitea-issues/wiki-get-page.sh <page_name> |
Affiche le markdown brut d’une page wiki (pour scripts ou agents). |
Correspondance fichier → page wiki : nom de fichier sans .md, _ remplacé par -, title-case par segment. Ex. OPERATIONS.md → Operations, README.md → Readme.
Les 17 fichiers de docs/ ont été migrés ; les pages sont visibles sur https://git.4nkweb.com/4nk/lecoffre_ng/wiki. La page Home contient le contenu de docs/README.md (index et correspondance). docs/ est exclu du versionnement (.gitignore) : maintenir docs/ localement (ne pas le supprimer), pousser les modifications vers le wiki avec wiki-migrate-docs.sh ou wiki-put-page.sh ; ne pas committer docs/.
Après un clone
Le répertoire docs/ n'est pas versionné. Pour disposer d'une copie locale (édition puis synchro wiki), recréer le contenu à partir du wiki : ex. ./gitea-issues/wiki-get-page.sh Home > docs/README.md, ou créer les fichiers manuellement à partir des pages wiki listées dans la section Migration ci-dessus.
Usage « wiki uniquement » pour les agents
La connaissance du projet peut reposer uniquement sur le wiki (sans lire docs/) : les agents peuvent exécuter ./gitea-issues/wiki-get-page.sh <PageName> pour récupérer le contenu markdown d’une page et l’utiliser comme référence. Exemples : ./gitea-issues/wiki-get-page.sh Home, ./gitea-issues/wiki-get-page.sh Operations, ./gitea-issues/wiki-get-page.sh Code-Standards. Prérequis : token Gitea (comme pour les autres scripts wiki). Les agents peuvent ainsi consulter la doc projet à la demande depuis le wiki, sans dépendre des fichiers locaux docs/.
Agents (commandes)
- /agent-loop (
agent-loop.md) : lance les 2 boucles (récupération + traitement) en arrière-plan ou exécute x cycles (récupération 1 fois puis traitement 1 fois). À la fin d'une boucle de récupération, la boucle traitement lance gitea-issues-process sur les mails reçus. - /gitea-issues-process (
gitea-issues-process.md) : traite les issues Gitea et les mails en attente (workflow script au maximum, /fix ou /evol, /push-by-script). Voir le fichier de l'agent pour le workflow exact.
Référence
- Wiki : https://git.4nkweb.com/4nk/lecoffre_ng/wiki
- Documentation opérationnelle (ex.
docs/OPERATIONS.md) : page wiki Operations (après migration).