diff options
| author | soryu <soryu@soryu.co> | 2026-02-21 19:33:44 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-02-21 19:33:44 +0000 |
| commit | d670dcb72984cfa483063d161bb468704038895c (patch) | |
| tree | 885ea969d2c5ea5c026d1caf25cd0a15f6753ca1 /makima/frontend/src/components/directives/DirectiveDetail.tsx | |
| parent | 61442ea1cb92ce8c28fe0622aa19d4e2947a8fd0 (diff) | |
| download | soryu-d670dcb72984cfa483063d161bb468704038895c.tar.gz soryu-d670dcb72984cfa483063d161bb468704038895c.zip | |
feat: add directive ask command, log backfill & specialized DAG steps (#75)
* feat: soryu-co/soryu - makima: Add makima directive ask CLI command
* feat: soryu-co/soryu - makima: Update directive skill docs and planning prompt to support asking questions
* feat: soryu-co/soryu - makima: Add log stream backfill for directive tasks
* feat: soryu-co/soryu - makima: Update planning prompts to inform tasks they can ask questions
* WIP: heartbeat checkpoint
* feat: soryu-co/soryu - makima: Add ask command to directive SKILL.md documentation
* feat: soryu-co/soryu - makima: Add log stream backfill for directive task output history
* feat: soryu-co/soryu - makima: Update planning prompt to tell planning tasks they can ask questions
* WIP: heartbeat checkpoint
* feat: soryu-co/soryu - makima: Show Planning, PR, and Cleanup tasks as specialized steps in DAG
Diffstat (limited to 'makima/frontend/src/components/directives/DirectiveDetail.tsx')
| -rw-r--r-- | makima/frontend/src/components/directives/DirectiveDetail.tsx | 91 |
1 files changed, 59 insertions, 32 deletions
diff --git a/makima/frontend/src/components/directives/DirectiveDetail.tsx b/makima/frontend/src/components/directives/DirectiveDetail.tsx index 98940d0..171654d 100644 --- a/makima/frontend/src/components/directives/DirectiveDetail.tsx +++ b/makima/frontend/src/components/directives/DirectiveDetail.tsx @@ -1,6 +1,7 @@ import { useState, useMemo, useEffect, useRef } from "react"; import type { DirectiveWithSteps, DirectiveStatus, UpdateDirectiveRequest } from "../../lib/api"; import { DirectiveDAG } from "./DirectiveDAG"; +import type { SpecializedStep } from "./DirectiveDAG"; import { DirectiveLogStream } from "./DirectiveLogStream"; import { useMultiTaskSubscription } from "../../hooks/useMultiTaskSubscription"; import { useSupervisorQuestions } from "../../contexts/SupervisorQuestionsContext"; @@ -108,6 +109,33 @@ export function DirectiveDetail({ return map; }, [taskMapKey]); // eslint-disable-line react-hooks/exhaustive-deps + // Build specialized steps for DAG visualization + const specializedSteps = useMemo(() => { + const steps: SpecializedStep[] = []; + + if (directive.orchestratorTaskId) { + steps.push({ + id: `orchestrator-${directive.orchestratorTaskId}`, + name: taskMap.get(directive.orchestratorTaskId) || "Planning", + type: "orchestrator", + taskId: directive.orchestratorTaskId, + status: "running", + }); + } + + if (directive.completionTaskId) { + steps.push({ + id: `completion-${directive.completionTaskId}`, + name: directive.prUrl ? "Updating PR" : "Creating PR", + type: "completion", + taskId: directive.completionTaskId, + status: "running", + }); + } + + return steps; + }, [directive.orchestratorTaskId, directive.completionTaskId, directive.prUrl, taskMap]); + // Subscribe to all task outputs const { connected, entries, clearEntries } = useMultiTaskSubscription({ taskMap, @@ -149,6 +177,36 @@ export function DirectiveDetail({ setEditingGoal(false); }; + // Build virtual steps for orchestrator tasks to display in the DAG + const virtualSteps = useMemo(() => { + const steps: VirtualStep[] = []; + if (directive.orchestratorTaskId) { + const hasOrchestratorQuestions = directiveQuestions.some( + (q) => q.taskId === directive.orchestratorTaskId + ); + steps.push({ + type: "planning", + taskId: directive.orchestratorTaskId, + status: "running", + label: "Planning", + hasQuestions: hasOrchestratorQuestions, + }); + } + if (directive.completionTaskId) { + const hasCompletionQuestions = directiveQuestions.some( + (q) => q.taskId === directive.completionTaskId + ); + steps.push({ + type: directive.prUrl ? "pr-update" : "pr", + taskId: directive.completionTaskId, + status: "running", + label: directive.prUrl ? "Updating PR" : "Creating PR", + hasQuestions: hasCompletionQuestions, + }); + } + return steps; + }, [directive.orchestratorTaskId, directive.completionTaskId, directive.prUrl, directiveQuestions]); + return ( <div className="flex flex-col h-full overflow-y-auto"> {/* Header */} @@ -217,22 +275,6 @@ export function DirectiveDetail({ </span> </div> - {/* Orchestrator planning indicator */} - {directive.orchestratorTaskId && ( - <div className="flex items-center gap-2 mb-2 px-2 py-1.5 bg-[#1a1a30] border border-[rgba(117,170,252,0.2)] rounded"> - <span className="inline-block w-2 h-2 rounded-full bg-[#75aafc] animate-pulse" /> - <span className="text-[10px] font-mono text-[#75aafc]"> - Planning in progress... - </span> - <a - href={`/mesh/${directive.orchestratorTaskId}`} - className="text-[9px] font-mono text-[#556677] hover:text-[#75aafc] underline ml-auto" - > - View task - </a> - </div> - )} - {/* PR link */} {directive.prUrl && ( <div className="flex items-center gap-2 mb-2 px-2 py-1.5 bg-[#0a1a10] border border-emerald-900 rounded"> @@ -251,22 +293,6 @@ export function DirectiveDetail({ </div> )} - {/* Completion task indicator */} - {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"> - {directive.prUrl ? "Updating PR..." : "Creating PR..."} - </span> - <a - href={`/mesh/${directive.completionTaskId}`} - className="text-[9px] font-mono text-[#556677] hover:text-yellow-400 underline ml-auto" - > - View task - </a> - </div> - )} - {/* Pending Questions */} {directiveQuestions.length > 0 && ( <div className="mb-2 space-y-2"> @@ -423,6 +449,7 @@ export function DirectiveDetail({ </span> <DirectiveDAG steps={directive.steps} + specializedSteps={specializedSteps} onComplete={onCompleteStep} onFail={onFailStep} onSkip={onSkipStep} |
