121 lines
15 KiB
Markdown
121 lines
15 KiB
Markdown
# 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/<id>/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 de `ia_dev`). Son contenu (slug) sert à charger la config dans `ia_dev/projects/<id>/`. Changer de projet = changer le dépôt (ou le contenu de `ai_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** : `.secrets` est sous **ia_dev** (`ia_dev/.secrets`, soit `./.secrets` depuis ia_dev), et **ne dépend pas du projet parent**. Les scripts résolvent la racine pour `.secrets` et `logs` via le répertoire contenant `gitea-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 jq` ou `brew install jq`
|
||
- **Token Gitea** : variable d’environnement `GITEA_TOKEN` ou fichier `.secrets/gitea-issues/token` (contenu = le token, non versionné). Créer le token dans Gitea : Settings → Applications → Generate New Token (scopes `read:issue`, `write:issue` si 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.
|
||
|
||
1. **Lire les non lus** : `./gitea-issues/mail-list-unread.sh` (ne marque pas les mails comme lus).
|
||
2. **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>` (sortie `THREAD_ID=...` à conserver), puis décider soit d’envoyer une réponse directe (demande d’infos) via `mail-send-reply.sh`, soit de formaliser et créer l’issue avec `mail-create-issue-from-email.sh` (optionnel `--title` / `--body` formalisés). Si la demande est une correction/évolution prête : créer l’issue, traiter (fix/evol), commenter l’issue, répondre au mail via `mail-send-reply.sh` (avec `--in-reply-to` pour 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.
|
||
3. **Réponses aux mails** : toujours via le Bridge avec `mail-send-reply.sh`. Le `--body` doit ê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 avec `mail-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_TOKEN` ou `.secrets/gitea-issues/token`).
|
||
- Config IMAP/SMTP : copier `gitea-issues/imap-bridge.env.example` vers `.secrets/gitea-issues/imap-bridge.env`. Pour la boucle agent (optionnel) : `agent-loop.env.example` vers `.secrets/gitea-issues/agent-loop.env` (voir AGENT_LOOP.md). Renseigner `IMAP_USER`, `IMAP_PASSWORD` (et optionnellement `SMTP_*` 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 pages
|
||
- `GET /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 page
|
||
- `DELETE /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).
|