From 4b1d608b839769052634b4facc345b891d468926 Mon Sep 17 00:00:00 2001 From: soryu Date: Wed, 29 Apr 2026 01:10:11 +0100 Subject: feat: document-mode directive UI proof of concept (Lexical) (#101) * WIP: heartbeat checkpoint * feat: soryu-co/soryu - makima: Backend: feature flag + goal-edit interrupt messaging * WIP: heartbeat checkpoint * WIP: heartbeat checkpoint * feat: soryu-co/soryu - makima: Frontend: Lexical document editor with step blocks, context menu, countdown --- makima/src/db/repository.rs | 50 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'makima/src/db') diff --git a/makima/src/db/repository.rs b/makima/src/db/repository.rs index 57e8a78..ca07d92 100644 --- a/makima/src/db/repository.rs +++ b/makima/src/db/repository.rs @@ -4962,6 +4962,22 @@ pub async fn get_directive_for_owner( .await } +/// Get a directive without an owner scope check. +/// +/// Used by background orchestration code that has already established the +/// directive identity through other means (e.g. it just received the +/// directive_id from a different already-authorized query). HTTP handlers +/// must continue to use `get_directive_for_owner` to enforce isolation. +pub async fn get_directive( + pool: &PgPool, + id: Uuid, +) -> Result, sqlx::Error> { + sqlx::query_as::<_, Directive>(r#"SELECT * FROM directives WHERE id = $1"#) + .bind(id) + .fetch_optional(pool) + .await +} + /// Get a directive with all its steps. pub async fn get_directive_with_steps_for_owner( pool: &PgPool, @@ -5637,6 +5653,40 @@ pub async fn update_directive_goal( .await } +/// Update a directive's goal WITHOUT clearing the orchestrator task id. +/// +/// This is the path used by the goal-edit interrupt cycle: when a small goal +/// edit arrives while a planner is already running, we want to keep the +/// planner attached so a `SendMessage` can summarise the change in-flight +/// instead of cancelling and respawning. We still bump `goal_updated_at` so +/// the timestamp reflects the edit, but we do NOT trigger replanning by +/// clearing the orchestrator task. We also do not flip status from +/// idle/paused → active here, since by definition a planner is already +/// running. +pub async fn update_directive_goal_keep_orchestrator( + pool: &PgPool, + owner_id: Uuid, + directive_id: Uuid, + goal: &str, +) -> Result, sqlx::Error> { + sqlx::query_as::<_, Directive>( + r#" + UPDATE directives + SET goal = $3, + goal_updated_at = NOW(), + updated_at = NOW(), + version = version + 1 + WHERE id = $1 AND owner_id = $2 + RETURNING * + "#, + ) + .bind(directive_id) + .bind(owner_id) + .bind(goal) + .fetch_optional(pool) + .await +} + /// Save a goal to the directive goal history. pub async fn save_directive_goal_history( pool: &PgPool, -- cgit v1.2.3