From d670dcb72984cfa483063d161bb468704038895c Mon Sep 17 00:00:00 2001 From: soryu Date: Sat, 21 Feb 2026 19:33:44 +0000 Subject: 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 --- .../src/components/directives/DirectiveDAG.tsx | 114 +++++++++++++++++++-- 1 file changed, 105 insertions(+), 9 deletions(-) (limited to 'makima/frontend/src/components/directives/DirectiveDAG.tsx') diff --git a/makima/frontend/src/components/directives/DirectiveDAG.tsx b/makima/frontend/src/components/directives/DirectiveDAG.tsx index 27a80ac..8c7def9 100644 --- a/makima/frontend/src/components/directives/DirectiveDAG.tsx +++ b/makima/frontend/src/components/directives/DirectiveDAG.tsx @@ -1,9 +1,31 @@ import { useMemo } from "react"; import type { DirectiveStep } from "../../lib/api"; import { StepNode } from "./StepNode"; +import { + OrchestratorStepNode, + type OrchestratorStepType, + type OrchestratorStepStatus, +} from "./OrchestratorStepNode"; + +export interface VirtualStep { + type: OrchestratorStepType; + taskId: string; + status: OrchestratorStepStatus; + label: string; + hasQuestions?: boolean; +} + +export interface SpecializedStep { + id: string; + name: string; + type: "orchestrator" | "completion"; + taskId: string; + status: "running" | "completed"; +} interface DirectiveDAGProps { steps: DirectiveStep[]; + specializedSteps?: SpecializedStep[]; onComplete?: (stepId: string) => void; onFail?: (stepId: string) => void; onSkip?: (stepId: string) => void; @@ -13,6 +35,13 @@ interface Layer { steps: DirectiveStep[]; } +/** Types that should appear before the regular DAG steps */ +const BEFORE_TYPES = new Set([ + "planning", + "replanning", + "plan-orders", +]); + function topoSort(steps: DirectiveStep[]): Layer[] { if (steps.length === 0) return []; @@ -31,10 +60,13 @@ function topoSort(steps: DirectiveStep[]): Layer[] { })); } -export function DirectiveDAG({ steps, onComplete, onFail, onSkip }: DirectiveDAGProps) { +export function DirectiveDAG({ steps, specializedSteps, onComplete, onFail, onSkip }: DirectiveDAGProps) { const layers = useMemo(() => topoSort(steps), [steps]); - if (steps.length === 0) { + const orchestratorSteps = specializedSteps?.filter(s => s.type === "orchestrator") ?? []; + const completionSteps = specializedSteps?.filter(s => s.type === "completion") ?? []; + + if (steps.length === 0 && orchestratorSteps.length === 0 && completionSteps.length === 0) { return (
No steps yet. Add steps to build the DAG. @@ -44,6 +76,19 @@ export function DirectiveDAG({ steps, onComplete, onFail, onSkip }: DirectiveDAG return (
+ {/* Orchestrator steps (Planning/Cleanup/Orders) - rendered above regular steps */} + {orchestratorSteps.map(step => ( + + ))} + + {/* Connector line if both orchestrator step and regular steps exist */} + {orchestratorSteps.length > 0 && layers.length > 0 && ( +
+
+
+ )} + + {/* Regular step layers */} {layers.map((layer, layerIdx) => (
{layerIdx > 0 && ( @@ -52,18 +97,69 @@ export function DirectiveDAG({ steps, onComplete, onFail, onSkip }: DirectiveDAG
)}
- {layer.steps.map((step) => ( - onComplete(step.id) : undefined} - onFail={onFail ? () => onFail(step.id) : undefined} - onSkip={onSkip ? () => onSkip(step.id) : undefined} + {afterSteps.map((vs) => ( + ))}
))} + + {/* Connector line if both regular steps and completion step exist */} + {completionSteps.length > 0 && layers.length > 0 && ( +
+
+
+ )} + + {/* Completion steps (PR creation) - rendered below regular steps */} + {completionSteps.map(step => ( + + ))} +
+ ); +} + +function SpecializedStepNode({ step }: { step: SpecializedStep }) { + const themeColors = step.type === "orchestrator" + ? { + bg: "bg-[#1a1a30]", + border: "border-[rgba(117,170,252,0.3)]", + text: "text-[#75aafc]", + dot: "bg-[#75aafc]", + label: step.name.startsWith("Cleanup") ? "CLEANUP" + : step.name.startsWith("Pick up") ? "ORDERS" + : "PLANNING", + } + : { + bg: "bg-[#1a1a10]", + border: "border-yellow-900/50", + text: "text-yellow-400", + dot: "bg-yellow-400", + label: "PR", + }; + + return ( +
+ + + {themeColors.label} + + + {step.name} + + + View task +
); } -- cgit v1.2.3