From e2c6f4b4b7b18ed00c3895a8f455576b0c06cab8 Mon Sep 17 00:00:00 2001 From: scotttong Date: Mon, 6 Jul 2026 18:37:50 -0700 Subject: [PATCH] =?UTF-8?q?feat(ui):=20gallery=20feedback=20round=202=20?= =?UTF-8?q?=E2=80=94=20incident-card=20legibility,=20bar-fill=20stragglers?= =?UTF-8?q?,=20cyan=20liveness=20sweep?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three user rulings from the tune-session gallery (intentional visible changes; snapshots NOT re-baselined): A. BudgetIncidentCard hard-stop card was unreadable in LIGHT mode (pre-existing: dark-tuned red-50/100/200 text over the light pink gradient, no light variants). Eyebrow/title/description/banner/icon/ validation now use red-600..950 light text with the original dark classes behind dark:; same treatment for sibling BudgetPolicyCard statusTone chips + red banner. B1 gradient tokens untouched. B. Remaining bar-fill stragglers -> canonical status hues: ClaudeSubscriptionPanel fillClass and ProviderQuotaCard quota-window fills (red-400 -> bg-(--status-task-blocked), amber/yellow-400 -> bg-(--status-task-todo), green-400 -> bg-(--status-task-done)). BudgetSidebarMarker is an icon badge, not a bar — left. C. Systematic cyan->status-blue liveness sweep (~50 sites / 20 files): running tones, live dots/pings, Live surfaces (LiveRunWidget, ActiveAgentsPanel Live-now box, AgentDetail live card, IssueDetail Live pill), scheduled-retry family, externalObjectStatus running maps, timeline now-marker #2dd4bf -> #2563eb, and liveness glow shadow token VALUES --shadow-extract-1/11/14 rgba(6,182,212,0.08) -> rgba(37,99,235,0.08) (sites unchanged). Non-liveness cyan left and documented (xterm cursor, on_demand chips, assets chip, import rename text, recovery_required, ledger Advanced/snoozed, UxLab). DECISION-SHEET.md: 'Gallery feedback round 2' section. Gates 3/3 CLEAN, typecheck green, ui build green. Co-Authored-By: Claude Fable 5 --- DECISION-SHEET.md | 7 +++++++ ui/src/components/ActiveAgentsPanel.tsx | 8 ++++---- ui/src/components/ArtifactsPanel.tsx | 6 +++--- ui/src/components/BudgetIncidentCard.tsx | 12 +++++------ ui/src/components/BudgetPolicyCard.tsx | 8 ++++---- ui/src/components/ClaudeSubscriptionPanel.tsx | 4 ++-- ui/src/components/CommentThread.tsx | 2 +- ui/src/components/FeedCard.tsx | 2 +- ui/src/components/IssueRunLedger.tsx | 6 +++--- ui/src/components/IssueScheduledRetryCard.tsx | 4 ++-- ui/src/components/LiveRunWidget.tsx | 10 +++++----- ui/src/components/OnboardingChat.tsx | 8 ++++---- ui/src/components/ProviderQuotaCard.tsx | 6 +++--- .../components/timeline/WorkTimelineChart.tsx | 2 +- .../transcript/RunTranscriptView.tsx | 20 +++++++++---------- ui/src/index.css | 6 +++--- ui/src/lib/interrupt-handoff.ts | 2 +- ui/src/lib/runRetryState.ts | 2 +- ui/src/lib/status-colors.ts | 6 +++--- ui/src/lib/timeline/layout.ts | 4 ++-- ui/src/pages/AgentDetail.tsx | 14 ++++++------- ui/src/pages/DesignGuide.tsx | 6 +++--- ui/src/pages/IssueDetail.tsx | 6 +++--- 23 files changed, 79 insertions(+), 72 deletions(-) diff --git a/DECISION-SHEET.md b/DECISION-SHEET.md index 94c5629fe2..e7c45d48e8 100644 --- a/DECISION-SHEET.md +++ b/DECISION-SHEET.md @@ -46,6 +46,13 @@ User rulings from the tune-session gallery review; all intentionally visible, sn 2. **Budget/quota BAR FILLS reuse status colors** — moving-fill elements only: healthy → `bg-(--status-task-done)`, warning → `bg-(--status-task-todo)`, exceeded/hard-stop → `bg-(--status-task-blocked)` in BudgetPolicyCard.tsx, QuotaBar.tsx (feeds ProviderQuotaCard/BillerSpendCard pages), Costs.tsx, CodexSubscriptionPanel.tsx (escalation tiers only). Inspected and deliberately LEFT: Org.tsx status dot (not a bar), BudgetPolicyCard chip washes/notice borders (not fills), CodexSubscriptionPanel healthy `bg-primary/70` + null `bg-zinc-700` (healthy tier uses brand primary by design — flagged as ambiguous, not emerald). 3. **RUNNING = status blue, not cyan/teal** — IssueChatThread running chip now composes `brandChipBadge.blue` (layout classes unchanged); RunTranscriptView running label uses new `runningLabelText` export (`text-[#1D4ED8] dark:text-[#2563EB]`, hexes kept in lib/status-colors.ts for gate cleanliness); `statusBadge.running` + `agentStatusDot.running` maps and AgentDetail `runStatusIcons.running` re-pointed cyan→blue. Deliberately LEFT + flagged: `externalObjectStatusIcon/Badge.running` (same-map collision — `open` is already blue there; documented UX-spec tone system), and the cyan "Live" branding family (LiveRunWidget theme, AgentDetail live-card border + Live pulse dots, DesignGuide Live sample) — "Live" is a distinct motif from RUNNING chips; note AgentDetail's mobile Live pill is already blue, so a dedicated Live-color decision is recommended. +## Gallery feedback round 2 (preset-tune session, Jul 6) — executed + +1. **BudgetIncidentCard light-mode legibility (pre-existing bug)** — the hard-stop card's eyebrow/title/description/banner used dark-tuned red-50/100/200 text with no light variants over the light pink gradient. Light mode now uses red-600..950-tier text (matching the app's existing `text-red-700 dark:text-red-300` light-red-surface pattern); dark classes preserved verbatim behind `dark:`. Sibling fix: BudgetPolicyCard statusTone chips (hard_stop/warning/ok) + its red banner had the same dark-only text — same treatment. Gradient backgrounds (kept B1 tokens) untouched. +2. **Bar fills, remaining stragglers → status hues** — ClaudeSubscriptionPanel fillClass ("Current week Opus only" salmon red) and ProviderQuotaCard quota-window fills: red-400→`bg-(--status-task-blocked)`, amber/yellow-400→`bg-(--status-task-todo)`, green-400→`bg-(--status-task-done)`. Healthy `bg-primary/70` + null `bg-zinc-700` tiers unchanged (r1 ruling). Inspected, NOT a bar: BudgetSidebarMarker circular icon badge (left). +3. **Systematic cyan→status-blue liveness sweep** (~50 sites / 20 files; supersedes r1's "Live family left" note per user ruling): running-status tones (CommentThread, interrupt-handoff, runRetryState, AgentDetail run chip + status maps), live dots/pings (AgentDetail, OnboardingChat, ArtifactsPanel generating, ActiveAgentsPanel, IssueDetail Live pill, RunTranscriptView, IssueRunLedger live chip, DesignGuide sample), Live surfaces (LiveRunWidget theme, ActiveAgentsPanel Live-now box, AgentDetail live-card border), scheduled-retry family (IssueScheduledRetryCard, runRetryState, IssueRunLedger retry-pending), externalObjectStatus icon/badge `running` (now shares blue with `open`; liveness pulse differentiates — flagged), timeline "now" marker `#2dd4bf`→`#2563eb` (1.5px line vs `#5b9bf6` delegated bars, shape differentiates — flagged), and the liveness glow shadow tokens `--shadow-extract-1/11/14` value-edited `rgba(6,182,212,0.08)`→`rgba(37,99,235,0.08)` (kept-token VALUES changed, call sites unchanged). + Deliberately LEFT (non-liveness cyan, one-line reasons): xterm terminal cursor (CompanyEnvironments — terminal chrome); `on_demand` invocation-source chips (AgentDetail x2 + DesignGuide sample — source tag, not liveness); CompanySkills "Includes assets" chip (content-type tag); CompanyImport renamed-file mono text x2 (rename annotation); BlockedReasonChip `recovery_required` (blocked-reason category); IssueRunLedger "Advanced" outcome + "Silence snoozed" tones (outcome/pause semantics, not live); UxLab decorative gradients (B1 allowlisted decoration). + ## Verification status (this review) - `pnpm check:token-gates` — re-run independently: 3/3 CLEAN (468 files, 31 allowlist entries). diff --git a/ui/src/components/ActiveAgentsPanel.tsx b/ui/src/components/ActiveAgentsPanel.tsx index 6d69c040aa..c248c37486 100644 --- a/ui/src/components/ActiveAgentsPanel.tsx +++ b/ui/src/components/ActiveAgentsPanel.tsx @@ -172,7 +172,7 @@ const AgentRunCard = memo(function AgentRunCard({
@@ -182,8 +182,8 @@ const AgentRunCard = memo(function AgentRunCard({
{isActive ? ( - - + + ) : ( @@ -209,7 +209,7 @@ const AgentRunCard = memo(function AgentRunCard({ to={`/issues/${issue?.identifier ?? run.issueId}`} className={cn( "line-clamp-2 hover:underline", - isActive ? "text-cyan-700 dark:text-cyan-300" : "text-muted-foreground hover:text-foreground", + isActive ? "text-blue-700 dark:text-blue-300" : "text-muted-foreground hover:text-foreground", )} title={issue?.title ? `${issue?.identifier ?? run.issueId.slice(0, 8)} - ${issue.title}` : issue?.identifier ?? run.issueId.slice(0, 8)} > diff --git a/ui/src/components/ArtifactsPanel.tsx b/ui/src/components/ArtifactsPanel.tsx index 61e7bfc7e7..afa8778941 100644 --- a/ui/src/components/ArtifactsPanel.tsx +++ b/ui/src/components/ArtifactsPanel.tsx @@ -193,8 +193,8 @@ export function ArtifactsPanel({ taskId, isAgentWorking, openDocKey, openDocTitl {showGenerating ? (
- - + +
) : ( @@ -212,7 +212,7 @@ export function ArtifactsPanel({ taskId, isAgentWorking, openDocKey, openDocTitl {wp.type.replace(/_/g, " ")}
{showGenerating ? ( - + Generating... diff --git a/ui/src/components/BudgetIncidentCard.tsx b/ui/src/components/BudgetIncidentCard.tsx index d4c52d6299..44fa60a7c9 100644 --- a/ui/src/components/BudgetIncidentCard.tsx +++ b/ui/src/components/BudgetIncidentCard.tsx @@ -48,25 +48,25 @@ export function BudgetIncidentCard({
-
+
{incident.scopeType} hard stop
{stateLabel}
- {incident.scopeName} - + {incident.scopeName} + Spending reached {formatCents(incident.amountObserved)} against a limit of {formatCents(incident.amountLimit)}.
-
+
-
+
{incident.scopeType === "project" @@ -98,7 +98,7 @@ export function BudgetIncidentCard({
{parsed !== null && parsed <= incident.amountObserved ? ( -

+

The new budget must exceed current observed spend.

) : null} diff --git a/ui/src/components/BudgetPolicyCard.tsx b/ui/src/components/BudgetPolicyCard.tsx index b24692c7f9..619da97edd 100644 --- a/ui/src/components/BudgetPolicyCard.tsx +++ b/ui/src/components/BudgetPolicyCard.tsx @@ -23,9 +23,9 @@ function windowLabel(windowKind: BudgetPolicySummary["windowKind"]) { } function statusTone(status: BudgetPolicySummary["status"]) { - if (status === "hard_stop") return "text-red-300 border-red-500/30 bg-red-500/10"; - if (status === "warning") return "text-amber-200 border-amber-500/30 bg-amber-500/10"; - return "text-emerald-200 border-emerald-500/30 bg-emerald-500/10"; + if (status === "hard_stop") return "text-red-700 dark:text-red-300 border-red-500/30 bg-red-500/10"; + if (status === "warning") return "text-amber-700 dark:text-amber-200 border-amber-500/30 bg-amber-500/10"; + return "text-emerald-700 dark:text-emerald-200 border-emerald-500/30 bg-emerald-500/10"; } export function BudgetPolicyCard({ @@ -116,7 +116,7 @@ export function BudgetPolicyCard({ ); const pausedPane = summary.paused ? ( -
+
{summary.scopeType === "project" diff --git a/ui/src/components/ClaudeSubscriptionPanel.tsx b/ui/src/components/ClaudeSubscriptionPanel.tsx index 5e9a929eb2..3a950a457a 100644 --- a/ui/src/components/ClaudeSubscriptionPanel.tsx +++ b/ui/src/components/ClaudeSubscriptionPanel.tsx @@ -46,8 +46,8 @@ function orderedWindows(windows: QuotaWindow[]): QuotaWindow[] { function fillClass(usedPercent: number | null): string { if (usedPercent == null) return "bg-zinc-700"; - if (usedPercent >= 90) return "bg-red-400"; - if (usedPercent >= 70) return "bg-amber-400"; + if (usedPercent >= 90) return "bg-(--status-task-blocked)"; + if (usedPercent >= 70) return "bg-(--status-task-todo)"; return "bg-primary/70"; } diff --git a/ui/src/components/CommentThread.tsx b/ui/src/components/CommentThread.tsx index 04ffd62c9e..9836380e42 100644 --- a/ui/src/components/CommentThread.tsx +++ b/ui/src/components/CommentThread.tsx @@ -233,7 +233,7 @@ function runStatusClass(status: string) { case "timed_out": return "text-orange-700 dark:text-orange-300"; case "running": - return "text-cyan-700 dark:text-cyan-300"; + return "text-blue-700 dark:text-blue-300"; case "queued": case "pending": return "text-amber-700 dark:text-amber-300"; diff --git a/ui/src/components/FeedCard.tsx b/ui/src/components/FeedCard.tsx index 91711b15e2..0bcda8af40 100644 --- a/ui/src/components/FeedCard.tsx +++ b/ui/src/components/FeedCard.tsx @@ -177,7 +177,7 @@ function getIconSpec( // Heartbeat — animated when active, static otherwise if (action.startsWith("heartbeat.")) { if (isActive && action === "heartbeat.invoked") { - return { kind: "lucide", Icon: Loader2, color: "text-cyan-600 dark:text-cyan-400", spin: true }; + return { kind: "lucide", Icon: Loader2, color: "text-blue-600 dark:text-blue-400", spin: true }; } return { kind: "lucide", Icon: Loader2, color: "text-muted-foreground" }; } diff --git a/ui/src/components/IssueRunLedger.tsx b/ui/src/components/IssueRunLedger.tsx index 9e72e95a8e..40e51043e5 100644 --- a/ui/src/components/IssueRunLedger.tsx +++ b/ui/src/components/IssueRunLedger.tsx @@ -121,7 +121,7 @@ const PENDING_LIVENESS_COPY: LivenessCopy = { const RETRY_PENDING_LIVENESS_COPY: LivenessCopy = { label: "Retry pending", - tone: "border-cyan-500/30 bg-cyan-500/10 text-cyan-700 dark:text-cyan-300", + tone: "border-blue-500/30 bg-blue-500/10 text-blue-700 dark:text-blue-300", description: "Paperclip queued an automatic retry that has not started yet.", }; @@ -734,8 +734,8 @@ export function IssueRunLedgerContent({ {statusLabel(run.status)} {run.isLive ? ( - - + + live ) : null} diff --git a/ui/src/components/IssueScheduledRetryCard.tsx b/ui/src/components/IssueScheduledRetryCard.tsx index 79c1f6812e..aeeb1802c9 100644 --- a/ui/src/components/IssueScheduledRetryCard.tsx +++ b/ui/src/components/IssueScheduledRetryCard.tsx @@ -69,12 +69,12 @@ export function IssueScheduledRetryCard({ return (
- + diff --git a/ui/src/components/LiveRunWidget.tsx b/ui/src/components/LiveRunWidget.tsx index 75e0525aac..027c74e37a 100644 --- a/ui/src/components/LiveRunWidget.tsx +++ b/ui/src/components/LiveRunWidget.tsx @@ -89,9 +89,9 @@ export function LiveRunWidget({ issueId, companyId }: LiveRunWidgetProps) { if (runs.length === 0) return null; return ( -
-
-
+
+
+
Live Runs
@@ -113,7 +113,7 @@ export function LiveRunWidget({ issueId, companyId }: LiveRunWidgetProps) {
{run.id.slice(0, 8)} @@ -135,7 +135,7 @@ export function LiveRunWidget({ issueId, companyId }: LiveRunWidgetProps) { )} Open run diff --git a/ui/src/components/OnboardingChat.tsx b/ui/src/components/OnboardingChat.tsx index 55af6fe7a4..0061ddf580 100644 --- a/ui/src/components/OnboardingChat.tsx +++ b/ui/src/components/OnboardingChat.tsx @@ -323,8 +323,8 @@ export function OnboardingChat({ {hasActiveRun ? ( <> - - + + {getRunStatusMessage(activeRun.status, agentName, elapsed)} @@ -468,8 +468,8 @@ function WelcomeMessage({ {!showMessage && (
- - + + {phase === "waking" ? `${agentName} is waking up...` diff --git a/ui/src/components/ProviderQuotaCard.tsx b/ui/src/components/ProviderQuotaCard.tsx index 38807aa772..bd20aedbe5 100644 --- a/ui/src/components/ProviderQuotaCard.tsx +++ b/ui/src/components/ProviderQuotaCard.tsx @@ -338,10 +338,10 @@ export function ProviderQuotaCard({ qw.usedPercent == null ? null : qw.usedPercent >= 90 - ? "bg-red-400" + ? "bg-(--status-task-blocked)" : qw.usedPercent >= 70 - ? "bg-yellow-400" - : "bg-green-400"; + ? "bg-(--status-task-todo)" + : "bg-(--status-task-done)"; return (
diff --git a/ui/src/components/timeline/WorkTimelineChart.tsx b/ui/src/components/timeline/WorkTimelineChart.tsx index 332b2cd392..f34a1b8a9a 100644 --- a/ui/src/components/timeline/WorkTimelineChart.tsx +++ b/ui/src/components/timeline/WorkTimelineChart.tsx @@ -439,7 +439,7 @@ export function WorkTimelineChart({ ); })} - {/* now line — teal "Signal" present marker */} + {/* now line — status-blue "Signal" present marker (gallery r2; was teal) */} {now >= layout.fromMs && now <= layout.toMs && ( 0 && "-ml-1.5", isRunning - ? "border-cyan-500/25 bg-cyan-500/[0.08] text-cyan-600 dark:text-cyan-300" + ? "border-blue-500/25 bg-blue-500/[0.08] text-blue-600 dark:text-blue-300" : "border-border/70 bg-background text-foreground/55", isRunning && "animate-pulse", )} @@ -934,7 +934,7 @@ function TranscriptCommandGroup({ item.status === "error" ? "border-red-500/25 bg-red-500/[0.08] text-red-600 dark:text-red-300" : item.status === "running" - ? "border-cyan-500/25 bg-cyan-500/[0.08] text-cyan-600 dark:text-cyan-300" + ? "border-blue-500/25 bg-blue-500/[0.08] text-blue-600 dark:text-blue-300" : "border-border/70 bg-background text-foreground/55", )}> @@ -985,7 +985,7 @@ function TranscriptToolGroup({ ? summarizeToolInput(runningItem.name, runningItem.input, density) : null; const statusTone = isRunning - ? "text-cyan-700 dark:text-cyan-300" + ? "text-blue-700 dark:text-blue-300" : "text-foreground/70"; return ( @@ -1008,7 +1008,7 @@ function TranscriptToolGroup({ "inline-flex h-6 w-6 items-center justify-center rounded-full border shadow-sm", index > 0 && "-ml-1.5", isItemRunning - ? "border-cyan-500/25 bg-cyan-500/[0.08] text-cyan-600 dark:text-cyan-300" + ? "border-blue-500/25 bg-blue-500/[0.08] text-blue-600 dark:text-blue-300" : isItemError ? "border-red-500/25 bg-red-500/[0.08] text-red-600 dark:text-red-300" : "border-border/70 bg-background text-foreground/55", @@ -1049,7 +1049,7 @@ function TranscriptToolGroup({ item.status === "error" ? "border-red-500/25 bg-red-500/[0.08] text-red-600 dark:text-red-300" : item.status === "running" - ? "border-cyan-500/25 bg-cyan-500/[0.08] text-cyan-600 dark:text-cyan-300" + ? "border-blue-500/25 bg-blue-500/[0.08] text-blue-600 dark:text-blue-300" : "border-border/70 bg-background text-foreground/55", )}> @@ -1106,8 +1106,8 @@ function TranscriptActivityRow({ ) : ( - - + + )}
status blue (value edit, site unchanged; originally extracted as rgba(6,182,212,0.08)). */ --shadow-extract-2: 0 20px 80px -40px rgba(0,0,0,0.55); /* Extracted from ui/src/components/BudgetPolicyCard.tsx (shadow-[0_20px_80px_-40px_rgba(0,0,0,0.55)]). */ --shadow-extract-3: 0 0 0 1px rgba(255,255,255,0.08); /* Extracted from ui/src/components/BudgetSidebarMarker.tsx (shadow-[0_0_0_1px_rgba(255,255,255,0.08)]). */ --shadow-extract-4: 0 -12px 28px rgba(15,23,42,0.08); /* Extracted from ui/src/components/ChatComposer.test.tsx (shadow-[0_-12px_28px_rgba(15,23,42,0.08)]). */ @@ -1691,10 +1691,10 @@ span.paperclip-mention-chip[data-mention-kind="external-object"] { --shadow-extract-8: 0 1px 0 rgba(15,23,42,0.02); /* Extracted from ui/src/components/IssueRecoveryActionCard.tsx (shadow-[0_1px_0_rgba(15,23,42,0.02)]). */ --shadow-extract-9: 0 18px 42px rgba(15,23,42,0.06); /* Extracted from ui/src/components/IssueThreadInteractionCard.tsx (shadow-[0_18px_42px_rgba(15,23,42,0.06)]). */ --shadow-extract-10: 0 1px 0 1px hsl(var(--border)); /* Extracted from ui/src/components/KeyboardShortcutsCheatsheet.tsx (shadow-[0_1px_0_1px_hsl(var(--border))]). */ - --shadow-extract-11: 0 18px 50px rgba(6,182,212,0.08); /* Extracted from ui/src/components/LiveRunWidget.tsx (shadow-[0_18px_50px_rgba(6,182,212,0.08)]). */ + --shadow-extract-11: 0 18px 50px rgba(37,99,235,0.08); /* LiveRunWidget.tsx glow. Gallery feedback r2: liveness glow recolored cyan->status blue (value edit, site unchanged; originally extracted as rgba(6,182,212,0.08)). */ --shadow-extract-12: 0 0 0 2px hsl(var(--background)); /* Extracted from ui/src/components/SidebarNavItem.tsx (shadow-[0_0_0_2px_hsl(var(--background))]). */ --shadow-extract-13: 0 0 0 3px rgba(245,158,11,0.18); /* Extracted from ui/src/components/environment-variables-editor/index.tsx (shadow-[0_0_0_3px_rgba(245,158,11,0.18)]). */ - --shadow-extract-14: 0 0 12px rgba(6,182,212,0.08); /* Extracted from ui/src/pages/AgentDetail.tsx (shadow-[0_0_12px_rgba(6,182,212,0.08)]). */ + --shadow-extract-14: 0 0 12px rgba(37,99,235,0.08); /* AgentDetail.tsx live-card glow. Gallery feedback r2: liveness glow recolored cyan->status blue (value edit, site unchanged; originally extracted as rgba(6,182,212,0.08)). */ --shadow-extract-18: 0 18px 44px -28px rgba(0,0,0,0.45); /* Extracted from ui/src/pages/ProfileSettings.tsx (shadow-[0_18px_44px_-28px_rgba(0,0,0,0.45)]). */ } diff --git a/ui/src/lib/interrupt-handoff.ts b/ui/src/lib/interrupt-handoff.ts index e2f1388b4d..f5c3d401b5 100644 --- a/ui/src/lib/interrupt-handoff.ts +++ b/ui/src/lib/interrupt-handoff.ts @@ -42,7 +42,7 @@ export function runStatusClassName(status: string): string { case "timed_out": return "text-orange-700 dark:text-orange-300"; case "running": - return "text-cyan-700 dark:text-cyan-300"; + return "text-blue-700 dark:text-blue-300"; case "queued": case "pending": return "text-amber-700 dark:text-amber-300"; diff --git a/ui/src/lib/runRetryState.ts b/ui/src/lib/runRetryState.ts index a8f71c3a3c..1cc33db189 100644 --- a/ui/src/lib/runRetryState.ts +++ b/ui/src/lib/runRetryState.ts @@ -66,7 +66,7 @@ export function describeRunRetryState(run: RetryAwareRun): RunRetryStateSummary return { kind: "scheduled", badgeLabel: isMaxTurnContinuation ? "Continuation scheduled" : "Retry scheduled", - tone: "border-cyan-500/30 bg-cyan-500/10 text-cyan-700 dark:text-cyan-300", + tone: "border-blue-500/30 bg-blue-500/10 text-blue-700 dark:text-blue-300", detail: joinFragments([attemptLabel, reasonLabel]), secondary: dueAt ? `${isMaxTurnContinuation ? "Next continuation" : "Next retry"} ${dueAt}` diff --git a/ui/src/lib/status-colors.ts b/ui/src/lib/status-colors.ts index c7133dfdaf..309f3a0434 100644 --- a/ui/src/lib/status-colors.ts +++ b/ui/src/lib/status-colors.ts @@ -262,7 +262,7 @@ export const priorityColorDefault = "text-yellow-600 dark:text-yellow-400"; // unknown → backlog hue (muted, dashed circle) // open → todo / blue // waiting → amber (distinct from internal in_progress yellow) -// running → cyan, animated when motion is allowed +// running → status blue (gallery r2; was cyan), animated when motion is allowed // succeeded → done / green // failed → red // blocked → red @@ -275,7 +275,7 @@ export const externalObjectStatusIcon: Record = { unknown: "text-muted-foreground border-muted-foreground", open: "text-blue-600 border-blue-600 dark:text-blue-400 dark:border-blue-400", waiting: "text-amber-600 border-amber-600 dark:text-amber-400 dark:border-amber-400", - running: "text-cyan-600 border-cyan-600 dark:text-cyan-400 dark:border-cyan-400", + running: "text-blue-600 border-blue-600 dark:text-blue-400 dark:border-blue-400", // Gallery feedback r2: running = status blue (pulse animation still distinguishes it from static blue `open`). succeeded: "text-green-600 border-green-600 dark:text-green-400 dark:border-green-400", merged: "text-violet-600 border-violet-600 dark:text-violet-400 dark:border-violet-400", failed: "text-red-600 border-red-600 dark:text-red-400 dark:border-red-400", @@ -292,7 +292,7 @@ export const externalObjectStatusBadge: Record = { unknown: "bg-muted text-muted-foreground", open: "bg-blue-100 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300", waiting: "bg-amber-100 text-amber-700 dark:bg-amber-900/50 dark:text-amber-300", - running: "bg-cyan-100 text-cyan-700 dark:bg-cyan-900/50 dark:text-cyan-300", + running: "bg-blue-100 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300", // Gallery feedback r2: running = status blue (now shares tint with `open`; liveness animation differentiates). succeeded: "bg-green-100 text-green-700 dark:bg-green-900/50 dark:text-green-300", failed: "bg-red-100 text-red-700 dark:bg-red-900/50 dark:text-red-300", blocked: "bg-red-100 text-red-700 dark:bg-red-900/50 dark:text-red-300", diff --git a/ui/src/lib/timeline/layout.ts b/ui/src/lib/timeline/layout.ts index 68b1d55398..0f27db9478 100644 --- a/ui/src/lib/timeline/layout.ts +++ b/ui/src/lib/timeline/layout.ts @@ -125,7 +125,7 @@ export function isCancelledStatus(status: string): boolean { * (kicked off by another actor) read blue; automation/self-started runs read * amber. The blue/amber pair is colour-blind-safe and holds contrast on both * light and dark backgrounds so the chart screenshots cleanly. Cancelled runs - * drop their fill entirely (rendered as a hollow dashed bar) and a teal "now" + * drop their fill entirely (rendered as a hollow dashed bar) and a status-blue "now" * line marks the present. */ export const TIMELINE_COLORS = { @@ -133,7 +133,7 @@ export const TIMELINE_COLORS = { automation: "#f4b740", /** stroke/ink for a hollow, cancelled bar. */ cancelled: "#9aa3ad", - now: "#2dd4bf", + now: "#2563eb", // Gallery feedback r2: "now" liveness marker = status blue (was teal #2dd4bf); shape (1.5px vertical line) still distinguishes it from #5b9bf6 delegated bars. } as const; export type RunSourceKind = "delegated" | "automation"; diff --git a/ui/src/pages/AgentDetail.tsx b/ui/src/pages/AgentDetail.tsx index c196c99b3e..b83f6e4312 100644 --- a/ui/src/pages/AgentDetail.tsx +++ b/ui/src/pages/AgentDetail.tsx @@ -477,7 +477,7 @@ function workspaceOperationStatusTone(status: WorkspaceOperation["status"]) { case "failed": return "border-red-500/20 bg-red-500/10 text-red-700 dark:text-red-300"; case "running": - return "border-cyan-500/20 bg-cyan-500/10 text-cyan-700 dark:text-cyan-300"; + return "border-blue-500/20 bg-blue-500/10 text-blue-700 dark:text-blue-300"; case "skipped": return "border-yellow-500/20 bg-yellow-500/10 text-yellow-700 dark:text-yellow-300"; default: @@ -1280,8 +1280,8 @@ function LatestRunCard({ runs, agentId }: { runs: HeartbeatRun[]; agentId: strin

{isLive && ( - - + + )} {isLive ? "Live Run" : "Latest Run"} @@ -1298,7 +1298,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-(--shadow-extract-14)" : "border-border" + isLive ? "border-blue-500/30 shadow-(--shadow-extract-14)" : "border-border" )} >
@@ -4132,10 +4132,10 @@ function LogViewer({ run, adapterType }: { run: HeartbeatRun; adapterType: strin )} {isLive && ( - + - - + + Live diff --git a/ui/src/pages/DesignGuide.tsx b/ui/src/pages/DesignGuide.tsx index 1d2c4e7cff..f89702ff6b 100644 --- a/ui/src/pages/DesignGuide.tsx +++ b/ui/src/pages/DesignGuide.tsx @@ -1402,10 +1402,10 @@ export function DesignGuide() {
[12:00:17] INFO Reconnected successfully
- - + + - Live + Live
diff --git a/ui/src/pages/IssueDetail.tsx b/ui/src/pages/IssueDetail.tsx index f0a2350456..95094441c9 100644 --- a/ui/src/pages/IssueDetail.tsx +++ b/ui/src/pages/IssueDetail.tsx @@ -3860,10 +3860,10 @@ export function IssueDetail() { {issue.identifier ?? issue.id.slice(0, 8)} {hasLiveRuns && ( - + - - + + Live