summaryrefslogtreecommitdiff
path: root/makima/frontend/src/components/directives/OrchestratorStepNode.tsx
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-02-21 19:33:44 +0000
committerGitHub <noreply@github.com>2026-02-21 19:33:44 +0000
commitd670dcb72984cfa483063d161bb468704038895c (patch)
tree885ea969d2c5ea5c026d1caf25cd0a15f6753ca1 /makima/frontend/src/components/directives/OrchestratorStepNode.tsx
parent61442ea1cb92ce8c28fe0622aa19d4e2947a8fd0 (diff)
downloadsoryu-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/OrchestratorStepNode.tsx')
-rw-r--r--makima/frontend/src/components/directives/OrchestratorStepNode.tsx161
1 files changed, 161 insertions, 0 deletions
diff --git a/makima/frontend/src/components/directives/OrchestratorStepNode.tsx b/makima/frontend/src/components/directives/OrchestratorStepNode.tsx
new file mode 100644
index 0000000..9c8e95e
--- /dev/null
+++ b/makima/frontend/src/components/directives/OrchestratorStepNode.tsx
@@ -0,0 +1,161 @@
+export type OrchestratorStepType =
+ | "planning"
+ | "replanning"
+ | "plan-orders"
+ | "pr"
+ | "pr-update"
+ | "cleanup"
+ | "verification";
+
+export type OrchestratorStepStatus = "running" | "completed" | "failed" | "pending";
+
+export interface OrchestratorStepNodeProps {
+ type: OrchestratorStepType;
+ taskId: string;
+ status: OrchestratorStepStatus;
+ label: string;
+ hasQuestions?: boolean;
+}
+
+const TYPE_COLORS: Record<
+ OrchestratorStepType,
+ { accent: string; bg: string; border: string; text: string; dot: string }
+> = {
+ planning: {
+ accent: "#75aafc",
+ bg: "bg-[#0d1a30]",
+ border: "border-[#75aafc]",
+ text: "text-[#75aafc]",
+ dot: "bg-[#75aafc]",
+ },
+ replanning: {
+ accent: "#75aafc",
+ bg: "bg-[#0d1a30]",
+ border: "border-[#75aafc]",
+ text: "text-[#75aafc]",
+ dot: "bg-[#75aafc]",
+ },
+ "plan-orders": {
+ accent: "#c084fc",
+ bg: "bg-[#1a0d30]",
+ border: "border-[#c084fc]",
+ text: "text-[#c084fc]",
+ dot: "bg-[#c084fc]",
+ },
+ pr: {
+ accent: "#34d399",
+ bg: "bg-[#0a1a14]",
+ border: "border-[#34d399]",
+ text: "text-[#34d399]",
+ dot: "bg-[#34d399]",
+ },
+ "pr-update": {
+ accent: "#34d399",
+ bg: "bg-[#0a1a14]",
+ border: "border-[#34d399]",
+ text: "text-[#34d399]",
+ dot: "bg-[#34d399]",
+ },
+ cleanup: {
+ accent: "#7788aa",
+ bg: "bg-[#141a24]",
+ border: "border-[#7788aa]",
+ text: "text-[#7788aa]",
+ dot: "bg-[#7788aa]",
+ },
+ verification: {
+ accent: "#7788aa",
+ bg: "bg-[#141a24]",
+ border: "border-[#7788aa]",
+ text: "text-[#7788aa]",
+ dot: "bg-[#7788aa]",
+ },
+};
+
+const TYPE_LABELS: Record<OrchestratorStepType, string> = {
+ planning: "PLANNING",
+ replanning: "REPLANNING",
+ "plan-orders": "PLAN ORDERS",
+ pr: "PR",
+ "pr-update": "PR UPDATE",
+ cleanup: "CLEANUP",
+ verification: "VERIFICATION",
+};
+
+const STATUS_LABELS: Record<OrchestratorStepStatus, string> = {
+ pending: "PENDING",
+ running: "RUNNING",
+ completed: "DONE",
+ failed: "FAILED",
+};
+
+export function OrchestratorStepNode({
+ type,
+ taskId,
+ status,
+ label,
+ hasQuestions,
+}: OrchestratorStepNodeProps) {
+ const colors = TYPE_COLORS[type];
+ const typeLabel = TYPE_LABELS[type];
+ const statusLabel = STATUS_LABELS[status];
+
+ return (
+ <div
+ className={`${colors.bg} ${colors.border} border border-dashed rounded px-3 py-2 min-w-[160px] max-w-[220px] relative`}
+ >
+ {/* Type badge */}
+ <div className="flex items-center justify-between gap-2 mb-1">
+ <div className="flex items-center gap-1.5 min-w-0">
+ {/* Status dot */}
+ {status === "running" && (
+ <span
+ className={`inline-block w-2 h-2 rounded-full ${colors.dot} animate-pulse shrink-0`}
+ />
+ )}
+ {status === "completed" && (
+ <span className="inline-block w-2 h-2 rounded-full bg-emerald-400 shrink-0" />
+ )}
+ {status === "failed" && (
+ <span className="inline-block w-2 h-2 rounded-full bg-red-400 shrink-0" />
+ )}
+ {status === "pending" && (
+ <span className="inline-block w-2 h-2 rounded-full bg-[#556677] shrink-0" />
+ )}
+ <span className={`text-[9px] font-mono ${colors.text} uppercase shrink-0`}>
+ {typeLabel}
+ </span>
+ </div>
+ <div className="flex items-center gap-1 shrink-0">
+ {hasQuestions && (
+ <span className="inline-block w-2 h-2 rounded-full bg-purple-400 animate-pulse" title="Has pending questions" />
+ )}
+ <span
+ className={`text-[9px] font-mono uppercase ${
+ status === "completed"
+ ? "text-emerald-400"
+ : status === "failed"
+ ? "text-red-400"
+ : colors.text
+ }`}
+ >
+ {statusLabel}
+ </span>
+ </div>
+ </div>
+
+ {/* Label */}
+ <span className="text-[11px] font-mono text-white truncate block font-medium mb-1">
+ {label}
+ </span>
+
+ {/* Task link */}
+ <a
+ href={`/mesh/${taskId}`}
+ className={`text-[9px] font-mono text-[#556677] hover:${colors.text} underline block`}
+ >
+ {status === "running" ? "View running task" : "View task"}
+ </a>
+ </div>
+ );
+}