refactor: rename gitea-issues to git-issues and symlink projects to monorepo
- Rename directory and scripts env GIT_ISSUES_DIR; secrets path .secrets/git-issues - Rename agent git-issues-process; update docs GIT_ISSUES_SCRIPTS_AGENTS.md - Symlink projects/enso, smart_ide, builazoo to ../../projects/<id> when used inside smart_ide - Update project conf paths for git-issues tokens and imap bridge
This commit is contained in:
parent
285e72039e
commit
e86a9fbb6e
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: agent-loop
|
||||
description: Orchestre la boucle de récupération des mails et le traitement par gitea-issues-process. Paramètre /agent-loop = nombre de boucles (1 min chacune), pas des secondes. Exécutions délimitées uniquement (N cycles) ; ne jamais lancer de processus en arrière-plan (nohup / &).
|
||||
description: Orchestre la boucle de récupération des mails et le traitement par git-issues-process. Paramètre /agent-loop = nombre de boucles (1 min chacune), pas des secondes. Exécutions délimitées uniquement (N cycles) ; ne jamais lancer de processus en arrière-plan (nohup / &).
|
||||
model: inherit
|
||||
is_background: false
|
||||
---
|
||||
@ -35,19 +35,19 @@ En tant qu'agent, avant de solliciter l'ia, regarde ce que tu peux scripter (imp
|
||||
|
||||
**Horodatage** : au début et à la fin d'exécution, afficher date/heure, projet (id), branche, répertoire de travail du dépôt concerné.
|
||||
|
||||
Tu es l'agent qui **orchestre** la surveillance des mails et leur traitement. Tu ne traites pas les mails toi‑même : le traitement (réponse, issues, marquage lu) est fait par l'**agent gitea-issues-process**. Tu lances les scripts et/ou les sous-agents selon la demande.
|
||||
Tu es l'agent qui **orchestre** la surveillance des mails et leur traitement. Tu ne traites pas les mails toi‑même : le traitement (réponse, issues, marquage lu) est fait par l'**agent git-issues-process**. Tu lances les scripts et/ou les sous-agents selon la demande.
|
||||
|
||||
**Récupération et filtrage** : la **récupération** des mails et le **filtrage** (to, from, `tickets.authorized_emails`, date) sont assurés par le **script** `tickets-fetch-inbox.sh` (qui appelle le Python associé). L'agent ne fait que **lancer** ce script ; il ne récupère ni ne filtre lui‑même. Les adresses « to » des mails reçus déterminent le projet (routage par le script) ; les réponses sont envoyées à l'**expéditeur** (« from »). Aucune adresse n'est fixée en dur.
|
||||
|
||||
**Paramètre de la commande /agent-loop** : lorsqu'on invoque l'agent avec un argument (ex. `/agent-loop 600`), cet argument est le **nombre de boucles** (chaque boucle = 1 minute). Ce n'est **pas** un intervalle en secondes. Ex. `/agent-loop 600` = exécuter **600 cycles** (section 2 : récupération + traitement + attente 1 min, répété 600 fois). Interpréter tout paramètre numérique comme ce nombre de boucles et lancer autant de cycles (section 2) ou passer N à `agent-loop-chat-iterations.sh [N]` (section 3).
|
||||
|
||||
**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`.
|
||||
**Références obligatoires** : lire `projects/ia_dev/docs/GIT_ISSUES_SCRIPTS_AGENTS.md` (contexte d'exécution). Usage standalone : tous les scripts sont invoqués depuis la **racine de ia_dev** : `./git-issues/<script>.sh`.
|
||||
|
||||
**Script agent-loop.sh** (lancement manuel uniquement, pas depuis l'agent) : premier argument optionnel = **intervalle en secondes** entre deux tours (ex. `./gitea-issues/agent-loop.sh 60` = 60 s). À ne pas confondre avec le paramètre de la commande /agent-loop (nombre de boucles). 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 » : `.smartIde/hooks/remonter-mails.sh` lit `projects/<id>/data/issues/*.pending` ou `agent-loop.pending`.
|
||||
**Script agent-loop.sh** (lancement manuel uniquement, pas depuis l'agent) : premier argument optionnel = **intervalle en secondes** entre deux tours (ex. `./git-issues/agent-loop.sh 60` = 60 s). À ne pas confondre avec le paramètre de la commande /agent-loop (nombre de boucles). 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/git-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/git-issues/agent-loop.pending` (chemins des .pending du spooler à traiter). Variables (optionnel `.secrets/git-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 » : `.smartIde/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 : `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`.
|
||||
- **Lock (une seule instance)** : `projects/<id>/logs/git-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/git-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) : ./git-issues/agent-loop-stop.sh` ou `touch projects/<id>/logs/git-issues/agent-loop.stop`.
|
||||
|
||||
---
|
||||
|
||||
@ -61,26 +61,26 @@ Si l'utilisateur demande explicitement « lancer les 2 boucles en arrière-plan
|
||||
|
||||
## 2. Lancer x fois : récupération 1 fois puis traitement 1 fois (x cycles)
|
||||
|
||||
Si l'utilisateur demande de **lancer x fois** les deux sous-agents (une récupération puis un traitement, répété x fois), ou invoque **/agent-loop N** (N = nombre de boucles de 1 min) : **x = N**. Chaque cycle = 1 récupération + 1 traitement (agent gitea-issues-process) + 1 min d'attente. **Pour que les N cycles s'exécutent réellement** (sans limite de session) : l'agent lance **une seule commande** `./gitea-issues/agent-loop-n-cycles.sh [N]` avec un timeout ≥ N minutes ; le script fait N × (récupération + agent via Cursor Agent CLI + 1 min). Voir section 3 (prérequis CLI et AGENT_LOOP_RUN_AGENT=1).
|
||||
Si l'utilisateur demande de **lancer x fois** les deux sous-agents (une récupération puis un traitement, répété x fois), ou invoque **/agent-loop N** (N = nombre de boucles de 1 min) : **x = N**. Chaque cycle = 1 récupération + 1 traitement (agent git-issues-process) + 1 min d'attente. **Pour que les N cycles s'exécutent réellement** (sans limite de session) : l'agent lance **une seule commande** `./git-issues/agent-loop-n-cycles.sh [N]` avec un timeout ≥ N minutes ; le script fait N × (récupération + agent via Cursor Agent CLI + 1 min). Voir section 3 (prérequis CLI et AGENT_LOOP_RUN_AGENT=1).
|
||||
|
||||
**Avant de commencer les x cycles** :
|
||||
- Exécuter depuis la racine de ia_dev : `./gitea-issues/agent-loop-lock-acquire.sh`.
|
||||
- Exécuter depuis la racine de ia_dev : `./git-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 `Depuis la racine de 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 : ./git-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 `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.
|
||||
**Au début du cycle** (avant l'étape 1) : exécuter `Depuis la racine de ia_dev : ./git-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
|
||||
Depuis la racine de ia_dev : ./gitea-issues/agent-loop-retrieval-once.sh
|
||||
Depuis la racine de ia_dev : ./git-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.
|
||||
Ce script exécute `tickets-fetch-inbox.sh` puis `list-pending-spooler.sh` et écrit les chemins des .pending dans `projects/<id>/logs/git-issues/agent-loop.pending` (et met à jour le fichier témoin). Pas d'arrière-plan : attendre la fin du script.
|
||||
|
||||
2. **Traitement une fois** : lancer **intégralement** l'agent **gitea-issues-process** sur les mails reçus (contenu de `projects/<id>/logs/gitea-issues/agent-loop.pending`). Utiliser le sous-agent Cursor (mcp_task ou équivalent) avec le type `gitea-issues-process` et un prompt du type :
|
||||
« Traite les mails du spooler listés dans `projects/<id>/logs/gitea-issues/agent-loop.pending` (chemins des .pending) ou en exécutant `list-pending-spooler.sh`. Pour chaque fichier .pending : lire le JSON (from, to, subject, body, message_id, base). Envoyer la réponse à l'**expéditeur** (champ « from » du JSON), pas à une adresse fixe ; le « to » du mail reçu a déjà déterminé le projet. 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.). Appeler mail-send-reply.sh --to <from> puis write-response-spooler.sh. Ne pas appeler mail-mark-read.sh (spooler). »
|
||||
2. **Traitement une fois** : lancer **intégralement** l'agent **git-issues-process** sur les mails reçus (contenu de `projects/<id>/logs/git-issues/agent-loop.pending`). Utiliser le sous-agent Cursor (mcp_task ou équivalent) avec le type `git-issues-process` et un prompt du type :
|
||||
« Traite les mails du spooler listés dans `projects/<id>/logs/git-issues/agent-loop.pending` (chemins des .pending) ou en exécutant `list-pending-spooler.sh`. Pour chaque fichier .pending : lire le JSON (from, to, subject, body, message_id, base). Envoyer la réponse à l'**expéditeur** (champ « from » du JSON), pas à une adresse fixe ; le « to » du mail reçu a déjà déterminé le projet. 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.). Appeler mail-send-reply.sh --to <from> puis write-response-spooler.sh. Ne pas appeler mail-mark-read.sh (spooler). »
|
||||
|
||||
3. **Attente 1 minute entre cycles** : après chaque cycle (après l’étape 2), si ce n’est pas le dernier cycle (`i` < x), attendre **1 minute** (60 secondes) avant de commencer le cycle suivant — exécuter `sleep 60` ou faire attendre l’orchestration 60 s. Pas d’attente après le dernier cycle.
|
||||
|
||||
@ -90,10 +90,10 @@ 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)** : pour **/agent-loop N** (ex. 600), l'agent exécute **une seule commande** depuis la racine de ia_dev : `./gitea-issues/agent-loop-n-cycles.sh [N]` (défaut N=600), avec un **timeout** d'au moins N minutes (ex. 39600000 ms pour N=600 ≈ 11 h). Le script effectue **exactement N cycles** (vérification arrêt → récupération → invocation de l'agent **gitea-issues-process** via **Cursor Agent CLI** si `AGENT_LOOP_RUN_AGENT=1` → attente 1 min) puis lock-release. Aucun contournement : le traitement à chaque cycle est le même agent gitea-issues-process, invoqué par le script via la CLI. **Prérequis** : Cursor Agent CLI dans le PATH et `AGENT_LOOP_RUN_AGENT=1` dans `.secrets/gitea-issues/agent-loop.env` pour que les mails soient traités à chaque cycle. Ne **pas** utiliser `agent-loop-chat-iterations.sh` pour /agent-loop N : ce script fait uniquement mail-list-unread (legacy) et **ne traite pas le spooler**. Pour une demande explicite « N itérations legacy (non lu uniquement) » sans réponse mail : `./gitea-issues/agent-loop-chat-iterations.sh [N]`. 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 `projects/<id>/logs/gitea-issues/agent-loop.pending` 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.
|
||||
- **Boucle limitée depuis le chat (N itérations, attente 1 min entre chaque)** : pour **/agent-loop N** (ex. 600), l'agent exécute **une seule commande** depuis la racine de ia_dev : `./git-issues/agent-loop-n-cycles.sh [N]` (défaut N=600), avec un **timeout** d'au moins N minutes (ex. 39600000 ms pour N=600 ≈ 11 h). Le script effectue **exactement N cycles** (vérification arrêt → récupération → invocation de l'agent **git-issues-process** via **Cursor Agent CLI** si `AGENT_LOOP_RUN_AGENT=1` → attente 1 min) puis lock-release. Aucun contournement : le traitement à chaque cycle est le même agent git-issues-process, invoqué par le script via la CLI. **Prérequis** : Cursor Agent CLI dans le PATH et `AGENT_LOOP_RUN_AGENT=1` dans `.secrets/git-issues/agent-loop.env` pour que les mails soient traités à chaque cycle. Ne **pas** utiliser `agent-loop-chat-iterations.sh` pour /agent-loop N : ce script fait uniquement mail-list-unread (legacy) et **ne traite pas le spooler**. Pour une demande explicite « N itérations legacy (non lu uniquement) » sans réponse mail : `./git-issues/agent-loop-chat-iterations.sh [N]`. 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) : ./git-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 `projects/<id>/logs/git-issues/agent-loop.pending` ou inviter l'utilisateur à lancer l'agent git-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/git-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.
|
||||
|
||||
---
|
||||
|
||||
@ -102,7 +102,7 @@ Répéter les étapes 1, 2 et 3 pour les x cycles demandés. Chaque cycle traite
|
||||
- **Pas de processus en arrière-plan** : ne jamais lancer `agent-loop.sh` ni `agent-loop-treatment.sh` avec `nohup` ou `&` ; les boucles sont gérées par l'agent via des exécutions délimitées (agent-loop-chat-iterations.sh N, ou cycles section 2).
|
||||
- Ne pas déclencher la CI, ne pas écrire en base, ne pas masquer les sorties des scripts.
|
||||
- Répertoire d'exécution des scripts : toujours **racine de ia_dev** (standalone).
|
||||
- Le traitement des mails (réponse réelle, workflow fil, marquage lu) est **uniquement** assuré par l'agent gitea-issues-process ; ne pas court-circuiter son workflow.
|
||||
- Le traitement des mails (réponse réelle, workflow fil, marquage lu) est **uniquement** assuré par l'agent git-issues-process ; ne pas court-circuiter son workflow.
|
||||
|
||||
## Clôture complète obligatoire (tous les cas, sans exception)
|
||||
|
||||
|
||||
@ -97,7 +97,7 @@ Tu appliques les règles ci-dessous **lorsqu'il y a du code à produire** (évol
|
||||
20. Lancer obligatoirement un lint
|
||||
Utiliser l'agent `.smartIde/agents/fix-lint.md` (commande /fix-lint)
|
||||
|
||||
21. **Documentation** : Compléter le wiki avec l'objectif, les impacts, les modifications, les modalités de déploiement et d'analyse. **`docs/` est hors versionnement** : maintenir les fichiers dans `docs/` localement (ne pas les supprimer), puis exécuter `./gitea-issues/wiki-migrate-docs.sh` pour pousser vers le wiki ; ou éditer la page wiki directement. Ne pas committer `docs/`. **Avant d'exécuter wiki-migrate-docs.sh :** lire le script, présenter un résumé de ce qu'il fait, puis l'exécuter.
|
||||
21. **Documentation** : Compléter le wiki avec l'objectif, les impacts, les modifications, les modalités de déploiement et d'analyse. **`docs/` est hors versionnement** : maintenir les fichiers dans `docs/` localement (ne pas les supprimer), puis exécuter `./git-issues/wiki-migrate-docs.sh` pour pousser vers le wiki ; ou éditer la page wiki directement. Ne pas committer `docs/`. **Avant d'exécuter wiki-migrate-docs.sh :** lire le script, présenter un résumé de ce qu'il fait, puis l'exécuter.
|
||||
|
||||
22. **Commit** : Préparer le commit avec le format de `.smartIde/agents/push-by-script.md` (lignes 15-32) :
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ Ce document **centralise toutes les informations** sur la documentation du proje
|
||||
|
||||
**Avant d'exécuter un script du projet :**
|
||||
|
||||
1. Lire le fichier du script avec l'outil de lecture (ex. `gitea-issues/wiki-migrate-docs.sh` lorsqu'il est invoqué).
|
||||
1. Lire le fichier du script avec l'outil de lecture (ex. `git-issues/wiki-migrate-docs.sh` lorsqu'il est invoqué).
|
||||
2. Présenter à l'utilisateur un résumé de ce que le script va faire : étapes principales, options utilisées, effets attendus.
|
||||
3. Lancer le script uniquement après cette présentation.
|
||||
|
||||
@ -55,21 +55,21 @@ Ce document **centralise toutes les informations** sur la documentation du proje
|
||||
* **Objectif des travaux :** Se concentrer sur la réalisation de la liste des tâches décrite dans `docs/todoFix/` et la documentation (wiki).
|
||||
* **Structure de la documentation :**
|
||||
* La documentation générale et pérenne se trouve dans le **wiki** du projet (URL dans `projects/<id>/conf.json` → `git.wiki_url`). Page d'accueil du wiki : **Home**.
|
||||
* Pour mettre à jour le wiki : modifier le fichier correspondant dans `docs/` puis exécuter depuis la racine projet (chemin absolu) : `./gitea-issues/wiki-migrate-docs.sh` ; ou éditer la page directement sur le wiki. Correspondance fichier → page : voir `projects/ia_dev/docs/GITEA_ISSUES_SCRIPTS_AGENTS.md` (section Migration docs/ → wiki).
|
||||
* Pour mettre à jour le wiki : modifier le fichier correspondant dans `docs/` puis exécuter depuis la racine projet (chemin absolu) : `./git-issues/wiki-migrate-docs.sh` ; ou éditer la page directement sur le wiki. Correspondance fichier → page : voir `projects/ia_dev/docs/GIT_ISSUES_SCRIPTS_AGENTS.md` (section Migration docs/ → wiki).
|
||||
* **`docs/` est hors versionnement** : maintenir `docs/` localement (ne pas le supprimer), pousser vers le wiki avec `wiki-migrate-docs.sh` après édition ; ne jamais committer `docs/`.
|
||||
* Les features et corrections sont documentées dans le wiki (pages Operations, Frontend, Code-Standards, etc.) ; les tâches en cours dans `docs/todoFix/`.
|
||||
* Les user stories se trouvent dans `docs/user_stories/` (43 user stories documentées).
|
||||
* **User Stories :** Consulter `docs/user_stories/INDEX.md` pour la liste complète et les dépendances. Chaque user story documente un parcours utilisateur avec actions précises, vérifications backend, valeurs de test. Utiliser comme référence pour l'autonomie du développement.
|
||||
* **Qualité et sécurité :** Consulter les pages wiki correspondantes (ex. Code-Standards) ou `docs/` si présents.
|
||||
* **Utilisation de la documentation existante :** Ne pas ajouter de nouveaux documents sans raison ; enrichir et mettre à jour le wiki (ou docs/ puis wiki-migrate-docs.sh).
|
||||
* **Mise à jour continue :** Mettre à jour la documentation (wiki via docs/ et `./gitea-issues/wiki-migrate-docs.sh`, `docs/todoFix/`, `docs/user_stories/` et commentaires dans le code) après les modifications ou pour clarifier.
|
||||
* **Mise à jour continue :** Mettre à jour la documentation (wiki via docs/ et `./git-issues/wiki-migrate-docs.sh`, `docs/todoFix/`, `docs/user_stories/` et commentaires dans le code) après les modifications ou pour clarifier.
|
||||
* **Changelog :** Le fichier `CHANGELOG.md` de cette version en cours intègre toutes les modifications majeures. Ce contenu est repris dans la splash notice de l'application front. Les mises à jour mineures sont ajoutées au `CHANGELOG.md` sans enlever d'élément existant.
|
||||
|
||||
## docs/features extract
|
||||
|
||||
Dans l'ordre et pour tous les documents de docs/features :
|
||||
|
||||
1) Extraire toutes les données pertinentes des documents de docs/features et les intégrer dans les pages wiki existantes (mettre à jour les fichiers correspondants dans docs/ puis exécuter `./gitea-issues/wiki-migrate-docs.sh`).
|
||||
1) Extraire toutes les données pertinentes des documents de docs/features et les intégrer dans les pages wiki existantes (mettre à jour les fichiers correspondants dans docs/ puis exécuter `./git-issues/wiki-migrate-docs.sh`).
|
||||
|
||||
2) Supprimer tous les fichiers dans docs/features
|
||||
|
||||
@ -77,7 +77,7 @@ Dans l'ordre et pour tous les documents de docs/features :
|
||||
|
||||
Dans l'ordre et pour tous les documents de docs/fixKnowledge :
|
||||
|
||||
1) Extraire toutes les données pertinentes des documents de docs/fixKnowledge et les intégrer dans les pages wiki existantes (mettre à jour docs/ puis `./gitea-issues/wiki-migrate-docs.sh`).
|
||||
1) Extraire toutes les données pertinentes des documents de docs/fixKnowledge et les intégrer dans les pages wiki existantes (mettre à jour docs/ puis `./git-issues/wiki-migrate-docs.sh`).
|
||||
|
||||
2) Supprimer tous les fichiers dans docs/fixKnowledge
|
||||
|
||||
@ -88,7 +88,7 @@ Dans l'ordre et pour tous les documents de docs et les pages wiki :
|
||||
Documents / pages à ne pas supprimer lors des étapes suivantes (équivalents wiki des anciens fichiers docs/) :
|
||||
|
||||
* Page wiki Home (page d'accueil du wiki)
|
||||
* Pages wiki : Api, Architecture, Code-Standards, Deployment, Operations, Readme, Scripts, etc. (voir projects/ia_dev/docs/GITEA_ISSUES_SCRIPTS_AGENTS.md pour la correspondance complète).
|
||||
* Pages wiki : Api, Architecture, Code-Standards, Deployment, Operations, Readme, Scripts, etc. (voir projects/ia_dev/docs/GIT_ISSUES_SCRIPTS_AGENTS.md pour la correspondance complète).
|
||||
* docs/sources/*
|
||||
* docs/fixKnowledge/*
|
||||
* docs/features/*
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: evol
|
||||
description: En charge des évolutions. Implémente les évolutions, documente les spécifications dans le wiki (docs/ puis ./gitea-issues/wiki-migrate-docs.sh), prépare le commit puis lance push-by-script. Réponse structurée selon cloture-evolution.mdc.
|
||||
description: En charge des évolutions. Implémente les évolutions, documente les spécifications dans le wiki (docs/ puis ./git-issues/wiki-migrate-docs.sh), prépare le commit puis lance push-by-script. Réponse structurée selon cloture-evolution.mdc.
|
||||
model: inherit
|
||||
is_background: false
|
||||
---
|
||||
@ -40,7 +40,7 @@ Tu es l'agent evol, en charge des **évolutions** (nouvelles fonctionnalités, a
|
||||
## Principes
|
||||
|
||||
- Implémenter l'évolution demandée en respectant l'architecture et les conventions du projet.
|
||||
- Documenter les spécifications dans le wiki (mettre à jour le fichier correspondant dans docs/ puis exécuter `./gitea-issues/wiki-migrate-docs.sh`, ou éditer la page wiki concernée). **`docs/` est hors versionnement** : maintenir `docs/` localement, ne pas le supprimer, ne pas committer `docs/` ; toujours pousser vers le wiki après édition. **Avant d'exécuter wiki-migrate-docs.sh :** lire le script, présenter un résumé de ce qu'il fait, puis l'exécuter.
|
||||
- Documenter les spécifications dans le wiki (mettre à jour le fichier correspondant dans docs/ puis exécuter `./git-issues/wiki-migrate-docs.sh`, ou éditer la page wiki concernée). **`docs/` est hors versionnement** : maintenir `docs/` localement, ne pas le supprimer, ne pas committer `docs/` ; toujours pousser vers le wiki après édition. **Avant d'exécuter wiki-migrate-docs.sh :** lire le script, présenter un résumé de ce qu'il fait, puis l'exécuter.
|
||||
|
||||
## Workflow
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@ Tu es l'agent fix-search, en charge des **investigations** en vue d'identifier l
|
||||
## Livrables
|
||||
|
||||
- Synthèse d'investigation (symptôme, causes, root cause, preuves).
|
||||
- Si des documents d'investigation ou de retour d'expérience doivent être créés ou complétés, les rédiger dans le wiki (page Operations ou autre) ou dans `docs/` puis exécuter `./gitea-issues/wiki-migrate-docs.sh`. **`docs/` est hors versionnement** : maintenir `docs/` localement, ne pas le supprimer, ne pas le committer ; toujours pousser vers le wiki après édition. **Avant d'exécuter wiki-migrate-docs.sh :** lire le script, présenter un résumé, puis l'exécuter. **Lecture/écriture limitée à la doc** (pas de modification du code ni des configs).
|
||||
- Si des documents d'investigation ou de retour d'expérience doivent être créés ou complétés, les rédiger dans le wiki (page Operations ou autre) ou dans `docs/` puis exécuter `./git-issues/wiki-migrate-docs.sh`. **`docs/` est hors versionnement** : maintenir `docs/` localement, ne pas le supprimer, ne pas le committer ; toujours pousser vers le wiki après édition. **Avant d'exécuter wiki-migrate-docs.sh :** lire le script, présenter un résumé, puis l'exécuter. **Lecture/écriture limitée à la doc** (pas de modification du code ni des configs).
|
||||
- Préparer le commit avec le format défini dans `.smartIde/agents/push-by-script.md` (lignes 15-32) :
|
||||
- Etat initial
|
||||
- Motivation du changement
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: fix
|
||||
description: En charge des correctifs. Applique les corrections en priorisant la root cause, lance fix-search, vérifie récurrence et solutions globales. Documente dans le wiki (docs/ puis ./gitea-issues/wiki-migrate-docs.sh) et prépare le commit puis push-by-script.
|
||||
description: En charge des correctifs. Applique les corrections en priorisant la root cause, lance fix-search, vérifie récurrence et solutions globales. Documente dans le wiki (docs/ puis ./git-issues/wiki-migrate-docs.sh) et prépare le commit puis push-by-script.
|
||||
model: inherit
|
||||
is_background: false
|
||||
---
|
||||
@ -53,7 +53,7 @@ Tu es l'agent fix, en charge des **correctifs** à partir d'un problème remont
|
||||
- Ne jamais contourner, supprimer le contexte du problème, créer de régression fonctionnelle, mettre de résultat en dur ni écraser les cas ; gérer tous les cas explicitement.
|
||||
- Étendre la correction aux endroits similaires identifiés.
|
||||
- Proposer, si pertinent, des évolutions plus globales (architecture, mutualisation, centralisation).
|
||||
- **Documentation** : `docs/` est hors versionnement ; maintenir `docs/` localement, pousser vers le wiki avec `./gitea-issues/wiki-migrate-docs.sh`, ne pas committer `docs/`.
|
||||
- **Documentation** : `docs/` est hors versionnement ; maintenir `docs/` localement, pousser vers le wiki avec `./git-issues/wiki-migrate-docs.sh`, ne pas committer `docs/`.
|
||||
- **En cas de code à produire**, appliquer intégralement les règles de `.smartIde/agents/code.md` (agent commande /code).
|
||||
|
||||
## Clôture complète obligatoire (tous les cas, sans exception)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: gitea-issues-process
|
||||
description: Traite les tickets Gitea (issues) en s'appuyant au maximum sur les scripts gitea-issues/. Liste les issues, crée une branche par issue, récupère le contenu via script, lance /fix ou /evol puis /push-by-script et optionnellement commente l'issue. Push direct uniquement ; ne jamais créer de pull request.
|
||||
name: git-issues-process
|
||||
description: Traite les tickets Gitea (issues) en s'appuyant au maximum sur les scripts git-issues/. Liste les issues, crée une branche par issue, récupère le contenu via script, lance /fix ou /evol puis /push-by-script et optionnellement commente l'issue. Push direct uniquement ; ne jamais créer de pull request.
|
||||
model: inherit
|
||||
is_background: false
|
||||
---
|
||||
@ -18,7 +18,7 @@ En tant qu'agent, avant de solliciter l'ia, regarde ce que tu peux scripter (imp
|
||||
|
||||
- **Lint (obligatoire avant clôture)** : Sur le dépôt applicatif du projet (`repository_root` et `build_dirs` dans `projects/<id>/conf.json`), exécuter `npm run lint` (ou équivalent) pour **chaque** `build_dir` de la conf — **tout** le périmètre à chaque fois, pas seulement le sous-projet modifié dans la session (ex. tâche front : lancer aussi le lint sur les autres `build_dirs`). Compter **erreurs + warnings**. Si **N ≥ 1** : appliquer des corrections dans **ce** run jusqu'à traiter **au moins min(5, N)** diagnostics (donc **au moins 5** lorsque N ≥ 5 ; si N < 5, tout corriger jusqu'à 0). **Interdit** de s'exonérer par un lint déjà passé dans `pousse`/build **sans** changements ESLint dans le workspace, ou en reportant sur un **`/fix-lint` ultérieur** : les corrections (min. 5 quand N ≥ 5) font partie **du même run** que la clôture. Clôture : commandes, périmètres, **décompte avant/après**. Voir `.smartIde/rules/cloture-lint.mdc`, dont la section **Diagnostics préexistants / hors périmètre de la session** (correction obligatoire pour tout diagnostic du périmètre, y compris hors fichiers modifiés dans ce run ; **interdit** en clôture : « warning existant », « hors scope session », « préexistait »).
|
||||
|
||||
# Agent gitea-issues-process
|
||||
# Agent git-issues-process
|
||||
|
||||
## Règle d'exécution intégrale (obligatoire, non négociable)
|
||||
|
||||
@ -29,50 +29,50 @@ En tant qu'agent, avant de solliciter l'ia, regarde ce que tu peux scripter (imp
|
||||
|
||||
---
|
||||
|
||||
**Documentation** : La doc des projets gérés est dans **`projects/<id>/docs`** ; la doc ia_dev (scripts gitea-issues, spooler) est dans **`projects/ia_dev/docs`**.
|
||||
**Documentation** : La doc des projets gérés est dans **`projects/<id>/docs`** ; la doc ia_dev (scripts git-issues, spooler) est dans **`projects/ia_dev/docs`**.
|
||||
|
||||
**À lire en début d'exécution** (documentation fournie à l'agent) :
|
||||
- projects/ia_dev/docs/GITEA_ISSUES_SCRIPTS_AGENTS.md (contexte d'exécution, scripts)
|
||||
- projects/ia_dev/docs/GIT_ISSUES_SCRIPTS_AGENTS.md (contexte d'exécution, scripts)
|
||||
- .smartIde/agents/agent-loop.md (fichier témoin, variables, boucles)
|
||||
- projects/ia_dev/docs/TICKETS_SPOOL_FORMAT.md (format JSON du spooler projects/<id>/data/issues/, schémas incoming/response, pièces jointes)
|
||||
|
||||
**Contexte projet :** La configuration et la documentation du projet sont dans `projects/<id>/`. L'identifiant `<id>` est résolu **uniquement** par **MAIL_TO** (adresse « to » des mails) ou **AI_AGENT_TOKEN** (token des requêtes) ; pas de fallback. Voir `docs/repo/ia-dev-project-conf-schema.md`. Rappeler en début d'exécution : projet = id résolu par MAIL_TO ou AI_AGENT_TOKEN, config = `ia_dev/projects/<id>/`. Ne pas hardcoder de chemin projet.
|
||||
|
||||
Tu es l'agent qui traite les **tickets (issues) Gitea** du dépôt du projet courant. Le dépôt et l'URL Gitea (ticketing, wiki) sont définis dans `projects/<id>/conf.json` (clé `tickets.ticketing_url`, `git.wiki_url`). Toute la logique d'appel API et Git doit passer par les **scripts** du dossier `gitea-issues/` ; l'agent ne fait pas d'appels curl ou git directs pour ces opérations.
|
||||
Tu es l'agent qui traite les **tickets (issues) Gitea** du dépôt du projet courant. Le dépôt et l'URL Gitea (ticketing, wiki) sont définis dans `projects/<id>/conf.json` (clé `tickets.ticketing_url`, `git.wiki_url`). Toute la logique d'appel API et Git doit passer par les **scripts** du dossier `git-issues/` ; l'agent ne fait pas d'appels curl ou git directs pour ces opérations.
|
||||
|
||||
**Horodatage et contexte** : au début et à la fin d'exécution, afficher date/heure, **projet** (id), **branche** et **répertoire de travail** du dépôt concerné.
|
||||
|
||||
**Avant d'exécuter un script du projet :**
|
||||
1. Lire le fichier du script avec l'outil de lecture (chaque script `gitea-issues/*.sh` avant de l'appeler).
|
||||
1. Lire le fichier du script avec l'outil de lecture (chaque script `git-issues/*.sh` avant de l'appeler).
|
||||
2. Présenter à l'utilisateur un résumé de ce que le script va faire : étapes principales, options/arguments, effets attendus.
|
||||
3. Lancer le script uniquement après cette présentation.
|
||||
|
||||
## Prérequis
|
||||
|
||||
- `GITEA_TOKEN` défini ou fichier `.secrets/gitea-issues/token` présent.
|
||||
- Exécution (standalone) depuis la **racine de ia_dev** : `./gitea-issues/*.sh`. Le projet est résolu par MAIL_TO ou AI_AGENT_TOKEN (voir `docs/repo/ia-dev-project-conf-schema.md`).
|
||||
- `GITEA_TOKEN` défini ou fichier `.secrets/git-issues/token` présent.
|
||||
- Exécution (standalone) depuis la **racine de ia_dev** : `./git-issues/*.sh`. Le projet est résolu par MAIL_TO ou AI_AGENT_TOKEN (voir `docs/repo/ia-dev-project-conf-schema.md`).
|
||||
- Dépendances : `jq`, `curl` (les scripts les utilisent).
|
||||
|
||||
**Contexte** : `gitea-issues/` est dans ia_dev ; l'id projet est résolu par MAIL_TO ou AI_AGENT_TOKEN ; la config est dans `ia_dev/projects/<id>/`. `.secrets` est sous ia_dev (`./.secrets`). Voir `projects/ia_dev/docs/GITEA_ISSUES_SCRIPTS_AGENTS.md` (Contexte d'exécution).
|
||||
**Contexte** : `git-issues/` est dans ia_dev ; l'id projet est résolu par MAIL_TO ou AI_AGENT_TOKEN ; la config est dans `ia_dev/projects/<id>/`. `.secrets` est sous ia_dev (`./.secrets`). Voir `projects/ia_dev/docs/GIT_ISSUES_SCRIPTS_AGENTS.md` (Contexte d'exécution).
|
||||
|
||||
## Workflow (script au maximum)
|
||||
|
||||
1. **Lister les issues**
|
||||
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.
|
||||
Exécuter depuis la racine de ia_dev : `./git-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** : `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.
|
||||
- **Créer la branche** : `Depuis la racine de ia_dev (MAIL_TO ou AI_AGENT_TOKEN défini) : ./git-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) : ./git-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 `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é).
|
||||
- **Commenter l'issue (optionnel)** : exécuter `Depuis la racine de ia_dev (MAIL_TO ou AI_AGENT_TOKEN défini) : ./git-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.
|
||||
|
||||
## Workflow mails (interaction agent ↔ scripts)
|
||||
|
||||
L'agent **ne fait pas** d'appels IMAP/SMTP ni de curl Gitea directs : il **invoque uniquement** les scripts `gitea-issues/*.sh` depuis la racine de ia_dev. Les scripts lisent la config (`.secrets` à la racine de ia_dev) et font les appels réels.
|
||||
L'agent **ne fait pas** d'appels IMAP/SMTP ni de curl Gitea directs : il **invoque uniquement** les scripts `git-issues/*.sh` depuis la racine de ia_dev. Les scripts lisent la config (`.secrets` à la racine de ia_dev) et font les appels réels.
|
||||
|
||||
**Ordre pour traiter les mails en attente** : deux sources possibles. **Aucun enregistrement ne doit être supprimé.**
|
||||
|
||||
@ -80,22 +80,22 @@ 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 `./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.
|
||||
- **Lister les mails à traiter** : exécuter `./git-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 `./git-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 `./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 `./git-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 n’envoie que ce corps plus la signature ; aucun autre contenu n’est 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 `./gitea-issues/tickets-fetch-inbox.sh` depuis la racine de ia_dev. C'est le **script** (et le Python qu'il appelle) qui **récupère** les mails et les **filtre** (to, from, `tickets.authorized_emails`, date) ; l'agent se contente de lancer le script. Le script écrit les mails retenus en `projects/<id>/data/issues/*.pending` (JSON). Mails à partir du 10 mars 2026 (ou `MAIL_SINCE_DATE`). 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.
|
||||
**Récupération mails (spooler data/issues)** : exécuter `./git-issues/tickets-fetch-inbox.sh` depuis la racine de ia_dev. C'est le **script** (et le Python qu'il appelle) qui **récupère** les mails et les **filtre** (to, from, `tickets.authorized_emails`, date) ; l'agent se contente de lancer le script. Le script écrit les mails retenus en `projects/<id>/data/issues/*.pending` (JSON). Mails à partir du 10 mars 2026 (ou `MAIL_SINCE_DATE`). 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 `./git-issues/agent-loop-chat-iterations.sh [N] [--repeat]`. Mails en attente : **projects/<id>/data/issues/*.pending** (prioritaire) ou `projects/<id>/logs/git-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 d’issue avec référence au fichier, etc.) sans les supprimer.
|
||||
|
||||
## Contraintes
|
||||
|
||||
- Ne pas appeler l'API Gitea ni exécuter des commandes git pour les issues en dehors des scripts `gitea-issues/*.sh`.
|
||||
- Ne pas appeler l'API Gitea ni exécuter des commandes git pour les issues en dehors des scripts `git-issues/*.sh`.
|
||||
- En cas d'échec d'un script (code de sortie non nul), rapporter l'erreur et s'arrêter pour cette issue sans masquer la sortie.
|
||||
- Les agents /fix et /evol appliquent la clôture complète (cloture-evolution.mdc) ; ne pas court-circuiter leur workflow.
|
||||
|
||||
@ -12,7 +12,7 @@ model: inherit
|
||||
|
||||
**Contexte projet :** Les agents sont définis et lancés depuis ia_dev (centralisé) mais sont **dédiés aux projets configurés** (lecoffreio, enso, algo, etc.), pas à ia_dev. La configuration et la documentation de chaque projet sont dans `projects/<id>/`. L'identifiant `<id>` est résolu par MAIL_TO ou AI_AGENT_TOKEN. Rappeler le projet et la branche au début de chaque agent.
|
||||
|
||||
**Répertoire d'exécution des scripts (standalone) :** Racine de ia_dev. Tous les scripts `deploy/` et `gitea-issues/` doivent être invoqués depuis la racine de ia_dev, ex. `./deploy/pousse.sh`, `./gitea-issues/wiki-migrate-docs.sh`. Les chemins absolus dans `conf.json` pointent vers les dépôts des projets.
|
||||
**Répertoire d'exécution des scripts (standalone) :** Racine de ia_dev. Tous les scripts `deploy/` et `git-issues/` doivent être invoqués depuis la racine de ia_dev, ex. `./deploy/pousse.sh`, `./git-issues/wiki-migrate-docs.sh`. Les chemins absolus dans `conf.json` pointent vers les dépôts des projets.
|
||||
|
||||
**Référence unique** : le détail de l'horodatage et des étapes 1 à 17 est défini uniquement ici. Les agents appliquent ce fichier intégralement et ne recopient pas les blocs détaillés.
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ model: inherit
|
||||
|
||||
**Contexte projet :** Les agents sont **définis et lancés depuis ia_dev** (code et définitions centralisés dans ce dépôt) mais sont **dédiés aux projets configurés** (lecoffreio, enso, algo, etc.) : ils opèrent sur ces projets, pas sur ia_dev. La configuration et la documentation de chaque projet sont dans `projects/<id>/`. L'identifiant `<id>` est résolu par MAIL_TO ou AI_AGENT_TOKEN. Rappeler le projet et la branche en début et en fin d'exécution de chaque agent.
|
||||
|
||||
**Répertoire d'exécution des scripts (standalone) :** Les scripts `deploy/` et `gitea-issues/` s'exécutent depuis la **racine de ia_dev**. Ils déploient ou traitent les **projets configurés** (chemins absolus dans `projects/<id>/conf.json`), pas ia_dev. Invoquer depuis la racine de ia_dev, ex. : `./deploy/pousse.sh`, `./gitea-issues/wiki-migrate-docs.sh`.
|
||||
**Répertoire d'exécution des scripts (standalone) :** Les scripts `deploy/` et `git-issues/` s'exécutent depuis la **racine de ia_dev**. Ils déploient ou traitent les **projets configurés** (chemins absolus dans `projects/<id>/conf.json`), pas ia_dev. Invoquer depuis la racine de ia_dev, ex. : `./deploy/pousse.sh`, `./git-issues/wiki-migrate-docs.sh`.
|
||||
|
||||
## Communication et langues
|
||||
|
||||
|
||||
@ -4,10 +4,10 @@
|
||||
# Runs in foreground (no background); chat can run it for a few iterations to avoid timeout.
|
||||
#
|
||||
# Usage:
|
||||
# ./gitea-issues/agent-loop-chat-iterations.sh [N] [--repeat]
|
||||
# ./git-issues/agent-loop-chat-iterations.sh [N] [--repeat]
|
||||
# N = number of iterations (default 3). Each iteration: mail-list-unread.sh then sleep 60.
|
||||
# --repeat = after N iterations, relaunch (infinite loop of N-by-N runs).
|
||||
# Output and mail list (expéditeur, sujet) are appended to projects/<id>/logs/gitea-issues/agent-loop-chat-iterations.log.
|
||||
# Output and mail list (expéditeur, sujet) are appended to projects/<id>/logs/git-issues/agent-loop-chat-iterations.log.
|
||||
#
|
||||
set -euo pipefail
|
||||
if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then
|
||||
@ -18,14 +18,14 @@ if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then
|
||||
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
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
ROOT="$(cd "${GIT_ISSUES_DIR}/../.." && pwd)"
|
||||
export GIT_ISSUES_DIR
|
||||
export REPO_ROOT="${ROOT}"
|
||||
cd "$ROOT"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
LOGS_GITEA="${PROJECT_LOGS_DIR:-$ROOT/logs}/gitea-issues"
|
||||
source "${GIT_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
LOGS_GIT_ISSUES="${PROJECT_LOGS_DIR:-$ROOT/logs}/git-issues"
|
||||
|
||||
REPEAT=""
|
||||
if [ "${1:-}" = "--repeat" ]; then
|
||||
@ -39,7 +39,7 @@ if ! [[ "$N" =~ ^[0-9]+$ ]] || [ "$N" -lt 1 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
LOG_DIR="${LOGS_GITEA}"
|
||||
LOG_DIR="${LOGS_GIT_ISSUES}"
|
||||
LOG_FILE="${LOG_DIR}/agent-loop-chat-iterations.log"
|
||||
mkdir -p "$LOG_DIR"
|
||||
# Ensure absolute path so logs are always in the same place
|
||||
@ -53,7 +53,7 @@ log_and_echo() {
|
||||
log_and_echo "[agent-loop-chat] $(date -Iseconds) — log file: $LOG_FILE"
|
||||
# Test send at launch: one test email to nicolas.cantu@pm.me
|
||||
log_and_echo "[agent-loop-chat] $(date -Iseconds) — test d'envoi vers nicolas.cantu@pm.me"
|
||||
"${GITEA_ISSUES_DIR}/mail-send-reply.sh" --to "nicolas.cantu@pm.me" --subject "Test envoi - agent-loop-chat $(date +%Y-%m-%dT%H:%M:%S)" --body "Mail de test envoyé au lancement de agent-loop-chat-iterations.sh." 2>&1 | tee -a "$LOG_FILE"
|
||||
"${GIT_ISSUES_DIR}/mail-send-reply.sh" --to "nicolas.cantu@pm.me" --subject "Test envoi - agent-loop-chat $(date +%Y-%m-%dT%H:%M:%S)" --body "Mail de test envoyé au lancement de agent-loop-chat-iterations.sh." 2>&1 | tee -a "$LOG_FILE"
|
||||
if [ "${PIPESTATUS[0]:-0}" -eq 0 ]; then
|
||||
log_and_echo "[agent-loop-chat] $(date -Iseconds) — test d'envoi OK"
|
||||
else
|
||||
@ -64,7 +64,7 @@ fi
|
||||
run_iterations() {
|
||||
for i in $(seq 1 "$N"); do
|
||||
log_and_echo "[agent-loop-chat] $(date -Iseconds) — iteration $i/$N"
|
||||
"${GITEA_ISSUES_DIR}/mail-list-unread.sh" 2>&1 | tee -a "$LOG_FILE" || true
|
||||
"${GIT_ISSUES_DIR}/mail-list-unread.sh" 2>&1 | tee -a "$LOG_FILE" || true
|
||||
if [ "$i" -lt "$N" ]; then
|
||||
log_and_echo "[agent-loop-chat] $(date -Iseconds) — attente 60 s avant prochaine itération"
|
||||
sleep 60
|
||||
@ -3,7 +3,7 @@
|
||||
# Run from repo root. Used by agent-loop agent before starting x cycles (section 2).
|
||||
#
|
||||
# Usage:
|
||||
# Depuis la racine de ia_dev : ./gitea-issues/agent-loop-lock-acquire.sh
|
||||
# Depuis la racine de ia_dev : ./git-issues/agent-loop-lock-acquire.sh
|
||||
#
|
||||
set -euo pipefail
|
||||
if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then
|
||||
@ -13,16 +13,16 @@ if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then
|
||||
set -u
|
||||
fi
|
||||
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
ROOT="$(cd "${GITEA_ISSUES_DIR}/../.." && pwd)"
|
||||
export GITEA_ISSUES_DIR
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
ROOT="$(cd "${GIT_ISSUES_DIR}/../.." && pwd)"
|
||||
export GIT_ISSUES_DIR
|
||||
export REPO_ROOT="${ROOT}"
|
||||
cd "$ROOT"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
LOGS_GITEA="${PROJECT_LOGS_DIR:-$ROOT/logs}/gitea-issues"
|
||||
source "${GIT_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
LOGS_GIT_ISSUES="${PROJECT_LOGS_DIR:-$ROOT/logs}/git-issues"
|
||||
|
||||
LOCK_FILE="${AGENT_LOOP_LOCK_FILE:-$LOGS_GITEA/agent-loop.lock}"
|
||||
LOCK_FILE="${AGENT_LOOP_LOCK_FILE:-$LOGS_GIT_ISSUES/agent-loop.lock}"
|
||||
STALE_SEC=$((24 * 3600)) # 24 hours
|
||||
mkdir -p "$(dirname "$LOCK_FILE")"
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
# Run from repo root.
|
||||
#
|
||||
# Usage:
|
||||
# Depuis la racine de ia_dev : ./gitea-issues/agent-loop-lock-release.sh
|
||||
# Depuis la racine de ia_dev : ./git-issues/agent-loop-lock-release.sh
|
||||
#
|
||||
set -euo pipefail
|
||||
if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then
|
||||
@ -13,17 +13,17 @@ if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then
|
||||
set -u
|
||||
fi
|
||||
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
ROOT="$(cd "${GITEA_ISSUES_DIR}/../.." && pwd)"
|
||||
export GITEA_ISSUES_DIR
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
ROOT="$(cd "${GIT_ISSUES_DIR}/../.." && pwd)"
|
||||
export GIT_ISSUES_DIR
|
||||
export REPO_ROOT="${ROOT}"
|
||||
cd "$ROOT"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
LOGS_GITEA="${PROJECT_LOGS_DIR:-$ROOT/logs}/gitea-issues"
|
||||
source "${GIT_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
LOGS_GIT_ISSUES="${PROJECT_LOGS_DIR:-$ROOT/logs}/git-issues"
|
||||
|
||||
LOCK_FILE="${AGENT_LOOP_LOCK_FILE:-$LOGS_GITEA/agent-loop.lock}"
|
||||
STOP_FILE="${AGENT_LOOP_STOP_FILE:-$LOGS_GITEA/agent-loop.stop}"
|
||||
LOCK_FILE="${AGENT_LOOP_LOCK_FILE:-$LOGS_GIT_ISSUES/agent-loop.lock}"
|
||||
STOP_FILE="${AGENT_LOOP_STOP_FILE:-$LOGS_GIT_ISSUES/agent-loop.stop}"
|
||||
|
||||
if [ -f "$LOCK_FILE" ]; then
|
||||
rm -f "$LOCK_FILE"
|
||||
@ -1,10 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run N cycles of (retrieval + treatment via Cursor Agent CLI + sleep 60s) in foreground.
|
||||
# Uses same lock as section 2. When AGENT_LOOP_RUN_AGENT=1 and "agent" in PATH, runs
|
||||
# gitea-issues-process workflow via CLI each cycle (same as agent-loop.sh). No contournement:
|
||||
# git-issues-process workflow via CLI each cycle (same as agent-loop.sh). No contournement:
|
||||
# /agent-loop 600 = agent runs this script with N=600 and timeout ~11h; script does 600 full cycles.
|
||||
#
|
||||
# Usage: from ia_dev root: ./gitea-issues/agent-loop-n-cycles.sh [N]
|
||||
# Usage: from ia_dev root: ./git-issues/agent-loop-n-cycles.sh [N]
|
||||
# N = number of cycles (default 600). Each cycle = retrieval + agent CLI (if configured) + 60s sleep.
|
||||
#
|
||||
set -euo pipefail
|
||||
@ -16,16 +16,16 @@ if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then
|
||||
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)"
|
||||
IA_DEV_ROOT="${GITEA_ISSUES_DIR}/.."
|
||||
export GITEA_ISSUES_DIR
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
ROOT="$(cd "${GIT_ISSUES_DIR}/../.." && pwd)"
|
||||
IA_DEV_ROOT="${GIT_ISSUES_DIR}/.."
|
||||
export GIT_ISSUES_DIR
|
||||
export REPO_ROOT="${ROOT}"
|
||||
cd "$ROOT"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
source "${GIT_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
|
||||
AGENT_LOOP_ENV="${IA_DEV_ROOT}/.secrets/gitea-issues/agent-loop.env"
|
||||
AGENT_LOOP_ENV="${IA_DEV_ROOT}/.secrets/git-issues/agent-loop.env"
|
||||
if [ -r "$AGENT_LOOP_ENV" ]; then
|
||||
set +u
|
||||
# shellcheck source=/dev/null
|
||||
@ -39,19 +39,19 @@ if ! [[ "$N" =~ ^[0-9]+$ ]] || [ "$N" -lt 1 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"${GITEA_ISSUES_DIR}/agent-loop-lock-acquire.sh" || exit 1
|
||||
"${GIT_ISSUES_DIR}/agent-loop-lock-acquire.sh" || exit 1
|
||||
|
||||
AGENT_PROMPT="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épondre à l'expéditeur (--to <from> du JSON), pas à une adresse fixe ; le « to » du mail reçu a déjà déterminé le projet. 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)."
|
||||
AGENT_PROMPT="Exécute le workflow mails du spooler (agent git-issues-process). 1) Lister les mails à traiter avec ./git-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épondre à l'expéditeur (--to <from> du JSON), pas à une adresse fixe ; le « to » du mail reçu a déjà déterminé le projet. 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 ./git-issues/mail-send-reply.sh --to <from> --subject \"Re: ...\" --body \"<ta_réponse>\" --in-reply-to \"<message_id>\". Après envoi réussi : ./git-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)."
|
||||
|
||||
i=1
|
||||
while [ "$i" -le "$N" ]; do
|
||||
if "${GITEA_ISSUES_DIR}/agent-loop-stop-requested.sh" 2>/dev/null; then
|
||||
if "${GIT_ISSUES_DIR}/agent-loop-stop-requested.sh" 2>/dev/null; then
|
||||
echo "[agent-loop-n-cycles] $(date -Iseconds) — Arrêt demandé (cycle $i/$N). Libération du lock."
|
||||
"${GITEA_ISSUES_DIR}/agent-loop-lock-release.sh"
|
||||
"${GIT_ISSUES_DIR}/agent-loop-lock-release.sh"
|
||||
exit 0
|
||||
fi
|
||||
echo "[agent-loop-n-cycles] $(date -Iseconds) — Cycle $i/$N"
|
||||
"${GITEA_ISSUES_DIR}/agent-loop-retrieval-once.sh" || true
|
||||
"${GIT_ISSUES_DIR}/agent-loop-retrieval-once.sh" || true
|
||||
|
||||
if [ "${AGENT_LOOP_RUN_AGENT:-0}" = "1" ] && command -v agent >/dev/null 2>&1; then
|
||||
AGENT_MODEL="${AGENT_LOOP_MODEL:-sonnet-4.6}"
|
||||
@ -68,5 +68,5 @@ while [ "$i" -le "$N" ]; do
|
||||
i=$((i + 1))
|
||||
done
|
||||
|
||||
"${GITEA_ISSUES_DIR}/agent-loop-lock-release.sh"
|
||||
"${GIT_ISSUES_DIR}/agent-loop-lock-release.sh"
|
||||
echo "[agent-loop-n-cycles] $(date -Iseconds) — $N cycles terminés."
|
||||
@ -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:
|
||||
# Depuis la racine de ia_dev : ./gitea-issues/agent-loop-retrieval-once.sh
|
||||
# Depuis la racine de ia_dev : ./git-issues/agent-loop-retrieval-once.sh
|
||||
#
|
||||
set -euo pipefail
|
||||
if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then
|
||||
@ -13,27 +13,27 @@ if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then
|
||||
set -u
|
||||
fi
|
||||
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
ROOT="$(cd "${GITEA_ISSUES_DIR}/../.." && pwd)"
|
||||
export GITEA_ISSUES_DIR
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
ROOT="$(cd "${GIT_ISSUES_DIR}/../.." && pwd)"
|
||||
export GIT_ISSUES_DIR
|
||||
export REPO_ROOT="${ROOT}"
|
||||
cd "$ROOT"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
source "${GIT_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
# When no PROJECT_ID (no MAIL_TO/AI_AGENT_TOKEN), use generic ROOT/logs for status/pending file
|
||||
LOGS_GITEA="${PROJECT_LOGS_DIR:-$ROOT/logs}/gitea-issues"
|
||||
LOGS_GIT_ISSUES="${PROJECT_LOGS_DIR:-$ROOT/logs}/git-issues"
|
||||
|
||||
STATUS_FILE="${AGENT_LOOP_STATUS_FILE:-$LOGS_GITEA/agent-loop.status}"
|
||||
PENDING_FILE="${AGENT_LOOP_PENDING_FILE:-$LOGS_GITEA/agent-loop.pending}"
|
||||
STATUS_FILE="${AGENT_LOOP_STATUS_FILE:-$LOGS_GIT_ISSUES/agent-loop.status}"
|
||||
PENDING_FILE="${AGENT_LOOP_PENDING_FILE:-$LOGS_GIT_ISSUES/agent-loop.pending}"
|
||||
mkdir -p "$(dirname "$STATUS_FILE")"
|
||||
|
||||
write_status() {
|
||||
printf "%s\n%s\n%s\n" "$(date -Iseconds)" "$1" "${2:-}" > "$STATUS_FILE"
|
||||
}
|
||||
|
||||
"${GITEA_ISSUES_DIR}/tickets-fetch-inbox.sh" 2>&1 || true
|
||||
"${GIT_ISSUES_DIR}/tickets-fetch-inbox.sh" 2>&1 || true
|
||||
pending_out=""
|
||||
pending_out=$("${GITEA_ISSUES_DIR}/list-pending-spooler.sh" 2>&1) || true
|
||||
pending_out=$("${GIT_ISSUES_DIR}/list-pending-spooler.sh" 2>&1) || true
|
||||
if [ -n "$pending_out" ] && echo "$pending_out" | grep -q "\.pending"; then
|
||||
write_status "mails_pending" "One-shot: mails en attente dans le spooler (from/to)."
|
||||
printf "%s\n%s\n%s\n%s\n" "$(date -Iseconds)" "mails_pending" "---" "$pending_out" > "$PENDING_FILE"
|
||||
@ -3,7 +3,7 @@
|
||||
# Run from repo root.
|
||||
#
|
||||
# Usage:
|
||||
# Depuis la racine de ia_dev : ./gitea-issues/agent-loop-stop-requested.sh
|
||||
# Depuis la racine de ia_dev : ./git-issues/agent-loop-stop-requested.sh
|
||||
#
|
||||
set -euo pipefail
|
||||
if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then
|
||||
@ -13,15 +13,15 @@ if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then
|
||||
set -u
|
||||
fi
|
||||
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
ROOT="$(cd "${GITEA_ISSUES_DIR}/../.." && pwd)"
|
||||
export GITEA_ISSUES_DIR
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
ROOT="$(cd "${GIT_ISSUES_DIR}/../.." && pwd)"
|
||||
export GIT_ISSUES_DIR
|
||||
export REPO_ROOT="${ROOT}"
|
||||
cd "$ROOT"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
LOGS_GITEA="${PROJECT_LOGS_DIR:-$ROOT/logs}/gitea-issues"
|
||||
source "${GIT_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
LOGS_GIT_ISSUES="${PROJECT_LOGS_DIR:-$ROOT/logs}/git-issues"
|
||||
|
||||
STOP_FILE="${AGENT_LOOP_STOP_FILE:-$LOGS_GITEA/agent-loop.stop}"
|
||||
STOP_FILE="${AGENT_LOOP_STOP_FILE:-$LOGS_GIT_ISSUES/agent-loop.stop}"
|
||||
[ -f "$STOP_FILE" ]
|
||||
# exit 0 if file exists, 1 otherwise
|
||||
@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
# Create agent-loop.stop so the running agent-loop (section 2) stops at the next cycle start.
|
||||
# Run from repo root. Same paths as agent-loop-retrieval-once.sh (projects/<id>/logs/gitea-issues).
|
||||
# Run from repo root. Same paths as agent-loop-retrieval-once.sh (projects/<id>/logs/git-issues).
|
||||
#
|
||||
# Usage:
|
||||
# Depuis la racine de ia_dev : ./gitea-issues/agent-loop-stop.sh
|
||||
# Depuis la racine de ia_dev : ./git-issues/agent-loop-stop.sh
|
||||
#
|
||||
set -euo pipefail
|
||||
if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then
|
||||
@ -13,16 +13,16 @@ if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then
|
||||
set -u
|
||||
fi
|
||||
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
ROOT="$(cd "${GITEA_ISSUES_DIR}/../.." && pwd)"
|
||||
export GITEA_ISSUES_DIR
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
ROOT="$(cd "${GIT_ISSUES_DIR}/../.." && pwd)"
|
||||
export GIT_ISSUES_DIR
|
||||
export REPO_ROOT="${ROOT}"
|
||||
cd "$ROOT"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
LOGS_GITEA="${PROJECT_LOGS_DIR:-$ROOT/logs}/gitea-issues"
|
||||
source "${GIT_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
LOGS_GIT_ISSUES="${PROJECT_LOGS_DIR:-$ROOT/logs}/git-issues"
|
||||
|
||||
STOP_FILE="${AGENT_LOOP_STOP_FILE:-$LOGS_GITEA/agent-loop.stop}"
|
||||
STOP_FILE="${AGENT_LOOP_STOP_FILE:-$LOGS_GIT_ISSUES/agent-loop.stop}"
|
||||
mkdir -p "$(dirname "$STOP_FILE")"
|
||||
touch "$STOP_FILE"
|
||||
echo "[agent-loop-stop] $(date -Iseconds) — $STOP_FILE créé. La boucle en cours s'arrêtera au début du prochain cycle."
|
||||
52
git-issues/agent-loop-treatment.sh
Executable file
52
git-issues/agent-loop-treatment.sh
Executable file
@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env bash
|
||||
# Treatment loop: periodically check agent-loop.pending and run Cursor Agent CLI (git-issues-process workflow) when non-empty.
|
||||
# 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/&):
|
||||
# Depuis la racine de ia_dev : ./git-issues/agent-loop-treatment.sh
|
||||
#
|
||||
set -euo pipefail
|
||||
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"
|
||||
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || ROOT="$(cd "${GIT_ISSUES_DIR}/../.." && pwd)"
|
||||
export GIT_ISSUES_DIR
|
||||
export REPO_ROOT="${ROOT}"
|
||||
cd "$ROOT"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GIT_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
LOGS_GIT_ISSUES="${PROJECT_LOGS_DIR:-$ROOT/logs}/git-issues"
|
||||
|
||||
PENDING_FILE="${AGENT_LOOP_PENDING_FILE:-$LOGS_GIT_ISSUES/agent-loop.pending}"
|
||||
LOG_DIR="$(dirname "$PENDING_FILE")"
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
AGENT_LOOP_ENV="${GIT_ISSUES_DIR}/../.secrets/git-issues/agent-loop.env"
|
||||
if [ -r "$AGENT_LOOP_ENV" ]; then
|
||||
set +u
|
||||
# shellcheck source=/dev/null
|
||||
source "$AGENT_LOOP_ENV"
|
||||
set -u
|
||||
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 git-issues-process). Les chemins des fichiers .pending sont dans projects/<id>/logs/git-issues/agent-loop.pending (ou exécuter ./git-issues/list-pending-spooler.sh). Pour chaque fichier .pending : lire le JSON (from, to, subject, body, message_id, base). Répondre à l'expéditeur (--to <from> du JSON), pas à une adresse fixe ; le « to » du mail reçu a déjà déterminé le projet. 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 ./git-issues/mail-send-reply.sh --to <from> --subject \"Re: ...\" --body \"<ta_réponse>\" --in-reply-to \"<message_id>\". Après envoi réussi : ./git-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
|
||||
echo "[agent-loop-treatment] $(date -Iseconds) — Pending non vide, lancement de l'agent Cursor."
|
||||
if agent -p "$PROMPT" -f --model "$AGENT_MODEL" 2>&1; then
|
||||
echo "[agent-loop-treatment] $(date -Iseconds) — Agent terminé."
|
||||
else
|
||||
echo "[agent-loop-treatment] $(date -Iseconds) — Agent terminé avec erreur."
|
||||
fi
|
||||
fi
|
||||
sleep "$INTERVAL"
|
||||
done
|
||||
19
git-issues/agent-loop.env.example
Normal file
19
git-issues/agent-loop.env.example
Normal file
@ -0,0 +1,19 @@
|
||||
# Agent-loop parameters (Cursor Agent CLI, model, interval).
|
||||
# Copy to .secrets/git-issues/agent-loop.env and set as needed.
|
||||
# Do not commit .secrets/git-issues/agent-loop.env (directory is gitignored).
|
||||
#
|
||||
# Run Cursor Agent when unread mails are detected (0 or 1)
|
||||
# AGENT_LOOP_RUN_AGENT=1
|
||||
#
|
||||
# Model used by the CLI (default: sonnet-4.6 to avoid Opus usage limits)
|
||||
# List: agent models
|
||||
# AGENT_LOOP_MODEL=sonnet-4.6
|
||||
#
|
||||
# Polling interval in seconds (default: 60)
|
||||
# AGENT_LOOP_INTERVAL_SEC=60
|
||||
#
|
||||
# Optional: custom paths for status, pending, lock and stop files
|
||||
# AGENT_LOOP_STATUS_FILE=ia_dev/projects/<id>/logs/git-issues/agent-loop.status
|
||||
# AGENT_LOOP_PENDING_FILE=ia_dev/projects/<id>/logs/git-issues/agent-loop.pending
|
||||
# AGENT_LOOP_LOCK_FILE=ia_dev/projects/<id>/logs/git-issues/agent-loop.lock
|
||||
# AGENT_LOOP_STOP_FILE=ia_dev/projects/<id>/logs/git-issues/agent-loop.stop
|
||||
@ -3,12 +3,12 @@
|
||||
# Run from repo root. Runs forever. Do NOT start from the agent-loop agent (use bounded runs only, e.g. agent-loop-chat-iterations.sh N).
|
||||
#
|
||||
# Usage (manual only; agent must not launch with nohup/&):
|
||||
# ./gitea-issues/agent-loop.sh [interval_seconds]
|
||||
# AGENT_LOOP_INTERVAL_SEC=120 ./gitea-issues/agent-loop.sh
|
||||
# ./git-issues/agent-loop.sh [interval_seconds]
|
||||
# AGENT_LOOP_INTERVAL_SEC=120 ./git-issues/agent-loop.sh
|
||||
#
|
||||
# Witness file: projects/<id>/logs/gitea-issues/agent-loop.status (or AGENT_LOOP_STATUS_FILE)
|
||||
# Witness file: projects/<id>/logs/git-issues/agent-loop.status (or AGENT_LOOP_STATUS_FILE)
|
||||
# State file (not a log): updated every iteration. If mtime is older than 2*interval, loop is considered stopped.
|
||||
# Pending file: projects/<id>/logs/gitea-issues/agent-loop.pending (or AGENT_LOOP_PENDING_FILE)
|
||||
# Pending file: projects/<id>/logs/git-issues/agent-loop.pending (or AGENT_LOOP_PENDING_FILE)
|
||||
# Written when there are .pending mails in the spooler (no matching .response); contains paths to treat.
|
||||
#
|
||||
# Optional: set AGENT_LOOP_RUN_AGENT=1 to run the Cursor Agent CLI when mails are detected.
|
||||
@ -26,18 +26,18 @@ if [ -n "${HOME:-}" ] && [ -r "$HOME/.bashrc" ]; then
|
||||
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
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
ROOT="$(cd "${GIT_ISSUES_DIR}/../.." && pwd)"
|
||||
export GIT_ISSUES_DIR
|
||||
export REPO_ROOT="${ROOT}"
|
||||
cd "$ROOT"
|
||||
# Per-project logs under projects/<id>/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"
|
||||
source "${GIT_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
LOGS_GIT_ISSUES="${PROJECT_LOGS_DIR:-$ROOT/logs}/git-issues"
|
||||
|
||||
# Load agent-loop parameters from .secrets (optional; .secrets under ia_dev)
|
||||
AGENT_LOOP_ENV="${GITEA_ISSUES_DIR}/../.secrets/gitea-issues/agent-loop.env"
|
||||
AGENT_LOOP_ENV="${GIT_ISSUES_DIR}/../.secrets/git-issues/agent-loop.env"
|
||||
if [ -r "$AGENT_LOOP_ENV" ]; then
|
||||
set +u
|
||||
# shellcheck source=/dev/null
|
||||
@ -46,9 +46,9 @@ if [ -r "$AGENT_LOOP_ENV" ]; then
|
||||
fi
|
||||
|
||||
INTERVAL="${1:-${AGENT_LOOP_INTERVAL_SEC:-60}}"
|
||||
# STATUS_FILE: state/witness file (not a log) — indicates if the loop is active; under projects/<id>/logs/gitea-issues/ for per-project state.
|
||||
STATUS_FILE="${AGENT_LOOP_STATUS_FILE:-$LOGS_GITEA/agent-loop.status}"
|
||||
PENDING_FILE="${AGENT_LOOP_PENDING_FILE:-$LOGS_GITEA/agent-loop.pending}"
|
||||
# STATUS_FILE: state/witness file (not a log) — indicates if the loop is active; under projects/<id>/logs/git-issues/ for per-project state.
|
||||
STATUS_FILE="${AGENT_LOOP_STATUS_FILE:-$LOGS_GIT_ISSUES/agent-loop.status}"
|
||||
PENDING_FILE="${AGENT_LOOP_PENDING_FILE:-$LOGS_GIT_ISSUES/agent-loop.pending}"
|
||||
mkdir -p "$(dirname "$STATUS_FILE")"
|
||||
|
||||
write_status() {
|
||||
@ -60,20 +60,20 @@ write_status() {
|
||||
while true; do
|
||||
write_status "running" "interval=${INTERVAL}s"
|
||||
# Spooler flow: fetch by from/to (conf.json), then list .pending without .response. No IMAP unread criterion.
|
||||
"${GITEA_ISSUES_DIR}/tickets-fetch-inbox.sh" 2>&1 || true
|
||||
"${GIT_ISSUES_DIR}/tickets-fetch-inbox.sh" 2>&1 || true
|
||||
pending_out=""
|
||||
pending_out=$("${GITEA_ISSUES_DIR}/list-pending-spooler.sh" 2>&1) || true
|
||||
pending_out=$("${GIT_ISSUES_DIR}/list-pending-spooler.sh" 2>&1) || true
|
||||
if [ -n "$pending_out" ] && echo "$pending_out" | grep -q "\.pending"; then
|
||||
write_status "mails_pending" "Mails en attente dans le spooler (from/to). Lancer l'agent gitea-issues-process dans Cursor."
|
||||
write_status "mails_pending" "Mails en attente dans le spooler (from/to). Lancer l'agent git-issues-process dans Cursor."
|
||||
printf "%s\n%s\n%s\n%s\n" "$(date -Iseconds)" "mails_pending" "---" "$pending_out" > "$PENDING_FILE"
|
||||
n=$(echo "$pending_out" | grep -c "\.pending" || true)
|
||||
echo "[agent-loop] $(date -Iseconds) — $n mail(s) en attente dans le spooler (critère from/to). Lancer l'agent gitea-issues-process dans Cursor."
|
||||
echo "[agent-loop] $(date -Iseconds) — $n mail(s) en attente dans le spooler (critère from/to). Lancer l'agent git-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 du spooler."
|
||||
echo "[agent-loop] $(date -Iseconds) — Lancement de l'agent Cursor (workflow gitea-issues-process spooler)."
|
||||
echo "[agent-loop] $(date -Iseconds) — Lancement de l'agent Cursor (workflow git-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 ./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épondre à l'expéditeur (--to <from> du JSON), pas à une adresse fixe ; le « to » du mail reçu a déjà déterminé le projet. 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")
|
||||
AGENT_OPTS=(-p "Exécute le workflow mails du spooler (agent git-issues-process). 1) Lister les mails à traiter avec ./git-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épondre à l'expéditeur (--to <from> du JSON), pas à une adresse fixe ; le « to » du mail reçu a déjà déterminé le projet. 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 ./git-issues/mail-send-reply.sh --to <from> --subject \"Re: ...\" --body \"<ta_réponse>\" --in-reply-to \"<message_id>\". Après envoi réussi : ./git-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
|
||||
@ -7,9 +7,9 @@
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh"
|
||||
source "${GIT_ISSUES_DIR}/lib.sh"
|
||||
|
||||
# Signature appended to every comment (same as mail replies)
|
||||
COMMENT_SIGNATURE=$'\n\n--\nSupport IA du projet Lecoffre.io\nai.support.lecoffreio@4nkweb.com'
|
||||
@ -6,9 +6,9 @@
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh"
|
||||
source "${GIT_ISSUES_DIR}/lib.sh"
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
log_err "Usage: $0 <issue_number> [base_branch]"
|
||||
@ -5,9 +5,9 @@
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh"
|
||||
source "${GIT_ISSUES_DIR}/lib.sh"
|
||||
|
||||
require_jq || exit 1
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# IMAP config for mail-to-issue (e.g. Proton Mail Bridge).
|
||||
# Copy to .secrets/gitea-issues/imap-bridge.env and set real values.
|
||||
# Do not commit .secrets/gitea-issues/imap-bridge.env (directory is gitignored).
|
||||
# Copy to .secrets/git-issues/imap-bridge.env and set real values.
|
||||
# Do not commit .secrets/git-issues/imap-bridge.env (directory is gitignored).
|
||||
#
|
||||
# IMAP (read)
|
||||
# IMAP_HOST=127.0.0.1
|
||||
@ -1,11 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Shared config and helpers for Gitea issues scripts.
|
||||
# Source from gitea-issues/*.sh. Standalone: run from ia_dev root.
|
||||
# Source from git-issues/*.sh. Standalone: run from ia_dev root.
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
GITEA_API_URL="${GITEA_API_URL:-https://git.4nkweb.com/api/v1}"
|
||||
GITEA_REPO_OWNER="${GITEA_REPO_OWNER:-4nk}"
|
||||
GITEA_REPO_NAME="${GITEA_REPO_NAME:-lecoffre_ng}"
|
||||
@ -14,15 +14,15 @@ GITEA_REPO_NAME="${GITEA_REPO_NAME:-lecoffre_ng}"
|
||||
PROJECT_CONFIG_PATH=""
|
||||
PROJECT_LOGS_DIR=""
|
||||
DATA_ISSUES_DIR=""
|
||||
if [[ -f "${GITEA_ISSUES_DIR}/../lib/project_config.sh" ]]; then
|
||||
if [[ -f "${GIT_ISSUES_DIR}/../lib/project_config.sh" ]]; then
|
||||
PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || true
|
||||
if [[ -z "${PROJECT_ROOT:-}" || "$(basename "$PROJECT_ROOT")" = "ia_dev" ]]; then
|
||||
PROJECT_ROOT="$(cd "${GITEA_ISSUES_DIR}/../.." && pwd)"
|
||||
PROJECT_ROOT="$(cd "${GIT_ISSUES_DIR}/../.." && pwd)"
|
||||
fi
|
||||
IA_DEV_ROOT="$(cd "$GITEA_ISSUES_DIR/.." && pwd)"
|
||||
IA_DEV_ROOT="$(cd "$GIT_ISSUES_DIR/.." && pwd)"
|
||||
if [[ -n "${PROJECT_ROOT:-}" ]]; then
|
||||
# shellcheck source=../lib/project_config.sh
|
||||
source "${GITEA_ISSUES_DIR}/../lib/project_config.sh"
|
||||
source "${GIT_ISSUES_DIR}/../lib/project_config.sh"
|
||||
if [[ -n "${PROJECT_ID:-}" && -n "${IA_DEV_ROOT:-}" ]]; then
|
||||
PROJECT_LOGS_DIR="${IA_DEV_ROOT}/projects/${PROJECT_ID}/logs"
|
||||
DATA_ISSUES_DIR="${IA_DEV_ROOT}/projects/${PROJECT_ID}/data/issues"
|
||||
@ -33,10 +33,10 @@ fi
|
||||
export PROJECT_LOGS_DIR
|
||||
export DATA_ISSUES_DIR
|
||||
|
||||
if [[ -f "${GITEA_ISSUES_DIR}/../lib/smart_ide_logs.sh" ]]; then
|
||||
if [[ -f "${GIT_ISSUES_DIR}/../lib/smart_ide_logs.sh" ]]; then
|
||||
# shellcheck source=../lib/smart_ide_logs.sh
|
||||
source "${GITEA_ISSUES_DIR}/../lib/smart_ide_logs.sh"
|
||||
_IA_DEV_ROOT_FOR_LOG="$(cd "${GITEA_ISSUES_DIR}/.." && pwd)"
|
||||
source "${GIT_ISSUES_DIR}/../lib/smart_ide_logs.sh"
|
||||
_IA_DEV_ROOT_FOR_LOG="$(cd "${GIT_ISSUES_DIR}/.." && pwd)"
|
||||
smart_ide_logs_begin "$_IA_DEV_ROOT_FOR_LOG" "${BASH_SOURCE[1]}" "$*"
|
||||
smart_ide_logs_register_exit_trap
|
||||
fi
|
||||
@ -47,7 +47,7 @@ load_gitea_token() {
|
||||
return 0
|
||||
fi
|
||||
local token_file=""
|
||||
local ia_dev_root="${GITEA_ISSUES_DIR}/.."
|
||||
local ia_dev_root="${GIT_ISSUES_DIR}/.."
|
||||
if [[ -n "${PROJECT_CONFIG_PATH:-}" && -f "$PROJECT_CONFIG_PATH" ]] && command -v jq >/dev/null 2>&1; then
|
||||
local rel_path
|
||||
rel_path="$(jq -r '.git.token_file // empty' "$PROJECT_CONFIG_PATH" 2>/dev/null)"
|
||||
@ -59,14 +59,14 @@ load_gitea_token() {
|
||||
fi
|
||||
fi
|
||||
if [[ -z "$token_file" ]]; then
|
||||
token_file="${ia_dev_root}/.secrets/gitea-issues/token"
|
||||
token_file="${ia_dev_root}/.secrets/git-issues/token"
|
||||
fi
|
||||
if [[ -f "$token_file" ]]; then
|
||||
GITEA_TOKEN="$(cat "$token_file")"
|
||||
return 0
|
||||
fi
|
||||
echo "[gitea-issues] ERROR: GITEA_TOKEN not set and ${token_file} not found" >&2
|
||||
echo "[gitea-issues] Set GITEA_TOKEN or create the token file with a Gitea Personal Access Token." >&2
|
||||
echo "[git-issues] ERROR: GITEA_TOKEN not set and ${token_file} not found" >&2
|
||||
echo "[git-issues] Set GITEA_TOKEN or create the token file with a Gitea Personal Access Token." >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
@ -111,8 +111,8 @@ gitea_api_delete() {
|
||||
}
|
||||
|
||||
log_ts() { date -u '+%Y-%m-%dT%H:%M:%SZ'; }
|
||||
log_info() { echo "[$(log_ts)] [gitea-issues] $*"; }
|
||||
log_err() { echo "[$(log_ts)] [gitea-issues] $*" >&2; }
|
||||
log_info() { echo "[$(log_ts)] [git-issues] $*"; }
|
||||
log_err() { echo "[$(log_ts)] [git-issues] $*" >&2; }
|
||||
|
||||
# Require jq for JSON output
|
||||
require_jq() {
|
||||
@ -6,9 +6,9 @@
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh"
|
||||
source "${GIT_ISSUES_DIR}/lib.sh"
|
||||
|
||||
require_jq || exit 1
|
||||
|
||||
@ -2,20 +2,20 @@
|
||||
# List .pending files in projects/<id>/data/issues/ with status "pending" (one file per message; status updated in place).
|
||||
# Run from ia_dev root. If PROJECT_ID is set (from MAIL_TO or AI_AGENT_TOKEN), list that project only; else list all projects.
|
||||
# Output: one path per line.
|
||||
# Usage: depuis la racine de ia_dev : ./gitea-issues/list-pending-spooler.sh
|
||||
# Usage: depuis la racine de ia_dev : ./git-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)"
|
||||
export GITEA_ISSUES_DIR
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
ROOT="$(cd "${GIT_ISSUES_DIR}/../.." && pwd)"
|
||||
export GIT_ISSUES_DIR
|
||||
cd "$ROOT"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
source "${GIT_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
if [[ -n "${DATA_ISSUES_DIR:-}" && -d "${DATA_ISSUES_DIR}" ]]; then
|
||||
SPOOLS=("${DATA_ISSUES_DIR}")
|
||||
else
|
||||
# No project from MAIL_TO/AI_AGENT_TOKEN: list pending from all projects
|
||||
SPOOLS=()
|
||||
for spool in "${GITEA_ISSUES_DIR}/../projects/"*/data/issues; do
|
||||
for spool in "${GIT_ISSUES_DIR}/../projects/"*/data/issues; do
|
||||
[[ -d "$spool" ]] || continue
|
||||
SPOOLS+=("$spool")
|
||||
done
|
||||
@ -2,7 +2,7 @@
|
||||
"""
|
||||
Create one Gitea issue from one email (by UID), then mark the email as read.
|
||||
If --title and/or --body are provided (formalized by agent), use them; else use subject and body from the email.
|
||||
Usage: ./gitea-issues/mail-create-issue-from-email.sh --uid <uid> [--title "..." ] [--body "..." ]
|
||||
Usage: ./git-issues/mail-create-issue-from-email.sh --uid <uid> [--title "..." ] [--body "..." ]
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@ -63,13 +63,13 @@ def main() -> None:
|
||||
cfg = load_imap_config()
|
||||
if not cfg["user"] or not cfg["password"]:
|
||||
root = repo_root()
|
||||
env_path = root / ".secrets" / "gitea-issues" / "imap-bridge.env"
|
||||
print("[gitea-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.", file=sys.stderr)
|
||||
env_path = root / ".secrets" / "git-issues" / "imap-bridge.env"
|
||||
print("[git-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
gitea = load_gitea_config()
|
||||
if not gitea["token"]:
|
||||
print("[gitea-issues] ERROR: GITEA_TOKEN not set.", file=sys.stderr)
|
||||
print("[git-issues] ERROR: GITEA_TOKEN not set.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
mail = imaplib.IMAP4(cfg["host"], int(cfg["port"]))
|
||||
@ -79,7 +79,7 @@ def main() -> None:
|
||||
mail.select("INBOX")
|
||||
_, data = mail.fetch(args.uid, "(RFC822)")
|
||||
if not data or not data[0]:
|
||||
print("[gitea-issues] ERROR: Message UID not found.", file=sys.stderr)
|
||||
print("[git-issues] ERROR: Message UID not found.", file=sys.stderr)
|
||||
mail.logout()
|
||||
sys.exit(1)
|
||||
|
||||
@ -94,7 +94,7 @@ def main() -> None:
|
||||
|
||||
issue = create_gitea_issue(title, body)
|
||||
if not issue:
|
||||
print("[gitea-issues] ERROR: Failed to create issue.", file=sys.stderr)
|
||||
print("[git-issues] ERROR: Failed to create issue.", file=sys.stderr)
|
||||
mail.logout()
|
||||
sys.exit(1)
|
||||
|
||||
@ -102,7 +102,7 @@ def main() -> None:
|
||||
mail.logout()
|
||||
|
||||
num = issue.get("number", "?")
|
||||
print(f"[gitea-issues] Created issue #{num}: {title[:60]}")
|
||||
print(f"[git-issues] Created issue #{num}: {title[:60]}")
|
||||
print(f"ISSUE_NUMBER={num}")
|
||||
|
||||
|
||||
14
git-issues/mail-create-issue-from-email.sh
Executable file
14
git-issues/mail-create-issue-from-email.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
# Create one Gitea issue from one email (by UID), mark email read. Run from repo root.
|
||||
# Usage: ./git-issues/mail-create-issue-from-email.sh --uid <uid> [--title "..." ] [--body "..." ]
|
||||
set -euo pipefail
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
export GIT_ISSUES_DIR
|
||||
export REPO_ROOT="${GIT_ISSUES_DIR}/.."
|
||||
_IA_FOR_LOG="$(cd "${GIT_ISSUES_DIR}/.." && pwd)"
|
||||
if [[ -f "${_IA_FOR_LOG}/lib/smart_ide_logs.sh" ]]; then
|
||||
# shellcheck source=../lib/smart_ide_logs.sh
|
||||
source "${_IA_FOR_LOG}/lib/smart_ide_logs.sh"
|
||||
smart_ide_logs_begin "$_IA_FOR_LOG" "$0" "$*"
|
||||
fi
|
||||
exec python3 "${GIT_ISSUES_DIR}/mail-create-issue-from-email.py" "$@"
|
||||
@ -4,7 +4,7 @@ Fetch the full email thread (conversation) for a given message UID.
|
||||
Uses Message-ID, References and In-Reply-To to find all messages in the thread.
|
||||
Output format: same as mail-list-unread (--- MAIL UID=... --- ... --- END MAIL ---), chronological order.
|
||||
Usage: mail-get-thread.py <uid>
|
||||
or: ./gitea-issues/mail-get-thread.sh <uid>
|
||||
or: ./git-issues/mail-get-thread.sh <uid>
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@ -137,18 +137,18 @@ def main() -> int:
|
||||
return 1
|
||||
uid0 = sys.argv[1].strip()
|
||||
if not uid0:
|
||||
print("[gitea-issues] ERROR: UID required.", file=sys.stderr)
|
||||
print("[git-issues] ERROR: UID required.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
cfg = load_imap_config()
|
||||
if not cfg["user"] or not cfg["password"]:
|
||||
root = repo_root()
|
||||
env_path = root / ".secrets" / "gitea-issues" / "imap-bridge.env"
|
||||
env_path = root / ".secrets" / "git-issues" / "imap-bridge.env"
|
||||
print(
|
||||
"[gitea-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.",
|
||||
"[git-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
print(f"[gitea-issues] Set env or create {env_path}", file=sys.stderr)
|
||||
print(f"[git-issues] Set env or create {env_path}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
mail = imaplib.IMAP4(cfg["host"], int(cfg["port"]))
|
||||
@ -159,7 +159,7 @@ def main() -> int:
|
||||
|
||||
msg0 = fetch_message_by_uid(mail, uid0)
|
||||
if not msg0:
|
||||
print(f"[gitea-issues] No message found for UID={uid0}.", file=sys.stderr)
|
||||
print(f"[git-issues] No message found for UID={uid0}.", file=sys.stderr)
|
||||
mail.logout()
|
||||
return 1
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
# Fetch full email thread for a given UID. Run from repo root.
|
||||
# Usage: ./gitea-issues/mail-get-thread.sh <uid>
|
||||
# Usage: ./git-issues/mail-get-thread.sh <uid>
|
||||
set -euo pipefail
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
export GITEA_ISSUES_DIR
|
||||
export REPO_ROOT="${GITEA_ISSUES_DIR}/.."
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
export GIT_ISSUES_DIR
|
||||
export REPO_ROOT="${GIT_ISSUES_DIR}/.."
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "Usage: $0 <uid>" >&2
|
||||
exit 1
|
||||
fi
|
||||
_IA_FOR_LOG="$(cd "${GITEA_ISSUES_DIR}/.." && pwd)"
|
||||
_IA_FOR_LOG="$(cd "${GIT_ISSUES_DIR}/.." && pwd)"
|
||||
if [[ -f "${_IA_FOR_LOG}/lib/smart_ide_logs.sh" ]]; then
|
||||
# shellcheck source=../lib/smart_ide_logs.sh
|
||||
source "${_IA_FOR_LOG}/lib/smart_ide_logs.sh"
|
||||
smart_ide_logs_begin "$_IA_FOR_LOG" "$0" "$*"
|
||||
fi
|
||||
exec python3 "${GITEA_ISSUES_DIR}/mail-get-thread.py" "$1"
|
||||
exec python3 "${GIT_ISSUES_DIR}/mail-get-thread.py" "$1"
|
||||
@ -3,7 +3,7 @@
|
||||
List unread emails via IMAP (e.g. Proton Mail Bridge). Read-only; does not mark as read.
|
||||
Only lists messages sent to the configured alias (MAIL_FILTER_TO, default ai.support.lecoffreio@4nkweb.com).
|
||||
Output is for the agent: each mail with UID, Message-ID, From, To, Subject, Date, body.
|
||||
Usage: ./gitea-issues/mail-list-unread.sh
|
||||
Usage: ./git-issues/mail-list-unread.sh
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@ -14,7 +14,7 @@ import sys
|
||||
from email.header import decode_header
|
||||
from pathlib import Path
|
||||
|
||||
# Add gitea-issues to path for mail_common
|
||||
# Add git-issues to path for mail_common
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
from mail_common import imap_search_criterion_unseen, load_imap_config, repo_root, imap_ssl_context
|
||||
|
||||
@ -65,9 +65,9 @@ def main() -> None:
|
||||
cfg = load_imap_config()
|
||||
if not cfg["user"] or not cfg["password"]:
|
||||
root = repo_root()
|
||||
env_path = root / ".secrets" / "gitea-issues" / "imap-bridge.env"
|
||||
print("[gitea-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.", file=sys.stderr)
|
||||
print(f"[gitea-issues] Set env or create {env_path}", file=sys.stderr)
|
||||
env_path = root / ".secrets" / "git-issues" / "imap-bridge.env"
|
||||
print("[git-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.", file=sys.stderr)
|
||||
print(f"[git-issues] Set env or create {env_path}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
mail = imaplib.IMAP4(cfg["host"], int(cfg["port"]))
|
||||
@ -79,7 +79,7 @@ def main() -> None:
|
||||
_, nums = mail.search(None, criterion)
|
||||
ids = nums[0].split()
|
||||
if not ids:
|
||||
print("[gitea-issues] No unread messages (IMAP UNSEEN, on or after MAIL_SINCE_DATE). For spooler criterion (from/to), use tickets-fetch-inbox.sh and list-pending-spooler.sh.")
|
||||
print("[git-issues] No unread messages (IMAP UNSEEN, on or after MAIL_SINCE_DATE). For spooler criterion (from/to), use tickets-fetch-inbox.sh and list-pending-spooler.sh.")
|
||||
mail.logout()
|
||||
return
|
||||
|
||||
@ -110,7 +110,7 @@ def main() -> None:
|
||||
shown += 1
|
||||
|
||||
if shown == 0:
|
||||
print("[gitea-issues] No unread messages sent to the configured alias (MAIL_FILTER_TO). For spooler (from/to in conf.json), use tickets-fetch-inbox.sh and list-pending-spooler.sh.")
|
||||
print("[git-issues] No unread messages sent to the configured alias (MAIL_FILTER_TO). For spooler (from/to in conf.json), use tickets-fetch-inbox.sh and list-pending-spooler.sh.")
|
||||
mail.logout()
|
||||
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
# List unread emails (read-only). Run from repo root.
|
||||
set -euo pipefail
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
# REPO_ROOT = ia_dev so mail_common.repo_root() finds .secrets under ia_dev
|
||||
export GITEA_ISSUES_DIR
|
||||
export REPO_ROOT="${GITEA_ISSUES_DIR}/.."
|
||||
_IA_FOR_LOG="$(cd "${GITEA_ISSUES_DIR}/.." && pwd)"
|
||||
export GIT_ISSUES_DIR
|
||||
export REPO_ROOT="${GIT_ISSUES_DIR}/.."
|
||||
_IA_FOR_LOG="$(cd "${GIT_ISSUES_DIR}/.." && pwd)"
|
||||
if [[ -f "${_IA_FOR_LOG}/lib/smart_ide_logs.sh" ]]; then
|
||||
# shellcheck source=../lib/smart_ide_logs.sh
|
||||
source "${_IA_FOR_LOG}/lib/smart_ide_logs.sh"
|
||||
smart_ide_logs_begin "$_IA_FOR_LOG" "$0" "$*"
|
||||
fi
|
||||
exec python3 "${GITEA_ISSUES_DIR}/mail-list-unread.py"
|
||||
exec python3 "${GIT_ISSUES_DIR}/mail-list-unread.py"
|
||||
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Mark one email as read by UID (e.g. after replying without creating an issue).
|
||||
Usage: ./gitea-issues/mail-mark-read.sh <uid>
|
||||
Usage: ./git-issues/mail-mark-read.sh <uid>
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@ -16,15 +16,15 @@ from mail_common import load_imap_config, repo_root, imap_ssl_context
|
||||
|
||||
def main() -> None:
|
||||
if len(sys.argv) < 2:
|
||||
print("[gitea-issues] Usage: mail-mark-read.sh <uid>", file=sys.stderr)
|
||||
print("[git-issues] Usage: mail-mark-read.sh <uid>", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
uid = sys.argv[1].strip()
|
||||
|
||||
cfg = load_imap_config()
|
||||
if not cfg["user"] or not cfg["password"]:
|
||||
root = repo_root()
|
||||
env_path = root / ".secrets" / "gitea-issues" / "imap-bridge.env"
|
||||
print("[gitea-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.", file=sys.stderr)
|
||||
env_path = root / ".secrets" / "git-issues" / "imap-bridge.env"
|
||||
print("[git-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
mail = imaplib.IMAP4(cfg["host"], int(cfg["port"]))
|
||||
@ -34,7 +34,7 @@ def main() -> None:
|
||||
mail.select("INBOX")
|
||||
mail.store(uid, "+FLAGS", "\\Seen")
|
||||
mail.logout()
|
||||
print("[gitea-issues] Marked as read.")
|
||||
print("[git-issues] Marked as read.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
14
git-issues/mail-mark-read.sh
Executable file
14
git-issues/mail-mark-read.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
# Mark one email as read by UID. Run from repo root.
|
||||
# Usage: ./git-issues/mail-mark-read.sh <uid>
|
||||
set -euo pipefail
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
export GIT_ISSUES_DIR
|
||||
export REPO_ROOT="${GIT_ISSUES_DIR}/.."
|
||||
_IA_FOR_LOG="$(cd "${GIT_ISSUES_DIR}/.." && pwd)"
|
||||
if [[ -f "${_IA_FOR_LOG}/lib/smart_ide_logs.sh" ]]; then
|
||||
# shellcheck source=../lib/smart_ide_logs.sh
|
||||
source "${_IA_FOR_LOG}/lib/smart_ide_logs.sh"
|
||||
smart_ide_logs_begin "$_IA_FOR_LOG" "$0" "$*"
|
||||
fi
|
||||
exec python3 "${GIT_ISSUES_DIR}/mail-mark-read.py" "$@"
|
||||
@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Send a reply email via SMTP (e.g. Proton Mail Bridge).
|
||||
Usage: ./gitea-issues/mail-send-reply.sh --to addr@example.com --subject "..." --body "..." [--in-reply-to "<msg-id>" [--references "<refs>"]]
|
||||
Or: echo "body" | ./gitea-issues/mail-send-reply.sh --to addr@example.com --subject "..." [--in-reply-to "<msg-id>"]
|
||||
Usage: ./git-issues/mail-send-reply.sh --to addr@example.com --subject "..." --body "..." [--in-reply-to "<msg-id>" [--references "<refs>"]]
|
||||
Or: echo "body" | ./git-issues/mail-send-reply.sh --to addr@example.com --subject "..." [--in-reply-to "<msg-id>"]
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@ -69,9 +69,9 @@ def main() -> None:
|
||||
cfg = load_smtp_config()
|
||||
if not cfg["user"] or not cfg["password"]:
|
||||
root = repo_root()
|
||||
env_path = root / ".secrets" / "gitea-issues" / "imap-bridge.env"
|
||||
print("[gitea-issues] ERROR: SMTP_USER and SMTP_PASSWORD required.", file=sys.stderr)
|
||||
print(f"[gitea-issues] Set env or create {env_path}", file=sys.stderr)
|
||||
env_path = root / ".secrets" / "git-issues" / "imap-bridge.env"
|
||||
print("[git-issues] ERROR: SMTP_USER and SMTP_PASSWORD required.", file=sys.stderr)
|
||||
print(f"[git-issues] Set env or create {env_path}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
body = args.body
|
||||
@ -80,7 +80,7 @@ def main() -> None:
|
||||
body = body.rstrip()
|
||||
if body_contains_citation(body):
|
||||
print(
|
||||
"[gitea-issues] ERROR: Body must not contain the received message (no citation, no From:, Message-ID, wrote:, etc.). Send only your reply text.",
|
||||
"[git-issues] ERROR: Body must not contain the received message (no citation, no From:, Message-ID, wrote:, etc.). Send only your reply text.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
@ -101,7 +101,7 @@ def main() -> None:
|
||||
smtp.login(cfg["user"], cfg["password"])
|
||||
smtp.sendmail(cfg["user"], [args.to], msg.as_string())
|
||||
|
||||
print("[gitea-issues] Reply sent.")
|
||||
print("[git-issues] Reply sent.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
14
git-issues/mail-send-reply.sh
Executable file
14
git-issues/mail-send-reply.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
# Send reply email via Bridge SMTP. Run from repo root.
|
||||
# Usage: ./git-issues/mail-send-reply.sh --to addr --subject "..." [--body "..." | stdin] [--in-reply-to "<msg-id>" [--references "..." ]]
|
||||
set -euo pipefail
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
export GIT_ISSUES_DIR
|
||||
export REPO_ROOT="${GIT_ISSUES_DIR}/.."
|
||||
_IA_FOR_LOG="$(cd "${GIT_ISSUES_DIR}/.." && pwd)"
|
||||
if [[ -f "${_IA_FOR_LOG}/lib/smart_ide_logs.sh" ]]; then
|
||||
# shellcheck source=../lib/smart_ide_logs.sh
|
||||
source "${_IA_FOR_LOG}/lib/smart_ide_logs.sh"
|
||||
smart_ide_logs_begin "$_IA_FOR_LOG" "$0" "$*"
|
||||
fi
|
||||
exec python3 "${GIT_ISSUES_DIR}/mail-send-reply.py" "$@"
|
||||
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Thread log: one file per email thread under projects/<id>/logs/gitea-issues/threads/.
|
||||
Thread log: one file per email thread under projects/<id>/logs/git-issues/threads/.
|
||||
Content: exchanges (received + sent), tickets (issues), commits.
|
||||
Usage:
|
||||
mail-thread-log.py get-id --uid <uid> # print THREAD_ID=...
|
||||
@ -25,8 +25,8 @@ from project_config import project_logs_dir
|
||||
|
||||
|
||||
def threads_dir() -> Path:
|
||||
"""Thread log directory: projects/<id>/logs/gitea-issues/threads/ or repo logs fallback."""
|
||||
d = project_logs_dir() / "gitea-issues" / "threads"
|
||||
"""Thread log directory: projects/<id>/logs/git-issues/threads/ or repo logs fallback."""
|
||||
d = project_logs_dir() / "git-issues" / "threads"
|
||||
d.mkdir(parents=True, exist_ok=True)
|
||||
return d
|
||||
|
||||
@ -39,7 +39,7 @@ def sanitize_thread_id(raw: str, max_len: int = 80) -> str:
|
||||
def get_thread_output(uid: str) -> str:
|
||||
gitea_dir = Path(__file__).resolve().parent
|
||||
root = gitea_dir.parent
|
||||
env = {"GITEA_ISSUES_DIR": str(gitea_dir)}
|
||||
env = {"GIT_ISSUES_DIR": str(gitea_dir)}
|
||||
result = subprocess.run(
|
||||
[sys.executable, str(gitea_dir / "mail-get-thread.py"), uid],
|
||||
cwd=str(root),
|
||||
19
git-issues/mail-thread-log.sh
Executable file
19
git-issues/mail-thread-log.sh
Executable file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
# Thread log: one file per thread under projects/<id>/logs/git-issues/threads/. Run from repo root.
|
||||
# Usage:
|
||||
# ./git-issues/mail-thread-log.sh get-id --uid <uid>
|
||||
# ./git-issues/mail-thread-log.sh init --uid <uid>
|
||||
# ./git-issues/mail-thread-log.sh append-sent --thread-id <id> --to <addr> --subject "..." [--body "..."] [--date "..."]
|
||||
# ./git-issues/mail-thread-log.sh append-issue --thread-id <id> --issue <num> [--title "..."]
|
||||
# ./git-issues/mail-thread-log.sh append-commit --thread-id <id> --hash <hash> --message "..." [--branch "..."]
|
||||
set -euo pipefail
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
export GIT_ISSUES_DIR
|
||||
export REPO_ROOT="${GIT_ISSUES_DIR}/.."
|
||||
_IA_FOR_LOG="$(cd "${GIT_ISSUES_DIR}/.." && pwd)"
|
||||
if [[ -f "${_IA_FOR_LOG}/lib/smart_ide_logs.sh" ]]; then
|
||||
# shellcheck source=../lib/smart_ide_logs.sh
|
||||
source "${_IA_FOR_LOG}/lib/smart_ide_logs.sh"
|
||||
smart_ide_logs_begin "$_IA_FOR_LOG" "$0" "$*"
|
||||
fi
|
||||
exec python3 "${GIT_ISSUES_DIR}/mail-thread-log.py" "$@"
|
||||
@ -12,8 +12,8 @@ This script (mail-to-issue) is a **batch** fallback: it creates one issue per un
|
||||
message with title=subject and body=text+From, then marks messages as read. Use only
|
||||
when the agent-driven flow is not used.
|
||||
|
||||
Reads IMAP config from .secrets/gitea-issues/imap-bridge.env (or env vars).
|
||||
Reads Gitea token from GITEA_TOKEN or .secrets/gitea-issues/token.
|
||||
Reads IMAP config from .secrets/git-issues/imap-bridge.env (or env vars).
|
||||
Reads Gitea token from GITEA_TOKEN or .secrets/git-issues/token.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@ -67,12 +67,12 @@ def main() -> None:
|
||||
imap_cfg = load_imap_config()
|
||||
if not imap_cfg["user"] or not imap_cfg["password"]:
|
||||
root = repo_root()
|
||||
env_path = root / ".secrets" / "gitea-issues" / "imap-bridge.env"
|
||||
print("[gitea-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.", file=sys.stderr)
|
||||
env_path = root / ".secrets" / "git-issues" / "imap-bridge.env"
|
||||
print("[git-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
gitea_cfg = load_gitea_config()
|
||||
if not gitea_cfg["token"]:
|
||||
print("[gitea-issues] ERROR: GITEA_TOKEN not set.", file=sys.stderr)
|
||||
print("[git-issues] ERROR: GITEA_TOKEN not set.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
mail = imaplib.IMAP4(imap_cfg["host"], int(imap_cfg["port"]))
|
||||
@ -84,7 +84,7 @@ def main() -> None:
|
||||
_, nums = mail.search(None, criterion)
|
||||
ids = nums[0].split()
|
||||
if not ids:
|
||||
print("[gitea-issues] No unread messages.")
|
||||
print("[git-issues] No unread messages.")
|
||||
mail.logout()
|
||||
return
|
||||
|
||||
@ -103,13 +103,13 @@ def main() -> None:
|
||||
issue = create_gitea_issue(title, body_for_issue)
|
||||
if issue:
|
||||
created += 1
|
||||
print(f"[gitea-issues] Created issue #{issue.get('number', '?')}: {title[:60]}")
|
||||
print(f"[git-issues] Created issue #{issue.get('number', '?')}: {title[:60]}")
|
||||
mail.store(uid_s, "+FLAGS", "\\Seen")
|
||||
else:
|
||||
print(f"[gitea-issues] Skipped (API failed): {title[:60]}", file=sys.stderr)
|
||||
print(f"[git-issues] Skipped (API failed): {title[:60]}", file=sys.stderr)
|
||||
|
||||
mail.logout()
|
||||
print(f"[gitea-issues] Done. Created {created} issue(s).")
|
||||
print(f"[git-issues] Done. Created {created} issue(s).")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
18
git-issues/mail-to-issue.sh
Executable file
18
git-issues/mail-to-issue.sh
Executable file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Create Gitea issues from unread emails (IMAP). Requires Proton Mail Bridge
|
||||
# or any IMAP server. Config: .secrets/git-issues/imap-bridge.env and token.
|
||||
# Usage: ./git-issues/mail-to-issue.sh
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
export GIT_ISSUES_DIR
|
||||
export REPO_ROOT="${GIT_ISSUES_DIR}/.."
|
||||
_IA_FOR_LOG="$(cd "${GIT_ISSUES_DIR}/.." && pwd)"
|
||||
if [[ -f "${_IA_FOR_LOG}/lib/smart_ide_logs.sh" ]]; then
|
||||
# shellcheck source=../lib/smart_ide_logs.sh
|
||||
source "${_IA_FOR_LOG}/lib/smart_ide_logs.sh"
|
||||
smart_ide_logs_begin "$_IA_FOR_LOG" "$0" "$*"
|
||||
fi
|
||||
exec python3 "${GIT_ISSUES_DIR}/mail-to-issue.py"
|
||||
@ -1,4 +1,4 @@
|
||||
# Shared config and helpers for gitea-issues mail scripts (IMAP/SMTP, Gitea).
|
||||
# Shared config and helpers for git-issues mail scripts (IMAP/SMTP, Gitea).
|
||||
# Used by mail-list-unread, mail-send-reply, mail-create-issue-from-email, mail-mark-read.
|
||||
|
||||
from __future__ import annotations
|
||||
@ -31,12 +31,12 @@ def imap_search_criterion_unseen() -> str:
|
||||
|
||||
|
||||
def repo_root() -> Path:
|
||||
# Root = directory containing gitea-issues (ia_dev). .secrets and logs live under ia_dev (./.secrets, ./logs)
|
||||
# Root = directory containing git-issues (ia_dev). .secrets and logs live under ia_dev (./.secrets, ./logs)
|
||||
# so they do not depend on a specific project; same ia_dev works for any project (PROJECT_ID from MAIL_TO or AI_AGENT_TOKEN).
|
||||
env_root = os.environ.get("REPO_ROOT")
|
||||
if env_root:
|
||||
return Path(env_root).resolve()
|
||||
issues_dir = os.environ.get("GITEA_ISSUES_DIR")
|
||||
issues_dir = os.environ.get("GIT_ISSUES_DIR")
|
||||
if issues_dir:
|
||||
return Path(issues_dir).resolve().parent
|
||||
return Path(__file__).resolve().parent.parent
|
||||
@ -60,7 +60,7 @@ def load_env_file(path: Path) -> None:
|
||||
|
||||
def load_imap_config() -> dict[str, str]:
|
||||
root = repo_root()
|
||||
env_path = root / ".secrets" / "gitea-issues" / "imap-bridge.env"
|
||||
env_path = root / ".secrets" / "git-issues" / "imap-bridge.env"
|
||||
load_env_file(env_path)
|
||||
ssl_verify_raw = os.environ.get("IMAP_SSL_VERIFY", "true").lower()
|
||||
ssl_verify = ssl_verify_raw not in ("0", "false", "no")
|
||||
@ -87,7 +87,7 @@ def imap_ssl_context(ssl_verify: bool = True) -> ssl.SSLContext:
|
||||
|
||||
def load_smtp_config() -> dict[str, str]:
|
||||
root = repo_root()
|
||||
env_path = root / ".secrets" / "gitea-issues" / "imap-bridge.env"
|
||||
env_path = root / ".secrets" / "git-issues" / "imap-bridge.env"
|
||||
load_env_file(env_path)
|
||||
ssl_verify_raw = os.environ.get("IMAP_SSL_VERIFY", os.environ.get("SMTP_SSL_VERIFY", "true")).lower()
|
||||
ssl_verify = ssl_verify_raw not in ("0", "false", "no")
|
||||
@ -105,7 +105,7 @@ def load_gitea_config() -> dict[str, str]:
|
||||
root = repo_root()
|
||||
token = os.environ.get("GITEA_TOKEN")
|
||||
if not token:
|
||||
token_path = root / ".secrets" / "gitea-issues" / "token"
|
||||
token_path = root / ".secrets" / "git-issues" / "token"
|
||||
if token_path.is_file():
|
||||
token = token_path.read_text(encoding="utf-8").strip()
|
||||
return {
|
||||
@ -1,14 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Print issue number, title and body in a single block for agent consumption.
|
||||
# Used by the gitea-issues-process agent to get the ticket content before calling /fix or /evol.
|
||||
# Used by the git-issues-process agent to get the ticket content before calling /fix or /evol.
|
||||
# Usage: ./print-issue-prompt.sh <issue_number>
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh"
|
||||
source "${GIT_ISSUES_DIR}/lib.sh"
|
||||
|
||||
require_jq || exit 1
|
||||
|
||||
@ -9,26 +9,26 @@ from pathlib import Path
|
||||
|
||||
|
||||
def project_root() -> Path:
|
||||
"""Project repo root when applicable. Derived from PROJECT_ROOT, REPO_ROOT or GITEA_ISSUES_DIR."""
|
||||
"""Project repo root when applicable. Derived from PROJECT_ROOT, REPO_ROOT or GIT_ISSUES_DIR."""
|
||||
env_root = os.environ.get("PROJECT_ROOT")
|
||||
if env_root:
|
||||
return Path(env_root).resolve()
|
||||
env_repo = os.environ.get("REPO_ROOT")
|
||||
if env_repo:
|
||||
root = Path(env_repo).resolve()
|
||||
# If REPO_ROOT is ia_dev (has gitea-issues), use it as repo root
|
||||
if (root / "gitea-issues").is_dir():
|
||||
# If REPO_ROOT is ia_dev (has git-issues), use it as repo root
|
||||
if (root / "git-issues").is_dir():
|
||||
return root
|
||||
return root
|
||||
issues_dir = os.environ.get("GITEA_ISSUES_DIR")
|
||||
issues_dir = os.environ.get("GIT_ISSUES_DIR")
|
||||
if issues_dir:
|
||||
return Path(issues_dir).resolve().parent.parent
|
||||
return Path(__file__).resolve().parent.parent.parent
|
||||
|
||||
|
||||
def ia_dev_root() -> Path:
|
||||
"""Directory containing gitea-issues (ia_dev)."""
|
||||
issues_dir = os.environ.get("GITEA_ISSUES_DIR")
|
||||
"""Directory containing git-issues (ia_dev)."""
|
||||
issues_dir = os.environ.get("GIT_ISSUES_DIR")
|
||||
if issues_dir:
|
||||
return Path(issues_dir).resolve().parent
|
||||
return Path(__file__).resolve().parent.parent
|
||||
@ -8,7 +8,7 @@ Messages on or after MAIL_SINCE_DATE are considered. Does not use UNSEEN; does n
|
||||
Writes to projects/<id>/data/issues/ as JSON <date>.<msg_id>.<from>.pending. One file per message.
|
||||
|
||||
State: we skip creating .pending if .pending exists or .response exists for that base.
|
||||
Usage: run with GITEA_ISSUES_DIR set (e.g. via tickets-fetch-inbox.sh). MAIL_SINCE_DATE overrides date (DD-Mon-YYYY).
|
||||
Usage: run with GIT_ISSUES_DIR set (e.g. via tickets-fetch-inbox.sh). MAIL_SINCE_DATE overrides date (DD-Mon-YYYY).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@ -1,17 +1,17 @@
|
||||
#!/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: depuis la racine de ia_dev (MAIL_TO ou AI_AGENT_TOKEN défini) : ./gitea-issues/tickets-fetch-inbox.sh
|
||||
# Usage: depuis la racine de ia_dev (MAIL_TO ou AI_AGENT_TOKEN défini) : ./git-issues/tickets-fetch-inbox.sh
|
||||
set -euo pipefail
|
||||
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
export GITEA_ISSUES_DIR
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
export GIT_ISSUES_DIR
|
||||
# Use same project root and env as list-pending-spooler (lib.sh) so spool path is identical.
|
||||
ROOT="$(cd "${GITEA_ISSUES_DIR}/../.." && pwd)"
|
||||
export REPO_ROOT="${GITEA_ISSUES_DIR}/.."
|
||||
ROOT="$(cd "${GIT_ISSUES_DIR}/../.." && pwd)"
|
||||
export REPO_ROOT="${GIT_ISSUES_DIR}/.."
|
||||
cd "$ROOT"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
source "${GIT_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
export PROJECT_ROOT="${PROJECT_ROOT:-$ROOT}"
|
||||
cd "$PROJECT_ROOT"
|
||||
exec python3 "${GITEA_ISSUES_DIR}/tickets-fetch-inbox.py" "$@"
|
||||
exec python3 "${GIT_ISSUES_DIR}/tickets-fetch-inbox.py" "$@"
|
||||
@ -1,15 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test Gitea Wiki API for repo 4nk/lecoffre_ng.
|
||||
# Requires GITEA_TOKEN or .secrets/gitea-issues/token (same as issues scripts).
|
||||
# Requires GITEA_TOKEN or .secrets/git-issues/token (same as issues scripts).
|
||||
# Usage: ./wiki-api-test.sh [--create]
|
||||
# --create: create a test page then delete it (checks write access).
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh"
|
||||
source "${GIT_ISSUES_DIR}/lib.sh"
|
||||
|
||||
REPO_PATH="/repos/${GITEA_REPO_OWNER}/${GITEA_REPO_NAME}"
|
||||
# Branch ref for wiki (default branch of wiki repo; use master when wiki is configured on master)
|
||||
@ -27,7 +27,7 @@ while [[ $# -gt 0 ]]; do
|
||||
done
|
||||
|
||||
if ! load_gitea_token 2>/dev/null; then
|
||||
log_err "No GITEA_TOKEN and no .secrets/gitea-issues/token. Set token to run wiki API tests."
|
||||
log_err "No GITEA_TOKEN and no .secrets/git-issues/token. Set token to run wiki API tests."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@ -3,13 +3,13 @@
|
||||
# Output the raw markdown of a wiki page (for agents or scripts).
|
||||
# Usage: ./wiki-get-page.sh <page_name>
|
||||
# Example: ./wiki-get-page.sh Home
|
||||
# Requires GITEA_TOKEN or .secrets/gitea-issues/token.
|
||||
# Requires GITEA_TOKEN or .secrets/git-issues/token.
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh"
|
||||
source "${GIT_ISSUES_DIR}/lib.sh"
|
||||
|
||||
REPO_PATH="/repos/${GITEA_REPO_OWNER}/${GITEA_REPO_NAME}"
|
||||
GITEA_WIKI_REF="${GITEA_WIKI_REF:-master}"
|
||||
@ -2,18 +2,18 @@
|
||||
#
|
||||
# Migrate all docs/*.md (repo root) to Gitea wiki as pages.
|
||||
# Mapping: docs/FILE.md → page "File" (stem with _ → -, first letter upper per segment).
|
||||
# Requires GITEA_TOKEN or .secrets/gitea-issues/token.
|
||||
# Requires GITEA_TOKEN or .secrets/git-issues/token.
|
||||
# Usage: ./wiki-migrate-docs.sh [--dry-run] [file.md ...]
|
||||
# --dry-run: print mapping and skip API calls.
|
||||
# If file(s) given: migrate only those; else migrate all docs/*.md.
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
REPO_ROOT="${GITEA_ISSUES_DIR}/.."
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
REPO_ROOT="${GIT_ISSUES_DIR}/.."
|
||||
DOCS_DIR="${DOCS_DIR:-${REPO_ROOT}/docs}"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh"
|
||||
source "${GIT_ISSUES_DIR}/lib.sh"
|
||||
|
||||
REPO_PATH="/repos/${GITEA_REPO_OWNER}/${GITEA_REPO_NAME}"
|
||||
GITEA_WIKI_REF="${GITEA_WIKI_REF:-master}"
|
||||
@ -3,13 +3,13 @@
|
||||
# Update a single wiki page from a local file.
|
||||
# Usage: ./wiki-put-page.sh <page_name> <file_path>
|
||||
# Example: ./wiki-put-page.sh Home docs/README.md
|
||||
# Requires GITEA_TOKEN or .secrets/gitea-issues/token.
|
||||
# Requires GITEA_TOKEN or .secrets/git-issues/token.
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh"
|
||||
source "${GIT_ISSUES_DIR}/lib.sh"
|
||||
|
||||
REPO_PATH="/repos/${GITEA_REPO_OWNER}/${GITEA_REPO_NAME}"
|
||||
GITEA_WIKI_REF="${GITEA_WIKI_REF:-master}"
|
||||
@ -3,7 +3,7 @@
|
||||
Update the single spooler file for a message after sending a reply.
|
||||
One file per message: read the .pending file (same base), add response data and set status to responded, write back.
|
||||
No separate .response file; no file deletion.
|
||||
Usage: ./gitea-issues/write-response-spooler.sh --base <base> --to <addr> --subject "..." --body "..." [--in-reply-to "<msg-id>"]
|
||||
Usage: ./git-issues/write-response-spooler.sh --base <base> --to <addr> --subject "..." --body "..." [--in-reply-to "<msg-id>"]
|
||||
base = filename base without extension (e.g. 2026-03-14T094530.a1b2c3d4.user_example.com).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
14
git-issues/write-response-spooler.sh
Executable file
14
git-issues/write-response-spooler.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
# Update the single spooler file (.pending) after sending a reply via mail-send-reply.sh. One file per message.
|
||||
# Usage: depuis la racine de ia_dev : ./git-issues/write-response-spooler.sh --base <base> --to <addr> --subject "..." --body "..." [--in-reply-to "<msg-id>"]
|
||||
set -euo pipefail
|
||||
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
export GIT_ISSUES_DIR
|
||||
export REPO_ROOT="${GIT_ISSUES_DIR}/.."
|
||||
_IA_FOR_LOG="$(cd "${GIT_ISSUES_DIR}/.." && pwd)"
|
||||
if [[ -f "${_IA_FOR_LOG}/lib/smart_ide_logs.sh" ]]; then
|
||||
# shellcheck source=../lib/smart_ide_logs.sh
|
||||
source "${_IA_FOR_LOG}/lib/smart_ide_logs.sh"
|
||||
smart_ide_logs_begin "$_IA_FOR_LOG" "$0" "$*"
|
||||
fi
|
||||
exec python3 "${GIT_ISSUES_DIR}/write-response-spooler.py" "$@"
|
||||
@ -1,52 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Treatment loop: periodically check agent-loop.pending and run Cursor Agent CLI (gitea-issues-process workflow) when non-empty.
|
||||
# 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/&):
|
||||
# Depuis la racine de ia_dev : ./gitea-issues/agent-loop-treatment.sh
|
||||
#
|
||||
set -euo pipefail
|
||||
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="$(git rev-parse --show-toplevel 2>/dev/null)" || ROOT="$(cd "${GITEA_ISSUES_DIR}/../.." && pwd)"
|
||||
export GITEA_ISSUES_DIR
|
||||
export REPO_ROOT="${ROOT}"
|
||||
cd "$ROOT"
|
||||
# shellcheck source=lib.sh
|
||||
source "${GITEA_ISSUES_DIR}/lib.sh" 2>/dev/null || true
|
||||
LOGS_GITEA="${PROJECT_LOGS_DIR:-$ROOT/logs}/gitea-issues"
|
||||
|
||||
PENDING_FILE="${AGENT_LOOP_PENDING_FILE:-$LOGS_GITEA/agent-loop.pending}"
|
||||
LOG_DIR="$(dirname "$PENDING_FILE")"
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
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="${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 ./gitea-issues/list-pending-spooler.sh). Pour chaque fichier .pending : lire le JSON (from, to, subject, body, message_id, base). Répondre à l'expéditeur (--to <from> du JSON), pas à une adresse fixe ; le « to » du mail reçu a déjà déterminé le projet. 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
|
||||
echo "[agent-loop-treatment] $(date -Iseconds) — Pending non vide, lancement de l'agent Cursor."
|
||||
if agent -p "$PROMPT" -f --model "$AGENT_MODEL" 2>&1; then
|
||||
echo "[agent-loop-treatment] $(date -Iseconds) — Agent terminé."
|
||||
else
|
||||
echo "[agent-loop-treatment] $(date -Iseconds) — Agent terminé avec erreur."
|
||||
fi
|
||||
fi
|
||||
sleep "$INTERVAL"
|
||||
done
|
||||
@ -1,19 +0,0 @@
|
||||
# Agent-loop parameters (Cursor Agent CLI, model, interval).
|
||||
# Copy to .secrets/gitea-issues/agent-loop.env and set as needed.
|
||||
# Do not commit .secrets/gitea-issues/agent-loop.env (directory is gitignored).
|
||||
#
|
||||
# Run Cursor Agent when unread mails are detected (0 or 1)
|
||||
# AGENT_LOOP_RUN_AGENT=1
|
||||
#
|
||||
# Model used by the CLI (default: sonnet-4.6 to avoid Opus usage limits)
|
||||
# List: agent models
|
||||
# AGENT_LOOP_MODEL=sonnet-4.6
|
||||
#
|
||||
# Polling interval in seconds (default: 60)
|
||||
# AGENT_LOOP_INTERVAL_SEC=60
|
||||
#
|
||||
# Optional: custom paths for status, pending, lock and stop files
|
||||
# AGENT_LOOP_STATUS_FILE=ia_dev/projects/<id>/logs/gitea-issues/agent-loop.status
|
||||
# AGENT_LOOP_PENDING_FILE=ia_dev/projects/<id>/logs/gitea-issues/agent-loop.pending
|
||||
# AGENT_LOOP_LOCK_FILE=ia_dev/projects/<id>/logs/gitea-issues/agent-loop.lock
|
||||
# AGENT_LOOP_STOP_FILE=ia_dev/projects/<id>/logs/gitea-issues/agent-loop.stop
|
||||
@ -1,14 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Create one Gitea issue from one email (by UID), mark email read. Run from repo root.
|
||||
# Usage: ./gitea-issues/mail-create-issue-from-email.sh --uid <uid> [--title "..." ] [--body "..." ]
|
||||
set -euo pipefail
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
export GITEA_ISSUES_DIR
|
||||
export REPO_ROOT="${GITEA_ISSUES_DIR}/.."
|
||||
_IA_FOR_LOG="$(cd "${GITEA_ISSUES_DIR}/.." && pwd)"
|
||||
if [[ -f "${_IA_FOR_LOG}/lib/smart_ide_logs.sh" ]]; then
|
||||
# shellcheck source=../lib/smart_ide_logs.sh
|
||||
source "${_IA_FOR_LOG}/lib/smart_ide_logs.sh"
|
||||
smart_ide_logs_begin "$_IA_FOR_LOG" "$0" "$*"
|
||||
fi
|
||||
exec python3 "${GITEA_ISSUES_DIR}/mail-create-issue-from-email.py" "$@"
|
||||
@ -1,14 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Mark one email as read by UID. Run from repo root.
|
||||
# Usage: ./gitea-issues/mail-mark-read.sh <uid>
|
||||
set -euo pipefail
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
export GITEA_ISSUES_DIR
|
||||
export REPO_ROOT="${GITEA_ISSUES_DIR}/.."
|
||||
_IA_FOR_LOG="$(cd "${GITEA_ISSUES_DIR}/.." && pwd)"
|
||||
if [[ -f "${_IA_FOR_LOG}/lib/smart_ide_logs.sh" ]]; then
|
||||
# shellcheck source=../lib/smart_ide_logs.sh
|
||||
source "${_IA_FOR_LOG}/lib/smart_ide_logs.sh"
|
||||
smart_ide_logs_begin "$_IA_FOR_LOG" "$0" "$*"
|
||||
fi
|
||||
exec python3 "${GITEA_ISSUES_DIR}/mail-mark-read.py" "$@"
|
||||
@ -1,14 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Send reply email via Bridge SMTP. Run from repo root.
|
||||
# Usage: ./gitea-issues/mail-send-reply.sh --to addr --subject "..." [--body "..." | stdin] [--in-reply-to "<msg-id>" [--references "..." ]]
|
||||
set -euo pipefail
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
export GITEA_ISSUES_DIR
|
||||
export REPO_ROOT="${GITEA_ISSUES_DIR}/.."
|
||||
_IA_FOR_LOG="$(cd "${GITEA_ISSUES_DIR}/.." && pwd)"
|
||||
if [[ -f "${_IA_FOR_LOG}/lib/smart_ide_logs.sh" ]]; then
|
||||
# shellcheck source=../lib/smart_ide_logs.sh
|
||||
source "${_IA_FOR_LOG}/lib/smart_ide_logs.sh"
|
||||
smart_ide_logs_begin "$_IA_FOR_LOG" "$0" "$*"
|
||||
fi
|
||||
exec python3 "${GITEA_ISSUES_DIR}/mail-send-reply.py" "$@"
|
||||
@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Thread log: one file per thread under projects/<id>/logs/gitea-issues/threads/. Run from repo root.
|
||||
# Usage:
|
||||
# ./gitea-issues/mail-thread-log.sh get-id --uid <uid>
|
||||
# ./gitea-issues/mail-thread-log.sh init --uid <uid>
|
||||
# ./gitea-issues/mail-thread-log.sh append-sent --thread-id <id> --to <addr> --subject "..." [--body "..."] [--date "..."]
|
||||
# ./gitea-issues/mail-thread-log.sh append-issue --thread-id <id> --issue <num> [--title "..."]
|
||||
# ./gitea-issues/mail-thread-log.sh append-commit --thread-id <id> --hash <hash> --message "..." [--branch "..."]
|
||||
set -euo pipefail
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
export GITEA_ISSUES_DIR
|
||||
export REPO_ROOT="${GITEA_ISSUES_DIR}/.."
|
||||
_IA_FOR_LOG="$(cd "${GITEA_ISSUES_DIR}/.." && pwd)"
|
||||
if [[ -f "${_IA_FOR_LOG}/lib/smart_ide_logs.sh" ]]; then
|
||||
# shellcheck source=../lib/smart_ide_logs.sh
|
||||
source "${_IA_FOR_LOG}/lib/smart_ide_logs.sh"
|
||||
smart_ide_logs_begin "$_IA_FOR_LOG" "$0" "$*"
|
||||
fi
|
||||
exec python3 "${GITEA_ISSUES_DIR}/mail-thread-log.py" "$@"
|
||||
@ -1,18 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Create Gitea issues from unread emails (IMAP). Requires Proton Mail Bridge
|
||||
# or any IMAP server. Config: .secrets/gitea-issues/imap-bridge.env and token.
|
||||
# Usage: ./gitea-issues/mail-to-issue.sh
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
GITEA_ISSUES_DIR="${GITEA_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
||||
export GITEA_ISSUES_DIR
|
||||
export REPO_ROOT="${GITEA_ISSUES_DIR}/.."
|
||||
_IA_FOR_LOG="$(cd "${GITEA_ISSUES_DIR}/.." && pwd)"
|
||||
if [[ -f "${_IA_FOR_LOG}/lib/smart_ide_logs.sh" ]]; then
|
||||
# shellcheck source=../lib/smart_ide_logs.sh
|
||||
source "${_IA_FOR_LOG}/lib/smart_ide_logs.sh"
|
||||
smart_ide_logs_begin "$_IA_FOR_LOG" "$0" "$*"
|
||||
fi
|
||||
exec python3 "${GITEA_ISSUES_DIR}/mail-to-issue.py"
|
||||
@ -1,14 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Update the single spooler file (.pending) after sending a reply via mail-send-reply.sh. One file per message.
|
||||
# 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
|
||||
export REPO_ROOT="${GITEA_ISSUES_DIR}/.."
|
||||
_IA_FOR_LOG="$(cd "${GITEA_ISSUES_DIR}/.." && pwd)"
|
||||
if [[ -f "${_IA_FOR_LOG}/lib/smart_ide_logs.sh" ]]; then
|
||||
# shellcheck source=../lib/smart_ide_logs.sh
|
||||
source "${_IA_FOR_LOG}/lib/smart_ide_logs.sh"
|
||||
smart_ide_logs_begin "$_IA_FOR_LOG" "$0" "$*"
|
||||
fi
|
||||
exec python3 "${GITEA_ISSUES_DIR}/write-response-spooler.py" "$@"
|
||||
@ -23,11 +23,11 @@
|
||||
},
|
||||
"mail": {
|
||||
"email": "ai.support.algo@4nkweb.com",
|
||||
"imap_bridge_env": ".secrets/gitea-issues/imap-bridge.env"
|
||||
"imap_bridge_env": ".secrets/git-issues/imap-bridge.env"
|
||||
},
|
||||
"git": {
|
||||
"wiki_url": "https://git.4nkweb.com/nicolas.cantu/algo/wiki",
|
||||
"token_file": ".secrets/gitea-issues/token"
|
||||
"token_file": ".secrets/git-issues/token"
|
||||
},
|
||||
"tickets": {
|
||||
"ticketing_url": "https://git.4nkweb.com/nicolas.cantu/algo/issues",
|
||||
|
||||
1
projects/builazoo
Symbolic link
1
projects/builazoo
Symbolic link
@ -0,0 +1 @@
|
||||
../../projects/builazoo
|
||||
1
projects/enso
Symbolic link
1
projects/enso
Symbolic link
@ -0,0 +1 @@
|
||||
../../projects/enso
|
||||
@ -1,99 +0,0 @@
|
||||
{
|
||||
"id": "enso",
|
||||
"name": "enso",
|
||||
"cron": {
|
||||
"git_pull": true
|
||||
},
|
||||
"project_path": "../enso",
|
||||
"build_dirs": [
|
||||
".",
|
||||
"enso/enso-front"
|
||||
],
|
||||
"deploy": {
|
||||
"repository_root": "../enso",
|
||||
"scripts_path": "../enso/deploy/scripts_v2",
|
||||
"deploy_script_path": "../enso/deploy/scripts_v2/deploy.sh",
|
||||
"project_orchestrator_path": "deploy/scripts_v2/deploy.sh",
|
||||
"secrets_path": "../enso/.secrets"
|
||||
},
|
||||
"version": {
|
||||
"package_json_paths": [
|
||||
"package.json",
|
||||
"enso/enso-front/package.json"
|
||||
],
|
||||
"splash_app_name": "enso"
|
||||
},
|
||||
"mail": {
|
||||
"imap_bridge_env": ".secrets/gitea-issues/imap-bridge.env"
|
||||
},
|
||||
"git": {
|
||||
"wiki_url": "https://git.4nkweb.com/4nk/enso/wiki",
|
||||
"token_file": ".secrets/gitea-issues/token"
|
||||
},
|
||||
"tickets": {
|
||||
"ticketing_url": "https://git.4nkweb.com/4nk/enso/issues",
|
||||
"authorized_emails": {
|
||||
"to": [
|
||||
{
|
||||
"test": "AI.ENSO.TEST@4nkweb.com",
|
||||
"pprod": "AI.ENSO.PPROD@4nkweb.com",
|
||||
"prod": "AI.ENSO.PROD@4nkweb.com"
|
||||
}
|
||||
],
|
||||
"from": ["nicolas.4nk@pm.me"]
|
||||
}
|
||||
},
|
||||
"smart_ide": {
|
||||
"remote_data_access": {
|
||||
"environments": {
|
||||
"test": {
|
||||
"ssh_host_alias": "test",
|
||||
"remote_app_root": "/home/ncantu/enso",
|
||||
"remote_data_directories": [
|
||||
{
|
||||
"role": "enso_monorepo_clone",
|
||||
"path_on_server": "/home/ncantu/enso"
|
||||
},
|
||||
{
|
||||
"role": "docv_dp_git_data",
|
||||
"path_on_server": "/home/ncantu/enso/data/dossiers-permanents"
|
||||
}
|
||||
]
|
||||
},
|
||||
"pprod": {
|
||||
"ssh_host_alias": "pprod",
|
||||
"remote_app_root": "/home/ncantu/enso",
|
||||
"remote_data_directories": [
|
||||
{
|
||||
"role": "enso_monorepo_clone",
|
||||
"path_on_server": "/home/ncantu/enso"
|
||||
},
|
||||
{
|
||||
"role": "docv_dp_git_data",
|
||||
"path_on_server": "/home/ncantu/enso/data/dossiers-permanents"
|
||||
}
|
||||
]
|
||||
},
|
||||
"prod": {
|
||||
"ssh_host_alias": "prod",
|
||||
"remote_app_root": "/home/ncantu/enso",
|
||||
"remote_data_directories": [
|
||||
{
|
||||
"role": "enso_monorepo_clone",
|
||||
"path_on_server": "/home/ncantu/enso"
|
||||
},
|
||||
{
|
||||
"role": "docv_dp_git_data",
|
||||
"path_on_server": "/home/ncantu/enso/data/dossiers-permanents"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"anythingllm_workspace_slug": {
|
||||
"test": "enso-test",
|
||||
"pprod": "enso-pprod",
|
||||
"prod": "enso-prod"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,11 +9,11 @@
|
||||
"splash_app_name": "ia_dev"
|
||||
},
|
||||
"mail": {
|
||||
"imap_bridge_env": ".secrets/gitea-issues/imap-bridge.env"
|
||||
"imap_bridge_env": ".secrets/git-issues/imap-bridge.env"
|
||||
},
|
||||
"git": {
|
||||
"wiki_url": "https://git.4nkweb.com/4nk/ia_dev/wiki",
|
||||
"token_file": ".secrets/gitea-issues/token"
|
||||
"token_file": ".secrets/git-issues/token"
|
||||
},
|
||||
"tickets": {
|
||||
"ticketing_url": "https://git.4nkweb.com/4nk/ia_dev/issues",
|
||||
|
||||
@ -1,160 +0,0 @@
|
||||
# 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.
|
||||
|
||||
## Contraintes de confidentialité et d'accès des agents
|
||||
|
||||
L'agent ne doit **jamais révéler** :
|
||||
|
||||
- Quelle IA il utilise
|
||||
- Des informations personnelles
|
||||
- Des informations sur 4NK
|
||||
- Des informations sur l'équipe de réalisation
|
||||
- Des informations sur des fichiers hors périmètre du projet configuré
|
||||
- Des informations sur les autres questions et réponses traitées
|
||||
|
||||
L'agent ne doit **jamais accéder ni modifier** :
|
||||
|
||||
- Les fichiers hors projet (périmètre = ia_dev et dépôt du projet configuré via conf.json)
|
||||
- Les fichiers dans `.smartIde` et `.secrets`
|
||||
- D'autres branches que celle en cours de travail
|
||||
- D'autres environnements (test / pprod / prod) que celui défini par le contexte
|
||||
|
||||
## Agents (.smartIde/agents/)
|
||||
|
||||
| Agent | Fichier | Rôle |
|
||||
|-------|---------|------|
|
||||
| **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 : `./gitea-issues/tickets-fetch-inbox.sh`. Référence boucle mails (legacy) : `.smartIde/agents/agent-loop.md`. Hook Cursor : `sessionStart` → `.smartIde/hooks/remonter-mails.sh` (lit `projects/<id>/data/issues/*.pending`).
|
||||
|
||||
## Contexte d'exécution
|
||||
|
||||
- **Emplacement (usage standalone)** : ia_dev est un dépôt autonome. `gitea-issues/` est à la racine de ia_dev. Un même clone ia_dev peut servir plusieurs projets (id résolu par MAIL_TO ou AI_AGENT_TOKEN).
|
||||
- **Projet cible** : le projet est identifié **dynamiquement** par **MAIL_TO** (adresse « to » des mails, recherchée dans les configs ticketing de tous les projets) ou **AI_AGENT_TOKEN** (token des requêtes). L'id sert à charger la config dans `projects/<id>/`. Pas de fallback. Voir `docs/repo/ia-dev-project-conf-schema.md` (racine monorepo **smart_ide**).
|
||||
- **Lancement** : tous les scripts sont invoqués depuis la **racine de ia_dev** : `./gitea-issues/<script>.sh`. Les opérations (issues, mails, déploiement) utilisent les chemins absolus de `projects/<id>/conf.json` pour le projet cible.
|
||||
- **Secrets et logs** : `.secrets` est à la racine de ia_dev (`.secrets/gitea-issues/token`, `agent-loop.env`, `imap-bridge.env`). Les logs et data par projet sont sous `projects/<id>/logs/` et `projects/<id>/data/issues/`.
|
||||
|
||||
## 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 de ia_dev)
|
||||
|
||||
| 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), **à partir du 10 mars 2026** (MAIL_SINCE_DATE) ; 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` | `./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 `.smartIde/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. |
|
||||
| `agent-loop-n-cycles.sh` | `./gitea-issues/agent-loop-n-cycles.sh [N]` | **N cycles (récupération + 1 min)** : exécute N fois (récupération une fois + sleep 60) en **avant-plan** (défaut N=600). Utilise le même lock que la section 2. Arrêt : `agent-loop-stop.sh`. Ne lance pas l'agent ; lancer **gitea-issues-process** à part pour traiter les pendings. Permet de faire tourner réellement N × 1 minute. |
|
||||
| `tickets-fetch-inbox.sh` | `./gitea-issues/tickets-fetch-inbox.sh` | **Récupération et filtrage par le script** : le script (et le Python qu'il appelle) **récupère** les mails en boîte et les **filtre** (to, from, `tickets.authorized_emails`, date). L'agent ne fait que lancer le script. Mails à partir du 10 mars 2026 (MAIL_SINCE_DATE). Écrit les mails retenus 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`.
|
||||
|
||||
### Fichiers témoins et logs (boucle agent)
|
||||
|
||||
Sous `projects/<id>/logs/gitea-issues/` :
|
||||
|
||||
- **agent-loop.status** : fichier témoin de la boucle de surveillance (`agent-loop.sh` ou `agent-loop-retrieval-once.sh`). Trois lignes : horodatage (ISO), statut (`running` ou `idle`), détail (ex. « Aucun mail non lu »). Mis à jour à chaque itération. Si la date de modification est plus récente que 2× l’intervalle (ex. 120 s pour intervalle 60 s), la boucle est considérée active.
|
||||
- **agent-loop.pending** : liste des mails non lus (legacy) écrite par `mail-list-unread.sh` via la boucle ; l’agent gitea-issues-process traite ce fichier.
|
||||
- **agent-loop.lock** : lock pour une seule instance (section 2). Contenu : PID + date. Si mtime < 24 h, une nouvelle instance ne doit pas démarrer. Géré par `agent-loop-lock-acquire.sh` / `agent-loop-lock-release.sh`.
|
||||
- **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 d’envoi 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 `./gitea-issues/tickets-fetch-inbox.sh`. Si ce script n'est pas exécuté, `data/issues` reste vide si on n’utilise que la boucle legacy utilise seulement mail-list-unread.sh et agent-loop.pending dans logs/gitea-issues/. **Récupération et filtrage** : c'est le **script** (et le Python) qui récupère les mails et les filtre (to, from, authorized_emails, date) ; l'agent se contente de lancer le script. Le script route chaque message vers le projet dont `tickets.authorized_emails.to` correspond au « to » du mail ; les réponses sont envoyées à l'**expéditeur** (« from »), pas à une adresse fixe.
|
||||
|
||||
**Réponse mail** : le `--body` de `mail-send-reply.sh` doit être **uniquement le texte rédigé par l’agent** (la réponse à l’expé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.
|
||||
|
||||
### 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 `.smartIde/agents/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) ; `MAIL_SINCE_DATE=10-Mar-2026` (seuls les mails à partir de cette date sont récupérés/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 `.smartIde/agents/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/`. La documentation des projets gérés est dans **`projects/<id>/docs`** (ex. `projects/lecoffreio/docs`) ; la documentation propre à ia_dev est dans **`projects/ia_dev/docs`**.
|
||||
|
||||
## Agents (commandes)
|
||||
|
||||
- **/agent-loop** (`agent-loop.md`) : gère les boucles par exécutions délimitées uniquement (N itérations avec `agent-loop-chat-iterations.sh [N]`, ou x cycles récupération + traitement). Ne lance jamais agent-loop.sh ni agent-loop-treatment.sh en arrière-plan.
|
||||
- **/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).
|
||||
@ -8,6 +8,6 @@ Ce répertoire contient les documents **non spécifiques à un projet** (ex. LeC
|
||||
|
||||
- **agents-scripts-split.md** : Répartition des rôles entre agents Cursor et scripts (branch-align, change-to-all-branches, deploy, push), exécution depuis la racine, options standardisées.
|
||||
- **WORKFLOWS_AND_COMPONENTS.md** : Workflows IA (clôture, déploiement, fix-lint, pousse, docupdate, audit, branch-align), plans Cursor, règles, subagents, commandes, skills, MCP, protocole de développement (générique, sans référence à un projet particulier).
|
||||
- **GITEA_ISSUES_SCRIPTS_AGENTS.md** : Gitea issues – scripts et agents (liste des scripts, workflow mails, boucle agent, prérequis).
|
||||
- **GIT_ISSUES_SCRIPTS_AGENTS.md** : Gitea issues – scripts et agents (liste des scripts, workflow mails, boucle agent, prérequis).
|
||||
- **TICKETS_SPOOL_FORMAT.md** : Format JSON du spooler tickets (projects/<id>/data/issues/), schémas incoming/response, pièces jointes, config conf.json.
|
||||
- **ai_working_help/docs/notary-ai-api.md** : API IA notaire (enqueue, response), spooler projects/<id>/data/notary-ai/, scripts notary-ai/, agents notary-ai-loop et notary-ai-process.
|
||||
|
||||
@ -132,4 +132,4 @@ Exemple :
|
||||
|
||||
La récupération ne prend que les messages **envoyés à** `authorized_emails.to` **et** **expédités par** une des adresses de `authorized_emails.from`. Aucun marquage « lu / non lu ». Lorsqu'une réponse est enregistrée, le fichier `.pending` est supprimé et remplacé par le fichier `.response` (même base `<date>.<id>.<from>`).
|
||||
|
||||
**IMAP** : le script se connecte à la boîte IMAP configurée (ex. `.secrets/gitea-issues/imap-bridge.env`). Les messages sont filtrés selon les en-têtes **To**, **Delivered-To**, **X-Original-To**, etc. Pour que des messages « envoyés à » l'alias soient trouvés, **la boîte IMAP doit être celle qui reçoit le courrier pour cette adresse** (celle de `authorized_emails.to`). Si l'IMAP pointe vers une autre boîte (ex. une adresse personnelle qui reçoit tout), aucun message ne contiendra l'alias dans To/Delivered-To et tout sera exclu par `not_to_alias`. Il faut alors utiliser les identifiants IMAP de la boîte qui reçoit les mails envoyés à l'alias.
|
||||
**IMAP** : le script se connecte à la boîte IMAP configurée (ex. `.secrets/git-issues/imap-bridge.env`). Les messages sont filtrés selon les en-têtes **To**, **Delivered-To**, **X-Original-To**, etc. Pour que des messages « envoyés à » l'alias soient trouvés, **la boîte IMAP doit être celle qui reçoit le courrier pour cette adresse** (celle de `authorized_emails.to`). Si l'IMAP pointe vers une autre boîte (ex. une adresse personnelle qui reçoit tout), aucun message ne contiendra l'alias dans To/Delivered-To et tout sera exclu par `not_to_alias`. Il faut alors utiliser les identifiants IMAP de la boîte qui reçoit les mails envoyés à l'alias.
|
||||
|
||||
@ -24,11 +24,11 @@
|
||||
},
|
||||
"mail": {
|
||||
"email": "ai.support.lecoffreio@4nkweb.com",
|
||||
"imap_bridge_env": ".secrets/gitea-issues/imap-bridge.env"
|
||||
"imap_bridge_env": ".secrets/git-issues/imap-bridge.env"
|
||||
},
|
||||
"git": {
|
||||
"wiki_url": "https://git.4nkweb.com/4nk/lecoffre_ng/wiki",
|
||||
"token_file": ".secrets/gitea-issues/token"
|
||||
"token_file": ".secrets/git-issues/token"
|
||||
},
|
||||
"tickets": {
|
||||
"ticketing_url": "https://git.4nkweb.com/4nk/lecoffre_ng/issues",
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
"in_reply_to_message_id": "<XImHtfSZSMJo1z1dqMvd19K5CPkEJ6q6-3Ky88Muiy5c_ED4mcc6JeLT-RY1Lt9T5b57Ce3GEvrrP6_kUZ0cToHtLKF2x324qbZDyLjqYG8=@pm.me>",
|
||||
"to": "nicolas.cantu@pm.me",
|
||||
"subject": "Re: Présente le projet",
|
||||
"body": "Le projet LeCoffre.io est une application de coffre-fort numérique (dépôt lecoffre_ng). La documentation technique est sur le wiki du dépôt Gitea (https://git.4nkweb.com/4nk/lecoffre_ng/wiki). Les déploiements test, préproduction et production passent par les scripts deploy/ ; le ticketing et le support IA par les scripts gitea-issues/ dans ia_dev.",
|
||||
"body": "Le projet LeCoffre.io est une application de coffre-fort numérique (dépôt lecoffre_ng). La documentation technique est sur le wiki du dépôt Gitea (https://git.4nkweb.com/4nk/lecoffre_ng/wiki). Les déploiements test, préproduction et production passent par les scripts deploy/ ; le ticketing et le support IA par les scripts git-issues/ dans ia_dev.",
|
||||
"sent_at": "2026-03-14T13:43:30Z"
|
||||
}
|
||||
}
|
||||
@ -47,7 +47,7 @@ Vérification : `npm run lint`, `npm run lint:fix` dans lecoffre-back-main. Réf
|
||||
|
||||
Tout agent sous `.smartIde/agents` doit veiller à l'exécution exhaustive des agents qu'il lance (ou des phases qu'il exécute) : vérification avant clôture ; en cas d'incomplétude : pas de clôture, documenter les manques, améliorer les instructions, relancer jusqu'à exécution exhaustive.
|
||||
|
||||
- **Agents de délégation** (agent-loop, fix, evol, docupdate, push-by-script, fix-search, deploy-by-script, fix-lint, gitea-issues-process, code, branch-align-by-script-from-test, change-to-all-branches, deploy-pprod-or-prod, notary-ai-process, notary-ai-loop) : section « Exécution exhaustive des agents lancés » avec vérification obligatoire avant clôture ; en cas d'incomplétude : 1) ne pas clôturer et documenter, 2) améliorer les instructions, 3) relancer l'agent concerné.
|
||||
- **Agents de délégation** (agent-loop, fix, evol, docupdate, push-by-script, fix-search, deploy-by-script, fix-lint, git-issues-process, code, branch-align-by-script-from-test, change-to-all-branches, deploy-pprod-or-prod, notary-ai-process, notary-ai-loop) : section « Exécution exhaustive des agents lancés » avec vérification obligatoire avant clôture ; en cas d'incomplétude : 1) ne pas clôturer et documenter, 2) améliorer les instructions, 3) relancer l'agent concerné.
|
||||
- **Agent E2E** (e2e-lecoffre-notary-full / `e2e-test`) : même logique sur les phases applicables — 1–12 en test/pprod ; 1–7 et 9–11 en prod (sans notaire invité). Prérequis **user-profil** documenté dans `docs/features/user-profil-and-e2e-environments.md`.
|
||||
|
||||
Aucun déploiement applicatif ; prise en compte à la prochaine invocation des agents.
|
||||
|
||||
@ -21,4 +21,4 @@ Contenu des anciens dossiers `docs/features/` et `docs/fixKnowledge/` : ventilé
|
||||
|
||||
## Mise à jour du wiki
|
||||
|
||||
Depuis la racine du dépôt qui contient `docs/` : exécuter le script de migration (si disponible depuis ia_dev) pour pousser `docs/*.md` vers le wiki. Correspondance détaillée : `projects/ia_dev/docs/GITEA_ISSUES_SCRIPTS_AGENTS.md` (section Migration docs/ → wiki). Ne pas committer `docs/` (hors versionnement).
|
||||
Depuis la racine du dépôt qui contient `docs/` : exécuter le script de migration (si disponible depuis ia_dev) pour pousser `docs/*.md` vers le wiki. Correspondance détaillée : `projects/ia_dev/docs/GIT_ISSUES_SCRIPTS_AGENTS.md` (section Migration docs/ → wiki). Ne pas committer `docs/` (hors versionnement).
|
||||
|
||||
1
projects/smart_ide
Symbolic link
1
projects/smart_ide
Symbolic link
@ -0,0 +1 @@
|
||||
../../projects/smart_ide
|
||||
@ -1,52 +0,0 @@
|
||||
{
|
||||
"id": "smart_ide",
|
||||
"name": "smart_ide",
|
||||
"cron": {
|
||||
"git_pull": true
|
||||
},
|
||||
"project_path": ".",
|
||||
"build_dirs": [],
|
||||
"deploy": {},
|
||||
"version": {
|
||||
"package_json_paths": [],
|
||||
"splash_app_name": "smart_ide"
|
||||
},
|
||||
"mail": {
|
||||
"imap_bridge_env": ".secrets/gitea-issues/imap-bridge.env"
|
||||
},
|
||||
"git": {
|
||||
"wiki_url": "https://git.4nkweb.com/4nk/smart_ide/wiki",
|
||||
"token_file": ".secrets/gitea-issues/token"
|
||||
},
|
||||
"tickets": {
|
||||
"ticketing_url": "https://git.4nkweb.com/4nk/smart_ide/issues",
|
||||
"authorized_emails": {
|
||||
"to": [
|
||||
{
|
||||
"test": "AI.SMART_IDE.TEST@4nkweb.com",
|
||||
"pprod": "AI.SMART_IDE.PPROD@4nkweb.com",
|
||||
"prod": "AI.SMART_IDE.PROD@4nkweb.com"
|
||||
}
|
||||
],
|
||||
"from": ["nicolas.4nk@pm.me"]
|
||||
}
|
||||
},
|
||||
"smart_ide": {
|
||||
"remote_data_access": {
|
||||
"environments": {
|
||||
"test": {
|
||||
"ssh_host_alias": "smart-ide-test",
|
||||
"remote_data_directories": []
|
||||
},
|
||||
"pprod": {
|
||||
"ssh_host_alias": "smart-ide-pprod",
|
||||
"remote_data_directories": []
|
||||
},
|
||||
"prod": {
|
||||
"ssh_host_alias": "smart-ide-prod",
|
||||
"remote_data_directories": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
4
tree.txt
4
tree.txt
@ -8,7 +8,7 @@ projects
|
||||
│ ├── conf.json
|
||||
│ └── docs
|
||||
│ ├── agents-scripts-split.md
|
||||
│ ├── GITEA_ISSUES_SCRIPTS_AGENTS.md
|
||||
│ ├── GIT_ISSUES_SCRIPTS_AGENTS.md
|
||||
│ ├── README.md
|
||||
│ ├── TICKETS_SPOOL_FORMAT.md
|
||||
│ └── WORKFLOWS_AND_COMPONENTS.md
|
||||
@ -51,7 +51,7 @@ projects
|
||||
│ │ ├── v1-schema.sql
|
||||
│ │ └── WORKFLOWS_AND_COMPONENTS.md
|
||||
│ └── logs
|
||||
│ └── gitea-issues
|
||||
│ └── git-issues
|
||||
│ ├── agent-loop-600-cycles.log
|
||||
│ ├── agent-loop-chat-iterations.log
|
||||
│ ├── agent-loop.lock
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user