summaryrefslogtreecommitdiff
path: root/makima/src/server/state.rs
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-05-18 01:21:30 +0100
committerGitHub <noreply@github.com>2026-05-18 01:21:30 +0100
commitf240675da99bc7705e473b8f70a2628812aa4c10 (patch)
tree3ee2d24b431ccb8cd1a3013c86b34a5782a3e224 /makima/src/server/state.rs
parent0d996cf7590e3e52f424859c7d6f0e68640f119e (diff)
downloadsoryu-master.tar.gz
soryu-master.zip
chore: drop legacy contracts + supervisor task-grouping (#136)HEADmaster
The contracts table, supervisor task type, and all their backing machinery have been inert for several PRs. The directives system reads its own active contract body for spec text, and PR #135 removed the last LLM surface that spawned supervisors. This PR wipes the dead surface in one shot — the user authorised a DB wipe, so the migration drops every legacy table with CASCADE rather than carrying forward stub rows. Net change: −12k LOC across handlers, repository, state, models, the TUI, and the listen module. What's gone: - contracts, contract_chat_*, contract_events, contract_repositories, contract_type_templates tables. - supervisor_states, supervisor_heartbeats tables. - mesh_chat_conversations, mesh_chat_messages tables. - tasks.contract_id/is_supervisor/supervisor_task_id/supervisor_worktree_task_id columns. - directive_steps.contract_id/contract_type columns. - files.contract_id/contract_phase columns. - history_events.contract_id/phase columns. - The Contract/Supervisor/MeshChat handler + model + repository surface, plus the daemon TUI views that read them. - The standalone listen.rs websocket handler (orphaned with the LLM). What stays: - mesh_supervisor handler: trimmed to just the questions + orders backchannel used by `makima directive ask` / `create-order` (kept the URL prefix for CLI client compat). - directive_documents (the user-facing "contracts" surface). - pending_questions in-memory state for the directive Ask flow. cargo check, cargo test --lib (68 passed), tsc, and vite build all clean. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'makima/src/server/state.rs')
-rw-r--r--makima/src/server/state.rs249
1 files changed, 6 insertions, 243 deletions
diff --git a/makima/src/server/state.rs b/makima/src/server/state.rs
index e267da1..9e06b4c 100644
--- a/makima/src/server/state.rs
+++ b/makima/src/server/state.rs
@@ -140,10 +140,8 @@ pub struct PrResultNotification {
pub struct SupervisorQuestionNotification {
/// Unique ID for this question
pub question_id: Uuid,
- /// Supervisor task that asked the question
+ /// Task that asked the question
pub task_id: Uuid,
- /// Contract this question relates to (Uuid::nil() for directive context)
- pub contract_id: Uuid,
/// Directive this question relates to (if from a directive task)
#[serde(skip_serializing_if = "Option::is_none")]
pub directive_id: Option<Uuid>,
@@ -172,7 +170,6 @@ pub struct SupervisorQuestionNotification {
pub struct PendingSupervisorQuestion {
pub question_id: Uuid,
pub task_id: Uuid,
- pub contract_id: Uuid,
/// Directive this question relates to (if from a directive task)
pub directive_id: Option<Uuid>,
pub owner_id: Uuid,
@@ -285,12 +282,6 @@ pub enum DaemonCommand {
/// Files to copy from parent task's worktree
#[serde(rename = "copyFiles")]
copy_files: Option<Vec<String>>,
- /// Contract ID if this task is associated with a contract
- #[serde(rename = "contractId")]
- contract_id: Option<Uuid>,
- /// Whether this task is a supervisor (long-running contract orchestrator)
- #[serde(rename = "isSupervisor")]
- is_supervisor: bool,
/// Whether to run in autonomous loop mode
#[serde(rename = "autonomousLoop", default)]
autonomous_loop: bool,
@@ -306,15 +297,12 @@ pub enum DaemonCommand {
/// Commit SHA to apply the patch on top of
#[serde(rename = "patchBaseSha", default, skip_serializing_if = "Option::is_none")]
patch_base_sha: Option<String>,
- /// Whether the contract is in local-only mode (skips automatic completion actions)
+ /// Whether to skip automatic completion actions (local-only mode).
#[serde(rename = "localOnly", default)]
local_only: bool,
/// Whether to auto-merge to target branch locally when local_only mode is enabled
#[serde(rename = "autoMergeLocal", default)]
auto_merge_local: bool,
- /// Task ID to share worktree with (supervisor's task ID). If Some, use that task's worktree instead of creating a new one.
- #[serde(rename = "supervisorWorktreeTaskId", default, skip_serializing_if = "Option::is_none")]
- supervisor_worktree_task_id: Option<Uuid>,
/// Directive ID if this task is associated with a directive
#[serde(rename = "directiveId", default, skip_serializing_if = "Option::is_none")]
directive_id: Option<Uuid>,
@@ -906,29 +894,12 @@ impl AppState {
let _ = self.pr_results.send(notification);
}
- /// Add a pending supervisor question and broadcast it.
+ /// Add a pending question and broadcast it. Questions live in
+ /// memory only; they're a back-channel for directive tasks to
+ /// pause for clarification (used by `makima directive ask`).
pub fn add_supervisor_question(
&self,
task_id: Uuid,
- contract_id: Uuid,
- owner_id: Uuid,
- question: String,
- choices: Vec<String>,
- context: Option<String>,
- multi_select: bool,
- question_type: String,
- ) -> Uuid {
- self.add_supervisor_question_with_directive(
- task_id, contract_id, None, owner_id,
- question, choices, context, multi_select, question_type,
- )
- }
-
- /// Add a pending supervisor question with optional directive context and broadcast it.
- pub fn add_supervisor_question_with_directive(
- &self,
- task_id: Uuid,
- contract_id: Uuid,
directive_id: Option<Uuid>,
owner_id: Uuid,
question: String,
@@ -940,13 +911,11 @@ impl AppState {
let question_id = Uuid::new_v4();
let now = chrono::Utc::now();
- // Store the pending question
self.pending_questions.insert(
question_id,
PendingSupervisorQuestion {
question_id,
task_id,
- contract_id,
directive_id,
owner_id,
question: question.clone(),
@@ -958,11 +927,9 @@ impl AppState {
},
);
- // Broadcast to subscribers
self.broadcast_supervisor_question(SupervisorQuestionNotification {
question_id,
task_id,
- contract_id,
directive_id,
owner_id: Some(owner_id),
question,
@@ -976,10 +943,9 @@ impl AppState {
tracing::info!(
question_id = %question_id,
task_id = %task_id,
- contract_id = %contract_id,
directive_id = ?directive_id,
question_type = %question_type,
- "Supervisor question added"
+ "Question added"
);
question_id
@@ -1029,7 +995,6 @@ impl AppState {
self.broadcast_supervisor_question(SupervisorQuestionNotification {
question_id,
task_id: question.1.task_id,
- contract_id: question.1.contract_id,
directive_id: question.1.directive_id,
owner_id: Some(question.1.owner_id),
question: question.1.question,
@@ -1093,38 +1058,6 @@ impl AppState {
count
}
- /// Remove all pending questions for a specific contract.
- ///
- /// This should be called when a contract is deleted to clean up orphaned questions.
- /// Returns the number of questions removed.
- pub fn remove_pending_questions_for_contract(&self, contract_id: Uuid) -> usize {
- // Collect question IDs to remove
- let question_ids: Vec<Uuid> = self
- .pending_questions
- .iter()
- .filter(|entry| entry.value().contract_id == contract_id)
- .map(|entry| entry.value().question_id)
- .collect();
-
- let count = question_ids.len();
-
- // Remove pending questions and their responses
- for question_id in question_ids {
- self.pending_questions.remove(&question_id);
- self.question_responses.remove(&question_id);
- }
-
- if count > 0 {
- tracing::info!(
- contract_id = %contract_id,
- count = count,
- "Cleaned up pending questions for deleted contract"
- );
- }
-
- count
- }
-
/// Register a new daemon connection.
///
/// Returns the connection_id for later reference.
@@ -1329,176 +1262,6 @@ impl AppState {
.map(|entry| entry.value().clone())
}
- // =========================================================================
- // Supervisor Notifications
- // =========================================================================
-
- /// Notify a contract's supervisor task about an event.
- ///
- /// This sends a message to the supervisor's stdin so it can react to changes
- /// in tasks or contract state.
- pub async fn notify_supervisor(
- &self,
- supervisor_task_id: Uuid,
- supervisor_daemon_id: Option<Uuid>,
- message: &str,
- ) -> Result<(), String> {
- // Only send if we have a daemon ID
- let daemon_id = match supervisor_daemon_id {
- Some(id) => id,
- None => {
- tracing::debug!(
- supervisor_task_id = %supervisor_task_id,
- "Supervisor has no daemon assigned, skipping notification"
- );
- return Ok(());
- }
- };
-
- let command = DaemonCommand::SendMessage {
- task_id: supervisor_task_id,
- message: message.to_string(),
- };
-
- self.send_daemon_command(daemon_id, command).await
- }
-
- /// Format and send a task completion notification to a supervisor.
- ///
- /// If `action_directive` is provided, it will be appended to the message
- /// as an [ACTION REQUIRED] block to prompt the supervisor to take action.
- pub async fn notify_supervisor_of_task_completion(
- &self,
- supervisor_task_id: Uuid,
- supervisor_daemon_id: Option<Uuid>,
- completed_task_id: Uuid,
- completed_task_name: &str,
- status: &str,
- progress_summary: Option<&str>,
- error_message: Option<&str>,
- action_directive: Option<&str>,
- ) {
- let mut message = format!(
- "TASK_COMPLETED task_id={} name=\"{}\" status={}",
- completed_task_id, completed_task_name, status
- );
-
- if let Some(summary) = progress_summary {
- // Escape newlines in summary
- let escaped = summary.replace('\n', "\\n");
- message.push_str(&format!(" summary=\"{}\"", escaped));
- }
-
- if let Some(err) = error_message {
- let escaped = err.replace('\n', "\\n");
- message.push_str(&format!(" error=\"{}\"", escaped));
- }
-
- // Append action directive if provided
- if let Some(directive) = action_directive {
- message.push_str("\n\n");
- message.push_str(directive);
- }
-
- if let Err(e) = self.notify_supervisor(
- supervisor_task_id,
- supervisor_daemon_id,
- &message,
- ).await {
- tracing::warn!(
- supervisor_task_id = %supervisor_task_id,
- completed_task_id = %completed_task_id,
- "Failed to notify supervisor of task completion: {}",
- e
- );
- }
- }
-
- /// Format and send a task status change notification to a supervisor.
- pub async fn notify_supervisor_of_task_update(
- &self,
- supervisor_task_id: Uuid,
- supervisor_daemon_id: Option<Uuid>,
- updated_task_id: Uuid,
- updated_task_name: &str,
- new_status: &str,
- updated_fields: &[String],
- ) {
- let message = format!(
- "TASK_UPDATED task_id={} name=\"{}\" status={} fields={}",
- updated_task_id,
- updated_task_name,
- new_status,
- updated_fields.join(",")
- );
-
- if let Err(e) = self.notify_supervisor(
- supervisor_task_id,
- supervisor_daemon_id,
- &message,
- ).await {
- tracing::warn!(
- supervisor_task_id = %supervisor_task_id,
- updated_task_id = %updated_task_id,
- "Failed to notify supervisor of task update: {}",
- e
- );
- }
- }
-
- /// Format and send a contract phase change notification to a supervisor.
- pub async fn notify_supervisor_of_phase_change(
- &self,
- supervisor_task_id: Uuid,
- supervisor_daemon_id: Option<Uuid>,
- contract_id: Uuid,
- new_phase: &str,
- ) {
- let message = format!(
- "PHASE_CHANGED contract_id={} phase={}",
- contract_id, new_phase
- );
-
- if let Err(e) = self.notify_supervisor(
- supervisor_task_id,
- supervisor_daemon_id,
- &message,
- ).await {
- tracing::warn!(
- supervisor_task_id = %supervisor_task_id,
- contract_id = %contract_id,
- "Failed to notify supervisor of phase change: {}",
- e
- );
- }
- }
-
- /// Format and send a new task created notification to a supervisor.
- pub async fn notify_supervisor_of_task_created(
- &self,
- supervisor_task_id: Uuid,
- supervisor_daemon_id: Option<Uuid>,
- new_task_id: Uuid,
- new_task_name: &str,
- ) {
- let message = format!(
- "TASK_CREATED task_id={} name=\"{}\"",
- new_task_id, new_task_name
- );
-
- if let Err(e) = self.notify_supervisor(
- supervisor_task_id,
- supervisor_daemon_id,
- &message,
- ).await {
- tracing::warn!(
- supervisor_task_id = %supervisor_task_id,
- new_task_id = %new_task_id,
- "Failed to notify supervisor of task creation: {}",
- e
- );
- }
- }
}
/// Type alias for the shared application state.