// Command palette — scenarios, steps, scenes, recents, real actions.
import { useEffect, useMemo } from "react";
import { Command } from "cmdk";
import { useApp, scenarioById } from "../state/store";
import { Play, Branch, Bot, Check, Home, HistoryIcon, Layers, Search, Refresh, Cog, User } from "./icons";
export default function CommandBar() {
const open = useApp((s) => s.cmdOpen);
const setOpen = useApp((s) => s.setCmdOpen);
const setScenarioId = useApp((s) => s.setScenarioId);
const setSelectedStepId = useApp((s) => s.setSelectedStepId);
const setScene = useApp((s) => s.setScene);
const recents = useApp((s) => s.recents);
const scenarioId = useApp((s) => s.scenarioId);
const pushRecent = useApp((s) => s.pushRecent);
const scenarios = useApp((s) => s.scenarios);
const mode = useApp((s) => s.mode);
const setMode = useApp((s) => s.setMode);
const refreshLive = useApp((s) => s.refreshLive);
const startInstance = useApp((s) => s.startInstance);
const executeAction = useApp((s) => s.executeAction);
const pushToast = useApp((s) => s.pushToast);
const setConsoleOpen = useApp((s) => s.setConsoleOpen);
const setTheme = useApp((s) => s.setTheme);
const theme = useApp((s) => s.theme);
const actor = useApp((s) => s.actor);
const sc = scenarioById(scenarioId);
useEffect(() => {
const onKey = (e: KeyboardEvent) => {
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
e.preventDefault();
setOpen(!open);
}
if (e.key === "Escape" && open) setOpen(false);
};
document.addEventListener("keydown", onKey);
return () => document.removeEventListener("keydown", onKey);
}, [open, setOpen]);
const stepItems = useMemo(() => sc?.steps ?? [], [sc]);
if (!open) return null;
const close = () => setOpen(false);
const canActLive = mode === "live" && actor?.user_id && sc?.live && sc.headlineTx;
const firstActionId = sc?.steps.find((s) => s.state === "running")?.actions?.[0]?.id;
return (
e.stopPropagation()} label="Command bar">
esc
No matches.
{recents.length > 0 && (
{recents.map((r, i) => (
{ pushRecent(r); close(); }}>
{r}
))}
)}
{ setScene("landing"); close(); }}>
Landing
{ setScene("mission"); close(); }}>
Mission Control
{ setScene("history"); close(); }}>
Run History
{ setScene("studio"); close(); }}>
Process Wizard
design & publish a new process
{ setScene("settings"); close(); }}>
Settings
{mode === "live" ? (
{ refreshLive(); close(); }}>
Refresh live scenarios
re-fetch demo.flow-master.ai
) : (
{ setMode("live"); close(); }}>
Switch to LIVE mode (fetch demo.flow-master.ai)
in-browser
)}
{ setMode("snapshot"); close(); }}>
Switch to SNAPSHOT mode
bundled JSON
{ setConsoleOpen(true); close(); }}>
Open live API console
stream every fetch
{ setTheme(theme === "dark" ? "light" : "dark"); close(); }}>
Toggle theme
{theme === "dark" ? "→ light" : "→ dark"}
{sc?.live ? (
{
close();
if (mode !== "live") { pushToast("warn", "Switch to LIVE mode to start a real instance."); return; }
await startInstance(sc.defKey, `Started via Mission Control · ${new Date().toLocaleString()}`);
}}
>
Start new instance of "{sc.defName}"
POST /api/runtime/transactions
) : (
Start new instance
switch to a LIVE scenario first
)}
{canActLive && firstActionId && (
{ close(); await executeAction(sc!.headlineTx!, firstActionId); }}
>
Execute "{firstActionId}" on headline tx
{sc?.headlineTx?.slice(0, 8)} · real
)}
{ setScene("settings"); close(); }}>
Sign in as different user
Settings → identity
{scenarios.map((s) => (
{ setScenarioId(s.id); setScene("mission"); close(); }}
>
{s.family.label}
{s.live ? "live" : "blueprint"} · {s.defName}
))}
{sc && (
{stepItems.map((st) => (
{ setSelectedStepId(st.id); setScene("mission"); close(); }}
>
{st.name}
{st.kind}
))}
)}
{
close();
pushToast("info", `Sidekick dispatch endpoint not yet wired — see Studio for process-level changes.`);
}}
>
Dispatch sidekick agent
coming soon
);
}