diff options
| author | soryu <soryu@soryu.co> | 2026-02-12 03:04:26 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-02-12 03:22:43 +0000 |
| commit | ffbd8fed748ff4b60c53ee6ac54d7cf0548a7048 (patch) | |
| tree | eb95056f7baeca66bf05737875704ec583f2d9bb | |
| parent | e03ac942b97255f01cb98f3a6c927da18e001b18 (diff) | |
| download | soryu-ffbd8fed748ff4b60c53ee6ac54d7cf0548a7048.tar.gz soryu-ffbd8fed748ff4b60c53ee6ac54d7cf0548a7048.zip | |
Add task cleanup and directive PR updating
| -rw-r--r-- | makima/frontend/src/components/directives/DirectiveDetail.tsx | 19 | ||||
| -rw-r--r-- | makima/frontend/src/hooks/useDirectives.ts | 17 | ||||
| -rw-r--r-- | makima/frontend/src/lib/api.ts | 8 | ||||
| -rw-r--r-- | makima/frontend/src/routes/directives.tsx | 3 | ||||
| -rw-r--r-- | makima/src/server/handlers/directives.rs | 1 | ||||
| -rw-r--r-- | makima/src/server/mod.rs | 1 | ||||
| -rw-r--r-- | makima/src/server/openapi.rs | 3 |
7 files changed, 44 insertions, 8 deletions
diff --git a/makima/frontend/src/components/directives/DirectiveDetail.tsx b/makima/frontend/src/components/directives/DirectiveDetail.tsx index ab6ddbb..332a417 100644 --- a/makima/frontend/src/components/directives/DirectiveDetail.tsx +++ b/makima/frontend/src/components/directives/DirectiveDetail.tsx @@ -34,6 +34,7 @@ interface DirectiveDetailProps { onUpdateGoal: (goal: string) => void; onDelete: () => void; onRefresh: () => void; + onCleanupTasks: () => void; } export function DirectiveDetail({ @@ -47,6 +48,7 @@ export function DirectiveDetail({ onUpdateGoal, onDelete, onRefresh, + onCleanupTasks, }: DirectiveDetailProps) { const [editingGoal, setEditingGoal] = useState(false); const [goalText, setGoalText] = useState(directive.goal); @@ -59,6 +61,8 @@ export function DirectiveDetail({ const completedSteps = directive.steps.filter((s) => s.status === "completed").length; const totalSteps = directive.steps.length; const progress = totalSteps > 0 ? Math.round((completedSteps / totalSteps) * 100) : 0; + const terminalStatuses = new Set(["completed", "failed", "skipped"]); + const hasTerminalTasks = directive.steps.some((s) => s.taskId && terminalStatuses.has(s.status)); // Memory panel state const [memoryOpen, setMemoryOpen] = useState(false); @@ -221,11 +225,11 @@ export function DirectiveDetail({ )} {/* Completion task indicator */} - {directive.completionTaskId && !directive.prUrl && ( + {directive.completionTaskId && ( <div className="flex items-center gap-2 mb-2 px-2 py-1.5 bg-[#1a1a10] border border-yellow-900 rounded"> <span className="inline-block w-2 h-2 rounded-full bg-yellow-400 animate-pulse" /> <span className="text-[10px] font-mono text-yellow-400"> - Creating PR... + {directive.prUrl ? "Updating PR..." : "Creating PR..."} </span> <a href={`/mesh/${directive.completionTaskId}`} @@ -279,10 +283,19 @@ export function DirectiveDetail({ </button> </div> )} + {hasTerminalTasks && ( + <button + type="button" + onClick={onCleanupTasks} + className="text-[10px] font-mono text-[#7788aa] hover:text-white border border-[#2a3a5a] rounded px-2 py-1 ml-auto" + > + Clean up tasks + </button> + )} <button type="button" onClick={onDelete} - className="text-[10px] font-mono text-red-400 hover:text-red-300 border border-red-800 rounded px-2 py-1 ml-auto" + className={`text-[10px] font-mono text-red-400 hover:text-red-300 border border-red-800 rounded px-2 py-1 ${hasTerminalTasks ? "" : "ml-auto"}`} > Delete </button> diff --git a/makima/frontend/src/hooks/useDirectives.ts b/makima/frontend/src/hooks/useDirectives.ts index f5f2b36..e67733c 100644 --- a/makima/frontend/src/hooks/useDirectives.ts +++ b/makima/frontend/src/hooks/useDirectives.ts @@ -19,6 +19,7 @@ import { failDirectiveStep, skipDirectiveStep, updateDirectiveGoal, + cleanupDirectiveTasks, } from "../lib/api"; export function useDirectives() { @@ -80,16 +81,18 @@ export function useDirective(id: string | undefined) { refresh(); }, [refresh]); - // Auto-poll while directive is active or has an orchestrator task + // Auto-poll while directive is active, has an orchestrator task, or has a completion task useEffect(() => { if (!directive) return; const needsPolling = - directive.status === "active" || directive.orchestratorTaskId != null; + directive.status === "active" || + directive.orchestratorTaskId != null || + directive.completionTaskId != null; if (!needsPolling) return; const interval = setInterval(refresh, 5000); return () => clearInterval(interval); - }, [directive?.status, directive?.orchestratorTaskId, refresh]); + }, [directive?.status, directive?.orchestratorTaskId, directive?.completionTaskId, refresh]); const update = useCallback(async (req: UpdateDirectiveRequest) => { if (!id) return; @@ -151,11 +154,17 @@ export function useDirective(id: string | undefined) { await refresh(); }, [id, refresh]); + const cleanupTasks = useCallback(async () => { + if (!id) return; + await cleanupDirectiveTasks(id); + await refresh(); + }, [id, refresh]); + return { directive, loading, error, refresh, update, addStep, removeStep, start, pause, advance, completeStep, failStep, skipStep, - updateGoal, + updateGoal, cleanupTasks, }; } diff --git a/makima/frontend/src/lib/api.ts b/makima/frontend/src/lib/api.ts index 552829a..9d9cb1c 100644 --- a/makima/frontend/src/lib/api.ts +++ b/makima/frontend/src/lib/api.ts @@ -3238,6 +3238,14 @@ export async function updateDirectiveGoal(id: string, goal: string): Promise<Dir return res.json(); } +export async function cleanupDirectiveTasks(id: string): Promise<{ deleted: number }> { + const res = await authFetch(`${API_BASE}/api/v1/directives/${id}/cleanup-tasks`, { + method: "POST", + }); + if (!res.ok) throw new Error(`Failed to cleanup tasks: ${res.statusText}`); + return res.json(); +} + // ============================================================================= // Directive Memory Types & API // ============================================================================= diff --git a/makima/frontend/src/routes/directives.tsx b/makima/frontend/src/routes/directives.tsx index bf6955b..ca4437c 100644 --- a/makima/frontend/src/routes/directives.tsx +++ b/makima/frontend/src/routes/directives.tsx @@ -12,7 +12,7 @@ export default function DirectivesPage() { const navigate = useNavigate(); const { id: selectedId } = useParams<{ id: string }>(); const { directives, loading: listLoading, create, remove } = useDirectives(); - const { directive, refresh: refreshDetail, start, pause, advance, completeStep, failStep, skipStep, updateGoal } = useDirective(selectedId); + const { directive, refresh: refreshDetail, start, pause, advance, completeStep, failStep, skipStep, updateGoal, cleanupTasks } = useDirective(selectedId); const [showCreate, setShowCreate] = useState(false); const [newTitle, setNewTitle] = useState(""); @@ -209,6 +209,7 @@ export default function DirectivesPage() { onUpdateGoal={updateGoal} onDelete={handleDelete} onRefresh={refreshDetail} + onCleanupTasks={cleanupTasks} /> ) : ( <div className="flex-1 flex items-center justify-center h-full"> diff --git a/makima/src/server/handlers/directives.rs b/makima/src/server/handlers/directives.rs index 585899e..9314031 100644 --- a/makima/src/server/handlers/directives.rs +++ b/makima/src/server/handlers/directives.rs @@ -1231,6 +1231,7 @@ pub async fn clear_memories( // Task Cleanup // ============================================================================= + /// Clean up terminal tasks associated with a directive. #[utoipa::path( post, diff --git a/makima/src/server/mod.rs b/makima/src/server/mod.rs index b380508..7110ef8 100644 --- a/makima/src/server/mod.rs +++ b/makima/src/server/mod.rs @@ -237,6 +237,7 @@ pub fn make_router(state: SharedState) -> Router { .route("/directives/{id}/steps/{step_id}/fail", post(directives::fail_step)) .route("/directives/{id}/steps/{step_id}/skip", post(directives::skip_step)) .route("/directives/{id}/goal", put(directives::update_goal)) + .route("/directives/{id}/cleanup-tasks", post(directives::cleanup_tasks)) // Directive memory endpoints .route("/directives/{id}/memories", get(directives::list_memories).post(directives::set_memory).delete(directives::clear_memories)) .route("/directives/{id}/memories/batch", post(directives::batch_set_memories)) diff --git a/makima/src/server/openapi.rs b/makima/src/server/openapi.rs index f049759..f28b105 100644 --- a/makima/src/server/openapi.rs +++ b/makima/src/server/openapi.rs @@ -8,6 +8,7 @@ use crate::db::models::{ ChangePhaseRequest, Contract, ContractChatHistoryResponse, ContractChatMessageRecord, ContractEvent, ContractListResponse, ContractRepository, ContractSummary, ContractWithRelations, + CleanupTasksResponse, CreateContractRequest, CreateDirectiveRequest, CreateDirectiveStepRequest, CreateFileRequest, CreateManagedRepositoryRequest, CreateTaskRequest, Daemon, DaemonDirectoriesResponse, DaemonDirectory, DaemonListResponse, Directive, DirectiveListResponse, DirectiveMemory, @@ -123,6 +124,7 @@ use crate::server::messages::{ApiError, AudioEncoding, StartMessage, StopMessage directives::fail_step, directives::skip_step, directives::update_goal, + directives::cleanup_tasks, // Directive memory endpoints directives::list_memories, directives::get_memory, @@ -226,6 +228,7 @@ use crate::server::messages::{ApiError, AudioEncoding, StartMessage, StopMessage UpdateGoalRequest, CreateDirectiveStepRequest, UpdateDirectiveStepRequest, + CleanupTasksResponse, DirectiveMemory, DirectiveMemoryListResponse, SetDirectiveMemoryRequest, |
