From bb14010db99b40792372bfcb4348cf4984f30b3f Mon Sep 17 00:00:00 2001 From: soryu Date: Sun, 1 Feb 2026 00:20:55 +0000 Subject: feat: Implement Phase 3 Tasks 3.1 and 3.2 - SupervisorState enum and Heartbeat Infrastructure Task 3.1: Enhanced Supervisor State Enum - Add SupervisorStateEnum with states: Initializing, Idle, Working, WaitingForUser, WaitingForTasks, Blocked, Completed, Failed, Interrupted - Implement Display, FromStr, Default, and serde serialization - Add SupervisorHeartbeatRecord and SupervisorHeartbeatRequest structs Task 3.2: Heartbeat Infrastructure - Create supervisor_heartbeats migration with proper indexes and constraints - Add heartbeat storage functions to repository.rs: - create_supervisor_heartbeat - get_latest_supervisor_heartbeat - get_supervisor_heartbeats - get_contract_supervisor_heartbeats - cleanup_old_heartbeats (24 hour TTL support) - find_stale_supervisors (for dead supervisor detection) - Add SupervisorHeartbeat message to protocol.rs with enhanced fields - Update mesh_daemon.rs to process and store supervisor heartbeats - Add unit tests for SupervisorStateEnum and heartbeat serialization Co-Authored-By: Claude Opus 4.5 --- makima/src/daemon/ws/protocol.rs | 46 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'makima/src/daemon/ws') diff --git a/makima/src/daemon/ws/protocol.rs b/makima/src/daemon/ws/protocol.rs index bfe6326..5c88038 100644 --- a/makima/src/daemon/ws/protocol.rs +++ b/makima/src/daemon/ws/protocol.rs @@ -2,6 +2,7 @@ //! //! These types mirror the server's protocol exactly for compatibility. +use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; @@ -26,6 +27,29 @@ pub enum DaemonMessage { active_tasks: Vec, }, + /// Enhanced supervisor heartbeat with detailed state. + /// Sent periodically by supervisor tasks to report their current state. + SupervisorHeartbeat { + #[serde(rename = "taskId")] + task_id: Uuid, + #[serde(rename = "contractId")] + contract_id: Uuid, + /// Supervisor state: initializing, idle, working, waiting_for_user, waiting_for_tasks, blocked, completed, failed, interrupted + state: String, + /// Current contract phase + phase: String, + /// Description of current activity + #[serde(rename = "currentActivity")] + current_activity: Option, + /// Progress percentage (0-100) + progress: u8, + /// Task IDs the supervisor is waiting on + #[serde(rename = "pendingTaskIds")] + pending_task_ids: Vec, + /// Timestamp of this heartbeat + timestamp: DateTime, + }, + /// Task output streaming (stdout/stderr from Claude Code). TaskOutput { #[serde(rename = "taskId")] @@ -857,6 +881,28 @@ impl DaemonMessage { pub fn revoke_tool_key(task_id: Uuid) -> Self { Self::RevokeToolKey { task_id } } + + /// Create a supervisor heartbeat message. + pub fn supervisor_heartbeat( + task_id: Uuid, + contract_id: Uuid, + state: &str, + phase: &str, + current_activity: Option, + progress: u8, + pending_task_ids: Vec, + ) -> Self { + Self::SupervisorHeartbeat { + task_id, + contract_id, + state: state.to_string(), + phase: phase.to_string(), + current_activity, + progress, + pending_task_ids, + timestamp: Utc::now(), + } + } } #[cfg(test)] -- cgit v1.2.3