Files
IdeA/.ideai/tickets/305/carnet.md

247 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
issueRef: "#305"
version: 7
updatedBy: {"kind":"agent","agent_id":"a6c6ea12-bfc6-4bdc-8031-324102dfa34d"}
updatedAt: 1789115934356
---
# Carnet #305 - Tâches planifiées projet avec outil MCP et menu utilisateur
## Demande
- Date: 2026-09-10.
- Ajouter des tâches planifiées liées au projet, gérées par IdeA plutôt que par le cron Linux.
- Les agents doivent disposer d'un tool MCP pour créer des tâches récurrentes/projet.
- L'utilisateur doit disposer d'un menu par projet pour créer, supprimer et modifier ces tasks.
- Motivation: un projet a grossi build après build; l'orchestrateur a créé un cron Linux pour nettoyer régulièrement le dossier. Objectif: permettre cette automatisation dans IdeA, scoped au projet et visible/gérable.
- Après livraison et QA: rebuild AppImage demandé.
## Contraintes initiales
- Les tâches sont liées au projet, pas au système global Linux.
- L'utilisateur doit pouvoir voir/modifier/supprimer ce que les agents créent.
- Le tool MCP doit éviter que les agents contournent IdeA avec `crontab` système.
- Sécurité: commandes planifiées potentiellement destructrices; besoin de permissions/sandbox claires.
- Réutiliser le modèle background tasks pour les exécutions si pertinent, mais distinguer tâche planifiée et exécution ponctuelle.
## Cadrage UX
Surface:
- Ajouter l'entrée `Tâches planifiées` dans le menu du projet.
- Surface unique pour les tâches créées par l'utilisateur et celles demandées par un agent.
- Ligne: état, nom, fréquence, prochaine exécution, résultat dernière exécution, origine (`Créée par vous` ou `Créée par {agent}`), menu `Modifier`, `Exécuter maintenant`, `Suspendre/Reprendre`, `Supprimer`.
- États visibles: `À approuver`, `Active`, `Suspendue`, `En cours`, `Échec`, `Projet inaccessible`.
- État vide: `Aucune tâche planifiée pour ce projet` puis `Créez une tâche pour automatiser une commande récurrente sans utiliser le cron du système.`
Création/édition:
- Action principale: `Nouvelle tâche planifiée`.
- Champs: `Nom`, `Commande`, `Dossier de travail` relatif au projet par défaut, `Planification` (presets `Toutes les heures`, `Chaque jour`, `Chaque semaine`, option `Personnalisée`), `Fuseau horaire`, `Limite de durée`, `Permissions et sandbox`, `Activée`.
- Avant activation: récapitulatif commande exacte, dossier, fréquence, prochaine exécution, permissions accordées.
- Modification de commande/périmètre/planification/permissions repasse par validation.
- Tâche créée par agent: état `À approuver`, ne s'exécute jamais silencieusement. Fiche: `Demandée par {agent}`, date et motif, commande/fréquence proposées, permissions nécessaires, actions `Approuver et activer`, `Modifier avant d’activer`, `Refuser`.
- Le tool MCP doit retourner cet état à l'agent, sans prétendre que la tâche est active.
Sécurité UX:
- Périmètre projet et profil sandbox toujours visibles.
- Accès hors projet, réseau ou commandes potentiellement destructrices signalés explicitement.
- Alerte: `Cette tâche pourra modifier ou supprimer des fichiers automatiquement.`
- Activation initiale d'une tâche demandée par agent exige confirmation utilisateur.
- Toute augmentation de permissions remet la tâche en état `À approuver`.
- `Exécuter maintenant` utilise exactement les permissions planifiées.
- Suppression active: confirmation `Supprimer définitivement cette tâche planifiée ?`.
- Si exécution en cours: choix séparés `Supprimer après l’exécution` et `Arrêter puis supprimer`; ne jamais interrompre implicitement.
Exécutions:
- Fiche: dernière/prochaine exécution, déclenchement `Planifié` ou `Manuel`, début, durée, code sortie, statut, stdout/stderr, permissions réellement utilisées, lien vers la tâche de fond correspondante.
- Succès silencieux.
- Échec: indicateur dans menu projet + notification discrète `Voir les détails`, sans avalanche de notifications répétées.
- IdeA doit indiquer que l'application doit fonctionner pour déclencher les tâches.
- Occurrences manquées pendant arrêt: pas de rattrapage en rafale; seule la prochaine occurrence future est programmée.
- Projet inaccessible: exécution `Ignorée — projet inaccessible`, sans lancer ailleurs.
## Cadrage Architect
Décision:
- Backend + frontend + docs.
- `BackgroundTask` est réutilisé uniquement pour les runs.
- Une tâche planifiée est un nouvel agrégat durable distinct: intention récurrente; chaque déclenchement crée une `BackgroundTask`.
Source de vérité:
- `<app_data_dir>/scheduled-project-tasks/<projectId>.json`.
- Ne pas utiliser `cron`, `systemd timer`, ni fichier auto-exécuté dans le repo.
- Machine-local et IdeA-owned pour éviter qu'un clone embarque une tâche destructrice.
Modèle domaine cible:
```ts
ScheduledProjectTask {
id: ScheduledTaskId
projectId: ProjectId
name: string
description?: string
enabled: boolean
command: { command: string; args: string[]; cwd?: string }
schedule: Interval | Daily | Weekly
timezone: string
nextRunAtMs: number | null
lastRunAtMs?: number
lastTaskId?: TaskId
createdBy: Human | Agent { agentId }
updatedBy: Human | Agent { agentId }
createdAtMs: number
updatedAtMs: number
auditRevision: number
}
```
V1 schedule borné:
- `interval { everyMinutes }`, minimum configurable, défaut min 5 ou 15 minutes.
- `daily { time: "HH:mm" }`.
- `weekly { days: [...], time: "HH:mm" }`.
- Pas de cron expression libre en V1.
Séparation schedule/run:
- `ScheduledProjectTask` = définition visible, éditable, activable/désactivable.
- `ScheduledTaskRun` optionnel = historique léger (`scheduleId`, `taskId`, `plannedAtMs`, `startedAtMs`, `status`).
- `BackgroundTask` = exécution concrète, sortie attachable, cancel/retry existants.
- Préférence architect: champ additif `origin: Scheduled { scheduledTaskId, plannedAtMs } | Manual` sur les runs/background tasks, plutôt que mélanger la nature et la provenance.
Ports/use cases:
- `ScheduledProjectTaskStore`: `list(projectId)`, `get(projectId, scheduleId)`, `save(task)`, `delete(projectId, scheduleId)`, `list_due(nowMs)`.
- `ScheduledProjectTaskAuditStore` ou audit via event store existant.
- `ProjectTaskScheduler`: `reconcile_project(projectId)`, `arm(scheduleId, nextRunAtMs)`, `cancel(scheduleId)`.
- Use cases: `ListScheduledProjectTasks`, `CreateScheduledProjectTask`, `UpdateScheduledProjectTask`, `DeleteScheduledProjectTask`, `RunScheduledProjectTaskNow`, `ReconcileScheduledProjectTasks`, `FireScheduledProjectTask`.
- `FireScheduledProjectTask`: calcule prochain run, persiste avant spawn, puis appelle `SpawnBackgroundCommand` avec `wakePolicy = RecordOnly` par défaut.
Scheduler/boot:
- Réutiliser `TokioScheduler` one-shot comme mécanisme de réveil, jamais comme source de vérité.
- Au boot: charger projets connus; pour chaque projet ouvert/restauré, `reconcile_project(projectId)`.
- V1: ne pas lancer de tâches pour projets fermés.
- Si `nextRunAtMs <= now`: politique `skipMissedAndScheduleNext`, pas de rafale.
- Si une run était `Running` avant crash: laisser le reconcile `BackgroundTask` existant marquer failed/lost handle.
Sécurité:
- `cwd` confiné au project root.
- Pas d'`env` libre V1, ou seulement références à variables existantes; jamais de secrets persistés.
- Commande/args visibles intégralement avant activation.
- Audit create/update/delete/enable/disable/runNow: actor, projectId, scheduleId, diff résumé, timestamp.
- Tools MCP création/modification/suppression = `WriteAction`, soumis aux permissions MCP natives.
- #305 fournit l'alternative visible au cron système; limiter les permissions shell/sandbox reste nécessaire pour empêcher un agent large de lancer `crontab` directement.
MCP tools à ajouter:
- `idea_scheduled_task_list` read-only
- `idea_scheduled_task_read` read-only
- `idea_scheduled_task_create` write-action
- `idea_scheduled_task_update` write-action
- `idea_scheduled_task_delete` write-action
- `idea_scheduled_task_run_now` write-action
- `idea_scheduled_task_set_enabled` write-action
- Project scope vient du serveur MCP du projet courant; l'agent ne choisit pas un autre projectId.
DTO/API Tauri + HTTP:
- `list_scheduled_project_tasks(projectId)`
- `create_scheduled_project_task(request)`
- `update_scheduled_project_task(request)`
- `delete_scheduled_project_task(projectId, scheduledTaskId)`
- `run_scheduled_project_task_now(projectId, scheduledTaskId)`
- `set_scheduled_project_task_enabled(projectId, scheduledTaskId, enabled)`
- DTO camelCase: `nextRunAtMs`, `lastRunAtMs`, `lastTaskId`, `createdBy`, `updatedBy`.
Frontend:
- Nouvelle surface projet/menu `Tâches planifiées`.
- `ScheduledTaskGateway` dans ports/adapters Tauri/HTTP/mock.
- Panneau liste + create/edit/delete/enable/run-now.
- Lien vers `BackgroundTask` du dernier run si `lastTaskId` existe.
- Ne pas fusionner avec WorkState: WorkState montre les runs; panneau planifié montre les définitions.
Docs:
- Mettre à jour la doc MCP/agent-facing pour `idea_scheduled_task_*`.
- `sdk/IdeaSDK/docs/services.md` si exposé aux plugins, sinon préciser que ce n'est pas un service plugin V1.
- `sdk/IdeaSDK/docs/manifest.md` seulement si contributions plugin touchent les schedules, déconseillé V1.
- Mentionner explicitement: ne pas utiliser cron système pour une maintenance projet IdeA.
Fichiers probables:
- Backend: `crates/domain/src/scheduled_task.rs`, `crates/domain/src/ports.rs`, `crates/application/src/scheduled_task/mod.rs`, `crates/application/src/background/mod.rs`, `crates/infrastructure/src/store/scheduled_task.rs`, `crates/infrastructure/src/scheduler/mod.rs`, `crates/backend/src/lib.rs`, `crates/app-tauri/src/commands.rs`, `crates/backend/src/dto.rs`, `crates/web-server/src/lib.rs`, `crates/infrastructure/src/orchestrator/mcp/tools.rs`.
- Frontend: `frontend/src/features/scheduled-tasks/*`, `frontend/src/ports/index.ts`, `frontend/src/adapters/scheduledTask.ts`, `frontend/src/adapters/http/requestResponseGateways.ts`, `frontend/src/adapters/mock/index.ts`, `frontend/src/features/projects/ProjectsView.tsx`, `frontend/src/features/web/webSurfaceCatalog.ts`.
## Critères QA
- Une tâche utilisateur et une tâche créée via MCP apparaissent dans la même liste.
- L'auteur, commande, fréquence, prochaine exécution et permissions sont identifiables.
- Tâche demandée par agent ne s'exécute pas avant approbation.
- Approuver/refuser/modifier/suspendre/reprendre/supprimer produisent les états attendus.
- Modification sensible redemande une approbation.
- Tâche suspendue ne s'exécute pas.
- Exécution manuelle et planifiée sont distinguables/auditables.
- Logs, durée, code de sortie et erreurs consultables.
- Projet inaccessible ne bloque pas IdeA et ne déplace jamais l'exécution ailleurs.
- Aucun rattrapage multiple après arrêt prolongé.
- Suppression pendant exécution ne l'interrompt pas sans choix explicite.
- Succès silencieux; échecs visibles sans notifications répétitives.
- Horaires respectent le fuseau configuré.
- Créer via MCP puis vérifier UI; créer/modifier/supprimer via UI puis vérifier MCP list/read.
- Échéance atteinte: `BackgroundTask` créée, visible WorkState, sortie attachable.
- Redémarrage avant échéance: reconcile rearme.
- Redémarrage après échéance manquée: pas de rafale, prochaine échéance recalculée, audit missed/skipped.
- Projet fermé: aucune exécution silencieuse.
- `cwd` hors projet rejeté.
- Tool MCP write refusé sans permission native.
- Delete/disable annule le timer armé.
- Deux reconciles concurrents ne créent pas deux runs pour la même échéance.
## Blocage — 2026-09-10
- Git a préparé `feature/305-scheduled-project-tasks-mcp`, mais a recommandé de finaliser #304 avant de démarrer #305.
- #304 est implémenté et QA vert, mais non committé/mergé: trois délégations Git pour le commit/merge #304 ont expiré à 600s malgré relance/rattachement.
- Le worktree courant porte encore les deux fichiers frontend #304 modifiés. Main ne doit pas démarrer #305 ni changer de branche tant que cette topologie n'est pas résolue, pour éviter de mélanger les changements.
- Prochaine reprise: débloquer Git ou faire exécuter par l'agent Git le commit/merge #304, puis checkout/rebase/reset de `feature/305-scheduled-project-tasks-mcp` par Git et lancer DevBackend #305.
## Validation QA — 2026-09-11
Verdict: VERT pour le périmètre #305 sur `feature/305-scheduled-project-tasks-mcp`.
Diff inspecté: nouvel agrégat durable `ScheduledProjectTask`, store machine-local `<app_data_dir>/scheduled-project-tasks/<projectId>.json`, service application de création/update/enable/delete/run/fire/reconcile, origine `BackgroundTaskOrigin::Scheduled`, tools MCP `idea_scheduled_task_*`, commandes Tauri/HTTP, surface frontend `Tâches planifiées`, adapters Tauri/HTTP/mock et doc `docs/scheduled-project-tasks.md`.
Preuves de commandes réelles:
```text
CARGO_HOME=/home/anthony/.local/share/app.idea.ide/managed-tmp/1d97033d-7b81-4f12-9b27-fe5a3842c5cc/data/cargo-home cargo test -p domain -- --nocapture
=> test result: ok. 311 passed; 0 failed; intégrations domain 11+14+2+12+11+49+6+72+16+21+16+5 passed; doc-tests 0.
CARGO_HOME=/home/anthony/.local/share/app.idea.ide/managed-tmp/1d97033d-7b81-4f12-9b27-fe5a3842c5cc/data/cargo-home cargo test -p application scheduled_task -- --nocapture
=> test result: ok. 3 passed; 0 failed; 185 filtered out.
CARGO_HOME=/home/anthony/.local/share/app.idea.ide/managed-tmp/1d97033d-7b81-4f12-9b27-fe5a3842c5cc/data/cargo-home cargo test -p infrastructure scheduled_task -- --nocapture
=> test result: ok. 1 passed; 0 failed; 380 filtered out.
CARGO_HOME=/home/anthony/.local/share/app.idea.ide/managed-tmp/1d97033d-7b81-4f12-9b27-fe5a3842c5cc/data/cargo-home cargo test -p infrastructure scheduled_create -- --nocapture
=> test result: ok. 1 passed; 0 failed; 380 filtered out.
CARGO_HOME=/home/anthony/.local/share/app.idea.ide/managed-tmp/1d97033d-7b81-4f12-9b27-fe5a3842c5cc/data/cargo-home cargo test -p infrastructure scheduled_read -- --nocapture
=> test result: ok. 1 passed; 0 failed; 380 filtered out.
CARGO_HOME=/home/anthony/.local/share/app.idea.ide/managed-tmp/1d97033d-7b81-4f12-9b27-fe5a3842c5cc/data/cargo-home cargo test -p backend scheduled_task -- --nocapture
=> test result: ok. 1 passed; 0 failed; 103 filtered out.
CARGO_HOME=/home/anthony/.local/share/app.idea.ide/managed-tmp/1d97033d-7b81-4f12-9b27-fe5a3842c5cc/data/cargo-home cargo test -p web-server scheduled_task -- --nocapture
=> test result: ok. 1 passed; 0 failed; 116 filtered out.
npm --prefix frontend test -- --run src/features/scheduled-tasks/scheduledTasks.test.tsx src/adapters/scheduledTask.test.ts src/adapters/http/scheduledTaskGateway.test.ts src/features/agents/CustomAgentChatView.test.tsx src/adapters/agent.test.ts src/adapters/http/agentGateway.test.ts
=> Test Files 6 passed (6); Tests 107 passed (107).
npm --prefix frontend run typecheck
=> tsc --noEmit passed.
npm --prefix frontend run build
=> tsc --noEmit && vite build passed; Vite emitted only the existing chunk-size warning.
```
Risques résiduels non bloquants:
- Pas de test live AppImage/desktop scheduler réel dans cette passe QA; validation limitée aux tests automatisés Rust/TS et inspection du câblage.
- Les critères UX exhaustifs comme notifications discrètes et parcours complet créer UI -> lire MCP / créer MCP -> lire UI sont couverts par contrat/adapters/tests unitaires ciblés, pas par un e2e navigateur/Tauri complet.
## Clôture Git/AppImage — 2026-09-11
- Feature commit: `7007b2c` sur `feature/305-scheduled-project-tasks-mcp`.
- Sync tickets: `686cf31`.
- Merge local develop: `600aae17`.
- Rebuild AppImage depuis `develop @ 600aae17` réussi.
- Artefact: `target/release/bundle/appimage/IdeA_0.3.0_amd64.AppImage`.
- Taille: `120560120` octets.
- SHA-256: `d7de4519736eee6b923ba5b9a6e966cea08760173bd85a66ae6422a60a95e0d1`.
- Commit dédié rebuild: `1e2cb5e`.
- Tag annoté: `v0.48.0`.
- Aucun push effectué.
- Restant manuel: remplacer l'AppImage installée puis relancer IdeA pour valider live le binaire v0.48.0.