15 KiB
issueRef, version, updatedBy, updatedAt
| issueRef | version | updatedBy | updatedAt | ||||
|---|---|---|---|---|---|---|---|
| #305 | 6 |
|
1789115266263 |
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
crontabsystè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éesdans 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 vousouCréée par {agent}), menuModifier,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 projetpuisCré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 travailrelatif au projet par défaut,Planification(presetsToutes les heures,Chaque jour,Chaque semaine, optionPersonnalisé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, actionsApprouver 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 maintenantutilise 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écutionetArrêter puis supprimer; ne jamais interrompre implicitement.
Exécutions:
- Fiche: dernière/prochaine exécution, déclenchement
PlanifiéouManuel, 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.
BackgroundTaskest 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:
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.ScheduledTaskRunoptionnel = 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 } | Manualsur 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).ScheduledProjectTaskAuditStoreou 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 appelleSpawnBackgroundCommandavecwakePolicy = RecordOnlypar défaut.
Scheduler/boot:
- Réutiliser
TokioSchedulerone-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: politiqueskipMissedAndScheduleNext, pas de rafale. - Si une run était
Runningavant crash: laisser le reconcileBackgroundTaskexistant marquer failed/lost handle.
Sécurité:
cwdconfiné au project root.- Pas d'
envlibre 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
crontabdirectement.
MCP tools à ajouter:
idea_scheduled_task_listread-onlyidea_scheduled_task_readread-onlyidea_scheduled_task_createwrite-actionidea_scheduled_task_updatewrite-actionidea_scheduled_task_deletewrite-actionidea_scheduled_task_run_nowwrite-actionidea_scheduled_task_set_enabledwrite-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. ScheduledTaskGatewaydans ports/adapters Tauri/HTTP/mock.- Panneau liste + create/edit/delete/enable/run-now.
- Lien vers
BackgroundTaskdu dernier run silastTaskIdexiste. - 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.mdsi exposé aux plugins, sinon préciser que ce n'est pas un service plugin V1.sdk/IdeaSDK/docs/manifest.mdseulement 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:
BackgroundTaskcréé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.
cwdhors 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-mcppar 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:
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.