summaryrefslogtreecommitdiff
path: root/makima/src/server/handlers/mesh_supervisor.rs
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-01-22 22:32:46 +0000
committersoryu <soryu@soryu.co>2026-01-23 01:03:04 +0000
commit1ed362424dafec690f919154f5116471951cda9c (patch)
tree19c7ca9231887394a791223fe32a8ad335a687a8 /makima/src/server/handlers/mesh_supervisor.rs
parent265f8cf14fec9d7116d09af49e4b48b357faceda (diff)
downloadsoryu-1ed362424dafec690f919154f5116471951cda9c.tar.gz
soryu-1ed362424dafec690f919154f5116471951cda9c.zip
Add patch checkpointing
Diffstat (limited to 'makima/src/server/handlers/mesh_supervisor.rs')
-rw-r--r--makima/src/server/handlers/mesh_supervisor.rs33
1 files changed, 33 insertions, 0 deletions
diff --git a/makima/src/server/handlers/mesh_supervisor.rs b/makima/src/server/handlers/mesh_supervisor.rs
index 57f3f2f..21c9515 100644
--- a/makima/src/server/handlers/mesh_supervisor.rs
+++ b/makima/src/server/handlers/mesh_supervisor.rs
@@ -9,6 +9,7 @@ use axum::{
response::IntoResponse,
Json,
};
+use base64::Engine;
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use uuid::Uuid;
@@ -364,8 +365,11 @@ async fn try_start_pending_task(
copy_files: updated_task.copy_files.as_ref().and_then(|v| serde_json::from_value(v.clone()).ok()),
contract_id: updated_task.contract_id,
is_supervisor: false,
+ autonomous_loop: false,
resume_session: false,
conversation_history: None,
+ patch_data: None,
+ patch_base_sha: None,
};
if let Err(e) = state.send_daemon_command(daemon.id, cmd).await {
@@ -663,8 +667,11 @@ pub async fn spawn_task(
copy_files: updated_task.copy_files.as_ref().and_then(|v| serde_json::from_value(v.clone()).ok()),
contract_id: updated_task.contract_id,
is_supervisor: false,
+ autonomous_loop: false,
resume_session: false,
conversation_history: None,
+ patch_data: None,
+ patch_base_sha: None,
};
if let Err(e) = state.send_daemon_command(daemon.id, cmd).await {
@@ -1992,6 +1999,29 @@ pub async fn resume_supervisor(
.into_response();
}
+ // Fetch latest checkpoint patch for worktree recovery
+ let (patch_data, patch_base_sha) = match repository::get_latest_checkpoint_patch(pool, supervisor_state.task_id).await {
+ Ok(Some(patch)) => {
+ tracing::info!(
+ task_id = %supervisor_state.task_id,
+ patch_size = patch.patch_size_bytes,
+ base_sha = %patch.base_commit_sha,
+ "Including checkpoint patch for worktree recovery"
+ );
+ // Encode patch as base64 for JSON transport
+ let encoded = base64::engine::general_purpose::STANDARD.encode(&patch.patch_data);
+ (Some(encoded), Some(patch.base_commit_sha))
+ }
+ Ok(None) => {
+ tracing::debug!(task_id = %supervisor_state.task_id, "No checkpoint patch found");
+ (None, None)
+ }
+ Err(e) => {
+ tracing::warn!(task_id = %supervisor_state.task_id, error = %e, "Failed to fetch checkpoint patch");
+ (None, None)
+ }
+ };
+
// Send SpawnTask with resume_session=true to use Claude's --continue
// Include conversation_history as fallback if worktree doesn't exist on target daemon
let command = DaemonCommand::SpawnTask {
@@ -2010,8 +2040,11 @@ pub async fn resume_supervisor(
copy_files: supervisor_task.copy_files.as_ref().and_then(|v| serde_json::from_value(v.clone()).ok()),
contract_id: supervisor_task.contract_id,
is_supervisor: true,
+ autonomous_loop: false,
resume_session: true, // Use --continue to preserve conversation
conversation_history: Some(supervisor_state.conversation_history.clone()), // Fallback if worktree missing
+ patch_data,
+ patch_base_sha,
};
if let Err(e) = state.send_daemon_command(target_daemon_id, command).await {