@sentry/junior-dashboard 0.247.0 → 0.249.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/dist/app.js +69 -15
  2. package/dist/client.js +51 -50
  3. package/dist/index.js +69 -15
  4. package/dist/tailwind.css +1 -1
  5. package/package.json +3 -3
  6. package/src/client/App.tsx +1 -5
  7. package/src/client/components/ActorAvatar.tsx +7 -4
  8. package/src/client/components/AutomationCard.tsx +2 -2
  9. package/src/client/components/Button.tsx +12 -11
  10. package/src/client/components/ConversationList.tsx +3 -3
  11. package/src/client/components/ConversationSummary.tsx +2 -1
  12. package/src/client/components/DetailList.tsx +3 -3
  13. package/src/client/components/Drawer.tsx +2 -2
  14. package/src/client/components/EmptyTelemetry.tsx +1 -1
  15. package/src/client/components/Field.tsx +1 -2
  16. package/src/client/components/FilterBar.tsx +6 -6
  17. package/src/client/components/Metric.tsx +11 -16
  18. package/src/client/components/Notice.tsx +7 -7
  19. package/src/client/components/PageContentSkeleton.tsx +2 -2
  20. package/src/client/components/Pagination.tsx +2 -2
  21. package/src/client/components/ParticipantAvatarStack.tsx +4 -4
  22. package/src/client/components/ProfileMenu.tsx +5 -7
  23. package/src/client/components/README.md +122 -58
  24. package/src/client/components/SearchInput.tsx +4 -3
  25. package/src/client/components/SegmentedNav.tsx +10 -17
  26. package/src/client/components/SegmentedTabs.tsx +3 -3
  27. package/src/client/components/Select.tsx +1 -1
  28. package/src/client/components/SelectableRow.tsx +2 -2
  29. package/src/client/components/Skeleton.tsx +1 -1
  30. package/src/client/components/StatusChip.tsx +1 -1
  31. package/src/client/components/StatusDot.tsx +1 -1
  32. package/src/client/components/TextInput.tsx +1 -1
  33. package/src/client/components/Tooltip.tsx +2 -2
  34. package/src/client/components/VersionDriftBanner.tsx +2 -2
  35. package/src/client/components/charts/ActivityChart.tsx +5 -6
  36. package/src/client/components/charts/CacheWrites.tsx +3 -3
  37. package/src/client/components/charts/ChartHeader.tsx +4 -4
  38. package/src/client/components/charts/ChartLegend.tsx +1 -1
  39. package/src/client/components/charts/InputCacheChart.tsx +5 -5
  40. package/src/client/components/charts/WorkspaceUsageChart.tsx +4 -11
  41. package/src/client/components/controls/DirectorySortSelect.tsx +2 -2
  42. package/src/client/components/directory/DirectoryMetric.tsx +2 -2
  43. package/src/client/components/directory/DirectoryRowsSkeleton.tsx +5 -5
  44. package/src/client/components/directory/DirectoryTable.tsx +3 -3
  45. package/src/client/components/layout/CardHeader.tsx +4 -4
  46. package/src/client/components/layout/DashboardChrome.tsx +9 -3
  47. package/src/client/components/layout/DashboardHeader.tsx +7 -7
  48. package/src/client/components/layout/PageHeader.tsx +2 -2
  49. package/src/client/components/layout/SecondaryNavigation.tsx +7 -14
  50. package/src/client/components/layout/SectionIntro.tsx +1 -1
  51. package/src/client/components/layout/SectionTitle.tsx +1 -1
  52. package/src/client/components/metrics/StatCard.tsx +2 -2
  53. package/src/client/conversations/ConversationArchiveNotices.tsx +1 -1
  54. package/src/client/conversations/ConversationBrief.tsx +4 -4
  55. package/src/client/conversations/ConversationChildAgents.tsx +13 -4
  56. package/src/client/conversations/ConversationComposer.tsx +8 -7
  57. package/src/client/conversations/ConversationHeader.tsx +5 -5
  58. package/src/client/conversations/ConversationHeaderActions.tsx +9 -9
  59. package/src/client/conversations/ConversationHomeList.tsx +3 -3
  60. package/src/client/conversations/ConversationListStatusIcon.tsx +1 -1
  61. package/src/client/conversations/ConversationMemories.tsx +4 -4
  62. package/src/client/conversations/ConversationMeta.tsx +30 -11
  63. package/src/client/conversations/ConversationPage.tsx +13 -5
  64. package/src/client/conversations/ConversationSidebar.tsx +6 -6
  65. package/src/client/conversations/ConversationUsageBreakdown.tsx +278 -0
  66. package/src/client/conversations/ConversationWorkspace.tsx +1 -1
  67. package/src/client/conversations/ConversationWorkspaceLoading.tsx +4 -4
  68. package/src/client/conversations/CopyMarkdownButton.tsx +1 -1
  69. package/src/client/conversations/EventUsage.tsx +2 -2
  70. package/src/client/conversations/PendingMailboxStack.tsx +5 -5
  71. package/src/client/conversations/README.md +9 -0
  72. package/src/client/conversations/SubagentTranscriptDrawer.tsx +39 -23
  73. package/src/client/conversations/TelemetryMetrics.tsx +327 -180
  74. package/src/client/conversations/ToolFrame.tsx +36 -14
  75. package/src/client/conversations/TranscriptActivityGroup.tsx +10 -3
  76. package/src/client/conversations/TranscriptAttachmentsDeliveredView.tsx +4 -6
  77. package/src/client/conversations/TranscriptContextEventView.tsx +2 -2
  78. package/src/client/conversations/TranscriptEventView.tsx +1 -1
  79. package/src/client/conversations/TranscriptMarkdown.tsx +3 -3
  80. package/src/client/conversations/TranscriptMessageContextView.tsx +7 -7
  81. package/src/client/conversations/TranscriptMessageView.tsx +2 -6
  82. package/src/client/conversations/TranscriptRailEvent.tsx +20 -8
  83. package/src/client/conversations/TranscriptReasoningView.tsx +12 -12
  84. package/src/client/conversations/TranscriptStructuredEventView.tsx +16 -11
  85. package/src/client/conversations/TranscriptSubagentView.tsx +64 -39
  86. package/src/client/conversations/TranscriptText.tsx +5 -4
  87. package/src/client/conversations/TranscriptToolView.tsx +9 -11
  88. package/src/client/conversations/TranscriptTurnContextView.tsx +3 -3
  89. package/src/client/conversations/TranscriptView.tsx +3 -3
  90. package/src/client/conversations/UsageCard.tsx +172 -0
  91. package/src/client/conversations/eventTranscript.ts +7 -0
  92. package/src/client/conversations/transcriptMarkdownLinks.ts +2 -4
  93. package/src/client/conversations/transcriptStyles.ts +1 -1
  94. package/src/client/format.ts +1 -0
  95. package/src/client/pages/PersonalTokensPage.tsx +4 -4
  96. package/src/client/pages/admin/AdminPage.tsx +2 -2
  97. package/src/client/pages/automations/AutomationCostChart.tsx +2 -2
  98. package/src/client/pages/automations/AutomationDetailsDrawer.tsx +5 -10
  99. package/src/client/pages/automations/AutomationEditor.tsx +1 -1
  100. package/src/client/pages/automations/AutomationExecutionChart.tsx +2 -2
  101. package/src/client/pages/automations/AutomationExecutionStatusChart.tsx +2 -2
  102. package/src/client/pages/automations/AutomationExecutionsPage.tsx +4 -4
  103. package/src/client/pages/automations/AutomationRow.tsx +4 -4
  104. package/src/client/pages/automations/AutomationRunsPage.tsx +3 -3
  105. package/src/client/pages/automations/AutomationScheduleFields.tsx +1 -1
  106. package/src/client/pages/automations/AutomationVersionsPage.tsx +1 -1
  107. package/src/client/pages/code/CodeActivityChart.tsx +7 -6
  108. package/src/client/pages/code/CodeChangeRow.tsx +1 -1
  109. package/src/client/pages/code/CodePage.tsx +5 -5
  110. package/src/client/pages/code/RepositoryPage.tsx +2 -2
  111. package/src/client/pages/dev/ComponentsPage.tsx +40 -146
  112. package/src/client/pages/dev/TranscriptActivityFixtures.tsx +206 -0
  113. package/src/client/pages/locations/LocationDetailPage.tsx +4 -4
  114. package/src/client/pages/locations/LocationDirectory.tsx +1 -1
  115. package/src/client/pages/locations/PrivateActivityCard.tsx +3 -3
  116. package/src/client/pages/memory/MemoryCostChart.tsx +3 -5
  117. package/src/client/pages/memory/MemoryDetailsDrawer.tsx +5 -5
  118. package/src/client/pages/memory/MemoryPage.tsx +15 -15
  119. package/src/client/pages/memory/MemoryTimeline.tsx +3 -5
  120. package/src/client/pages/people/ContributionGrid.tsx +8 -5
  121. package/src/client/pages/people/PersonProfilePage.tsx +3 -6
  122. package/src/client/pages/people/ProfilePluginReports.tsx +2 -2
  123. package/src/client/pages/system/GuardianActivity.tsx +9 -9
  124. package/src/client/pages/system/PluginBarChart.tsx +4 -6
  125. package/src/client/pages/system/PluginDetails.tsx +11 -7
  126. package/src/client/pages/system/PluginPanels.tsx +8 -8
  127. package/src/client/pages/system/PluginReportRecordSet.tsx +14 -14
  128. package/src/client/pages/system/PluginReports.tsx +7 -11
  129. package/src/client/pages/system/SkillInventory.tsx +9 -9
  130. package/src/client/pages/system/SystemActivity.tsx +1 -1
  131. package/src/client/pages/system/SystemPage.tsx +3 -6
  132. package/src/client/pages/system/WorkspaceDetails.tsx +2 -5
  133. package/src/client/pages/system/WorkspaceEditor.tsx +2 -2
  134. package/src/client/pages/system/WorkspaceList.tsx +2 -2
  135. package/src/client/pages/user/PluginUserPage.tsx +3 -3
  136. package/src/client/styles.ts +5 -4
  137. package/src/client/types.ts +3 -0
  138. package/src/mock-reporting/fixtures.ts +73 -14
  139. package/src/tailwind.css +36 -38
@@ -26,11 +26,12 @@ export const TranscriptText = memo(function TranscriptText(props: {
26
26
  }
27
27
 
28
28
  return (
29
- <HighlightedCode
30
- code={block.code}
29
+ <div
30
+ className="min-w-0 overflow-hidden rounded-md border border-dashboard-border-subtle bg-dashboard-surface-panel px-3 py-2.5"
31
31
  key={index}
32
- language={block.language}
33
- />
32
+ >
33
+ <HighlightedCode code={block.code} language={block.language} />
34
+ </div>
34
35
  );
35
36
  })}
36
37
  </div>
@@ -1,5 +1,5 @@
1
1
  import { memo, useMemo } from "react";
2
- import { TriangleAlert } from "lucide-react";
2
+ import { TriangleAlert, Wrench } from "lucide-react";
3
3
 
4
4
  import { HighlightedCode } from "../code";
5
5
  import {
@@ -45,6 +45,12 @@ export const TranscriptToolView = memo(function TranscriptToolView(props: {
45
45
  const frame = (
46
46
  <ToolFrame
47
47
  expandable={hasDetails}
48
+ icon={props.part.status === "error" ? TriangleAlert : Wrench}
49
+ iconClassName={
50
+ props.part.status === "error"
51
+ ? "text-rose-300"
52
+ : "text-dashboard-text-faint"
53
+ }
48
54
  meta={meta}
49
55
  mobileSummaryMeta={mobileSummary}
50
56
  signature={signature}
@@ -78,14 +84,6 @@ function ToolSignature(props: {
78
84
 
79
85
  return (
80
86
  <>
81
- {failed ? (
82
- <TriangleAlert
83
- aria-hidden="true"
84
- className="shrink-0 !text-rose-300"
85
- size={12}
86
- strokeWidth={2.2}
87
- />
88
- ) : null}
89
87
  <ShimmerText
90
88
  active={shimmering}
91
89
  aria-label={statusLabel}
@@ -109,8 +107,8 @@ function ToolSignature(props: {
109
107
  function ToolPayload(props: { label: string; value: unknown }) {
110
108
  const code = useMemo(() => stringifyPartValue(props.value), [props.value]);
111
109
  return (
112
- <div className="min-w-0 max-w-full overflow-hidden bg-black/20 px-2.5 py-2">
113
- <div className="pb-1.5 font-mono text-2xs font-bold uppercase leading-none tracking-[0.08em] text-dashboard-text-muted">
110
+ <div className="min-w-0 max-w-full overflow-hidden border-dashboard-border-subtle px-3 py-2.5 [&+&]:border-t">
111
+ <div className="pb-1.5 font-sans text-xs font-medium leading-none text-dashboard-text-muted">
114
112
  {props.label}
115
113
  </div>
116
114
  <HighlightedCode code={code} language="json" />
@@ -24,7 +24,7 @@ export function TranscriptTurnContextView(props: {
24
24
  aria-expanded={open}
25
25
  aria-label="View turn context"
26
26
  className={cn(
27
- "inline-flex size-6 shrink-0 cursor-pointer items-center justify-center rounded text-dashboard-text-muted transition-colors hover:bg-dashboard-fill-hover hover:text-dashboard-text focus-visible:bg-dashboard-fill-hover focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-dashboard-focus",
27
+ "inline-flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-md text-dashboard-text-muted transition-colors hover:bg-dashboard-fill-hover hover:text-dashboard-text focus-visible:bg-dashboard-fill-hover focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-dashboard-focus",
28
28
  open && "bg-dashboard-fill-hover text-dashboard-text",
29
29
  )}
30
30
  onClick={() => setOpen(true)}
@@ -80,13 +80,13 @@ function TurnContext(props: { context: TranscriptViewTurnContext }) {
80
80
  {memory ? (
81
81
  <Brain
82
82
  aria-hidden="true"
83
- className="shrink-0 text-cyan-100/60"
83
+ className="shrink-0 text-dashboard-accent-text/60"
84
84
  size={15}
85
85
  />
86
86
  ) : (
87
87
  <Braces
88
88
  aria-hidden="true"
89
- className="shrink-0 text-cyan-100/60"
89
+ className="shrink-0 text-dashboard-accent-text/60"
90
90
  size={15}
91
91
  />
92
92
  )}
@@ -72,10 +72,10 @@ export function Transcript(props: {
72
72
  ) : null}
73
73
  {props.hasPreviousPage || props.loadingPreviousPage ? (
74
74
  <div className="mb-3 flex items-center gap-3">
75
- <span className="h-px min-w-4 flex-1 bg-white/[0.08]" />
75
+ <span className="h-px min-w-4 flex-1 bg-dashboard-fill-strong" />
76
76
  <button
77
77
  aria-label="Load earlier events"
78
- className="shrink-0 cursor-pointer border-0 bg-transparent px-1 py-0.5 font-sans text-xs font-medium text-dashboard-text-muted transition-colors hover:text-dashboard-text focus-visible:outline focus-visible:outline-1 focus-visible:outline-cyan-300/55 disabled:cursor-not-allowed disabled:opacity-50"
78
+ className="shrink-0 cursor-pointer border-0 bg-transparent px-1 py-0.5 font-sans text-xs font-medium text-dashboard-text-muted transition-colors hover:text-dashboard-text focus-visible:outline focus-visible:outline-1 focus-visible:outline-dashboard-focus/55 disabled:cursor-not-allowed disabled:opacity-50"
79
79
  disabled={props.loadingPreviousPage}
80
80
  onClick={() => {
81
81
  bottomPinning.preserveViewportForPrepend();
@@ -88,7 +88,7 @@ export function Transcript(props: {
88
88
  ? `Loading earlier ${historyLabel}…`
89
89
  : `Show earlier ${historyLabel}`}
90
90
  </button>
91
- <span className="h-px min-w-4 flex-1 bg-white/[0.08]" />
91
+ <span className="h-px min-w-4 flex-1 bg-dashboard-fill-strong" />
92
92
  </div>
93
93
  ) : null}
94
94
  {props.historyError ? (
@@ -0,0 +1,172 @@
1
+ import { cn } from "../styles";
2
+ import { ShimmerText } from "../components/ShimmerText";
3
+
4
+ export type UsageCardRow = {
5
+ label: string;
6
+ live?: boolean;
7
+ /** Render the label in the code face, such as a model id. */
8
+ code?: boolean;
9
+ value: string;
10
+ };
11
+
12
+ export type UsageCardSection = {
13
+ /** Rows rolled up into one "N more" line, with their combined value. */
14
+ more?: { count: number; value: string };
15
+ rows: UsageCardRow[];
16
+ title: string;
17
+ /** Section total shown after the title, such as all auxiliary cost. */
18
+ total?: string;
19
+ };
20
+
21
+ export type UsageCardSplit = {
22
+ count: number;
23
+ self: string;
24
+ /** Share of the total that belongs to this agent, from 0 to 1. */
25
+ selfShare: number;
26
+ subagents: string;
27
+ };
28
+
29
+ export type UsageCardProps = {
30
+ /** Closing hint, such as where to find the full breakdown. */
31
+ footer?: string;
32
+ /** Muted detail after the title, such as a compaction count. */
33
+ note?: string;
34
+ sections: UsageCardSection[];
35
+ split?: UsageCardSplit;
36
+ title: string;
37
+ total: string;
38
+ };
39
+
40
+ const SELF_FILL = "bg-dashboard-focus/80";
41
+ const SUBAGENT_FILL = "bg-dashboard-focus/30";
42
+
43
+ function Swatch(props: { className: string }) {
44
+ return (
45
+ <span
46
+ aria-hidden="true"
47
+ className={cn("size-2 shrink-0 rounded-xs", props.className)}
48
+ />
49
+ );
50
+ }
51
+
52
+ /**
53
+ * Summarize one usage total: the total up top, how it splits between this
54
+ * agent and its subagents, then the largest contributors. Long lists roll
55
+ * their tail into one "N more" row so the card never needs to scroll.
56
+ */
57
+ export function UsageCard(props: UsageCardProps) {
58
+ const selfPercent = Math.min(
59
+ 100,
60
+ Math.max(0, (props.split?.selfShare ?? 1) * 100),
61
+ );
62
+ return (
63
+ <span className="grid gap-3">
64
+ <span
65
+ className={cn(
66
+ "grid gap-2.5",
67
+ (props.sections.length > 0 || props.footer) &&
68
+ "border-b border-dashboard-border pb-3",
69
+ )}
70
+ >
71
+ <span className="flex items-baseline justify-between gap-3">
72
+ <span className="min-w-0 truncate">
73
+ {props.title}
74
+ {props.note ? (
75
+ <span className="text-dashboard-text-faint"> · {props.note}</span>
76
+ ) : null}
77
+ </span>
78
+ <span className="whitespace-nowrap text-lg font-semibold tabular-nums text-dashboard-text">
79
+ {props.total}
80
+ </span>
81
+ </span>
82
+ {props.split ? (
83
+ <>
84
+ <span
85
+ aria-hidden="true"
86
+ className="flex h-1.5 overflow-hidden rounded-full bg-dashboard-fill-hover"
87
+ >
88
+ <span
89
+ className={SELF_FILL}
90
+ style={{ width: `${selfPercent}%` }}
91
+ />
92
+ <span
93
+ className={SUBAGENT_FILL}
94
+ style={{ width: `${100 - selfPercent}%` }}
95
+ />
96
+ </span>
97
+ <span className="flex flex-wrap justify-between gap-x-3 gap-y-1 tabular-nums">
98
+ <span className="inline-flex items-center gap-1.5 whitespace-nowrap">
99
+ <Swatch className={SELF_FILL} />
100
+ this agent
101
+ <span className="font-medium text-dashboard-text">
102
+ {props.split.self}
103
+ </span>
104
+ </span>
105
+ <span className="inline-flex items-center gap-1.5 whitespace-nowrap">
106
+ <Swatch className={SUBAGENT_FILL} />
107
+ {props.split.count} subagent{props.split.count === 1 ? "" : "s"}
108
+ <span className="font-medium text-dashboard-text">
109
+ {props.split.subagents}
110
+ </span>
111
+ </span>
112
+ </span>
113
+ </>
114
+ ) : null}
115
+ </span>
116
+ {props.sections.map((section) => (
117
+ <span
118
+ className="grid grid-cols-[minmax(0,1fr)_auto] gap-x-3 gap-y-2"
119
+ key={section.title}
120
+ >
121
+ <span className="col-span-2 font-sans font-medium text-dashboard-text-faint">
122
+ {section.title}
123
+ {section.total ? ` · ${section.total}` : null}
124
+ </span>
125
+ {section.rows.map((row) => (
126
+ <span className="contents" key={row.label}>
127
+ <span
128
+ className={cn(
129
+ "flex min-w-0 items-baseline gap-2",
130
+ row.code && "font-mono text-dashboard-text",
131
+ )}
132
+ >
133
+ <span className="min-w-0 truncate" title={row.label}>
134
+ {row.label}
135
+ </span>
136
+ {row.live ? (
137
+ <span className="shrink-0 font-sans text-2xs text-dashboard-text-muted">
138
+ <ShimmerText active>in progress</ShimmerText>
139
+ </span>
140
+ ) : null}
141
+ </span>
142
+ <span className="whitespace-nowrap text-right tabular-nums text-dashboard-text">
143
+ {row.value}
144
+ </span>
145
+ </span>
146
+ ))}
147
+ {section.more ? (
148
+ <>
149
+ <span className="text-dashboard-text-faint">
150
+ {section.more.count} more
151
+ </span>
152
+ <span className="whitespace-nowrap text-right tabular-nums">
153
+ {section.more.value}
154
+ </span>
155
+ </>
156
+ ) : null}
157
+ </span>
158
+ ))}
159
+ {props.footer ? (
160
+ <span
161
+ className={cn(
162
+ "text-dashboard-text-faint",
163
+ props.sections.length > 0 &&
164
+ "border-t border-dashboard-border pt-3",
165
+ )}
166
+ >
167
+ {props.footer}
168
+ </span>
169
+ ) : null}
170
+ </span>
171
+ );
172
+ }
@@ -352,8 +352,12 @@ export function transcriptMessagesFromEvents(
352
352
  if (data.type === "subagent") {
353
353
  const subagentId = `${data.childConversationId}:${data.startedSeq}`;
354
354
  const existing = subagents.get(subagentId);
355
+ const finishedTimestamp =
356
+ data.status === "running" ? undefined : eventTimestamp(event);
355
357
  if (existing) {
356
358
  existing.status = data.status;
359
+ if (finishedTimestamp === undefined) delete existing.finishedTimestamp;
360
+ else existing.finishedTimestamp = finishedTimestamp;
357
361
  continue;
358
362
  }
359
363
  const part = {
@@ -362,6 +366,9 @@ export function transcriptMessagesFromEvents(
362
366
  childConversationId: data.childConversationId,
363
367
  subagentKind: data.subagentKind,
364
368
  status: data.status,
369
+ ...(finishedTimestamp === undefined
370
+ ? undefined
371
+ : { finishedTimestamp }),
365
372
  ...(data.agentName ? { agentName: data.agentName } : undefined),
366
373
  ...(data.task ? { task: data.task } : undefined),
367
374
  ...(data.title ? { title: data.title } : undefined),
@@ -1,5 +1,5 @@
1
1
  export const TRANSCRIPT_ANCHOR_CLASS =
2
- "font-medium text-cyan-100 underline decoration-cyan-300/35 underline-offset-2 transition-colors hover:text-dashboard-text hover:decoration-white";
2
+ "font-medium text-dashboard-accent-text underline decoration-dashboard-accent/35 underline-offset-2 transition-colors hover:text-dashboard-text hover:decoration-dashboard-text-solid";
3
3
 
4
4
  export type TranscriptMarkdownLink = {
5
5
  end: number;
@@ -36,9 +36,7 @@ export function findTranscriptMarkdownLinks(
36
36
  ...markdownLinks,
37
37
  ...autolinks,
38
38
  ...findBareLinks(text, bareRanges),
39
- ].sort(
40
- (left, right) => left.start - right.start || left.end - right.end,
41
- );
39
+ ].sort((left, right) => left.start - right.start || left.end - right.end);
42
40
  }
43
41
 
44
42
  function findMarkdownLinks(
@@ -5,6 +5,6 @@ export function transcriptEmptyClass(
5
5
  const colors =
6
6
  tone === "error"
7
7
  ? "border-rose-300/25 bg-rose-300/[0.07] text-rose-100"
8
- : "border-white/[0.07] bg-white/[0.025] text-dashboard-text-muted";
8
+ : "border-dashboard-border bg-dashboard-fill-soft text-dashboard-text-muted";
9
9
  return `rounded-lg border p-5 text-sm leading-relaxed ${colors}`;
10
10
  }
@@ -919,6 +919,7 @@ export function buildConversations(
919
919
  channel: summary.channel,
920
920
  channelName: summary.channelName,
921
921
  channelNameRedacted: summary.channelNameRedacted,
922
+ childAgentTotals: summary.childAgentTotals,
922
923
  cumulativeDurationMs: summary.cumulativeDurationMs,
923
924
  cumulativeUsage: summary.cumulativeUsage,
924
925
  displayTitle: summary.displayTitle,
@@ -110,11 +110,11 @@ export function PersonalTokensPage() {
110
110
 
111
111
  <Card className="mb-0 mt-6" padding="md" variant="raised">
112
112
  {createdToken ? (
113
- <div className="mt-5 rounded border border-emerald-400/40 bg-emerald-400/5 p-3">
113
+ <div className="mt-5 rounded-md border border-emerald-400/40 bg-emerald-400/5 p-3">
114
114
  <p className="mt-0 mb-2 text-sm font-semibold">
115
115
  Copy this token now. It won't be shown again.
116
116
  </p>
117
- <code className="block overflow-x-auto rounded bg-black p-2 text-xs text-emerald-300">
117
+ <code className="block overflow-x-auto rounded-md bg-dashboard-ink p-2 text-xs text-emerald-300">
118
118
  {createdToken.token}
119
119
  </code>
120
120
  <Button
@@ -166,10 +166,10 @@ export function PersonalTokensPage() {
166
166
  ) : (
167
167
  tokens.map((token) => (
168
168
  <div
169
- className="flex items-center gap-3 rounded border border-white/10 p-3"
169
+ className="flex items-center gap-3 rounded-md border border-dashboard-border-strong p-3"
170
170
  key={token.id}
171
171
  >
172
- <KeyRound className="text-[#beaaff]" size={16} />
172
+ <KeyRound className="text-dashboard-accent" size={16} />
173
173
  <div className="min-w-0 flex-1">
174
174
  <p className="m-0 truncate text-sm font-semibold">
175
175
  {token.name}
@@ -31,7 +31,7 @@ export function AdminPage(props: { pages: PluginUserPageLink[] }) {
31
31
  {adminPages.length === 0 ? (
32
32
  <Card padding="md">
33
33
  <div className="flex items-center gap-4">
34
- <div className="grid size-10 shrink-0 place-items-center rounded border border-white/[0.07] bg-white/[0.025] text-dashboard-text-muted">
34
+ <div className="grid size-10 shrink-0 place-items-center rounded-md border border-dashboard-border bg-dashboard-fill-soft text-dashboard-text-muted">
35
35
  <Boxes aria-hidden="true" size={17} />
36
36
  </div>
37
37
  <p className="m-0 text-sm text-dashboard-text-muted">
@@ -50,7 +50,7 @@ export function AdminPage(props: { pages: PluginUserPageLink[] }) {
50
50
  <Card padding="md">
51
51
  <div className="flex items-center gap-3">
52
52
  <div className="min-w-0 flex-1">
53
- <div className="font-mono text-xs uppercase tracking-[0.12em] text-dashboard-text-muted">
53
+ <div className="font-sans font-medium text-xs text-dashboard-text-muted">
54
54
  {page.pluginDisplayName}
55
55
  </div>
56
56
  <h2 className="mt-1 mb-0 font-display text-base font-medium text-dashboard-text">
@@ -45,7 +45,7 @@ export function AutomationCostChart(props: {
45
45
  <h2 className="m-0 font-display text-xl font-medium text-dashboard-text">
46
46
  {formatCostSummary({ total }) || "$0.00"}
47
47
  </h2>
48
- <p className="mt-1 mb-0 font-mono text-xs leading-relaxed text-dashboard-text-muted">
48
+ <p className="mt-1 mb-0 font-sans text-xs leading-relaxed text-dashboard-text-muted">
49
49
  Spend from conversations linked to completed automation executions.
50
50
  </p>
51
51
  </div>
@@ -112,7 +112,7 @@ export function AutomationCostChart(props: {
112
112
  />
113
113
  </ChartSvg>
114
114
  {!hasCost ? (
115
- <div className="pointer-events-none absolute inset-0 grid place-items-center pt-12 font-mono text-xs text-dashboard-text-muted">
115
+ <div className="pointer-events-none absolute inset-0 grid place-items-center pt-12 font-sans text-xs text-dashboard-text-muted">
116
116
  No linked spend in this period.
117
117
  </div>
118
118
  ) : null}
@@ -17,6 +17,7 @@ import {
17
17
  import { conversationPath } from "../../conversations/conversationRoutes";
18
18
  import { formatTime, peoplePath } from "../../format";
19
19
  import { TranscriptText } from "../../conversations/TranscriptText";
20
+ import { cn, dashboardInlineLinkClass } from "../../styles";
20
21
 
21
22
  /** Show one automation's instruction and metadata in a right-side slide-out. */
22
23
  export function AutomationDetailsDrawer(props: {
@@ -30,7 +31,7 @@ export function AutomationDetailsDrawer(props: {
30
31
  const { automation } = props;
31
32
  const createdBy = automation.createdByEmail ? (
32
33
  <Link
33
- className="font-semibold text-dashboard-text underline decoration-white/20 underline-offset-2 transition-colors hover:decoration-white/60"
34
+ className={cn("font-semibold", dashboardInlineLinkClass)}
34
35
  to={peoplePath(automation.createdByEmail)}
35
36
  >
36
37
  {automation.ownedByViewer ? "you" : automation.createdBy}
@@ -175,10 +176,7 @@ function AutomationExecutionSummary(props: {
175
176
  return (
176
177
  <div className="text-sm text-dashboard-text-muted">
177
178
  {automation.totalRuns > 0 ? (
178
- <Link
179
- className="text-dashboard-text underline decoration-white/20 underline-offset-2 hover:decoration-white/60"
180
- to={executionsPath}
181
- >
179
+ <Link className={dashboardInlineLinkClass} to={executionsPath}>
182
180
  {runCount} runs / {rangeLabel}
183
181
  </Link>
184
182
  ) : (
@@ -189,10 +187,7 @@ function AutomationExecutionSummary(props: {
189
187
  <span className="mx-2 opacity-45">·</span>
190
188
  <span>
191
189
  {automation.totalRuns > 0 ? (
192
- <Link
193
- className="text-dashboard-text underline decoration-white/20 underline-offset-2 hover:decoration-white/60"
194
- to={executionsPath}
195
- >
190
+ <Link className={dashboardInlineLinkClass} to={executionsPath}>
196
191
  {automation.totalRuns} total
197
192
  </Link>
198
193
  ) : (
@@ -201,7 +196,7 @@ function AutomationExecutionSummary(props: {
201
196
  {automation.lastRunAt ? " · Last run " : " · Never run"}
202
197
  {automation.lastRunAt && automation.lastConversationId ? (
203
198
  <Link
204
- className="text-dashboard-text underline decoration-white/20 underline-offset-2 hover:decoration-white/60"
199
+ className={dashboardInlineLinkClass}
205
200
  to={conversationPath(automation.lastConversationId)}
206
201
  >
207
202
  {formatAutomationRunTime(automation.lastRunAt)}
@@ -425,7 +425,7 @@ export function AutomationEditor(props: {
425
425
  <div className="flex shrink-0 gap-2">
426
426
  <Link
427
427
  to={props.returnPath}
428
- className="inline-flex min-h-11 items-center rounded border border-dashboard-border-emphasis px-3 text-sm text-dashboard-text no-underline sm:min-h-9"
428
+ className="inline-flex min-h-11 items-center rounded-md border border-dashboard-border-emphasis px-3 text-sm text-dashboard-text no-underline sm:min-h-9"
429
429
  >
430
430
  Cancel
431
431
  </Link>
@@ -45,7 +45,7 @@ export function AutomationExecutionChart(props: {
45
45
  <h2 className="m-0 font-display text-xl font-medium text-dashboard-text">
46
46
  {totals.reduce((sum, value) => sum + value, 0).toLocaleString()} runs
47
47
  </h2>
48
- <p className="mt-1 mb-0 font-mono text-xs leading-relaxed text-dashboard-text-muted">
48
+ <p className="mt-1 mb-0 font-sans text-xs leading-relaxed text-dashboard-text-muted">
49
49
  Completed automation executions over time.
50
50
  </p>
51
51
  </div>
@@ -104,7 +104,7 @@ export function AutomationExecutionChart(props: {
104
104
  />
105
105
  </ChartSvg>
106
106
  {!hasExecutions ? (
107
- <div className="pointer-events-none absolute inset-0 grid place-items-center pt-12 font-mono text-xs text-dashboard-text-muted">
107
+ <div className="pointer-events-none absolute inset-0 grid place-items-center pt-12 font-sans text-xs text-dashboard-text-muted">
108
108
  No automation executions in this period.
109
109
  </div>
110
110
  ) : null}
@@ -44,7 +44,7 @@ export function AutomationExecutionStatusChart(props: {
44
44
  <h2 className="m-0 font-display text-xl font-medium text-dashboard-text">
45
45
  Executions over time
46
46
  </h2>
47
- <p className="mt-1 mb-0 font-mono text-xs leading-relaxed text-dashboard-text-muted">
47
+ <p className="mt-1 mb-0 font-sans text-xs leading-relaxed text-dashboard-text-muted">
48
48
  {bucketUnit === "hour"
49
49
  ? "Terminal runs for this automation each hour."
50
50
  : bucketUnit === "6hour"
@@ -121,7 +121,7 @@ export function AutomationExecutionStatusChart(props: {
121
121
  />
122
122
  </ChartSvg>
123
123
  {!hasExecutions ? (
124
- <div className="pointer-events-none absolute inset-0 grid place-items-center pt-12 font-mono text-xs text-dashboard-text-muted">
124
+ <div className="pointer-events-none absolute inset-0 grid place-items-center pt-12 font-sans text-xs text-dashboard-text-muted">
125
125
  No automation executions in this period.
126
126
  </div>
127
127
  ) : null}
@@ -87,7 +87,7 @@ export function AutomationExecutionsPage(props: { enabled: boolean }) {
87
87
  : "Automation executions could not be loaded. Try again."}
88
88
  </InlineError>
89
89
  <Link
90
- className="mt-3 inline-flex items-center gap-2 font-mono text-xs text-dashboard-text-muted no-underline hover:text-dashboard-text"
90
+ className="mt-3 inline-flex items-center gap-2 font-sans text-xs text-dashboard-text-muted no-underline hover:text-dashboard-text"
91
91
  to={
92
92
  automationId ? automationPath(automationId) : "/automations/list"
93
93
  }
@@ -122,7 +122,7 @@ function AutomationExecutionsView(props: {
122
122
  <>
123
123
  <div>
124
124
  <Link
125
- className="mb-3 inline-flex items-center gap-2 font-mono text-xs text-dashboard-text-muted no-underline hover:text-dashboard-text"
125
+ className="mb-3 inline-flex items-center gap-2 font-sans text-xs text-dashboard-text-muted no-underline hover:text-dashboard-text"
126
126
  to={props.backTo}
127
127
  >
128
128
  <ArrowLeft aria-hidden="true" size={14} />
@@ -177,7 +177,7 @@ function AutomationExecutionsView(props: {
177
177
  <div className="min-w-[36rem]">
178
178
  <div
179
179
  className={cn(
180
- "sticky top-0 z-[1] hidden items-center gap-4 border-b border-dashboard-border-subtle bg-dashboard-overlay-soft px-4 py-2.5 font-mono text-xs uppercase tracking-[0.1em] text-dashboard-text-muted md:grid",
180
+ "sticky top-0 z-[1] hidden items-center gap-4 border-b border-dashboard-border-subtle bg-dashboard-overlay-soft px-4 py-2.5 font-sans font-medium text-xs text-dashboard-text-muted md:grid",
181
181
  EXECUTION_GRID,
182
182
  )}
183
183
  role="row"
@@ -290,7 +290,7 @@ function MetricCell(props: { label: string; value: string }) {
290
290
  <div className="min-w-0 max-md:flex max-md:items-center max-md:gap-2">
291
291
  <div
292
292
  aria-hidden="true"
293
- className="mb-1 hidden font-mono text-2xs uppercase tracking-[0.1em] text-dashboard-text-muted max-md:mb-0 max-md:block"
293
+ className="mb-1 hidden font-sans font-medium text-2xs text-dashboard-text-muted max-md:mb-0 max-md:block"
294
294
  >
295
295
  {props.label}
296
296
  </div>
@@ -58,7 +58,7 @@ export function AutomationRow(props: {
58
58
  <button
59
59
  aria-expanded={props.selected}
60
60
  aria-label={`View automation details: ${automation.title}`}
61
- className="block w-full min-w-0 cursor-pointer rounded border-0 bg-transparent p-0 text-left focus-visible:outline focus-visible:outline-2 focus-visible:outline-dashboard-focus"
61
+ className="block w-full min-w-0 cursor-pointer rounded-md border-0 bg-transparent p-0 text-left focus-visible:outline focus-visible:outline-2 focus-visible:outline-dashboard-focus"
62
62
  onClick={props.onSelect}
63
63
  type="button"
64
64
  >
@@ -88,7 +88,7 @@ export function AutomationRow(props: {
88
88
  <div className="mt-2.5 flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1 text-xs text-dashboard-text-muted">
89
89
  {automation.createdByEmail ? (
90
90
  <Link
91
- className="inline-flex min-w-0 max-w-full items-center gap-2 rounded text-dashboard-text no-underline hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-dashboard-focus"
91
+ className="inline-flex min-w-0 max-w-full items-center gap-2 rounded-md text-dashboard-text no-underline hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-dashboard-focus"
92
92
  title={automation.createdBy}
93
93
  to={peoplePath(automation.createdByEmail)}
94
94
  >
@@ -320,12 +320,12 @@ function AutomationActions(props: {
320
320
  <Link
321
321
  role="menuitem"
322
322
  to={props.editPath}
323
- className="flex min-h-11 items-center rounded px-3 text-sm text-dashboard-text no-underline hover:bg-dashboard-fill-hover focus-visible:outline focus-visible:outline-dashboard-focus"
323
+ className="flex min-h-11 items-center rounded-md px-3 text-sm text-dashboard-text no-underline hover:bg-dashboard-fill-hover focus-visible:outline focus-visible:outline-dashboard-focus"
324
324
  >
325
325
  Edit automation
326
326
  </Link>
327
327
  <button
328
- className="flex min-h-11 w-full cursor-pointer items-center gap-2 rounded border-0 bg-transparent px-3 text-sm text-rose-300 hover:bg-dashboard-fill-hover focus-visible:bg-dashboard-fill-hover focus-visible:outline focus-visible:outline-2 focus-visible:outline-dashboard-focus"
328
+ className="flex min-h-11 w-full cursor-pointer items-center gap-2 rounded-md border-0 bg-transparent px-3 text-sm text-rose-300 hover:bg-dashboard-fill-hover focus-visible:bg-dashboard-fill-hover focus-visible:outline focus-visible:outline-2 focus-visible:outline-dashboard-focus"
329
329
  onClick={() => {
330
330
  close();
331
331
  props.onDelete();
@@ -156,7 +156,7 @@ export function AutomationRunsPage(props: { enabled: boolean }) {
156
156
  <div className="min-w-[44rem]">
157
157
  <div
158
158
  className={cn(
159
- "sticky top-0 z-[1] hidden items-center gap-4 border-b border-dashboard-border-subtle bg-dashboard-overlay-soft px-4 py-2.5 font-mono text-xs uppercase tracking-[0.1em] text-dashboard-text-muted md:grid",
159
+ "sticky top-0 z-[1] hidden items-center gap-4 border-b border-dashboard-border-subtle bg-dashboard-overlay-soft px-4 py-2.5 font-sans font-medium text-xs text-dashboard-text-muted md:grid",
160
160
  RUN_GRID,
161
161
  )}
162
162
  role="row"
@@ -278,7 +278,7 @@ function MetricCell(props: { label: string; value: string }) {
278
278
  <div className="min-w-0 max-md:flex max-md:items-center max-md:gap-2">
279
279
  <div
280
280
  aria-hidden="true"
281
- className="mb-1 hidden font-mono text-2xs uppercase tracking-[0.1em] text-dashboard-text-muted max-md:mb-0 max-md:block"
281
+ className="mb-1 hidden font-sans font-medium text-2xs text-dashboard-text-muted max-md:mb-0 max-md:block"
282
282
  >
283
283
  {props.label}
284
284
  </div>
@@ -297,7 +297,7 @@ function AutomationKindIcon(props: { kind: AutomationRun["kind"] }) {
297
297
  return (
298
298
  <span
299
299
  aria-label={label}
300
- className="inline-flex size-3.5 shrink-0 items-center justify-center text-cyan-300/80"
300
+ className="inline-flex size-3.5 shrink-0 items-center justify-center text-dashboard-accent/80"
301
301
  role="img"
302
302
  title={label}
303
303
  >
@@ -152,7 +152,7 @@ export function AutomationScheduleFields(props: {
152
152
  })
153
153
  }
154
154
  className={cn(
155
- "min-h-11 cursor-pointer rounded border px-1 text-xs font-medium capitalize focus-visible:outline-2 focus-visible:outline-dashboard-focus sm:min-h-10 sm:text-sm",
155
+ "min-h-11 cursor-pointer rounded-md border px-1 text-xs font-medium capitalize focus-visible:outline-2 focus-visible:outline-dashboard-focus sm:min-h-10 sm:text-sm",
156
156
  value.weekdays?.includes(day)
157
157
  ? "border-dashboard-focus/50 bg-dashboard-focus/10 text-dashboard-focus"
158
158
  : "border-dashboard-border-emphasis text-dashboard-text-muted hover:bg-dashboard-fill-hover",
@@ -77,7 +77,7 @@ export function AutomationVersionsPage(props: { enabled: boolean }) {
77
77
  function BackLink(props: { to: string }) {
78
78
  return (
79
79
  <Link
80
- className="mb-3 inline-flex items-center gap-2 font-mono text-xs text-dashboard-text-muted no-underline hover:text-dashboard-text"
80
+ className="mb-3 inline-flex items-center gap-2 font-sans text-xs text-dashboard-text-muted no-underline hover:text-dashboard-text"
81
81
  to={props.to}
82
82
  >
83
83
  <ArrowLeft aria-hidden="true" size={14} />