centralized

This commit is contained in:
Nicolas Cantu 2026-03-16 16:38:55 +01:00
parent 55f8588eba
commit c0fd688a0a
22 changed files with 100 additions and 71 deletions

View File

@ -17,11 +17,11 @@ Tu es l'agent qui **orchestre** la surveillance des mails et leur traitement. Tu
**Références obligatoires** : lire `projects/ia_dev/docs/GITEA_ISSUES_SCRIPTS_AGENTS.md` (contexte d'exécution). Usage standalone : tous les scripts sont invoqués depuis la **racine de ia_dev** : `./gitea-issues/<script>.sh`.
**Script agent-loop.sh** : intervalle en premier argument (ex. `./ia_dev/gitea-issues/agent-loop.sh 50` = 50 s). La boucle utilise le **spooler** (critère from/to dans conf.json), pas le statut IMAP « non lu ». Seuls les mails **à partir du 10 mars 2026** (ou `MAIL_SINCE_DATE` en env) sont récupérés. **Fichier témoin** `projects/<id>/logs/gitea-issues/agent-loop.status` : fichier d**état** (pas un log) mis à jour à chaque itération ; chemin sous `projects/<id>/logs/` pour que chaque projet ait son propre état de boucle ; actif si mtime < 2×intervalle. Fichier pending : `projects/<id>/logs/gitea-issues/agent-loop.pending` (chemins des .pending du spooler à traiter). Variables (optionnel `.secrets/gitea-issues/agent-loop.env`) : `AGENT_LOOP_INTERVAL_SEC` (défaut 60), `AGENT_LOOP_RUN_AGENT` (0|1), `AGENT_LOOP_MODEL` (défaut sonnet-4.6), `AGENT_LOOP_STATUS_FILE`, `AGENT_LOOP_PENDING_FILE`. Hook « remonter mails » : `.cursor/hooks/remonter-mails.sh` lit `projects/<id>/data/issues/*.pending` ou `agent-loop.pending`.
**Script agent-loop.sh** : intervalle en premier argument (ex. `./gitea-issues/agent-loop.sh 50` = 50 s). La boucle utilise le **spooler** (critère from/to dans conf.json), pas le statut IMAP « non lu ». Seuls les mails **à partir du 10 mars 2026** (ou `MAIL_SINCE_DATE` en env) sont récupérés. **Fichier témoin** `projects/<id>/logs/gitea-issues/agent-loop.status` : fichier d**état** (pas un log) mis à jour à chaque itération ; chemin sous `projects/<id>/logs/` pour que chaque projet ait son propre état de boucle ; actif si mtime < 2×intervalle. Fichier pending : `projects/<id>/logs/gitea-issues/agent-loop.pending` (chemins des .pending du spooler à traiter). Variables (optionnel `.secrets/gitea-issues/agent-loop.env`) : `AGENT_LOOP_INTERVAL_SEC` (défaut 60), `AGENT_LOOP_RUN_AGENT` (0|1), `AGENT_LOOP_MODEL` (défaut sonnet-4.6), `AGENT_LOOP_STATUS_FILE`, `AGENT_LOOP_PENDING_FILE`. Hook « remonter mails » : `.cursor/hooks/remonter-mails.sh` lit `projects/<id>/data/issues/*.pending` ou `agent-loop.pending`.
**Fichiers de contrôle (section 2 — boucle x cycles)** :
- **Lock (une seule instance)** : `projects/<id>/logs/gitea-issues/agent-loop.lock`. Utiliser les scripts : **agent-loop-lock-acquire.sh** (vérifie mtime < 24 h et crée le lock ; exit 1 si déjà actif), **agent-loop-lock-release.sh** (supprime lock et fichier stop).
- **Arrêt à la demande** : `projects/<id>/logs/gitea-issues/agent-loop.stop`. Au début de chaque cycle, exécuter **agent-loop-stop-requested.sh** (exit 0 si le fichier existe) ; si oui, lancer **agent-loop-lock-release.sh** et sortir. Pour demander l'arrêt : `cd <racine_projet> && ./ia_dev/gitea-issues/agent-loop-stop.sh` ou `touch projects/<id>/logs/gitea-issues/agent-loop.stop`.
- **Arrêt à la demande** : `projects/<id>/logs/gitea-issues/agent-loop.stop`. Au début de chaque cycle, exécuter **agent-loop-stop-requested.sh** (exit 0 si le fichier existe) ; si oui, lancer **agent-loop-lock-release.sh** et sortir. Pour demander l'arrêt : `Depuis la racine de ia_dev (MAIL_TO ou AI_AGENT_TOKEN défini) : ./gitea-issues/agent-loop-stop.sh` ou `touch projects/<id>/logs/gitea-issues/agent-loop.stop`.
---
@ -38,18 +38,18 @@ Si l'utilisateur demande explicitement « lancer les 2 boucles en arrière-plan
Si l'utilisateur demande de **lancer x fois** les deux sous-agents (une récupération puis un traitement, répété x fois) :
**Avant de commencer les x cycles** :
- Exécuter depuis la racine du dépôt : `cd .. && ./ia_dev/gitea-issues/agent-loop-lock-acquire.sh`.
- Exécuter depuis la racine du dépôt : `Depuis la racine de ia_dev : ./gitea-issues/agent-loop-lock-acquire.sh`.
- Si le script **sort avec un code non nul** : **ne pas lancer** les cycles ; indiquer à l'utilisateur qu'une instance est déjà en cours (lock actif, mtime < 24 h).
- Si le script sort 0 : le lock est acquis ; poursuivre.
- **À la fin** (normale ou après arrêt) : exécuter `cd .. && ./ia_dev/gitea-issues/agent-loop-lock-release.sh` (supprime le lock et le fichier stop s'il existe).
- **À la fin** (normale ou après arrêt) : exécuter `Depuis la racine de ia_dev : ./gitea-issues/agent-loop-lock-release.sh` (supprime le lock et le fichier stop s'il existe).
Pour chaque cycle `i` de 1 à x :
**Au début du cycle** (avant l'étape 1) : exécuter `cd .. && ./ia_dev/gitea-issues/agent-loop-stop-requested.sh`. Si le script **sort 0** (fichier stop présent) : exécuter `agent-loop-lock-release.sh`, puis **sortir** en indiquant que la boucle a été arrêtée à la demande.
**Au début du cycle** (avant l'étape 1) : exécuter `Depuis la racine de ia_dev : ./gitea-issues/agent-loop-stop-requested.sh`. Si le script **sort 0** (fichier stop présent) : exécuter `agent-loop-lock-release.sh`, puis **sortir** en indiquant que la boucle a été arrêtée à la demande.
1. **Récupération une fois** : exécuter depuis la racine de ia_dev :
```bash
cd .. && ./ia_dev/gitea-issues/agent-loop-retrieval-once.sh
Depuis la racine de ia_dev : ./gitea-issues/agent-loop-retrieval-once.sh
```
Ce script exécute `tickets-fetch-inbox.sh` puis `list-pending-spooler.sh` et écrit les chemins des .pending dans `projects/<id>/logs/gitea-issues/agent-loop.pending` (et met à jour le fichier témoin). Pas d'arrière-plan : attendre la fin du script.
@ -64,8 +64,8 @@ Répéter les étapes 1, 2 et 3 pour les x cycles demandés. Chaque cycle traite
## 3. Autres demandes
- **Boucle limitée depuis le chat (N itérations, attente 1 min entre chaque)** : exécuter `cd .. && ./ia_dev/gitea-issues/agent-loop-chat-iterations.sh [N] [--repeat]` (sans arrière-plan, pour éviter timeout). Par défaut N=3 ; `--repeat` pour relancer après N itérations.
- **Arrêter la boucle en cours (section 2)** : exécuter `cd <racine_projet> && ./ia_dev/gitea-issues/agent-loop-stop.sh`. Cela crée le fichier `agent-loop.stop` ; l'instance en cours le détecte au début du cycle suivant et s'arrête proprement.
- **Boucle limitée depuis le chat (N itérations, attente 1 min entre chaque)** : exécuter `Depuis la racine de ia_dev : ./gitea-issues/agent-loop-chat-iterations.sh [N] [--repeat]` (sans arrière-plan, pour éviter timeout). Par défaut N=3 ; `--repeat` pour relancer après N itérations.
- **Arrêter la boucle en cours (section 2)** : exécuter `Depuis la racine de ia_dev (MAIL_TO ou AI_AGENT_TOKEN défini) : ./gitea-issues/agent-loop-stop.sh`. Cela crée le fichier `agent-loop.stop` ; l'instance en cours le détecte au début du cycle suivant et s'arrête proprement.
- **Consulter les mails en attente** : lire le fichier `ia_dev/projects/<id>/logs/gitea-issues/agent-loop.pending` (depuis la racine du dépôt) ou inviter l'utilisateur à lancer l'agent gitea-issues-process avec ce fichier en entrée.
- **Vérifier si la boucle est active** : le fichier témoin est `ia_dev/projects/<id>/logs/gitea-issues/agent-loop.status` ; s'il a été modifié depuis moins de 2 × intervalle (ex. 120 s si intervalle 60 s), la boucle est considérée active.

View File

@ -20,12 +20,12 @@ is_background: false
1. **Vérifier la branche** : La machine doit être sur la branche **test** au démarrage. Si ce n'est pas le cas, indiquer à l'utilisateur de passer sur test (ou exécuter `git checkout test` depuis la racine projet) avant de continuer.
2. **Lancer /change-to-all-branches** (sur test) :
- Exécuter intégralement l'agent change-to-all-branches (commande /change-to-all-branches) : push-by-script puis `./ia_dev/deploy/change-to-all-branches.sh`.
- Exécuter intégralement l'agent change-to-all-branches (commande /change-to-all-branches) : push-by-script puis `./deploy/change-to-all-branches.sh`.
- **Si KO :** Analyser la sortie et les logs (logs/deploy_*.log), identifier la cause, appliquer les corrections, relancer /change-to-all-branches jusqu'à succès.
- **Si OK :** Passer à l'étape 3.
3. **Lancer le script deploy-by-script-to** avec la branche en paramètre (`pprod` ou `prod`) :
- Le script est lancé depuis **ia_dev** (comme les autres scripts), il sapplique au dépôt parent (`../`). Lancer depuis la racine de ia_dev : `./deploy/deploy-by-script-to.sh <pprod|prod>`. Le script utilise les chemins absolus de `projects/<id>/conf.json` pour le projet cible.
- Le script est lancé depuis la racine de ia_dev. Avec MAIL_TO ou AI_AGENT_TOKEN le dépôt cible est celui de la conf (deploy.secrets_path) ; sinon dépôt parent de ia_dev. Lancer : `./deploy/deploy-by-script-to.sh <pprod|prod>`.
- Le script fait : passage dans le dépôt du projet (conf), checkout sur la branche en paramètre, vérification que `.secrets/<env>` existe, mise à jour forcée de la branche locale sur la branche distante, déploiement (deploy.sh avec --import-v1 --skipSetupHost), checkout test.
- **Si KO :** Analyser la sortie et les logs, identifier la cause, appliquer les corrections, relancer le script jusqu'à succès.
- **Si OK :** Passer à l'étape 4.

View File

@ -39,12 +39,12 @@ Tu es l'agent qui traite les **tickets (issues) Gitea** du dépôt du projet cou
Exécuter depuis la racine de ia_dev : `./gitea-issues/list-open-issues.sh --lines`. Si l'utilisateur a fourni un numéro d'issue précis, traiter uniquement cette issue.
2. **Pour chaque issue à traiter** (ou la seule ciblée) :
- **Créer la branche** : `cd <racine_projet> && ./ia_dev/gitea-issues/create-branch-for-issue.sh <issue_number> [base]` (base par défaut : `test`). Ne pas inventer de commande git ; utiliser uniquement ce script.
- **Récupérer le contenu du ticket** : `cd <racine_projet> && ./ia_dev/gitea-issues/print-issue-prompt.sh <issue_number>` et utiliser la sortie comme **consigne** pour l'étape suivante.
- **Créer la branche** : `Depuis la racine de ia_dev (MAIL_TO ou AI_AGENT_TOKEN défini) : ./gitea-issues/create-branch-for-issue.sh <issue_number> [base]` (base par défaut : `test`). Ne pas inventer de commande git ; utiliser uniquement ce script.
- **Récupérer le contenu du ticket** : `Depuis la racine de ia_dev (MAIL_TO ou AI_AGENT_TOKEN défini) : ./gitea-issues/print-issue-prompt.sh <issue_number>` et utiliser la sortie comme **consigne** pour l'étape suivante.
- **Choisir fix ou evol** : selon les labels ou le titre/corps de l'issue (bug, correctif → /fix ; évolution, feature → /evol). En cas de doute, privilégier /evol.
- **Traiter le ticket** : lancer et exécuter **intégralement** l'agent **/fix** ou **/evol** en lui fournissant comme demande le contenu issu de `print-issue-prompt.sh` (titre + corps de l'issue).
- **Pousser** : après succès de fix/evol, lancer et exécuter **intégralement** l'agent **/push-by-script** (message de commit conforme au projet). Push direct sur la branche ; ne jamais créer de pull request.
- **Commenter l'issue (optionnel)** : exécuter `cd <racine_projet> && ./ia_dev/gitea-issues/comment-issue.sh <issue_number> "Traitement effectué dans la branche issue/<num>. Commit poussé."` (ou message adapté).
- **Commenter l'issue (optionnel)** : exécuter `Depuis la racine de ia_dev (MAIL_TO ou AI_AGENT_TOKEN défini) : ./gitea-issues/comment-issue.sh <issue_number> "Traitement effectué dans la branche issue/<num>. Commit poussé."` (ou message adapté).
3. **Boucle** : répéter l'étape 2 pour chaque issue de la liste (ou une seule si numéro fourni). Ne pas traiter en parallèle : une issue après l'autre.
@ -56,16 +56,16 @@ L'agent **ne fait pas** d'appels IMAP/SMTP ni de curl Gitea directs : il **invoq
**A. Spooler data/issues (prioritaire)** — Un seul fichier par message (`<base>.pending`). Le statut est dans le JSON (`status`: `pending` | `responded`). À traiter = fichiers dont `status` est `pending`.
- **Lister les mails à traiter** : exécuter `./ia_dev/gitea-issues/list-pending-spooler.sh`. Sortie = chemins des fichiers `projects/<id>/data/issues/<date>.<id>.<from>.pending` pour lesquels `status == "pending"`. Ne traiter **que** ces fichiers.
- **Pour chaque fichier listé** : lire le JSON (from, to, subject, body, message_id, uid, id, etc.). Le **base** est le nom du fichier sans `.pending` (ex. `2026-03-14T094530.a1b2c3d4.user_example.com`). Répondre uniquement si pertinent (demande d'info, évolution, etc.). Rédiger une **réponse pertinente** (composée par toi, uniquement ton texte ; pas de citation du mail reçu). Appeler `mail-send-reply.sh --to <from> --subject "Re: ..." --body "<ta réponse>" --in-reply-to "<message_id du JSON>"`. **Ne pas appeler** `mail-mark-read.sh` (inutile avec le spooler). Après envoi réussi : appeler `./ia_dev/gitea-issues/write-response-spooler.sh --base <base> --to <from> --subject "Re: ..." --body "<ta réponse>" --in-reply-to "<message_id>"`. Le script met à jour le **même** fichier (ajout de `response`, `status` = `responded`). Optionnel : `mail-thread-log.sh append-sent` pour tracer.
- **Lister les mails à traiter** : exécuter `./gitea-issues/list-pending-spooler.sh`. Sortie = chemins des fichiers `projects/<id>/data/issues/<date>.<id>.<from>.pending` pour lesquels `status == "pending"`. Ne traiter **que** ces fichiers.
- **Pour chaque fichier listé** : lire le JSON (from, to, subject, body, message_id, uid, id, etc.). Le **base** est le nom du fichier sans `.pending` (ex. `2026-03-14T094530.a1b2c3d4.user_example.com`). Répondre uniquement si pertinent (demande d'info, évolution, etc.). Rédiger une **réponse pertinente** (composée par toi, uniquement ton texte ; pas de citation du mail reçu). Appeler `mail-send-reply.sh --to <from> --subject "Re: ..." --body "<ta réponse>" --in-reply-to "<message_id du JSON>"`. **Ne pas appeler** `mail-mark-read.sh` (inutile avec le spooler). Après envoi réussi : appeler `./gitea-issues/write-response-spooler.sh --base <base> --to <from> --subject "Re: ..." --body "<ta réponse>" --in-reply-to "<message_id>"`. Le script met à jour le **même** fichier (ajout de `response`, `status` = `responded`). Optionnel : `mail-thread-log.sh append-sent` pour tracer.
**B. Legacy agent-loop.pending** — Mails « non lus » listés par `mail-list-unread.sh` (également limités à partir du 10 mars 2026 / `MAIL_SINCE_DATE`).
- **Lister** : exécuter `./ia_dev/gitea-issues/mail-list-unread.sh`. Pour chaque UID listé : `mail-get-thread.sh <uid>`, `mail-thread-log.sh init --uid <uid>`, rédiger réponse, `mail-send-reply.sh`, **puis** `mail-mark-read.sh <uid>` uniquement après succès de l'envoi, puis `mail-thread-log.sh append-sent`.
- **Lister** : exécuter `./gitea-issues/mail-list-unread.sh`. Pour chaque UID listé : `mail-get-thread.sh <uid>`, `mail-thread-log.sh init --uid <uid>`, rédiger réponse, `mail-send-reply.sh`, **puis** `mail-mark-read.sh <uid>` uniquement après succès de l'envoi, puis `mail-thread-log.sh append-sent`.
**Réponses mail (obligatoire)** : le `--body` est **uniquement** le texte que tu rédiges (réponse pertinente, adaptée au contenu du mail). Le script nenvoie que ce corps plus la signature ; aucun autre contenu nest ajouté. Ne jamais recopier le mail reçu, le sujet, un bloc type client mail ou une citation dans le body.
**Récupération mails (spooler data/issues)** : exécuter `cd <racine_projet> && ./ia_dev/gitea-issues/tickets-fetch-inbox.sh` pour récupérer les mails filtrés par `tickets.authorized_emails` (conf.json) et les écrire en `projects/<id>/data/issues/*.pending` (JSON). Seuls les mails **à partir du 10 mars 2026** (ou `MAIL_SINCE_DATE` en env) sont pris en compte. Pas de marquage lu/non lu. **Boucle legacy (non lu)** : si l'utilisateur demande « Lance la boucle récupération emails… N itérations », exécuter `./ia_dev/gitea-issues/agent-loop-chat-iterations.sh [N] [--repeat]`. Mails en attente : **projects/<id>/data/issues/*.pending** (prioritaire) ou `projects/<id>/logs/gitea-issues/agent-loop.pending` ; les traiter selon le workflow ci-dessus.
**Récupération mails (spooler data/issues)** : exécuter `Depuis la racine de ia_dev (MAIL_TO ou AI_AGENT_TOKEN défini) : ./gitea-issues/tickets-fetch-inbox.sh` pour récupérer les mails filtrés par `tickets.authorized_emails` (conf.json) et les écrire en `projects/<id>/data/issues/*.pending` (JSON). Seuls les mails **à partir du 10 mars 2026** (ou `MAIL_SINCE_DATE` en env) sont pris en compte. Pas de marquage lu/non lu. **Boucle legacy (non lu)** : si l'utilisateur demande « Lance la boucle récupération emails… N itérations », exécuter `./gitea-issues/agent-loop-chat-iterations.sh [N] [--repeat]`. Mails en attente : **projects/<id>/data/issues/*.pending** (prioritaire) ou `projects/<id>/logs/gitea-issues/agent-loop.pending` ; les traiter selon le workflow ci-dessus.
**Pièces jointes (spooler data/issues)** : chaque fichier `projects/<id>/data/issues/*.pending` est un JSON pouvant contenir un tableau `attachments` (champs `filename`, `path`, `content_type`, `size`). Les fichiers sont stockés sous `projects/<id>/data/issues/<base>.d/` (`<base>` = `<date>.<id>.<from>`) ; `path` est relatif à `data/issues/`. Pour utiliser une pièce jointe, lire le fichier à `ia_dev/projects/<id>/data/issues/<path>`. Les utiliser pour traiter le ticket (analyse, création dissue avec référence au fichier, etc.) sans les supprimer.

View File

@ -25,12 +25,12 @@ Pour chaque cycle `i` de 1 à x :
1. **Lister les pending**
Exécuter depuis la racine du dépôt (depuis ia_dev : `cd ..`) :
`cd .. && ./ia_dev/ai_working_help/notary-ai/list-pending-notary-ai.sh`
`Depuis la racine de ia_dev : ./ai_working_help/notary-ai/list-pending-notary-ai.sh`
Sortie : un chemin par ligne (fichiers dans `projects/<slug>/data/notary-ai/pending/`).
2. **Traitement une fois**
Si la sortie est **non vide** : lancer **intégralement** l'agent **notary-ai-process** avec un prompt du type :
« Traite les questions IA notaire en attente : exécute `./ia_dev/ai_working_help/notary-ai/list-pending-notary-ai.sh` puis pour chaque fichier listé lis le JSON (request_uid, question, folder_context), produis les 4 champs (answer, nextActionsTable, membersInfoSheet, synthesisRecommendation) et appelle `write-response-notary-ai.sh --request-uid <uid> --answer "..." --next-actions-table "..." --members-info-sheet "..." --synthesis-recommendation "..."`. »
« Traite les questions IA notaire en attente : exécute `./ai_working_help/notary-ai/list-pending-notary-ai.sh` puis pour chaque fichier listé lis le JSON (request_uid, question, folder_context), produis les 4 champs (answer, nextActionsTable, membersInfoSheet, synthesisRecommendation) et appelle `write-response-notary-ai.sh --request-uid <uid> --answer "..." --next-actions-table "..." --members-info-sheet "..." --synthesis-recommendation "..."`. »
Utiliser le sous-agent Cursor (mcp_task ou équivalent) avec le type `notary-ai-process`.
Si la sortie est **vide**, ne pas lancer l'agent ; passer à l'étape 3.
@ -45,7 +45,7 @@ Répéter les étapes 1 à 3 pour les x cycles.
Si l'utilisateur demande de **traiter une fois** les questions en attente (sans boucle) :
- Exécuter `cd .. && ./ia_dev/ai_working_help/notary-ai/list-pending-notary-ai.sh`.
- Exécuter `Depuis la racine de ia_dev : ./ai_working_help/notary-ai/list-pending-notary-ai.sh`.
- Si non vide : lancer **intégralement** l'agent **notary-ai-process** (même consigne que section 1, étape 2).
- Si vide : indiquer qu'il n'y a rien à traiter.
@ -53,7 +53,7 @@ Si l'utilisateur demande de **traiter une fois** les questions en attente (sans
## 3. Autres demandes
- **Consulter les pending** : exécuter `cd .. && ./ia_dev/ai_working_help/notary-ai/list-pending-notary-ai.sh` et afficher les chemins (ou le contenu dun fichier pour vérification).
- **Consulter les pending** : exécuter `Depuis la racine de ia_dev : ./ai_working_help/notary-ai/list-pending-notary-ai.sh` et afficher les chemins (ou le contenu dun fichier pour vérification).
- **Documentation** : `ia_dev/ai_working_help/docs/notary-ai-api.md` (API, spooler, scripts). Agent de traitement : `.cursor/agents/notary-ai-process.md`.
---

View File

@ -22,14 +22,14 @@ Tu es l'agent qui traite les **questions IA notaire** en attente dans le spooler
## Prérequis
- Exécution depuis la **racine du dépôt** (parent de ia_dev) : `cd <racine_projet> && ./ia_dev/ai_working_help/notary-ai/list-pending-notary-ai.sh`, etc.
- Exécution depuis la **racine de ia_dev** (MAIL_TO ou AI_AGENT_TOKEN défini) : `Depuis la racine de ia_dev (MAIL_TO ou AI_AGENT_TOKEN défini) : ./ai_working_help/notary-ai/list-pending-notary-ai.sh`, etc.
- **jq** installé (les scripts l'utilisent).
- Id projet résolu **uniquement** par `MAIL_TO` ou `AI_AGENT_TOKEN` (voir `projects/README.md`).
## Workflow
1. **Lister les pending**
Exécuter : `cd <racine_projet> && ./ia_dev/ai_working_help/notary-ai/list-pending-notary-ai.sh`
Exécuter : `Depuis la racine de ia_dev (MAIL_TO ou AI_AGENT_TOKEN défini) : ./ai_working_help/notary-ai/list-pending-notary-ai.sh`
Sortie : un chemin par ligne (fichiers JSON dans `projects/<slug>/data/notary-ai/pending/`). Si vide, ne rien faire.
2. **Pour chaque fichier listé**
@ -40,7 +40,7 @@ Tu es l'agent qui traite les **questions IA notaire** en attente dans le spooler
- **membersInfoSheet** : **fiche d'information** sur les membres du dossier (infos collectées, rôles, noms).
- **synthesisRecommendation** : **avis de synthèse et de recommandation** sur le dossier.
- Appeler le script d'écriture :
`./ia_dev/ai_working_help/notary-ai/write-response-notary-ai.sh --request-uid <request_uid> --answer "..." --next-actions-table "..." --members-info-sheet "..." --synthesis-recommendation "..."`
`./ai_working_help/notary-ai/write-response-notary-ai.sh --request-uid <request_uid> --answer "..." --next-actions-table "..." --members-info-sheet "..." --synthesis-recommendation "..."`
(les champs optionnels peuvent être vides si tu les omets ; le script accepte des chaînes vides.)
3. **Boucle**

View File

@ -1,19 +1,19 @@
# ia_dev
Dépôt de pilotage par lIA pour les projets : **équipe dagents IA** dont le code et les définitions sont dans ia_dev, lancés de façon centralisée pour tous les projets configurés (lecoffreio, enso, algo, etc.) ; ils agissent sur ces projets, pas sur ia_dev. Objectif : une équipe autonome couvrant la **documentation**, le **code** (correctifs, évolutions), le **ticketing** (issues Gitea, mails), le **devops** (push, déploiement, branches), la **sécurité** et la **qualité** (lint, règles).
Dépôt de pilotage par l'IA pour les projets : **équipe d'agents IA** dont le code et les définitions sont dans ia_dev, lancés de façon centralisée pour tous les projets configurés (lecoffreio, enso, algo, etc.) ; ils agissent sur ces projets, pas sur ia_dev. Objectif : une équipe autonome couvrant la **documentation**, le **code** (correctifs, évolutions), le **ticketing** (issues Gitea, mails), le **devops** (push, déploiement, branches), la **sécurité** et la **qualité** (lint, règles).
**Principe** : ia_dev est un **dépôt autonome** (usage unique : standalone). La config par projet est dans `projects/<id>/conf.json` ; lid projet est résolu par **MAIL_TO** (adresse « to » des mails) ou **AI_AGENT_TOKEN** (token des requêtes). Voir `projects/README.md`.
**Principe** : ia_dev est un **dépôt autonome** (usage unique : standalone). La config par projet est dans `projects/<id>/conf.json` ; l'id projet est résolu par **MAIL_TO** (adresse « to » des mails) ou **AI_AGENT_TOKEN** (token des requêtes). Voir `projects/README.md`.
## Usage (standalone)
- **Racine dexécution** : tous les scripts sont lancés depuis la **racine de ia_dev** (ce dépôt). Variable optionnelle : `IA_PROJECT` pour forcer lid projet.
- **Racine d'exécution** : tous les scripts sont lancés depuis la **racine de ia_dev** (ce dépôt). L'id projet est résolu uniquement par **MAIL_TO** ou **AI_AGENT_TOKEN** (voir `projects/README.md`).
- **Config** : dans `projects/<id>/conf.json`, les champs `project_path`, `build_dirs`, `deploy.scripts_path`, `deploy.deploy_script_path`, `deploy.secrets_path`, `version.package_json_paths` sont des **chemins absolus** (vers les dépôts des projets). Les champs `mail.imap_bridge_env` et `git.token_file` sont **relatifs à la racine de ia_dev**. Le répertoire `.secrets` à la racine de ia_dev contient `token` et `gitea-issues/agent-loop.env`, `gitea-issues/imap-bridge.env`.
Voir `projects/README.md` pour le schéma de configuration et les exemples.
## Agents et domaines
Les **agents** ont leur **code et définitions** dans ia_dev (`.cursor/agents/`, `.cursor/rules/`) et sont **lancés de façon centralisée** depuis ce dépôt pour **tous les projets**. Ils sont **dédiés aux projets configurés** (lecoffreio, enso, algo, etc.) : ils agissent sur ces projets (doc, code, déploiement, ticketing), pas sur ia_dev. ia_dev est uniquement le projet qui porte leurs définitions et doù on les invoque.
Les **agents** ont leur **code et définitions** dans ia_dev (`.cursor/agents/`, `.cursor/rules/`) et sont **lancés de façon centralisée** depuis ce dépôt pour **tous les projets**. Ils sont **dédiés aux projets configurés** (lecoffreio, enso, algo, etc.) : ils agissent sur ces projets (doc, code, déploiement, ticketing), pas sur ia_dev. ia_dev est uniquement le projet qui porte leurs définitions et d'où on les invoque.
Chaque agent indique où se trouve la doc : **projets gérés**`projects/<id>/docs` ; **ia_dev**`projects/ia_dev/docs`.
@ -28,7 +28,7 @@ Chaque agent indique où se trouve la doc : **projets gérés** → `projects/<i
Référence détaillée scripts et agents : `projects/ia_dev/docs/GITEA_ISSUES_SCRIPTS_AGENTS.md`. Index de la doc ia_dev : `projects/ia_dev/docs/README.md`.
## Répertoire dexécution (standalone)
## Répertoire d'exécution (standalone)
Tous les scripts sont invoqués depuis la **racine de ia_dev** (ce dépôt).
@ -42,4 +42,4 @@ Les scripts dans `deploy/` **déploient et versionnent les projets configurés**
- **bump-version.sh** : lit `projects/<id>/conf.json` (version.package_json_paths, version.splash_app_name) et met à jour VERSION + package.json du **projet configuré**. Invocation : `./deploy/bump-version.sh <version> [message]` depuis la racine de ia_dev.
- **deploy-by-script-to.sh** : checkout branche cible (pprod|prod), sync origin, exécute `deploy/scripts_v2/deploy.sh` du **projet configuré** (chemin dans conf), puis revient sur test.
- **deploy/_lib/** : bibliothèque partagée pour les scripts de déploiement. Les `deploy/scripts_v2/` de chaque projet peuvent sy lier (symlink) pour réutiliser cette lib.
- **deploy/_lib/** : bibliothèque partagée pour les scripts de déploiement. Les `deploy/scripts_v2/` de chaque projet peuvent s'y lier (symlink) pour réutiliser cette lib.

View File

@ -39,17 +39,17 @@
- **GET /v1/health** et **GET /health** : santé du service (sans authentification).
Lancement : depuis **ia_dev** : `cd ia_dev && node ai_working_help/server.js`. Port par défaut : **3020** (`AI_WORKING_HELP_PORT`).
Lancement : depuis la racine de ia_dev : `node ai_working_help/server.js`. Port par défaut : **3020** (`AI_WORKING_HELP_PORT`).
## Configuration côté application déployée
- **NOTARY_AI_AGENT_URL** : URL de base **sans** slug, sans slash final, ex. : `http://192.168.1.173:3020/v1`. Le backend ajoute `/enqueue` et `/response/:request_uid`.
- **NOTARY_AI_AGENT_TOKEN** : le token envoyé par lapp est de la forme **base** + **env**. **env** est le nom denvironnement (test, pprod, prod), à modifier selon les environnements. Côté ia_dev, ce token est trouvé en parcourant tous les projets et tous les envs (fichiers `projects/<id>/.secrets/<env>/ia_token`) ; le fichier peut contenir le token complet (ex. `nicolecoffreiotest`) ou la base seule (ex. `nicolecoffreio`), le serveur comparant alors le Bearer à `contenu_du_fichier + env`.
## Scripts (depuis la racine du dépôt, parent de ia_dev)
## Scripts (depuis la racine de ia_dev, MAIL_TO ou AI_AGENT_TOKEN défini)
- **./ia_dev/ai_working_help/notary-ai/list-pending-notary-ai.sh** : liste les fichiers `projects/<id>/data/notary-ai/pending/*.json` (id résolu par MAIL_TO ou AI_AGENT_TOKEN).
- **./ia_dev/ai_working_help/notary-ai/write-response-notary-ai.sh** : écrit la réponse dans responded/, supprime le pending.
- **./ai_working_help/notary-ai/list-pending-notary-ai.sh** : liste les fichiers `projects/<id>/data/notary-ai/pending/*.json` (id résolu par MAIL_TO ou AI_AGENT_TOKEN).
- **./ai_working_help/notary-ai/write-response-notary-ai.sh** : écrit la réponse dans responded/, supprime le pending.
Options : `--pending-path <path> --response-json <json>` ou `--request-uid <uid> --answer "..." [--next-actions-table "..." ] [--members-info-sheet "..."] [--synthesis-recommendation "..."]`.
## Agents Cursor
@ -57,4 +57,4 @@ Lancement : depuis **ia_dev** : `cd ia_dev && node ai_working_help/server.js`. P
- **notary-ai-loop** (`.cursor/agents/notary-ai-loop.md`) : orchestre la boucle (liste pending, lance notary-ai-process ; x cycles ou une fois).
- **notary-ai-process** (`.cursor/agents/notary-ai-process.md`) : pour chaque pending, produit les 4 champs et appelle write-response-notary-ai.sh.
Les agents sont dans **ia_dev/.cursor/agents/**. À invoquer depuis le dépôt qui contient ia_dev (racine = parent de ia_dev) ; les scripts s'exécutent depuis cette racine.
Les agents sont dans **.cursor/agents/**. À invoquer depuis la racine de ia_dev ; les scripts s'exécutent depuis la racine de ia_dev.

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash
# List pending JSON files in projects/<slug>/data/notary-ai/pending/.
# Run from repo root (parent of ia_dev). Output: one path per line.
# Usage: ./ia_dev/ai_working_help/notary-ai/list-pending-notary-ai.sh
# Usage: depuis la racine de ia_dev (MAIL_TO ou AI_AGENT_TOKEN défini) : ./ai_working_help/notary-ai/list-pending-notary-ai.sh
set -euo pipefail
NOTARY_AI_DIR="${NOTARY_AI_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
export NOTARY_AI_DIR

View File

@ -1,12 +1,23 @@
#!/usr/bin/env bash
# deploy-by-script-to <target_branch>: checkout target, verify .secrets/<env>, force sync with origin, deploy target, checkout test.
# Launched from ia_dev (like other deploy scripts); applies to parent repo (../). Call after /change-to-all-branches (agent). Target: pprod | prod only.
# Launched from ia_dev root. Project root from projects/<id>/conf.json when MAIL_TO or AI_AGENT_TOKEN set; else parent of ia_dev. Target: pprod | prod only.
set -euo pipefail
SCRIPT_REAL="$(readlink -f "${BASH_SOURCE[0]:-$0}" 2>/dev/null || realpath "${BASH_SOURCE[0]:-$0}" 2>/dev/null || echo "${BASH_SOURCE[0]:-$0}")"
DEPLOY_IA="$(cd "$(dirname "$SCRIPT_REAL")" && pwd)"
# Parent of ia_dev = project root (deploy applies to ../)
PROJECT_ROOT="$(cd "$DEPLOY_IA/../.." && pwd)"
IA_DEV_ROOT="$(cd "$DEPLOY_IA/.." && pwd)"
# shellcheck source=../lib/project_config.sh
source "${IA_DEV_ROOT}/lib/project_config.sh"
PROJECT_ROOT=""
if [[ -n "${PROJECT_SLUG:-}" && -f "${PROJECT_CONFIG_PATH:-}" ]] && command -v jq >/dev/null 2>&1; then
_secrets_path="$(jq -r '.deploy.secrets_path // ""' "$PROJECT_CONFIG_PATH" 2>/dev/null)"
if [[ -n "$_secrets_path" ]]; then
PROJECT_ROOT="$(dirname "$_secrets_path")"
fi
fi
if [[ -z "$PROJECT_ROOT" || ! -d "$PROJECT_ROOT" ]]; then
PROJECT_ROOT="$(cd "$DEPLOY_IA/../.." && pwd)"
fi
if [[ "$(pwd)" != "$PROJECT_ROOT" ]]; then
cd "$PROJECT_ROOT" && exec "$SCRIPT_REAL" "$@"
fi
@ -50,7 +61,12 @@ git fetch origin
git reset --hard "origin/${TARGET_BRANCH}"
echo "[deploy-by-script-to] Step 4/5: deploy ${TARGET_BRANCH} (--import-v1 --skipSetupHost)..."
"$PROJECT_ROOT/deploy/scripts_v2/deploy.sh" "$TARGET_BRANCH" --import-v1 --skipSetupHost
deploy_script="$PROJECT_ROOT/deploy/scripts_v2/deploy.sh"
if [[ -n "${PROJECT_CONFIG_PATH:-}" && -f "${PROJECT_CONFIG_PATH:-}" ]] && command -v jq >/dev/null 2>&1; then
_cfg_script="$(jq -r '.deploy.deploy_script_path // ""' "$PROJECT_CONFIG_PATH" 2>/dev/null)"
[[ -n "$_cfg_script" && -x "$_cfg_script" ]] && deploy_script="$_cfg_script"
fi
"$deploy_script" "$TARGET_BRANCH" --import-v1 --skipSetupHost
echo "[deploy-by-script-to] Step 5/5: checkout test..."
git checkout test

View File

@ -82,19 +82,31 @@ while [[ $# -gt 0 ]]; do
esac
done
repo_root="$(git rev-parse --show-toplevel)"
# When run from ia_dev root, use configured project repo for git operations (MAIL_TO or AI_AGENT_TOKEN must be set)
git_work_root="$repo_root"
if [[ -n "${PROJECT_CONFIG_PATH:-}" && -f "$PROJECT_CONFIG_PATH" ]] && command -v jq >/dev/null 2>&1 && [[ "$repo_root" == "$IA_DEV_ROOT" ]]; then
_secrets_path="$(jq -r '.deploy.secrets_path // ""' "$PROJECT_CONFIG_PATH" 2>/dev/null)"
if [[ -n "$_secrets_path" ]]; then
_gwr="$(dirname "$_secrets_path")"
if [[ -d "$_gwr" ]]; then
git_work_root="$_gwr"
fi
fi
fi
if [[ "$(pwd)" != "$git_work_root" ]]; then
cd "$git_work_root" || { echo "[pousse][ERROR] Cannot cd to project root ${git_work_root}" >&2; exit 1; }
fi
branch="$(git rev-parse --abbrev-ref HEAD)"
if [[ -z "$branch" || "$branch" == "HEAD" ]]; then
echo "[pousse][ERROR] Detached HEAD is not supported" >&2
exit 1
fi
author_name="$(git config user.name || true)"
if [[ "$author_name" != "4NK" && "$author_name" != "Nicolas Cantu" ]]; then
echo "[pousse][ERROR] Refusing to commit: git user.name must be '4NK' or 'Nicolas Cantu' (got: '${author_name}')" >&2
exit 1
fi
repo_root="$(git rev-parse --show-toplevel)"
# Build dirs from project config (projects/<id>/conf.json); skip if no config or no build_dirs
build_dirs=()
if [[ -n "${PROJECT_CONFIG_PATH:-}" && -f "$PROJECT_CONFIG_PATH" ]] && command -v jq >/dev/null 2>&1; then
@ -138,7 +150,7 @@ if [[ ! -s "$msg_file" ]]; then
fi
if [[ "$bump_version" == "true" ]]; then
version_file="${repo_root}/VERSION"
version_file="${git_work_root}/VERSION"
if [[ ! -f "$version_file" ]]; then
echo "[pousse][ERROR] VERSION not found at ${version_file}" >&2
exit 1

View File

@ -3,7 +3,7 @@
# Run from repo root. Used by agent-loop agent before starting x cycles (section 2).
#
# Usage:
# cd <racine_projet> && ./ia_dev/gitea-issues/agent-loop-lock-acquire.sh
# Depuis la racine de ia_dev : ./gitea-issues/agent-loop-lock-acquire.sh
#
set -euo pipefail
if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then

View File

@ -3,7 +3,7 @@
# Run from repo root.
#
# Usage:
# cd <racine_projet> && ./ia_dev/gitea-issues/agent-loop-lock-release.sh
# Depuis la racine de ia_dev : ./gitea-issues/agent-loop-lock-release.sh
#
set -euo pipefail
if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then

View File

@ -3,7 +3,7 @@
# Run from repo root. Used by agent-loop agent for "x times" cycles. Criterion: from/to in conf.json, not IMAP unread.
#
# Usage:
# cd <racine_projet> && ./ia_dev/gitea-issues/agent-loop-retrieval-once.sh
# Depuis la racine de ia_dev : ./gitea-issues/agent-loop-retrieval-once.sh
#
set -euo pipefail
if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then

View File

@ -3,7 +3,7 @@
# Run from repo root.
#
# Usage:
# cd <racine_projet> && ./ia_dev/gitea-issues/agent-loop-stop-requested.sh
# Depuis la racine de ia_dev : ./gitea-issues/agent-loop-stop-requested.sh
#
set -euo pipefail
if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then

View File

@ -3,7 +3,7 @@
# Run from repo root. Same paths as agent-loop-retrieval-once.sh (projects/<id>/logs/gitea-issues).
#
# Usage:
# cd <racine_projet> && ./ia_dev/gitea-issues/agent-loop-stop.sh
# Depuis la racine de ia_dev : ./gitea-issues/agent-loop-stop.sh
#
set -euo pipefail
if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then

View File

@ -3,7 +3,7 @@
# Run from repo root. No timeout; runs forever. Do NOT start this script from the agent-loop agent (use bounded runs only).
#
# Usage (manual only; agent must not launch with nohup/&):
# cd <racine_projet> && ./ia_dev/gitea-issues/agent-loop-treatment.sh
# Depuis la racine de ia_dev : ./gitea-issues/agent-loop-treatment.sh
#
set -euo pipefail
if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then
@ -37,7 +37,7 @@ fi
INTERVAL="${AGENT_LOOP_TREATMENT_INTERVAL_SEC:-60}"
AGENT_MODEL="${AGENT_LOOP_MODEL:-sonnet-4.6}"
PROMPT="Exécute le workflow mails du spooler (agent gitea-issues-process). Les chemins des fichiers .pending sont dans projects/<id>/logs/gitea-issues/agent-loop.pending (ou exécuter ./ia_dev/gitea-issues/list-pending-spooler.sh). Pour chaque fichier .pending : lire le JSON (from, to, subject, body, message_id, base). Rédiger une réponse pertinente (uniquement ton texte ; pas de citation — mail-send-reply.sh refuse si le body contient From:, Message-ID, wrote:, etc.). Envoyer avec ./ia_dev/gitea-issues/mail-send-reply.sh --to <from> --subject \"Re: ...\" --body \"<ta_réponse>\" --in-reply-to \"<message_id>\". Après envoi réussi : ./ia_dev/gitea-issues/write-response-spooler.sh --base <base> --to <from> --subject \"Re: ...\" --body \"<ta_réponse>\" --in-reply-to \"<message_id>\". Ne pas appeler mail-mark-read.sh (spooler)."
PROMPT="Exécute le workflow mails du spooler (agent gitea-issues-process). Les chemins des fichiers .pending sont dans projects/<id>/logs/gitea-issues/agent-loop.pending (ou exécuter ./gitea-issues/list-pending-spooler.sh). Pour chaque fichier .pending : lire le JSON (from, to, subject, body, message_id, base). Rédiger une réponse pertinente (uniquement ton texte ; pas de citation — mail-send-reply.sh refuse si le body contient From:, Message-ID, wrote:, etc.). Envoyer avec ./gitea-issues/mail-send-reply.sh --to <from> --subject \"Re: ...\" --body \"<ta_réponse>\" --in-reply-to \"<message_id>\". Après envoi réussi : ./gitea-issues/write-response-spooler.sh --base <base> --to <from> --subject \"Re: ...\" --body \"<ta_réponse>\" --in-reply-to \"<message_id>\". Ne pas appeler mail-mark-read.sh (spooler)."
while true; do
if [ -s "$PENDING_FILE" ] && command -v agent >/dev/null 2>&1; then

View File

@ -73,7 +73,7 @@ while true; do
echo "[agent-loop] $(date -Iseconds) — Lancement de l'agent Cursor (workflow gitea-issues-process spooler)."
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 du spooler (agent gitea-issues-process). 1) Lister les mails à traiter avec ./ia_dev/gitea-issues/list-pending-spooler.sh (ou utiliser les chemins dans agent-loop.pending). 2) Pour chaque fichier .pending : lire le JSON (from, to, subject, body, message_id, base). Rédiger une réponse pertinente (uniquement ton texte, pas de citation ; mail-send-reply.sh refuse si le body contient From:, Message-ID, wrote:, etc.). Envoyer avec ./ia_dev/gitea-issues/mail-send-reply.sh --to <from> --subject \"Re: ...\" --body \"<ta_réponse>\" --in-reply-to \"<message_id>\". Après envoi réussi : ./ia_dev/gitea-issues/write-response-spooler.sh --base <base> --to <from> --subject \"Re: ...\" --body \"<ta_réponse>\" --in-reply-to \"<message_id>\". Ne pas appeler mail-mark-read.sh (spooler)." -f --model "$AGENT_MODEL")
AGENT_OPTS=(-p "Exécute le workflow mails du spooler (agent gitea-issues-process). 1) Lister les mails à traiter avec ./gitea-issues/list-pending-spooler.sh (ou utiliser les chemins dans agent-loop.pending). 2) Pour chaque fichier .pending : lire le JSON (from, to, subject, body, message_id, base). Rédiger une réponse pertinente (uniquement ton texte, pas de citation ; mail-send-reply.sh refuse si le body contient From:, Message-ID, wrote:, etc.). Envoyer avec ./gitea-issues/mail-send-reply.sh --to <from> --subject \"Re: ...\" --body \"<ta_réponse>\" --in-reply-to \"<message_id>\". Après envoi réussi : ./gitea-issues/write-response-spooler.sh --base <base> --to <from> --subject \"Re: ...\" --body \"<ta_réponse>\" --in-reply-to \"<message_id>\". Ne pas appeler mail-mark-read.sh (spooler)." -f --model "$AGENT_MODEL")
if agent "${AGENT_OPTS[@]}" 2>&1; then
write_status "agent_done" "Agent terminé."
else

View File

@ -2,7 +2,7 @@
# List .pending files in projects/<id>/data/issues/ with status "pending" (one file per message; status updated in place).
# Run from repo root. If PROJECT_SLUG is set (from MAIL_TO or AI_AGENT_TOKEN), list that project only; else list all projects.
# Output: one path per line.
# Usage: ./ia_dev/gitea-issues/list-pending-spooler.sh
# Usage: depuis la racine de ia_dev : ./gitea-issues/list-pending-spooler.sh
set -euo pipefail
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
ROOT="$(cd "${GITEA_ISSUES_DIR}/../.." && pwd)"

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash
# Fetch inbox messages filtered by tickets.authorized_emails (conf.json). No UNSEEN; no mark read.
# Writes new messages to projects/<id>/data/issues/ as JSON (<date>.<id>.<from>.pending).
# Usage: cd <racine_projet> && ./ia_dev/gitea-issues/tickets-fetch-inbox.sh
# Usage: depuis la racine de ia_dev (MAIL_TO ou AI_AGENT_TOKEN défini) : ./gitea-issues/tickets-fetch-inbox.sh
set -euo pipefail
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash
# Update the single spooler file (.pending) after sending a reply via mail-send-reply.sh. One file per message.
# Usage: ./ia_dev/gitea-issues/write-response-spooler.sh --base <base> --to <addr> --subject "..." --body "..." [--in-reply-to "<msg-id>"]
# Usage: depuis la racine de ia_dev : ./gitea-issues/write-response-spooler.sh --base <base> --to <addr> --subject "..." --body "..." [--in-reply-to "<msg-id>"]
set -euo pipefail
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
export GITEA_ISSUES_DIR

View File

@ -3,7 +3,7 @@
This repo (`ia_dev`) is a **standalone** depot. Project-specific parameters are stored in `projects/<id>/conf.json` (e.g. `projects/lecoffreio/conf.json`). The `<id>` is the project identifier (directory name under `projects/`).
**Paths in conf.json:**
The scripts in `ia_dev/deploy/` deploy and build the **configured projects** (lecoffreio, enso, algo, etc.) in their own directories; they do not deploy ia_dev.
The scripts in `deploy/` deploy and build the **configured projects** (lecoffreio, enso, algo, etc.) in their own directories; they do not deploy ia_dev.
- **Absolute** (required): `project_path`, `build_dirs`, `deploy.scripts_path`, `deploy.deploy_script_path`, `deploy.secrets_path`, `version.package_json_paths` — they point to each project repo.
- **Relative to ia_dev root** (this project): `mail.imap_bridge_env`, `git.token_file`. They point to files under ia_devs own `.secrets/`.
@ -28,7 +28,8 @@ One JSON file per project: `projects/<id>/conf.json` (e.g. `projects/lecoffreio/
| Field | Required | Description |
|-------|----------|-------------|
| `name` | yes | Human-readable project name |
| `id` | no | Project identifier (directory name under `projects/`); default: directory name. |
| `name` | no | Human-readable project name. |
| `project_path` | no | **Absolute** path to the project deploy root (e.g. `/home/desk/code/lecoffre_ng_test/deploy`). |
| `build_dirs` | no | **Absolute** paths to directories where `npm run build` is run. |
| `deploy.scripts_path` | no | **Absolute** path to deploy scripts (e.g. `…/deploy/scripts_v2`). |
@ -41,7 +42,7 @@ One JSON file per project: `projects/<id>/conf.json` (e.g. `projects/lecoffreio/
| `version` | no | Version/bump configuration; `version.splash_app_name` for splash message template |
| `mail` | no | Mail/imap bridge config; `mail.imap_bridge_env` relative to ia_dev root |
| `git` | no | Git hosting: `wiki_url`, `git.token_file` (relative to ia_dev root). Ticketing URL is under `tickets`, not `git`. |
| `tickets` | no | Ticketing: `ticketing_url` (Gitea issues URL), `authorized_emails` (`to`: alias or list of env-keyed objects, `from`: list of allowed sender addresses). **to** resolves the project id when processing mails. See projects/ia_dev/docs/TICKETS_SPOOL_FORMAT.md. |
| `tickets` | no | Ticketing: `ticketing_url` (Gitea issues URL), `authorized_emails` (`to`, `from`). **to** resolves the project id when processing mails; format: string (single address) or list of strings or list of objects keyed by env (e.g. `[{ "test": "AI.X.TEST@…", "pprod": "…", "prod": "…" }]`). **from**: list of allowed sender addresses. See projects/ia_dev/docs/TICKETS_SPOOL_FORMAT.md. |
**.secrets at ia_dev root** (this repo): contains `token` and `gitea-issues/agent-loop.env`, `gitea-issues/imap-bridge.env`. The paths `mail.imap_bridge_env` and `git.token_file` in conf are relative to ia_dev root and point to these files.

View File

@ -27,7 +27,7 @@ L'agent ne doit **jamais accéder ni modifier** :
| **agent-loop** | `agent-loop.md` | Orchestre la boucle de récupération des mails et le traitement par **exécutions délimitées** uniquement (N itérations ou x cycles) ; ne lance jamais de processus en arrière-plan (nohup/&). |
| **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 : `projects/ia_dev/docs/TICKETS_SPOOL_FORMAT.md`. Récupération : `./ia_dev/gitea-issues/tickets-fetch-inbox.sh`. Référence boucle mails (legacy) : `.cursor/agents/agent-loop.md`. Hook Cursor : `sessionStart``.cursor/hooks/remonter-mails.sh` (lit `projects/<id>/data/issues/*.pending`).
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 : `projects/ia_dev/docs/TICKETS_SPOOL_FORMAT.md`. Récupération : `./gitea-issues/tickets-fetch-inbox.sh`. Référence boucle mails (legacy) : `.cursor/agents/agent-loop.md`. Hook Cursor : `sessionStart``.cursor/hooks/remonter-mails.sh` (lit `projects/<id>/data/issues/*.pending`).
## Contexte d'exécution
@ -57,17 +57,17 @@ Spooler tickets (nouveau) : mails dans **projects/<id>/data/issues/** (filtre pa
| `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 cidessous). |
| `agent-loop.sh` | `./ia_dev/gitea-issues/agent-loop.sh [interval_sec]` | **Boucle de surveillance** : tourne indéfiniment (spooler ou legacy). **Ne pas lancer depuis l'agent** ; utiliser agent-loop-chat-iterations.sh ou cycles délimités. Voir `.cursor/agents/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. Tourne indéfiniment ; **ne pas lancer depuis l'agent** (préférer agent-loop-chat-iterations.sh ou cycles délimités). |
| `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 ». |
| `agent-loop-lock-acquire.sh` | `./ia_dev/gitea-issues/agent-loop-lock-acquire.sh` | **Lock (section 2)** : acquiert `agent-loop.lock` si absent ou périmé (>24 h). Exit 1 si lock actif ; l'agent ne doit pas lancer une deuxième instance. |
| `agent-loop-lock-release.sh` | `./ia_dev/gitea-issues/agent-loop-lock-release.sh` | **Lock (section 2)** : supprime `agent-loop.lock` et `agent-loop.stop`. À exécuter en fin de cycles (normale ou arrêt). |
| `agent-loop-stop.sh` | `./ia_dev/gitea-issues/agent-loop-stop.sh` | **Arrêt à la demande** : crée `agent-loop.stop` ; l'instance en cours s'arrête au début du cycle suivant. |
| `agent-loop-stop-requested.sh` | `./ia_dev/gitea-issues/agent-loop-stop-requested.sh` | **Vérification arrêt** : exit 0 si `agent-loop.stop` existe (utilisé par l'agent au début de chaque cycle). |
| `agent-loop-is-running.sh` | `./ia_dev/gitea-issues/agent-loop-is-running.sh` | **Vérifier si l'agent est en cours** : affiche fichier lock, PID et date ; indique si le processus est actif ou lock orphelin. Exit 0 si instance en cours (lock mtime < 24 h), 1 sinon. |
| `tickets-fetch-inbox.sh` | `./ia_dev/gitea-issues/tickets-fetch-inbox.sh` | **Récupération par expéditeurs autorisés** : mails **à partir du 10 mars 2026** (MAIL_SINCE_DATE), filtre `tickets.authorized_emails` (conf.json), pas de marquage lu/non lu. Écrit les nouveaux mails dans `projects/<id>/data/issues/*.pending` (JSON). Ne crée pas de .pending si un .response existe déjà. Voir `projects/ia_dev/docs/TICKETS_SPOOL_FORMAT.md`. |
| `list-pending-spooler.sh` | `./ia_dev/gitea-issues/list-pending-spooler.sh` | **Spooler** : liste les fichiers `projects/<id>/data/issues/*.pending` qui n'ont **pas** de fichier `.response` correspondant (mails à traiter). Une ligne par chemin. |
| `write-response-spooler.sh` | `./ia_dev/gitea-issues/write-response-spooler.sh --base <base> --to <addr> --subject "..." --body "..." [--in-reply-to "<msg-id>"]` | **Spooler** : après envoi réussi avec `mail-send-reply.sh`, écrit `projects/<id>/data/issues/<base>.response` (JSON de la réponse envoyée). |
| `agent-loop.sh` | `./gitea-issues/agent-loop.sh [interval_sec]` | **Boucle de surveillance** : tourne indéfiniment (spooler ou legacy). **Ne pas lancer depuis l'agent** ; utiliser agent-loop-chat-iterations.sh ou cycles délimités. Voir `.cursor/agents/agent-loop.md`. |
| `agent-loop-treatment.sh` | `./gitea-issues/agent-loop-treatment.sh` | **Boucle traitement** : vérifie périodiquement `agent-loop.pending` ; si non vide, lance l'agent Cursor. Tourne indéfiniment ; **ne pas lancer depuis l'agent** (préférer agent-loop-chat-iterations.sh ou cycles délimités). |
| `agent-loop-retrieval-once.sh` | `./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 ». |
| `agent-loop-lock-acquire.sh` | `./gitea-issues/agent-loop-lock-acquire.sh` | **Lock (section 2)** : acquiert `agent-loop.lock` si absent ou périmé (>24 h). Exit 1 si lock actif ; l'agent ne doit pas lancer une deuxième instance. |
| `agent-loop-lock-release.sh` | `./gitea-issues/agent-loop-lock-release.sh` | **Lock (section 2)** : supprime `agent-loop.lock` et `agent-loop.stop`. À exécuter en fin de cycles (normale ou arrêt). |
| `agent-loop-stop.sh` | `./gitea-issues/agent-loop-stop.sh` | **Arrêt à la demande** : crée `agent-loop.stop` ; l'instance en cours s'arrête au début du cycle suivant. |
| `agent-loop-stop-requested.sh` | `./gitea-issues/agent-loop-stop-requested.sh` | **Vérification arrêt** : exit 0 si `agent-loop.stop` existe (utilisé par l'agent au début de chaque cycle). |
| `agent-loop-is-running.sh` | `./gitea-issues/agent-loop-is-running.sh` | **Vérifier si l'agent est en cours** : affiche fichier lock, PID et date ; indique si le processus est actif ou lock orphelin. Exit 0 si instance en cours (lock mtime < 24 h), 1 sinon. |
| `tickets-fetch-inbox.sh` | `./gitea-issues/tickets-fetch-inbox.sh` | **Récupération par expéditeurs autorisés** : mails **à partir du 10 mars 2026** (MAIL_SINCE_DATE), filtre `tickets.authorized_emails` (conf.json), pas de marquage lu/non lu. Écrit les nouveaux mails dans `projects/<id>/data/issues/*.pending` (JSON). Ne crée pas de .pending si un .response existe déjà. Voir `projects/ia_dev/docs/TICKETS_SPOOL_FORMAT.md`. |
| `list-pending-spooler.sh` | `./gitea-issues/list-pending-spooler.sh` | **Spooler** : liste les fichiers `projects/<id>/data/issues/*.pending` qui n'ont **pas** de fichier `.response` correspondant (mails à traiter). Une ligne par chemin. |
| `write-response-spooler.sh` | `./gitea-issues/write-response-spooler.sh --base <base> --to <addr> --subject "..." --body "..." [--in-reply-to "<msg-id>"]` | **Spooler** : après envoi réussi avec `mail-send-reply.sh`, écrit `projects/<id>/data/issues/<base>.response` (JSON de la réponse envoyée). |
Variables optionnelles : `GITEA_API_URL`, `GITEA_REPO_OWNER`, `GITEA_REPO_NAME`, `GITEA_ISSUES_DIR`.
@ -81,7 +81,7 @@ Sous `projects/<id>/logs/gitea-issues/` :
- **agent-loop.stop** : si présent, l'instance en cours s'arrête au début du cycle suivant. Création : `agent-loop-stop.sh` ou `touch …/agent-loop.stop`.
- **agent-loop-chat-iterations.log** : sortie de `agent-loop-chat-iterations.sh` (test denvoi au lancement, puis à chaque itération le résultat de `mail-list-unread.sh`).
Le répertoire **projects/<id>/data/issues/** (spooler) est rempli **uniquement** par `./ia_dev/gitea-issues/tickets-fetch-inbox.sh`. Si ce script n'est pas exécuté, `data/issues` reste vide si on nutilise que la boucle legacy utilise seulement mail-list-unread.sh et agent-loop.pending dans logs/gitea-issues/.
Le répertoire **projects/<id>/data/issues/** (spooler) est rempli **uniquement** par `./gitea-issues/tickets-fetch-inbox.sh`. Si ce script n'est pas exécuté, `data/issues` reste vide si on nutilise que la boucle legacy utilise seulement mail-list-unread.sh et agent-loop.pending dans logs/gitea-issues/.
**Réponse mail** : le `--body` de `mail-send-reply.sh` doit être **uniquement le texte rédigé par lagent** (la réponse à lexpéditeur). Ne jamais y mettre le mail reçu, le sujet, une citation ou un bloc « From: » / « Message-ID » : sinon le destinataire reçoit son propre message au lieu de la réponse.