-
+
Viewing revision {selectedHistoricalRevision.revisionNumber}
@@ -415,7 +415,7 @@ export function PipelineItemBodyDocument({
/>
) : null}
actionsSlot={editing ? (
- ● Editing · unsaved
+ ● Editing · unsaved
) : (
diff --git a/ui/src/components/RoutineHistoryTab.tsx b/ui/src/components/RoutineHistoryTab.tsx
index bf9f7508f4a..13bdc28a450 100644
--- a/ui/src/components/RoutineHistoryTab.tsx
+++ b/ui/src/components/RoutineHistoryTab.tsx
@@ -335,7 +335,7 @@ function HistoricalPreviewBanner({
-
+
Viewing revision {revisionNumber} (read-only)
@@ -374,7 +374,7 @@ function ConflictBanner({
-
Unsaved routine edits
+
Unsaved routine edits
You changed {fieldsText} but haven't saved yet. Save or discard before previewing or
restoring an older revision.
@@ -465,7 +465,7 @@ function RevisionList({
)}
{revision.restoredFromRevisionId && (
-
+
Restored
)}
@@ -611,7 +611,7 @@ function RevisionPreview({
{row.value || — }
{row.differs && (
-
+
differs from current
)}
@@ -738,7 +738,7 @@ function RestoreConfirmDialog({
Previous run history is preserved.
{recreatedWebhookLabels.map((label) => (
-
+
The webhook trigger {label} will be recreated with a new URL and secret. Paperclip will
show the secret once after restore — copy it before closing.
@@ -858,10 +858,10 @@ function RoutineRevisionDiffModal({
{fieldChanges.map((change) => (
{change.field}
-
+
{change.oldValue ?? "—"}
-
+
{change.newValue ?? "—"}
@@ -907,8 +907,8 @@ function RevisionPicker({
tone: "red" | "green";
}) {
const toneClass = tone === "red"
- ? "border-red-500/30 bg-red-500/10 text-red-300"
- : "border-green-500/30 bg-green-500/10 text-green-300";
+ ? "border-red-500/30 bg-red-500/10 text-red-700 dark:text-red-300"
+ : "border-green-500/30 bg-green-500/10 text-green-700 dark:text-green-300";
return (
= {
context: "bg-transparent",
- removed: "bg-red-500/10 text-red-100",
- added: "bg-green-500/10 text-green-100",
+ removed: "bg-red-500/10 text-red-900 dark:text-red-100",
+ added: "bg-green-500/10 text-green-900 dark:text-green-100",
};
const markerByKind: Record = {
context: " ",
diff --git a/ui/src/components/RoutineSaveBar.tsx b/ui/src/components/RoutineSaveBar.tsx
index 9d0f6742400..5c7d2a5a8e9 100644
--- a/ui/src/components/RoutineSaveBar.tsx
+++ b/ui/src/components/RoutineSaveBar.tsx
@@ -79,7 +79,7 @@ export function RoutineSaveBar({
)}
>
{saveConflict ? (
-
+
Routine changed elsewhere. Reload to merge.
diff --git a/ui/src/components/agent-config-primitives.tsx b/ui/src/components/agent-config-primitives.tsx
index 6cfa9985d6d..0ffabc35b91 100644
--- a/ui/src/components/agent-config-primitives.tsx
+++ b/ui/src/components/agent-config-primitives.tsx
@@ -116,23 +116,14 @@ export function ToggleField({
{label}
{hint &&
}
- onChange(!checked)}
- >
-
-
+ checked={checked}
+ onCheckedChange={onChange}
+ />
);
}
diff --git a/ui/src/components/issue-output/OutputFileTile.tsx b/ui/src/components/issue-output/OutputFileTile.tsx
index 366b1311fbd..66227961679 100644
--- a/ui/src/components/issue-output/OutputFileTile.tsx
+++ b/ui/src/components/issue-output/OutputFileTile.tsx
@@ -3,9 +3,9 @@ import { getOutputFileGlyph, type OutputFileTone } from "@/lib/issue-output";
const TONE_CLASSES: Record = {
video: "bg-indigo-500/15 text-indigo-300",
- pdf: "bg-red-500/15 text-red-300",
- zip: "bg-amber-500/15 text-amber-300",
- image: "bg-emerald-500/15 text-emerald-300",
+ pdf: "bg-red-500/15 text-red-700 dark:text-red-300",
+ zip: "bg-amber-500/15 text-amber-700 dark:text-amber-300",
+ image: "bg-emerald-500/15 text-emerald-700 dark:text-emerald-300",
bin: "bg-muted text-muted-foreground",
};
diff --git a/ui/src/lib/status-colors.ts b/ui/src/lib/status-colors.ts
index 309f3a0434f..42a7de40c85 100644
--- a/ui/src/lib/status-colors.ts
+++ b/ui/src/lib/status-colors.ts
@@ -42,17 +42,42 @@ export const issueStatusText: Record = {
export const issueStatusTextDefault = "text-muted-foreground";
+// ---------------------------------------------------------------------------
+// Brand `.task-chip` status palette (PAP-75 / status-reference.html)
+//
+// Colour-named, 1px border, light + dark — values straight from paperclip.ing
+// `brand.css`. Shared by the agents section (PAP-80) and the All Projects page
+// (PAP-91); PAP-99 brings it to issue/task status chips, adding `violet` for
+// `in_review`.
+// ---------------------------------------------------------------------------
+
+export type BrandChipColor = "gray" | "blue" | "amber" | "green" | "violet" | "red";
+
+export const brandChipBadge: Record = {
+ gray: "bg-[#F5F3F0] text-[#52585D] border-[#A8AEB2] dark:bg-[#6e696024] dark:text-[#9A958A] dark:border-[#9e958a73]",
+ blue: "bg-[#DBEAFE] text-[#1D4ED8] border-[#2563EB] dark:bg-[#2563eb2e] dark:text-[#2563EB] dark:border-[#2563eb73]",
+ amber: "bg-[#FEF3C7] text-[#B45309] border-[#F59E0B] dark:bg-[#f59e0b24] dark:text-[#F59E0B] dark:border-[#f59e0b73]",
+ green: "bg-[#DCFCE7] text-[#188A3C] border-[#22C55E] dark:bg-[#22c55e1f] dark:text-[#22C55E] dark:border-[#22c55e73]",
+ violet: "bg-[#EDE9FE] text-[#5B21B6] border-[#7C3AED] dark:bg-[#7c3aed2e] dark:text-[#7C3AED] dark:border-[#7c3aed73]",
+ red: "bg-[#FEE2E2] text-[#991B1B] border-[#DC2626] dark:bg-[#dc26262e] dark:text-[#DC2626] dark:border-[#dc262673]",
+};
+
// ---------------------------------------------------------------------------
// Badge colors — used by StatusBadge for all entity types
// ---------------------------------------------------------------------------
export const statusBadge: Record = {
// Agent statuses
- active: "bg-green-100 text-green-700 dark:bg-green-900/50 dark:text-green-300",
- running: "bg-blue-100 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300", // Gallery feedback r1: running = status blue (matches in_progress liveness), not cyan.
+ // Gallery feedback r3: agent chips route through the brand chip families
+ // (bordered .task-chip recipes) instead of ad-hoc tints. NOTE: `active` has
+ // no canonical agent status — user-ruled mapping to the brand GREEN family;
+ // `idle` is the gray family (was a yellow/amber tint); `error` rides the
+ // shared run-status red entry below.
+ active: `border ${brandChipBadge.green}`,
+ running: `border ${brandChipBadge.blue}`, // r1 made this blue; r3 routes through brandChipBadge.blue.
scheduled_retry: "bg-sky-100 text-sky-700 dark:bg-sky-900/50 dark:text-sky-300",
- paused: "bg-orange-100 text-orange-700 dark:bg-orange-900/50 dark:text-orange-300",
- idle: "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/50 dark:text-yellow-300",
+ paused: `border ${brandChipBadge.amber}`,
+ idle: `border ${brandChipBadge.gray}`,
archived: "bg-muted text-muted-foreground",
// Goal statuses
@@ -126,25 +151,6 @@ export const agentStatusMotion: Record = {
error: "hb-blink",
};
-// ---------------------------------------------------------------------------
-// Brand `.task-chip` status palette (PAP-75 / status-reference.html)
-//
-// Colour-named, 1px border, light + dark — values straight from paperclip.ing
-// `brand.css`. Shared by the agents section (PAP-80) and the All Projects page
-// (PAP-91); PAP-99 brings it to issue/task status chips, adding `violet` for
-// `in_review`.
-// ---------------------------------------------------------------------------
-
-export type BrandChipColor = "gray" | "blue" | "amber" | "green" | "violet" | "red";
-
-export const brandChipBadge: Record = {
- gray: "bg-[#F5F3F0] text-[#52585D] border-[#A8AEB2] dark:bg-[#6e696024] dark:text-[#9A958A] dark:border-[#9e958a73]",
- blue: "bg-[#DBEAFE] text-[#1D4ED8] border-[#2563EB] dark:bg-[#2563eb2e] dark:text-[#2563EB] dark:border-[#2563eb73]",
- amber: "bg-[#FEF3C7] text-[#B45309] border-[#F59E0B] dark:bg-[#f59e0b24] dark:text-[#F59E0B] dark:border-[#f59e0b73]",
- green: "bg-[#DCFCE7] text-[#188A3C] border-[#22C55E] dark:bg-[#22c55e1f] dark:text-[#22C55E] dark:border-[#22c55e73]",
- violet: "bg-[#EDE9FE] text-[#5B21B6] border-[#7C3AED] dark:bg-[#7c3aed2e] dark:text-[#7C3AED] dark:border-[#7c3aed73]",
- red: "bg-[#FEE2E2] text-[#991B1B] border-[#DC2626] dark:bg-[#dc26262e] dark:text-[#DC2626] dark:border-[#dc262673]",
-};
/**
* Brand blue TEXT pair (the text hues of `brandChipBadge.blue`) for non-chip
diff --git a/ui/src/pages/AgentDetail.tsx b/ui/src/pages/AgentDetail.tsx
index b83f6e43128..bc838024bfd 100644
--- a/ui/src/pages/AgentDetail.tsx
+++ b/ui/src/pages/AgentDetail.tsx
@@ -963,7 +963,7 @@ export function AgentDetail() {
return (
{showLeftAgentNotice ? (
-
+
You left this agent. It no longer appears in your sidebar.
@@ -988,7 +988,7 @@ export function AgentDetail() {
/>
setDismissedLeftAgentIds((current) => new Set(current).add(agent.id))}
>
@@ -997,20 +997,20 @@ export function AgentDetail() {
) : null}
{hasInvalidOrgChain ? (
-
+
Invalid reporting chain
-
+
{agent.name} cannot accept tasks or start runs until its reporting chain is repaired.
-
+
{formatOrgChainHealthPath(agent)}
{agent.orgChainHealth?.repairGuidance ? (
-
{agent.orgChainHealth.repairGuidance}
+
{agent.orgChainHealth.repairGuidance}
) : (
-
+
Assign this agent to an active manager/root, or explicitly pause or terminate the affected agent/subtree.
)}
@@ -2156,7 +2156,7 @@ function PromptsTab({
{(bundle?.warnings ?? []).length > 0 && (
{(bundle?.warnings ?? []).map((warning) => (
-
+
{warning}
))}
@@ -2435,7 +2435,7 @@ function PromptsTab({
return (
-
+
virtual file
diff --git a/ui/src/pages/CompanyAccess.tsx b/ui/src/pages/CompanyAccess.tsx
index be09b51b9ce..24ef4b60619 100644
--- a/ui/src/pages/CompanyAccess.tsx
+++ b/ui/src/pages/CompanyAccess.tsx
@@ -249,7 +249,7 @@ export function CompanyAccess() {
{access && !access.currentUserRole && (
-
+
This account can manage access here through instance-admin privileges, but it does not currently hold an active company membership.
)}
diff --git a/ui/src/pages/CompanySkills.tsx b/ui/src/pages/CompanySkills.tsx
index 95f310effcd..1d023705d4f 100644
--- a/ui/src/pages/CompanySkills.tsx
+++ b/ui/src/pages/CompanySkills.tsx
@@ -422,13 +422,13 @@ function TrustChip({ level }: { level: CompanySkillTrustLevel }) {
icon: Folder,
label: "Includes assets",
tooltip: "Ships images, fonts, or other non-script files.",
- className: "border-cyan-500/30 bg-cyan-500/10 text-cyan-200",
+ className: "border-cyan-500/30 bg-cyan-500/10 text-cyan-800 dark:text-cyan-200",
},
scripts_executables: {
icon: AlertTriangle,
label: "Includes scripts",
tooltip: "Ships executable scripts. Review before installing.",
- className: "border-amber-500/40 bg-amber-500/10 text-amber-200",
+ className: "border-amber-500/40 bg-amber-500/10 text-amber-800 dark:text-amber-200",
},
} as const;
const config = map[level] ?? map.markdown_only;
@@ -453,7 +453,7 @@ function CompatChip({ compatibility }: { compatibility: CompanySkillCompatibilit
icon: HelpCircle,
label: "Unknown format",
tooltip: "Paperclip could not validate this skill as Agent Skills markdown. Install at your own risk.",
- className: "border-yellow-500/40 bg-yellow-500/10 text-yellow-200",
+ className: "border-yellow-500/40 bg-yellow-500/10 text-yellow-800 dark:text-yellow-200",
},
invalid: {
icon: XOctagon,
@@ -864,7 +864,7 @@ function SkillCard({ card, onOpen }: { card: DiscoveryCard; onOpen: (card: Disco
{card.installed ? (
-
+
Installed
) : null}
@@ -1727,7 +1727,7 @@ function CatalogDetailPane({
);
} else if (hashOutOfSync) {
cta = (
-
+
Update from catalog
@@ -1770,7 +1770,7 @@ function CatalogDetailPane({
{hashOutOfSync ? (
-
+
Update available
@@ -1908,7 +1908,7 @@ function InstallPreviewDialog({
{skill.trustLevel === "markdown_only" ? (
Safe
) : skill.trustLevel === "scripts_executables" ? (
- Review required
+ Review required
) : (
Non-script assets
)}
@@ -1952,7 +1952,7 @@ function InstallPreviewDialog({
{conflict ? (
-
+
An existing skill with key {conflict.key} is installed (
{conflict.sourceLabel ?? conflict.sourceType}). Installing will {defaultAction === "update" ? "overwrite the catalog content" : "replace the existing skill"}.
@@ -2456,8 +2456,8 @@ function SkillVersionDiffDialog({
);
const lineClassesByKind: Record
= {
context: "bg-transparent",
- removed: "bg-red-500/10 text-red-100",
- added: "bg-green-500/10 text-green-100",
+ removed: "bg-red-500/10 text-red-900 dark:text-red-100",
+ added: "bg-green-500/10 text-green-900 dark:text-green-100",
};
const markerByKind: Record = {
context: " ",
diff --git a/ui/src/pages/Dashboard.tsx b/ui/src/pages/Dashboard.tsx
index 4c78a1e32c2..68a0a9cca74 100644
--- a/ui/src/pages/Dashboard.tsx
+++ b/ui/src/pages/Dashboard.tsx
@@ -221,17 +221,17 @@ export function Dashboard() {
{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/Org.tsx b/ui/src/pages/Org.tsx
index 2cbc1816438..1cd2b8a9748 100644
--- a/ui/src/pages/Org.tsx
+++ b/ui/src/pages/Org.tsx
@@ -10,6 +10,7 @@ import { EmptyState } from "../components/EmptyState";
import { PageSkeleton } from "../components/PageSkeleton";
import { ChevronRight, GitBranch } from "lucide-react";
import { cn } from "../lib/utils";
+import { agentStatusDot, agentStatusDotDefault } from "../lib/status-colors";
function OrgTree({
nodes,
@@ -67,15 +68,9 @@ function OrgTreeNode({
{node.name}
diff --git a/ui/src/pages/ProjectDetail.tsx b/ui/src/pages/ProjectDetail.tsx
index 2be189a9d17..b9265a52fe4 100644
--- a/ui/src/pages/ProjectDetail.tsx
+++ b/ui/src/pages/ProjectDetail.tsx
@@ -729,7 +729,7 @@ export function ProjectDetail() {
return (
{showLeftProjectNotice ? (
-
+
You left this project. It no longer appears in your sidebar.
@@ -754,7 +754,7 @@ export function ProjectDetail() {
/>
setDismissedLeftProjectIds((current) => new Set(current).add(project.id))}
>
@@ -779,7 +779,7 @@ export function ProjectDetail() {
className="text-xl font-bold"
/>
{project.pauseReason === "budget" ? (
-
+
Paused by budget hard stop