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

16 KiB
Raw Blame History

issueRef, version, updatedBy, updatedAt
issueRef version updatedBy updatedAt
#305 7
kind agent_id
agent a6c6ea12-bfc6-4bdc-8031-324102dfa34d
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:

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:

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.