feat(backend,frontend): tâches planifiées projet — tool MCP idea_scheduled_task_* et menu utilisateur #305, fix transcript lié indisponible après reboot #314 (QA verte)
#305: nouvel agrégat durable ScheduledProjectTask dans domain (scheduled_task.rs, ids, ports ScheduledProjectTaskStore), source de vérité <app_data_dir>/scheduled-project-tasks/<projectId>.json, schedules bornés V1 interval/daily/weekly avec fuseau, cycle À approuver/Active/Suspendue avec approbation obligatoire des tâches demandées par agent; use cases application/scheduled_task (list/create/update/delete/run_now/reconcile/fire) réutilisant BackgroundTask pour les runs avec distinction planifié/manuel; store infrastructure dédié + scheduler reconcile au boot sans rattrapage en rafale, cwd confiné au projet; 7 tools MCP idea_scheduled_task_* (list/read lecture seule, create/update/delete/run_now/set_enabled write-actions soumises aux permissions natives); commandes Tauri + routes HTTP aux contrats DTO identiques (camelCase nextRunAtMs/lastRunAtMs/lastTaskId/createdBy/updatedBy); frontend: gateways Tauri/HTTP/mock + types ports/domain, surface projet 'Tâches planifiées' (liste utilisateur+agent unifiée, création/édition avec récapitulatif avant activation, approbation/refus, exécuter maintenant, suspendre/reprendre, suppression), catalogage surface web (webSurfaceCatalog/viewPlacement/ViewPanelBody/WebWorkspace); docs/scheduled-project-tasks.md et sdk docs/services.md (047c38b: pas un service plugin V1, pas d'émulation via cron système). #314: correction de 'Conversation liée — transcript indisponible' après reboot: restauration du transcript lié côté application (orchestrator service, lifecycle, session_limit, background sink, terminal registry) et côté frontend (adapters agent/http frames/stream/requestResponse, workStateNormalization, CustomAgentChatView avec état et action utile), tests dto_chat/agent_lifecycle/structured_registry_d1/background_completion_sink étendus. QA verte rapportée par QA sur feature/305-scheduled-project-tasks-mcp, sans bloquant, pour #305 et #314. Hors périmètre worktree: tickets non liés, attachments/, scripts/; aucun push.
This commit is contained in:
@ -1037,6 +1037,16 @@ pub enum ScheduledTask {
|
||||
/// id, comme le reste du chemin de reprise §15).
|
||||
conversation_id: Option<String>,
|
||||
},
|
||||
/// Fire a durable project task. The application re-reads the definition
|
||||
/// before execution so stale one-shot payloads cannot bypass updates.
|
||||
FireProjectTask {
|
||||
/// Owning project.
|
||||
project_id: ProjectId,
|
||||
/// Durable definition id.
|
||||
scheduled_task_id: crate::ScheduledTaskId,
|
||||
/// Occurrence this wake-up represents.
|
||||
planned_at_ms: u64,
|
||||
},
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@ -1272,6 +1282,20 @@ pub enum BackgroundTaskPortError {
|
||||
Store(String),
|
||||
}
|
||||
|
||||
/// Errors from the machine-local scheduled task store.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Error)]
|
||||
pub enum ScheduledTaskStoreError {
|
||||
/// Requested definition is absent.
|
||||
#[error("scheduled project task not found")]
|
||||
NotFound,
|
||||
/// Persisted or supplied data is invalid.
|
||||
#[error("scheduled project task invalid: {0}")]
|
||||
Invalid(String),
|
||||
/// Persistence failed.
|
||||
#[error("scheduled project task store failed: {0}")]
|
||||
Store(String),
|
||||
}
|
||||
|
||||
/// Errors from the owner wake port.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Error)]
|
||||
pub enum WakeError {
|
||||
@ -2790,6 +2814,40 @@ pub trait BackgroundTaskStore: Send + Sync {
|
||||
) -> Result<(), BackgroundTaskPortError>;
|
||||
}
|
||||
|
||||
/// Persistence port for durable project-scoped schedule definitions and audit.
|
||||
#[async_trait]
|
||||
pub trait ScheduledProjectTaskStore: Send + Sync {
|
||||
/// Lists one project's definitions.
|
||||
async fn list(
|
||||
&self,
|
||||
project_id: ProjectId,
|
||||
) -> Result<Vec<crate::ScheduledProjectTask>, ScheduledTaskStoreError>;
|
||||
/// Reads one definition.
|
||||
async fn get(
|
||||
&self,
|
||||
project_id: ProjectId,
|
||||
scheduled_task_id: crate::ScheduledTaskId,
|
||||
) -> Result<Option<crate::ScheduledProjectTask>, ScheduledTaskStoreError>;
|
||||
/// Upserts a definition and appends its audit entry atomically.
|
||||
async fn save(
|
||||
&self,
|
||||
task: &crate::ScheduledProjectTask,
|
||||
audit: crate::ScheduledTaskAuditEntry,
|
||||
) -> Result<(), ScheduledTaskStoreError>;
|
||||
/// Deletes a definition and appends its audit entry atomically.
|
||||
async fn delete(
|
||||
&self,
|
||||
project_id: ProjectId,
|
||||
scheduled_task_id: crate::ScheduledTaskId,
|
||||
audit: crate::ScheduledTaskAuditEntry,
|
||||
) -> Result<(), ScheduledTaskStoreError>;
|
||||
/// Lists enabled, approved definitions whose persisted deadline is due.
|
||||
async fn list_due(
|
||||
&self,
|
||||
now_ms: u64,
|
||||
) -> Result<Vec<crate::ScheduledProjectTask>, ScheduledTaskStoreError>;
|
||||
}
|
||||
|
||||
/// Execution port for first-class background tasks.
|
||||
#[async_trait]
|
||||
pub trait BackgroundTaskRunner: Send + Sync {
|
||||
|
||||
Reference in New Issue
Block a user