Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions interface/api/routes/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,18 +130,24 @@ async def get_health(request: Request) -> dict:
db_ok = False
checks.append({"name": "database", "status": "ok" if db_ok else "fail"})

# Engine availability summary
# Engine availability summary. Drivers live in container.agent_drivers,
# keyed by AgentEngineType (NOT a non-existent `engine_registry`).
from domain.value_objects.agent_engine import AgentEngineType

drivers = getattr(container, "agent_drivers", {}) or {}
for engine_name in ["claude_code", "gemini_cli", "codex_cli", "openhands"]:
registry = getattr(container, "engine_registry", None)
driver = registry.get(engine_name) if registry else None
if driver:
try:
available = await driver.is_available()
checks.append({"name": engine_name, "status": "ok" if available else "warn"})
except Exception:
checks.append({"name": engine_name, "status": "fail"})
else:
try:
driver = drivers.get(AgentEngineType(engine_name))
except ValueError:
driver = None
if driver is None:
checks.append({"name": engine_name, "status": "skip"})
continue
try:
available = await driver.is_available()
checks.append({"name": engine_name, "status": "ok" if available else "warn"})
except Exception:
checks.append({"name": engine_name, "status": "fail"})

overall = "ok" if all(c["status"] in ("ok", "skip") for c in checks) else "degraded"
return {"overall": overall, "checks": checks}
50 changes: 25 additions & 25 deletions ui/app/globals.css
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
@import "tailwindcss";

:root {
/* ── Existing Morphic custom vars ── */
--background: #0a0a0f;
--foreground: #e2e8f0;
--surface: #12121a;
--border: #1e1e2e;
--accent: #6366f1;
--success: #10b981;
--warning: #f59e0b;
--danger: #ef4444;
--info: #38bdf8;
--local-free: #34d399;
--text-muted: #94a3b8;
/* ── Claude-like warm beige theme (light) ── */
--background: #f4f1ea; /* warm cream canvas */
--foreground: #33312b; /* warm near-black text (font) */
--surface: #fbf9f3; /* lighter cream for cards/panels */
--border: #e3ded2; /* warm light border */
--accent: #c15f3c; /* Claude terracotta */
--success: #4f7a52;
--warning: #b9821f;
--danger: #c0492f;
--info: #3b7a99;
--local-free: #4f7a52;
--text-muted: #7a776e; /* warm muted text */

/* ── shadcn semantic vars (mapped to existing theme) ── */
--card: #12121a;
--card-foreground: #e2e8f0;
--popover: #12121a;
--popover-foreground: #e2e8f0;
--primary: #6366f1;
/* ── shadcn semantic vars (mapped to the warm theme) ── */
--card: #fbf9f3;
--card-foreground: #33312b;
--popover: #fbf9f3;
--popover-foreground: #33312b;
--primary: #c15f3c;
--primary-foreground: #ffffff;
--secondary: #1e1e2e;
--secondary-foreground: #e2e8f0;
--muted: #12121a;
--muted-foreground: #94a3b8;
--destructive: #ef4444;
--secondary: #eae5d9;
--secondary-foreground: #33312b;
--muted: #efeae0;
--muted-foreground: #7a776e;
--destructive: #c0492f;
--destructive-foreground: #ffffff;
--input: #1e1e2e;
--ring: #6366f1;
--input: #e3ded2;
--ring: #c15f3c;
--radius: 0.5rem;
}

Expand Down
2 changes: 1 addition & 1 deletion ui/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
<html lang="en" className="dark">
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased bg-background text-foreground`}
>
Expand Down
6 changes: 3 additions & 3 deletions ui/components/CodeBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ export default function CodeBlock({ code, language }: CodeBlockProps) {
}, [code]);

return (
<div className="relative rounded-lg border border-border bg-[#0D0D14] overflow-hidden">
<div className="relative rounded-lg border border-border bg-card overflow-hidden">
{/* Header: language label + copy button */}
<div className="flex items-center justify-between border-b border-border bg-[#12121A] px-3 py-1.5">
<div className="flex items-center justify-between border-b border-border bg-muted px-3 py-1.5">
<span className="flex items-center gap-1.5 text-[10px] font-mono uppercase tracking-wider text-text-muted">
<Code2 size={11} />
{language || "code"}
Expand All @@ -43,7 +43,7 @@ export default function CodeBlock({ code, language }: CodeBlockProps) {
</div>
{/* Code content */}
<pre className="overflow-x-auto p-3 text-xs leading-relaxed">
<code className="font-mono text-emerald-300">{code}</code>
<code className="font-mono text-foreground">{code}</code>
</pre>
</div>
);
Expand Down
6 changes: 3 additions & 3 deletions ui/components/ExecutionResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default function ExecutionResult({
{/* Execution output */}
{output && (
<div className="rounded-lg border border-border overflow-hidden">
<div className="flex items-center gap-1.5 border-b border-border bg-[#12121A] px-3 py-1.5">
<div className="flex items-center gap-1.5 border-b border-border bg-muted px-3 py-1.5">
{success ? (
<CheckCircle2 size={11} className="text-success" />
) : (
Expand All @@ -35,8 +35,8 @@ export default function ExecutionResult({
Output
</span>
</div>
<pre className="overflow-x-auto bg-[#0A0A0F] p-3 text-xs leading-relaxed">
<code className={`font-mono ${success ? "text-text" : "text-danger"}`}>
<pre className="overflow-x-auto bg-card p-3 text-xs leading-relaxed">
<code className={`font-mono ${success ? "text-foreground" : "text-danger"}`}>
{output}
</code>
</pre>
Expand Down
18 changes: 9 additions & 9 deletions ui/components/TaskGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ function SubTaskNode({ data }: NodeProps) {
className={classNames}
style={{
animationDelay: d.isNew ? `${d.enterDelay}ms` : undefined,
borderTop: d.selected ? `2px solid ${accentColor}` : `1px solid #1E1E2E`,
borderRight: d.selected ? `2px solid ${accentColor}` : `1px solid #1E1E2E`,
borderBottom: d.selected ? `2px solid ${accentColor}` : `1px solid #1E1E2E`,
borderTop: d.selected ? `2px solid ${accentColor}` : `1px solid #E3DED2`,
borderRight: d.selected ? `2px solid ${accentColor}` : `1px solid #E3DED2`,
borderBottom: d.selected ? `2px solid ${accentColor}` : `1px solid #E3DED2`,
borderLeft: `4px solid ${accentColor}`,
minWidth: 240,
maxWidth: 320,
Expand Down Expand Up @@ -373,9 +373,9 @@ export default function TaskGraph({ task }: TaskGraphProps) {
data: { label: truncateWithEllipsis(task.goal, 30) },
className: isGoalNew ? "morphic-node-enter" : undefined,
style: {
background: "#12121A",
color: "#E2E8F0",
border: `2px solid ${STATUS_COLORS[task.status] || "#6366F1"}`,
background: "#FBF9F3",
color: "#33312B",
border: `2px solid ${STATUS_COLORS[task.status] || "#C15F3C"}`,
borderRadius: 8,
padding: "8px 12px",
fontWeight: 600,
Expand Down Expand Up @@ -485,12 +485,12 @@ export default function TaskGraph({ task }: TaskGraphProps) {
nodeTypes={nodeTypes}
fitView
proOptions={{ hideAttribution: true }}
style={{ background: "#0A0A0F" }}
style={{ background: "#F4F1EA" }}
onPaneClick={() => setSelectedId(null)}
>
<Background color="#1E1E2E" gap={20} />
<Background color="#E3DED2" gap={20} />
<Controls
style={{ background: "#12121A", borderColor: "#1E1E2E" }}
style={{ background: "#FBF9F3", borderColor: "#E3DED2" }}
/>
</ReactFlow>
</div>
Expand Down
32 changes: 16 additions & 16 deletions ui/lib/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@

export const theme = {
colors: {
background: "#0A0A0F",
surface: "#12121A",
border: "#1E1E2E",
accent: "#6366F1",
success: "#10B981",
warning: "#F59E0B",
danger: "#EF4444",
info: "#38BDF8",
localFree: "#34D399",
text: "#E2E8F0",
textMuted: "#94A3B8",
background: "#F4F1EA",
surface: "#FBF9F3",
border: "#E3DED2",
accent: "#C15F3C",
success: "#4F7A52",
warning: "#B9821F",
danger: "#C0492F",
info: "#3B7A99",
localFree: "#4F7A52",
text: "#33312B",
textMuted: "#7A776E",
},
} as const;

export const statusStyles: Record<string, { border: string; icon: string }> = {
pending: { border: "#2D2D42", icon: "\u23F3" },
running: { border: "#38BDF8", icon: "\u26A1" },
success: { border: "#10B981", icon: "\u2713" },
failed: { border: "#EF4444", icon: "\u2717" },
fallback: { border: "#F59E0B", icon: "\u21BB" },
pending: { border: "#C8C2B2", icon: "\u23F3" },
running: { border: "#3B7A99", icon: "\u26A1" },
success: { border: "#4F7A52", icon: "\u2713" },
failed: { border: "#C0492F", icon: "\u2717" },
fallback: { border: "#B9821F", icon: "\u21BB" },
};
Loading