) : (
@@ -1094,7 +1094,7 @@ function TranscriptStderrGroup({
const [open, setOpen] = useState(false);
const compact = density === "compact";
return (
-
+
{open && (
-
+
{block.lines.map((line, i) => (
- {i > 0 ? "\n" : ""}
+ {i > 0 ? "\n" : ""}
{line.text}
))}
diff --git a/ui/src/pages/AgentDetail.tsx b/ui/src/pages/AgentDetail.tsx
index d387ffce..00bc4116 100644
--- a/ui/src/pages/AgentDetail.tsx
+++ b/ui/src/pages/AgentDetail.tsx
@@ -99,12 +99,12 @@ import {
} from "../lib/agent-skills-state";
const runStatusIcons: Record = {
- succeeded: { icon: CheckCircle2, color: "text-green-600 dark:text-green-400" },
- failed: { icon: XCircle, color: "text-red-600 dark:text-red-400" },
- running: { icon: Loader2, color: "text-cyan-600 dark:text-cyan-400" },
- queued: { icon: Clock, color: "text-yellow-600 dark:text-yellow-400" },
- timed_out: { icon: Timer, color: "text-orange-600 dark:text-orange-400" },
- cancelled: { icon: Slash, color: "text-neutral-500 dark:text-neutral-400" },
+ succeeded: { icon: CheckCircle2, color: "text-success" },
+ failed: { icon: XCircle, color: "text-destructive" },
+ running: { icon: Loader2, color: "text-primary" },
+ queued: { icon: Clock, color: "text-warning" },
+ timed_out: { icon: Timer, color: "text-warning" },
+ cancelled: { icon: Slash, color: "text-muted-foreground" },
};
const REDACTED_ENV_VALUE = "***REDACTED***";
@@ -324,13 +324,13 @@ function workspaceOperationPhaseLabel(phase: WorkspaceOperation["phase"]) {
function workspaceOperationStatusTone(status: WorkspaceOperation["status"]) {
switch (status) {
case "succeeded":
- return "border-green-500/20 bg-green-500/10 text-green-700 dark:text-green-300";
+ return "border-success/20 bg-success/10 text-success";
case "failed":
- return "border-red-500/20 bg-red-500/10 text-red-700 dark:text-red-300";
+ return "border-destructive/20 bg-destructive/10 text-destructive";
case "running":
- return "border-cyan-500/20 bg-cyan-500/10 text-cyan-700 dark:text-cyan-300";
+ return "border-primary/20 bg-primary/10 text-primary";
case "skipped":
- return "border-yellow-500/20 bg-yellow-500/10 text-yellow-700 dark:text-yellow-300";
+ return "border-warning/20 bg-warning/10 text-warning";
default:
return "border-border bg-muted/40 text-muted-foreground";
}
@@ -390,19 +390,19 @@ function WorkspaceOperationLogViewer({
No persisted log lines.
)}
{chunks.length > 0 && (
-
+
{chunks.map((chunk, index) => (
-
+
{new Date(chunk.ts).toLocaleTimeString("en-US", { hour12: false })}
@@ -488,8 +488,8 @@ function WorkspaceOperationsSection({
)}
{operation.stderrExcerpt && operation.stderrExcerpt.trim() && (
-
stderr excerpt
-
+ stderr excerpt
+
{redactPathText(operation.stderrExcerpt, censorUsernameInLogs)}
@@ -497,7 +497,7 @@ function WorkspaceOperationsSection({
{operation.stdoutExcerpt && operation.stdoutExcerpt.trim() && (
stdout excerpt
-
+
{redactPathText(operation.stdoutExcerpt, censorUsernameInLogs)}
@@ -849,13 +849,13 @@ export function AgentDetail() {
{mobileLiveRun && (
-
-
+
+
- Live
+ Live
)}
@@ -924,7 +924,7 @@ export function AgentDetail() {
{actionError && {actionError}
}
{isPendingApproval && (
-
+
This agent is pending board approval and cannot be invoked yet.
)}
@@ -1074,7 +1074,7 @@ function LatestRunCard({ runs, agentId }: { runs: HeartbeatRun[]; agentId: strin
const liveRun = sorted.find((r) => r.status === "running" || r.status === "queued");
const run = liveRun ?? sorted[0];
const isLive = run.status === "running" || run.status === "queued";
- const statusInfo = runStatusIcons[run.status] ?? { icon: Clock, color: "text-neutral-400" };
+ const statusInfo = runStatusIcons[run.status] ?? { icon: Clock, color: "text-muted-foreground" };
const StatusIcon = statusInfo.icon;
const summary = run.resultJson
? String((run.resultJson as Record).summary ?? (run.resultJson as Record).result ?? "")
@@ -1086,8 +1086,8 @@ function LatestRunCard({ runs, agentId }: { runs: HeartbeatRun[]; agentId: strin
{isLive && (
-
-
+
+
)}
{isLive ? "Live Run" : "Latest Run"}
@@ -1104,7 +1104,7 @@ function LatestRunCard({ runs, agentId }: { runs: HeartbeatRun[]; agentId: strin
to={`/agents/${agentId}/runs/${run.id}`}
className={cn(
"block border rounded-lg p-4 space-y-2 w-full no-underline transition-colors hover:bg-muted/50 cursor-pointer",
- isLive ? "border-cyan-500/30 shadow-[0_0_12px_rgba(6,182,212,0.08)]" : "border-border"
+ isLive ? "border-primary/30 shadow-[0_0_12px_rgba(6,182,212,0.08)]" : "border-border"
)}
>
@@ -1113,9 +1113,9 @@ function LatestRunCard({ runs, agentId }: { runs: HeartbeatRun[]; agentId: strin
{run.id.slice(0, 8)}
{sourceLabels[run.invocationSource] ?? run.invocationSource}
@@ -1571,7 +1571,7 @@ function ConfigurationTab({
aria-checked={canCreateAgents}
className={cn(
"relative inline-flex h-5 w-9 items-center rounded-full transition-colors shrink-0 disabled:cursor-not-allowed disabled:opacity-50",
- canCreateAgents ? "bg-green-600" : "bg-muted",
+ canCreateAgents ? "bg-success" : "bg-muted",
)}
onClick={() =>
updatePermissions.mutate({
@@ -1603,7 +1603,7 @@ function ConfigurationTab({
aria-checked={canAssignTasks}
className={cn(
"relative inline-flex h-5 w-9 items-center rounded-full transition-colors shrink-0 disabled:cursor-not-allowed disabled:opacity-50",
- canAssignTasks ? "bg-green-600" : "bg-muted",
+ canAssignTasks ? "bg-success" : "bg-muted",
)}
onClick={() =>
updatePermissions.mutate({
@@ -1955,7 +1955,7 @@ function PromptsTab({
{(bundle?.warnings ?? []).length > 0 && (
{(bundle?.warnings ?? []).map((warning) => (
-
+
{warning}
))}
@@ -2222,7 +2222,7 @@ function PromptsTab({
return (
-
+
virtual file
@@ -2592,7 +2592,7 @@ function AgentSkillsTab({
{skillSnapshot?.warnings.length ? (
-
+
{skillSnapshot.warnings.map((warning) => (
{warning}
))}
@@ -2745,7 +2745,7 @@ function AgentSkillsTab({
})()}
{desiredOnlyMissingSkills.length > 0 && (
-
+
Requested skills missing from the company library
{desiredOnlyMissingSkills.join(", ")}
@@ -2784,7 +2784,7 @@ function AgentSkillsTab({
/* ---- Runs Tab ---- */
function RunListItem({ run, isSelected, agentId }: { run: HeartbeatRun; isSelected: boolean; agentId: string }) {
- const statusInfo = runStatusIcons[run.status] ?? { icon: Clock, color: "text-neutral-400" };
+ const statusInfo = runStatusIcons[run.status] ?? { icon: Clock, color: "text-muted-foreground" };
const StatusIcon = statusInfo.icon;
const metrics = runMetrics(run);
const summary = run.resultJson
@@ -2806,9 +2806,9 @@ function RunListItem({ run, isSelected, agentId }: { run: HeartbeatRun; isSelect
{sourceLabels[run.invocationSource] ?? run.invocationSource}
@@ -3138,7 +3138,7 @@ function RunDetail({ run: initialRun, agentRouteId, adapterType }: { run: Heartb
)}
{run.error && (
- {run.error}
+ {run.error}
{run.errorCode && ({run.errorCode}) }
)}
@@ -3165,7 +3165,7 @@ function RunDetail({ run: initialRun, agentRouteId, adapterType }: { run: Heartb
Login URL:
@@ -3176,12 +3176,12 @@ function RunDetail({ run: initialRun, agentRouteId, adapterType }: { run: Heartb
{claudeLoginResult && (
<>
{!!claudeLoginResult.stdout && (
-
+
{claudeLoginResult.stdout}
)}
{!!claudeLoginResult.stderr && (
-
+
{claudeLoginResult.stderr}
)}
@@ -3190,7 +3190,7 @@ function RunDetail({ run: initialRun, agentRouteId, adapterType }: { run: Heartb
)}
{hasNonZeroExit && (
-
+
Exit code {run.exitCode}
{run.signal && (signal: {run.signal}) }
@@ -3229,7 +3229,7 @@ function RunDetail({ run: initialRun, agentRouteId, adapterType }: { run: Heartb
>
Session
- {sessionChanged &&
(changed) }
+ {sessionChanged &&
(changed) }
{sessionOpen && (
@@ -3304,8 +3304,8 @@ function RunDetail({ run: initialRun, agentRouteId, adapterType }: { run: Heartb
{/* stderr excerpt for failed runs */}
{run.stderrExcerpt && (
-
stderr
-
{run.stderrExcerpt}
+
stderr
+
{run.stderrExcerpt}
)}
@@ -3313,7 +3313,7 @@ function RunDetail({ run: initialRun, agentRouteId, adapterType }: { run: Heartb
{run.stdoutExcerpt && !run.logRef && (
stdout
-
{run.stdoutExcerpt}
+
{run.stdoutExcerpt}
)}
@@ -3716,14 +3716,14 @@ function LogViewer({ run, adapterType }: { run: HeartbeatRun; adapterType: strin
const levelColors: Record
= {
info: "text-foreground",
- warn: "text-yellow-600 dark:text-yellow-400",
- error: "text-red-600 dark:text-red-400",
+ warn: "text-warning",
+ error: "text-destructive",
};
const streamColors: Record = {
stdout: "text-foreground",
- stderr: "text-red-600 dark:text-red-300",
- system: "text-blue-600 dark:text-blue-300",
+ stderr: "text-destructive",
+ system: "text-primary",
};
return (
@@ -3771,7 +3771,7 @@ function LogViewer({ run, adapterType }: { run: HeartbeatRun; adapterType: strin
{adapterInvokePayload.prompt !== undefined && (
Prompt
-
+
{typeof adapterInvokePayload.prompt === "string"
? redactPathText(adapterInvokePayload.prompt, censorUsernameInLogs)
: JSON.stringify(redactPathValue(adapterInvokePayload.prompt, censorUsernameInLogs), null, 2)}
@@ -3781,7 +3781,7 @@ function LogViewer({ run, adapterType }: { run: HeartbeatRun; adapterType: strin
{adapterInvokePayload.context !== undefined && (
Context
-
+
{JSON.stringify(redactPathValue(adapterInvokePayload.context, censorUsernameInLogs), null, 2)}
@@ -3789,7 +3789,7 @@ function LogViewer({ run, adapterType }: { run: HeartbeatRun; adapterType: strin
{adapterInvokePayload.env !== undefined && (
Environment
-
+
{formatEnvForDisplay(adapterInvokePayload.env, censorUsernameInLogs)}
@@ -3835,10 +3835,10 @@ function LogViewer({ run, adapterType }: { run: HeartbeatRun; adapterType: strin
)}
{isLive && (
-
+
-
-
+
+
Live
@@ -3853,7 +3853,7 @@ function LogViewer({ run, adapterType }: { run: HeartbeatRun; adapterType: strin
emptyMessage={run.logRef ? "Waiting for transcript..." : "No persisted transcript for this run."}
/>
{logError && (
-
+
{logError}
)}
@@ -3861,34 +3861,34 @@ function LogViewer({ run, adapterType }: { run: HeartbeatRun; adapterType: strin
{(run.status === "failed" || run.status === "timed_out") && (
-
-
Failure details
+
+
Failure details
{run.error && (
-
-
Error:
+
+ Error:
{redactPathText(run.error, censorUsernameInLogs)}
)}
{run.stderrExcerpt && run.stderrExcerpt.trim() && (
-
stderr excerpt
-
+ stderr excerpt
+
{redactPathText(run.stderrExcerpt, censorUsernameInLogs)}
)}
{run.resultJson && (
-
adapter result JSON
-
+ adapter result JSON
+
{JSON.stringify(redactPathValue(run.resultJson, censorUsernameInLogs), null, 2)}
)}
{run.stdoutExcerpt && run.stdoutExcerpt.trim() && !run.resultJson && (
-
stdout excerpt
-
+ stdout excerpt
+
{redactPathText(run.stdoutExcerpt, censorUsernameInLogs)}
@@ -3899,7 +3899,7 @@ function LogViewer({ run, adapterType }: { run: HeartbeatRun; adapterType: strin
{events.length > 0 && (
Events ({events.length})
-
+
{events.map((evt) => {
const color = evt.color
?? (evt.level ? levelColors[evt.level] : null)
@@ -3908,10 +3908,10 @@ function LogViewer({ run, adapterType }: { run: HeartbeatRun; adapterType: strin
return (
-
+
{new Date(evt.createdAt).toLocaleTimeString("en-US", { hour12: false })}
-
+
{evt.stream ? `[${evt.stream}]` : ""}
@@ -3976,12 +3976,12 @@ function KeysTab({ agentId, companyId }: { agentId: string; companyId?: string }
{/* New token banner */}
{newToken && (
-
-
+
+
API key created — copy it now, it will not be shown again.
-
+
{tokenVisible ? newToken : newToken.replace(/./g, "•")}
- {copied && Copied! }
+ {copied && Copied! }
e.stopPropagation()}
>
-
-
+
+
-
+
Live{liveCount > 1 ? ` (${liveCount})` : ""}
diff --git a/ui/src/pages/ApprovalDetail.tsx b/ui/src/pages/ApprovalDetail.tsx
index 105a09d2..f818e3d2 100644
--- a/ui/src/pages/ApprovalDetail.tsx
+++ b/ui/src/pages/ApprovalDetail.tsx
@@ -174,16 +174,16 @@ export function ApprovalDetail() {
return (
{showApprovedBanner && (
-
+
-
-
+
+
-
Approval confirmed
-
+
Approval confirmed
+
Requesting agent was notified to review this approval and linked issues.
@@ -191,7 +191,7 @@ export function ApprovalDetail() {
navigate(resolvedCta.to)}
>
{resolvedCta.label}
@@ -266,7 +266,7 @@ export function ApprovalDetail() {
<>
approveMutation.mutate()}
disabled={approveMutation.isPending}
>
diff --git a/ui/src/pages/Approvals.tsx b/ui/src/pages/Approvals.tsx
index 1989b1eb..9324aa5d 100644
--- a/ui/src/pages/Approvals.tsx
+++ b/ui/src/pages/Approvals.tsx
@@ -91,7 +91,7 @@ export function Approvals() {
{ value: "pending", label: <>Pending{pendingCount > 0 && (
{pendingCount}
diff --git a/ui/src/pages/Companies.tsx b/ui/src/pages/Companies.tsx
index d6a6e015..df5353c8 100644
--- a/ui/src/pages/Companies.tsx
+++ b/ui/src/pages/Companies.tsx
@@ -159,7 +159,7 @@ export function Companies() {
onClick={saveEdit}
disabled={editMutation.isPending}
>
-
+
@@ -171,9 +171,9 @@ export function Companies() {
diff --git a/ui/src/pages/CompanyExport.tsx b/ui/src/pages/CompanyExport.tsx
index 7314818f..7e260d90 100644
--- a/ui/src/pages/CompanyExport.tsx
+++ b/ui/src/pages/CompanyExport.tsx
@@ -942,7 +942,7 @@ export function CompanyExport() {
{selectedCount} / {totalFiles} file{totalFiles === 1 ? "" : "s"} selected
{warnings.length > 0 && (
-
+
{warnings.length} warning{warnings.length === 1 ? "" : "s"}
)}
@@ -962,9 +962,9 @@ export function CompanyExport() {
{/* Warnings */}
{warnings.length > 0 && (
-
+
{warnings.map((w) => (
-
{w}
+
{w}
))}
)}
diff --git a/ui/src/pages/CompanyImport.tsx b/ui/src/pages/CompanyImport.tsx
index e4f5fa00..fd18cdb5 100644
--- a/ui/src/pages/CompanyImport.tsx
+++ b/ui/src/pages/CompanyImport.tsx
@@ -104,10 +104,10 @@ function ensureMarkdownPath(p: string): string {
}
const ACTION_COLORS: Record
= {
- create: "text-emerald-500 border-emerald-500/30",
- update: "text-amber-500 border-amber-500/30",
- overwrite: "text-red-500 border-red-500/30",
- replace: "text-red-500 border-red-500/30",
+ create: "text-success border-success/30",
+ update: "text-warning border-warning/30",
+ overwrite: "text-destructive border-destructive/30",
+ replace: "text-destructive border-destructive/30",
skip: "text-muted-foreground border-border",
none: "text-muted-foreground border-border",
};
@@ -163,7 +163,7 @@ function renderImportFileExtra(node: FileTreeNode, checked: boolean, renameMap:
return (
{renamedTo && checked && (
-
+
→ {renamedTo}
)}
@@ -222,7 +222,7 @@ function ImportPreviewPane({
{selectedFile}
{renamedTo && (
-
+
→ {renamedTo}
)}
@@ -428,7 +428,7 @@ function ConflictResolutionList({
className={cn(
"flex items-center gap-3 px-4 py-2.5 text-sm",
isSkipped && "opacity-40",
- isConfirmed && !isSkipped && "bg-emerald-500/5",
+ isConfirmed && !isSkipped && "bg-success/5",
)}
>
{/* Skip button on the left */}
@@ -450,8 +450,8 @@ function ConflictResolutionList({
isSkipped
? "text-muted-foreground border-border"
: isConfirmed
- ? "text-emerald-500 border-emerald-500/30"
- : "text-amber-500 border-amber-500/30",
+ ? "text-success border-success/30"
+ : "text-warning border-warning/30",
)}>
{item.kind}
@@ -467,7 +467,7 @@ function ConflictResolutionList({
<>
{isConfirmed ? (
-
+
{currentName}
) : (
@@ -487,7 +487,7 @@ function ConflictResolutionList({
className={cn(
"ml-auto shrink-0 rounded-md border px-2.5 py-1 text-xs transition-colors inline-flex items-center gap-1.5",
isConfirmed
- ? "border-emerald-500/30 bg-emerald-500/10 text-emerald-500"
+ ? "border-success/30 bg-success/10 text-success"
: "border-border text-muted-foreground hover:bg-accent/50",
)}
onClick={() => onToggleConfirm(item.slug)}
@@ -565,7 +565,7 @@ function AdapterPickerList({
agent
@@ -1252,7 +1252,7 @@ export function CompanyImport() {
{selectedCount} / {totalFiles} file{totalFiles === 1 ? "" : "s"} selected
{conflicts.length > 0 && (
-
+
{conflicts.length} conflict{conflicts.length === 1 ? "" : "s"}
)}
@@ -1302,9 +1302,9 @@ export function CompanyImport() {
{/* Warnings */}
{importPreview.warnings.length > 0 && (
-
+
{importPreview.warnings.map((w) => (
-
{w}
+
{w}
))}
)}
diff --git a/ui/src/pages/CompanySettings.tsx b/ui/src/pages/CompanySettings.tsx
index b35b4654..6ba3258a 100644
--- a/ui/src/pages/CompanySettings.tsx
+++ b/ui/src/pages/CompanySettings.tsx
@@ -345,7 +345,7 @@ export function CompanySettings() {
setBrandColor(e.target.value)}
className="h-8 w-8 cursor-pointer rounded border border-border bg-transparent p-0"
/>
@@ -498,7 +498,7 @@ export function CompanySettings() {
{snippetCopied && (
Copied
diff --git a/ui/src/pages/ContentStudio.tsx b/ui/src/pages/ContentStudio.tsx
index 5205e03a..438df48e 100644
--- a/ui/src/pages/ContentStudio.tsx
+++ b/ui/src/pages/ContentStudio.tsx
@@ -20,7 +20,7 @@ export function ContentStudio() {
const companyId = selectedCompanyId ?? "";
const themeJob = useContentJob(companyId);
const [showApplyDialog, setShowApplyDialog] = useState(false);
- const [seedColor, setSeedColor] = useState("#4f46e5");
+ const [seedColor, setSeedColor] = useState("var(--primary)");
const [themeBundle, setThemeBundle] = useState<{
palette: PaletteRole[];
exports: { css: string; tailwind: string; vscode: string; json: string };
diff --git a/ui/src/pages/Costs.tsx b/ui/src/pages/Costs.tsx
index 8a5c9c4a..04e62e84 100644
--- a/ui/src/pages/Costs.tsx
+++ b/ui/src/pages/Costs.tsx
@@ -695,10 +695,10 @@ export function Costs() {
className={cn(
"h-full transition-[width,background-color] duration-150",
spendData.summary.utilizationPercent > 90
- ? "bg-red-400"
+ ? "bg-destructive"
: spendData.summary.utilizationPercent > 70
- ? "bg-yellow-400"
- : "bg-emerald-400",
+ ? "bg-warning"
+ : "bg-success",
)}
style={{ width: `${Math.min(100, spendData.summary.utilizationPercent)}%` }}
/>
diff --git a/ui/src/pages/Dashboard.tsx b/ui/src/pages/Dashboard.tsx
index 770435cc..048a5446 100644
--- a/ui/src/pages/Dashboard.tsx
+++ b/ui/src/pages/Dashboard.tsx
@@ -191,16 +191,16 @@ export function Dashboard() {
{error && {error.message}
}
{hasNoAgents && (
-
+
-
-
+
+
You have no agents.
openOnboarding({ initialStep: 2, companyId: selectedCompanyId! })}
- className="text-sm font-medium text-amber-700 hover:text-amber-900 dark:text-amber-300 dark:hover:text-amber-100 underline underline-offset-2 shrink-0"
+ className="text-sm font-medium text-warning hover:text-warning hover:text-warning underline underline-offset-2 shrink-0"
>
Create one here
@@ -212,19 +212,19 @@ export function Dashboard() {
{data && (
<>
{data.budgets.activeIncidents > 0 ? (
-
+
-
+
-
+
{data.budgets.activeIncidents} active budget incident{data.budgets.activeIncidents === 1 ? "" : "s"}
-
+
{data.budgets.pausedAgents} agents paused · {data.budgets.pausedProjects} projects paused · {data.budgets.pendingApprovals} pending budget approvals
-
+
Open budgets
diff --git a/ui/src/pages/DesignGuide.tsx b/ui/src/pages/DesignGuide.tsx
index a35cb574..75e9bfd8 100644
--- a/ui/src/pages/DesignGuide.tsx
+++ b/ui/src/pages/DesignGuide.tsx
@@ -461,9 +461,9 @@ export function DesignGuide() {
{[
- ["timer", "bg-blue-100 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300"],
- ["assignment", "bg-violet-100 text-violet-700 dark:bg-violet-900/50 dark:text-violet-300"],
- ["on_demand", "bg-cyan-100 text-cyan-700 dark:bg-cyan-900/50 dark:text-cyan-300"],
+ ["timer", "bg-primary/10 text-primary"],
+ ["assignment", "bg-muted text-primary"],
+ ["on_demand", "bg-primary/10 text-primary"],
["automation", "bg-muted text-muted-foreground"],
].map(([label, cls]) => (
@@ -1033,9 +1033,9 @@ export function DesignGuide() {
{[
- { label: "Under budget (40%)", pct: 40, color: "bg-green-400" },
- { label: "Warning (75%)", pct: 75, color: "bg-yellow-400" },
- { label: "Over budget (95%)", pct: 95, color: "bg-red-400" },
+ { label: "Under budget (40%)", pct: 40, color: "bg-success" },
+ { label: "Warning (75%)", pct: 75, color: "bg-warning" },
+ { label: "Over budget (95%)", pct: 95, color: "bg-destructive" },
].map(({ label, pct, color }) => (
@@ -1057,20 +1057,20 @@ export function DesignGuide() {
{/* LOG VIEWER */}
{/* ============================================================ */}
-
+
[12:00:01] INFO Agent started successfully
[12:00:02] INFO Processing task PAP-001
-
[12:00:05] WARN Rate limit approaching (80%)
+
[12:00:05] WARN Rate limit approaching (80%)
[12:00:08] INFO Task PAP-001 completed
-
[12:00:12] ERROR Connection timeout to upstream service
-
[12:00:12] SYS Retrying connection in 5s...
+
[12:00:12] ERROR Connection timeout to upstream service
+
[12:00:12] SYS Retrying connection in 5s...
[12:00:17] INFO Reconnected successfully
-
-
+
+
- Live
+ Live
diff --git a/ui/src/pages/ExecutionWorkspaceDetail.tsx b/ui/src/pages/ExecutionWorkspaceDetail.tsx
index c0db7f88..24615a74 100644
--- a/ui/src/pages/ExecutionWorkspaceDetail.tsx
+++ b/ui/src/pages/ExecutionWorkspaceDetail.tsx
@@ -384,7 +384,7 @@ export function ExecutionWorkspaceDetail() {
{workspace.mode}
{workspace.providerType}
-
+
{workspace.status}
diff --git a/ui/src/pages/Inbox.tsx b/ui/src/pages/Inbox.tsx
index 8407ad5f..ecb11dfc 100644
--- a/ui/src/pages/Inbox.tsx
+++ b/ui/src/pages/Inbox.tsx
@@ -188,22 +188,22 @@ export function InboxIssueMetaLeading({
-
+
Live
@@ -286,7 +286,7 @@ export function InboxIssueTrailingColumns({
if (column === "project") {
if (projectName) {
- const accentColor = projectColor ?? "#64748b";
+ const accentColor = projectColor ?? "var(--muted-foreground)";
return (
@@ -441,8 +441,8 @@ export function FailedRunInboxRow({
>
{!showUnreadSlot && }
-
-
+
+
@@ -563,13 +563,13 @@ function ApprovalInboxRow({
onClick={onMarkRead}
className={cn(
"inline-flex h-4 w-4 items-center justify-center rounded-full transition-colors",
- "hover:bg-blue-500/20",
+ "hover:bg-primary/20",
)}
aria-label="Mark as read"
>
@@ -615,7 +615,7 @@ function ApprovalInboxRow({
@@ -637,7 +637,7 @@ function ApprovalInboxRow({
@@ -702,13 +702,13 @@ function JoinRequestInboxRow({
onClick={onMarkRead}
className={cn(
"inline-flex h-4 w-4 items-center justify-center rounded-full transition-colors",
- "hover:bg-blue-500/20",
+ "hover:bg-primary/20",
)}
aria-label="Mark as read"
>
@@ -746,7 +746,7 @@ function JoinRequestInboxRow({
@@ -766,7 +766,7 @@ function JoinRequestInboxRow({
@@ -1775,8 +1775,8 @@ export function Inbox() {
if (showTodayDivider) {
elements.push(
,
@@ -1979,7 +1979,7 @@ export function Inbox() {
to="/agents"
className="flex flex-1 cursor-pointer items-center gap-3 no-underline text-inherit"
>
-
+
{dashboard!.agents.error} {" "}
{dashboard!.agents.error === 1 ? "agent has" : "agents have"} errors
@@ -2001,7 +2001,7 @@ export function Inbox() {
to="/costs"
className="flex flex-1 cursor-pointer items-center gap-3 no-underline text-inherit"
>
-
+
Budget at{" "}
{dashboard!.costs.monthUtilizationPercent}% {" "}
diff --git a/ui/src/pages/InstanceExperimentalSettings.tsx b/ui/src/pages/InstanceExperimentalSettings.tsx
index 050166ff..78827a0b 100644
--- a/ui/src/pages/InstanceExperimentalSettings.tsx
+++ b/ui/src/pages/InstanceExperimentalSettings.tsx
@@ -89,7 +89,7 @@ export function InstanceExperimentalSettings() {
disabled={toggleMutation.isPending}
className={cn(
"relative inline-flex h-5 w-9 items-center rounded-full transition-colors disabled:cursor-not-allowed disabled:opacity-60",
- enableIsolatedWorkspaces ? "bg-green-600" : "bg-muted",
+ enableIsolatedWorkspaces ? "bg-success" : "bg-muted",
)}
onClick={() => toggleMutation.mutate({ enableIsolatedWorkspaces: !enableIsolatedWorkspaces })}
>
@@ -119,7 +119,7 @@ export function InstanceExperimentalSettings() {
disabled={toggleMutation.isPending}
className={cn(
"relative inline-flex h-5 w-9 items-center rounded-full transition-colors disabled:cursor-not-allowed disabled:opacity-60",
- autoRestartDevServerWhenIdle ? "bg-green-600" : "bg-muted",
+ autoRestartDevServerWhenIdle ? "bg-success" : "bg-muted",
)}
onClick={() =>
toggleMutation.mutate({ autoRestartDevServerWhenIdle: !autoRestartDevServerWhenIdle })
diff --git a/ui/src/pages/InstanceGeneralSettings.tsx b/ui/src/pages/InstanceGeneralSettings.tsx
index 15942ff9..cbeff1ff 100644
--- a/ui/src/pages/InstanceGeneralSettings.tsx
+++ b/ui/src/pages/InstanceGeneralSettings.tsx
@@ -123,7 +123,7 @@ export function InstanceGeneralSettings() {
disabled={updateGeneralMutation.isPending}
className={cn(
"relative inline-flex h-5 w-9 items-center rounded-full transition-colors disabled:cursor-not-allowed disabled:opacity-60",
- censorUsernameInLogs ? "bg-green-600" : "bg-muted",
+ censorUsernameInLogs ? "bg-success" : "bg-muted",
)}
onClick={() =>
updateGeneralMutation.mutate({
@@ -157,7 +157,7 @@ export function InstanceGeneralSettings() {
disabled={updateGeneralMutation.isPending}
className={cn(
"relative inline-flex h-5 w-9 items-center rounded-full transition-colors disabled:cursor-not-allowed disabled:opacity-60",
- keyboardShortcuts ? "bg-green-600" : "bg-muted",
+ keyboardShortcuts ? "bg-success" : "bg-muted",
)}
onClick={() => updateGeneralMutation.mutate({ keyboardShortcuts: !keyboardShortcuts })}
>
diff --git a/ui/src/pages/InviteLanding.tsx b/ui/src/pages/InviteLanding.tsx
index 1a4bf488..e6e1071f 100644
--- a/ui/src/pages/InviteLanding.tsx
+++ b/ui/src/pages/InviteLanding.tsx
@@ -218,7 +218,7 @@ export function InviteLandingPage() {
Connectivity diagnostics
{diagnostics.map((diag, idx) => (
-
+
[{diag.level}] {diag.message}
{diag.hint &&
{diag.hint}
}
diff --git a/ui/src/pages/IssueDetail.tsx b/ui/src/pages/IssueDetail.tsx
index 72ad69c3..3463b605 100644
--- a/ui/src/pages/IssueDetail.tsx
+++ b/ui/src/pages/IssueDetail.tsx
@@ -1177,10 +1177,10 @@ export function IssueDetail() {
{issue.identifier ?? issue.id.slice(0, 8)}
{hasLiveRuns && (
-
+
-
-
+
+
Live
@@ -1189,7 +1189,7 @@ export function IssueDetail() {
{issue.originKind === "routine_execution" && issue.originId && (
Routine
@@ -1239,7 +1239,7 @@ export function IssueDetail() {
onClick={copyIssueToClipboard}
title="Copy issue as markdown"
>
- {copied ? : }
+ {copied ? : }
- {copied ? : }
+ {copied ? : }
{node.name}
diff --git a/ui/src/pages/OrgChart.tsx b/ui/src/pages/OrgChart.tsx
index 0bd939c2..0c9ac762 100644
--- a/ui/src/pages/OrgChart.tsx
+++ b/ui/src/pages/OrgChart.tsx
@@ -129,15 +129,17 @@ const adapterLabels: Record = {
http: "HTTP",
};
+// [nexus] Design system migration Phase 3 — status colors now reference
+// semantic CSS variables so they auto-switch with light/dark themes.
const statusDotColor: Record = {
- running: "#22d3ee",
- active: "#4ade80",
- paused: "#facc15",
- idle: "#facc15",
- error: "#f87171",
- terminated: "#a3a3a3",
+ running: "var(--primary)",
+ active: "var(--success)",
+ paused: "var(--warning)",
+ idle: "var(--muted-foreground)",
+ error: "var(--destructive)",
+ terminated: "var(--muted-foreground)",
};
-const defaultDotColor = "#a3a3a3";
+const defaultDotColor = "var(--muted-foreground)";
// ── Main component ──────────────────────────────────────────────────────
diff --git a/ui/src/pages/PluginManager.tsx b/ui/src/pages/PluginManager.tsx
index 4efb1552..7affa9a0 100644
--- a/ui/src/pages/PluginManager.tsx
+++ b/ui/src/pages/PluginManager.tsx
@@ -205,9 +205,9 @@ export function PluginManager() {
-
+
-
+
Plugins are alpha.
@@ -251,7 +251,7 @@ export function PluginManager() {
{installedPlugin ? (
{installedPlugin.status}
@@ -347,15 +347,15 @@ export function PluginManager() {
{plugin.manifestJson.description || "No description provided."}
{plugin.status === "error" && (
-
+
-
+
{errorSummaryByPluginId.get(plugin.id)}
@@ -364,7 +364,7 @@ export function PluginManager() {
setErrorDetailsPlugin(plugin)}
>
View full error
@@ -386,7 +386,7 @@ export function PluginManager() {
}
className={cn(
"shrink-0",
- plugin.status === "ready" ? "bg-green-600 hover:bg-green-700" : ""
+ plugin.status === "ready" ? "bg-success hover:bg-success" : ""
)}
>
{plugin.status}
@@ -405,7 +405,7 @@ export function PluginManager() {
}}
disabled={enableMutation.isPending || disableMutation.isPending}
>
-
+
-
+
-
+
-
+
What errored
-
+
{errorDetailsPlugin ? getPluginErrorSummary(errorDetailsPlugin) : "No error summary available."}
diff --git a/ui/src/pages/PluginSettings.tsx b/ui/src/pages/PluginSettings.tsx
index 436f3974..380b32d7 100644
--- a/ui/src/pages/PluginSettings.tsx
+++ b/ui/src/pages/PluginSettings.tsx
@@ -290,7 +290,7 @@ export function PluginSettings() {
<>
-
+
Crashes
@@ -409,7 +409,7 @@ export function PluginSettings() {
entry.level === "error"
? "text-destructive"
: entry.level === "warn"
- ? "text-yellow-600 dark:text-yellow-400"
+ ? "text-warning"
: entry.level === "debug"
? "text-muted-foreground/60"
: "text-muted-foreground"
@@ -454,7 +454,7 @@ export function PluginSettings() {
{check.name}
{check.passed ? (
-
+
) : (
)}
@@ -682,7 +682,7 @@ function PluginConfigForm({ pluginId, schema, initialValues, isLoading, pluginSt
@@ -694,7 +694,7 @@ function PluginConfigForm({ pluginId, schema, initialValues, isLoading, pluginSt
@@ -800,14 +800,14 @@ function formatTimestamp(epochMs: number): string {
function JobStatusDot({ status }: { status: string }) {
const colorClass =
status === "success" || status === "succeeded"
- ? "bg-green-500"
+ ? "bg-success"
: status === "failed"
- ? "bg-red-500"
+ ? "bg-destructive"
: status === "running"
- ? "bg-blue-500 animate-pulse"
+ ? "bg-primary animate-pulse"
: status === "cancelled"
- ? "bg-gray-400"
- : "bg-amber-500"; // queued, pending
+ ? "bg-muted"
+ : "bg-warning"; // queued, pending
return (
{summary.serviceCount > 0 ? (
-
-
+
+
{summary.runningServiceCount}/{summary.serviceCount}
) : null}
@@ -410,7 +410,7 @@ function ProjectWorkspacesContent({
Cleanup attention needed
-
+
{cleanupFailedSummaries.map(renderSummaryRow)}
@@ -796,7 +796,7 @@ export function ProjectDetail() {
updateProject.mutate({ color })}
/>
@@ -808,8 +808,8 @@ export function ProjectDetail() {
className="text-xl font-bold"
/>
{project.pauseReason === "budget" ? (
-
-
+
+
Paused by budget hard stop
) : null}
diff --git a/ui/src/pages/ProjectWorkspaceDetail.tsx b/ui/src/pages/ProjectWorkspaceDetail.tsx
index 5831ec82..1ff850a7 100644
--- a/ui/src/pages/ProjectWorkspaceDetail.tsx
+++ b/ui/src/pages/ProjectWorkspaceDetail.tsx
@@ -389,7 +389,7 @@ export function ProjectWorkspaceDetail() {
Make primary
) : (
-
+
This is the project’s primary codebase workspace.
diff --git a/ui/src/pages/RoutineDetail.tsx b/ui/src/pages/RoutineDetail.tsx
index d8287401..f7e74d24 100644
--- a/ui/src/pages/RoutineDetail.tsx
+++ b/ui/src/pages/RoutineDetail.tsx
@@ -663,7 +663,7 @@ export function RoutineDetail() {
const automationLabelClassName = routine.status === "archived"
? "text-muted-foreground"
: automationEnabled
- ? "text-emerald-400"
+ ? "text-success"
: "text-muted-foreground";
return (
@@ -719,7 +719,7 @@ export function RoutineDetail() {
aria-label={automationEnabled ? "Pause automatic triggers" : "Enable automatic triggers"}
disabled={automationToggleDisabled}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${
- automationEnabled ? "bg-emerald-500" : "bg-muted"
+ automationEnabled ? "bg-success" : "bg-muted"
} ${automationToggleDisabled ? "cursor-not-allowed opacity-50" : ""}`}
onClick={() => updateRoutineStatus.mutate(automationEnabled ? "paused" : "active")}
>
@@ -737,7 +737,7 @@ export function RoutineDetail() {
{/* Secret message banner */}
{secretMessage && (
-
+
{secretMessage.title}
{`Save this now. ${VOCAB.appName} will not show the secret value again.`}
@@ -825,7 +825,7 @@ export function RoutineDetail() {
<>
{option.label}
>
@@ -840,7 +840,7 @@ export function RoutineDetail() {
<>
{option.label}
>
@@ -920,7 +920,7 @@ export function RoutineDetail() {
{/* Save bar */}
{isEditDirty ? (
-
Unsaved changes
+
Unsaved changes
) : (
)}
@@ -945,7 +945,7 @@ export function RoutineDetail() {
Runs
- {hasLiveRun && }
+ {hasLiveRun && }
diff --git a/ui/src/pages/Routines.tsx b/ui/src/pages/Routines.tsx
index 20c26e79..94e6c64e 100644
--- a/ui/src/pages/Routines.tsx
+++ b/ui/src/pages/Routines.tsx
@@ -282,7 +282,7 @@ export function Routines() {
Routines
- Beta
+ Beta
Recurring work definitions that materialize into auditable execution issues.
@@ -425,7 +425,7 @@ export function Routines() {
<>
{option.label}
>
@@ -440,7 +440,7 @@ export function Routines() {
<>
{option.label}
>
@@ -610,7 +610,7 @@ export function Routines() {
{projectById.get(routine.projectId)?.name ?? "Unknown"}
diff --git a/ui/src/pages/RunTranscriptUxLab.tsx b/ui/src/pages/RunTranscriptUxLab.tsx
index 80759cf9..7141643a 100644
--- a/ui/src/pages/RunTranscriptUxLab.tsx
+++ b/ui/src/pages/RunTranscriptUxLab.tsx
@@ -97,9 +97,9 @@ function LiveWidgetPreview({
density: TranscriptDensity;
}) {
return (
-
-
-
+
+
+
Live Runs
@@ -151,7 +151,7 @@ function DashboardPreview({
@@ -160,7 +160,7 @@ function DashboardPreview({
@@ -172,7 +172,7 @@ function DashboardPreview({
-
+
{runTranscriptFixtureMeta.issueIdentifier} - {runTranscriptFixtureMeta.issueTitle}
@@ -204,7 +204,7 @@ export function RunTranscriptUxLab() {
-
+
UX Lab
@@ -225,12 +225,12 @@ export function RunTranscriptUxLab() {
className={cn(
"w-full rounded-xl border px-4 py-3 text-left transition-all",
selectedSurface === option.id
- ? "border-cyan-500/35 bg-cyan-500/[0.10] shadow-[0_12px_24px_rgba(6,182,212,0.12)]"
- : "border-border/70 bg-background/70 hover:border-cyan-500/20 hover:bg-cyan-500/[0.04]",
+ ? "border-primary/35 bg-primary/[0.10] shadow-[0_12px_24px_rgba(6,182,212,0.12)]"
+ : "border-border/70 bg-background/70 hover:border-primary/20 hover:bg-primary/[0.04]",
)}
>
-
+
diff --git a/ui/src/pages/SkillDetail.tsx b/ui/src/pages/SkillDetail.tsx
index 957fa455..4ce5e812 100644
--- a/ui/src/pages/SkillDetail.tsx
+++ b/ui/src/pages/SkillDetail.tsx
@@ -58,8 +58,8 @@ function VersionDiff({ oldContent, newContent }: { oldContent: string; newConten
@@ -343,7 +343,7 @@ export function SkillDetail() {
{skill.averageRating != null ? (
<>
-
+
{skill.averageRating.toFixed(1)}
>
) : (