From 5139937d279d68c7e1a1826ffd44f300b46da228 Mon Sep 17 00:00:00 2001 From: Nicolas Cantu Date: Fri, 13 Mar 2026 09:18:38 +0100 Subject: [PATCH] chat control --- .cursor/agents/deploy-pprod-or-prod.md | 4 +- .cursor/agents/gitea-issues-process.md | 16 ++++--- deploy/deploy-by-script-to.sh | 18 ++++---- gitea-issues/AGENT_LOOP.md | 13 ++++++ gitea-issues/README.md | 7 +++ gitea-issues/agent-loop-chat-iterations.sh | 52 ++++++++++++++++++++++ gitea-issues/mail_common.py | 3 +- projects/ia_dev/conf.json | 1 + projects/lecoffreio/conf.json | 1 + 9 files changed, 97 insertions(+), 18 deletions(-) create mode 100755 gitea-issues/agent-loop-chat-iterations.sh diff --git a/.cursor/agents/deploy-pprod-or-prod.md b/.cursor/agents/deploy-pprod-or-prod.md index 33c97c3..44933c1 100644 --- a/.cursor/agents/deploy-pprod-or-prod.md +++ b/.cursor/agents/deploy-pprod-or-prod.md @@ -23,8 +23,8 @@ is_background: false - **Si OK :** Passer à l'étape 3. 3. **Lancer le script deploy-by-script-to** avec la branche en paramètre (`pprod` ou `prod`) : - - Commande : `cd /home/desk/code/lecoffre_ng_test && ./ia_dev/deploy/deploy-by-script-to.sh ` - - Le script fait : checkout sur la branche en paramètre, vérification que `.secrets/` existe, mise à jour forcée de la branche locale sur la branche distante, déploiement (deploy.sh avec --import-v1 --skipSetupHost), checkout test. + - Le script est lancé depuis **ia_dev** (comme les autres scripts), il s’applique au dépôt parent (`../`). Depuis la racine projet : `cd /home/desk/code/lecoffre_ng_test/ia_dev && ./deploy/deploy-by-script-to.sh ` (ou depuis la racine : `./ia_dev/deploy/deploy-by-script-to.sh `). + - Le script fait : passage dans le dépôt parent, checkout sur la branche en paramètre, vérification que `.secrets/` existe, mise à jour forcée de la branche locale sur la branche distante, déploiement (deploy.sh avec --import-v1 --skipSetupHost), checkout test. - **Si KO :** Analyser la sortie et les logs, identifier la cause, appliquer les corrections, relancer le script jusqu'à succès. - **Si OK :** Passer à l'étape 4. diff --git a/.cursor/agents/gitea-issues-process.md b/.cursor/agents/gitea-issues-process.md index 882b889..1135685 100644 --- a/.cursor/agents/gitea-issues-process.md +++ b/.cursor/agents/gitea-issues-process.md @@ -7,7 +7,7 @@ is_background: false # Agent gitea-issues-process -**Contexte projet :** La configuration et la documentation du projet sont dans `projects//` (chemin absolu : `/home/desk/code/lecoffre_ng_test/ia_dev/projects/`). L'identifiant `` vient du slug (contenu du fichier `../ai_project_id`). Rappeler ce chemin en début d'exécution. +**Contexte projet :** La configuration et la documentation du projet sont dans `projects//` ; `` = contenu du fichier `../ai_project_id` (à la racine du dépôt projet, parent de ia_dev). Rappeler en début d'exécution : projet = contenu de `../ai_project_id`, config = `ia_dev/projects//`. Même schéma pour tout projet utilisant ia_dev ; 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/.json` (clé `git.ticketing_url`, `git.wiki_url`) ; le slug projet est donné par `.ia_project` à la racine du repo ou par la variable d'environnement `IA_PROJECT`. 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. @@ -21,24 +21,28 @@ Tu es l'agent qui traite les **tickets (issues) Gitea** du dépôt du projet cou ## Prérequis - `GITEA_TOKEN` défini ou fichier `.secrets/gitea-issues/token` présent. -- Exécution depuis la **racine du dépôt projet** (chemin absolu) : `cd /home/desk/code/lecoffre_ng_test` puis invoquer les scripts `./ia_dev/gitea-issues/*.sh`. Ne pas exécuter depuis un autre répertoire. +- Exécution depuis la **racine du dépôt projet** (répertoire parent de ia_dev, contenant `ai_project_id`) : `cd && ./ia_dev/gitea-issues/*.sh`. Depuis le workspace ia_dev, racine projet = `..`. Ne pas hardcoder le chemin d'un projet ; fonctionne pour tout projet configuré par `../ai_project_id`. - Dépendances : `jq`, `curl` (les scripts les utilisent). +**Contexte** : `gitea-issues/` est dans ia_dev ; le projet est identifié par `../ai_project_id` ; la config est dans `ia_dev/projects//`. `.secrets` est sous ia_dev (`./.secrets`), indépendant du projet parent. Voir `gitea-issues/README.md` (Contexte d'exécution). + ## Workflow (script au maximum) 1. **Lister les issues** - Exécuter `cd /home/desk/code/lecoffre_ng_test && ./ia_dev/gitea-issues/list-open-issues.sh --lines` pour obtenir la liste des issues ouvertes. Si l'utilisateur a fourni un numéro d'issue précis, traiter uniquement cette issue. + Exécuter depuis la racine du dépôt projet : `cd && ./ia_dev/gitea-issues/list-open-issues.sh --lines` (depuis workspace ia_dev : `cd .. && ./ia_dev/gitea-issues/list-open-issues.sh --lines`). Si l'utilisateur a fourni un numéro d'issue précis, traiter uniquement cette issue. 2. **Pour chaque issue à traiter** (ou la seule ciblée) : - - **Créer la branche** : `cd /home/desk/code/lecoffre_ng_test && ./ia_dev/gitea-issues/create-branch-for-issue.sh [base]` (base par défaut : `test`). Ne pas inventer de commande git ; utiliser uniquement ce script. - - **Récupérer le contenu du ticket** : `cd /home/desk/code/lecoffre_ng_test && ./ia_dev/gitea-issues/print-issue-prompt.sh ` et utiliser la sortie comme **consigne** pour l'étape suivante. + - **Créer la branche** : `cd && ./ia_dev/gitea-issues/create-branch-for-issue.sh [base]` (base par défaut : `test`). Ne pas inventer de commande git ; utiliser uniquement ce script. + - **Récupérer le contenu du ticket** : `cd && ./ia_dev/gitea-issues/print-issue-prompt.sh ` et utiliser la sortie comme **consigne** pour l'étape suivante. - **Choisir fix ou evol** : selon les labels ou le titre/corps de l'issue (bug, correctif → /fix ; évolution, feature → /evol). En cas de doute, privilégier /evol. - **Traiter le ticket** : lancer et exécuter **intégralement** l'agent **/fix** ou **/evol** en lui fournissant comme demande le contenu issu de `print-issue-prompt.sh` (titre + corps de l'issue). - **Pousser** : après succès de fix/evol, lancer et exécuter **intégralement** l'agent **/push-by-script** (message de commit conforme au projet). Push direct sur la branche ; ne jamais créer de pull request. - - **Commenter l'issue (optionnel)** : exécuter `cd /home/desk/code/lecoffre_ng_test && ./ia_dev/gitea-issues/comment-issue.sh "Traitement effectué dans la branche issue/. Commit poussé."` (ou message adapté). + - **Commenter l'issue (optionnel)** : exécuter `cd && ./ia_dev/gitea-issues/comment-issue.sh "Traitement effectué dans la branche issue/. 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. +**Boucle récupération mails (depuis le chat)** : si l'utilisateur demande « Lance la boucle récupération emails, attend 1 min et relance, N itérations », exécuter depuis la racine du dépôt projet : `cd && ./ia_dev/gitea-issues/agent-loop-chat-iterations.sh [N]` (depuis workspace ia_dev : `cd .. && ./ia_dev/gitea-issues/agent-loop-chat-iterations.sh [N]`). Pour N élevé (ex. 300), indiquer de lancer le script en terminal (tmux/screen) depuis la même racine. Au lancement le script envoie un mail de test à nicolas.cantu@pm.me ; les mails en attente sont dans `logs/gitea-issues/agent-loop.pending`. Traiter les mails selon le workflow (mail-get-thread, mail-thread-log, réponse ou issue, mail-mark-read). Voir `gitea-issues/AGENT_LOOP.md`. + ## Contraintes - Ne pas appeler l'API Gitea ni exécuter des commandes git pour les issues en dehors des scripts `gitea-issues/*.sh`. diff --git a/deploy/deploy-by-script-to.sh b/deploy/deploy-by-script-to.sh index fd4c08c..816aeb2 100755 --- a/deploy/deploy-by-script-to.sh +++ b/deploy/deploy-by-script-to.sh @@ -1,29 +1,29 @@ #!/usr/bin/env bash # deploy-by-script-to : checkout target, verify .secrets/, force sync with origin, deploy target, checkout test. -# Centralized in ia_dev. Call after /change-to-all-branches (agent). Requires: start on branch test. Target: pprod | prod only. +# Launched from ia_dev (like other deploy scripts); applies to parent repo (../). Call after /change-to-all-branches (agent). Target: pprod | prod only. set -euo pipefail -if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then - echo "[deploy-by-script-to][ERROR] Not in a git repository" >&2 - exit 1 -fi - -PROJECT_ROOT="$(git rev-parse --show-toplevel)" SCRIPT_REAL="$(readlink -f "${BASH_SOURCE[0]:-$0}" 2>/dev/null || realpath "${BASH_SOURCE[0]:-$0}" 2>/dev/null || echo "${BASH_SOURCE[0]:-$0}")" DEPLOY_IA="$(cd "$(dirname "$SCRIPT_REAL")" && pwd)" +# Parent of ia_dev = project root (deploy applies to ../) +PROJECT_ROOT="$(cd "$DEPLOY_IA/../.." && pwd)" if [[ "$(pwd)" != "$PROJECT_ROOT" ]]; then cd "$PROJECT_ROOT" && exec "$SCRIPT_REAL" "$@" fi +if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then + echo "[deploy-by-script-to][ERROR] Not in a git repository (PROJECT_ROOT=${PROJECT_ROOT})" >&2 + exit 1 +fi TARGET_BRANCH="${1:-}" if [[ -z "$TARGET_BRANCH" ]]; then echo "[deploy-by-script-to][ERROR] Missing argument (expected: pprod | prod)" >&2 - echo "Usage: ./ia_dev/deploy/deploy-by-script-to.sh (pprod or prod only)" >&2 + echo "Usage: ./deploy/deploy-by-script-to.sh (from ia_dev; pprod or prod only)" >&2 exit 1 fi if [[ ! "$TARGET_BRANCH" =~ ^(pprod|prod)$ ]]; then echo "[deploy-by-script-to][ERROR] Invalid target branch: must be pprod or prod (got: '${TARGET_BRANCH}')" >&2 - echo "Usage: ./ia_dev/deploy/deploy-by-script-to.sh " >&2 + echo "Usage: ./deploy/deploy-by-script-to.sh " >&2 exit 1 fi diff --git a/gitea-issues/AGENT_LOOP.md b/gitea-issues/AGENT_LOOP.md index ad291ca..217db26 100644 --- a/gitea-issues/AGENT_LOOP.md +++ b/gitea-issues/AGENT_LOOP.md @@ -111,3 +111,16 @@ nohup ./gitea-issues/agent-loop.sh 60 >> logs/gitea-issues/agent-loop.log 2>&1 & - Si lancé en arrière-plan : `kill ` (ou `pkill -f agent-loop.sh`). Après arrêt, le fichier témoin ne sera plus mis à jour ; après 2 × intervalle, il doit être considéré comme inactif. + +## Boucle limitée depuis le chat (sans API payante) + +Pour lancer depuis **ce** chat (instance Cursor ouverte, abonnement Ultra) une boucle limitée : récupération des mails → attente 1 min → récupération → … sans consommer de crédits API ni lancer la CLI `agent` : + +1. Demander dans le chat : *« Lance la boucle récupération emails : subagent puis attend 1 min et relance, N itérations »* (ou similaire). +2. L’agent exécute `cd /home/desk/code/lecoffre_ng_test && ./ia_dev/gitea-issues/agent-loop-chat-iterations.sh [N]` depuis la racine du dépôt projet. Par défaut N=3 ; pour 300 itérations, lancer en terminal (tmux/screen) depuis la même racine. +3. Au lancement, le script envoie un mail de test à nicolas.cantu@pm.me pour vérifier SMTP ; si l'envoi échoue, le script s'arrête (code 1). +4. Chaque itération exécute `mail-list-unread.sh` puis attend 60 secondes. Les mails en attente sont écrits dans `logs/gitea-issues/agent-loop.pending` ; traiter ensuite dans le même chat (workflow gitea-issues-process, voir `.cursor/agents/gitea-issues-process.md`). + +**Pourquoi l'envoi pouvait échouer** : si le script était invoqué depuis la racine projet avec ROOT = toplevel Git (racine projet), le chemin `./gitea-issues/` n'existait pas (gitea-issues est dans ia_dev). Le script utilise maintenant le répertoire contenant gitea-issues (ia_dev) comme racine et appelle les sous-scripts via `GITEA_ISSUES_DIR`. + +Script : `gitea-issues/agent-loop-chat-iterations.sh [N]`. Boucle illimitée en terminal : `cd && while true; do ./ia_dev/gitea-issues/mail-list-unread.sh; sleep 60; done`. diff --git a/gitea-issues/README.md b/gitea-issues/README.md index a7f6a61..6d8f2dd 100644 --- a/gitea-issues/README.md +++ b/gitea-issues/README.md @@ -2,6 +2,13 @@ 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 ; l’agent orchestre et appelle /fix ou /evol. +## Contexte d'exécution + +- **Emplacement** : `gitea-issues/` est dans le sous-module **ia_dev** du dépôt projet. Chemin typique : `/ia_dev/gitea-issues/`. Fonctionne pour tout projet utilisant ia_dev de la même manière. +- **Projet cible** : le projet est identifié **dynamiquement** par le fichier `../ai_project_id` (à la racine du dépôt projet, parent de `ia_dev`). Son contenu (slug) sert à charger la config dans `ia_dev/projects//`. Changer de projet = changer le dépôt (ou le contenu de `ai_project_id`) ; aucun chemin à hardcoder. +- **Lancement** : le chat Cursor et les scripts sont lancés depuis **ia_dev** (`/ia_dev/`), mais les opérations (issues, mails, déploiement) concernent le dépôt **parent** (`../` = racine projet). Invoquer les scripts depuis la racine du dépôt projet : `cd && ./ia_dev/gitea-issues/