@sentry/junior-dashboard 0.248.0 → 0.250.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/README.md +3 -0
  2. package/dist/app.js +2 -2
  3. package/dist/client.js +40 -38
  4. package/dist/index.js +2 -2
  5. package/dist/tailwind.css +1 -1
  6. package/package.json +3 -3
  7. package/src/client/App.tsx +19 -5
  8. package/src/client/components/ActorAvatar.tsx +7 -4
  9. package/src/client/components/AutomationCard.tsx +2 -2
  10. package/src/client/components/Button.tsx +12 -11
  11. package/src/client/components/ConversationList.tsx +3 -3
  12. package/src/client/components/ConversationSummary.tsx +2 -1
  13. package/src/client/components/DetailList.tsx +3 -3
  14. package/src/client/components/Drawer.tsx +2 -2
  15. package/src/client/components/EmptyTelemetry.tsx +1 -1
  16. package/src/client/components/Field.tsx +1 -2
  17. package/src/client/components/FilterBar.tsx +6 -6
  18. package/src/client/components/Metric.tsx +4 -4
  19. package/src/client/components/Notice.tsx +7 -7
  20. package/src/client/components/PageContentSkeleton.tsx +2 -2
  21. package/src/client/components/Pagination.tsx +2 -2
  22. package/src/client/components/ParticipantAvatarStack.tsx +4 -4
  23. package/src/client/components/ProfileMenu.tsx +17 -7
  24. package/src/client/components/README.md +122 -58
  25. package/src/client/components/SearchInput.tsx +4 -3
  26. package/src/client/components/SegmentedNav.tsx +10 -17
  27. package/src/client/components/SegmentedTabs.tsx +3 -3
  28. package/src/client/components/Select.tsx +1 -1
  29. package/src/client/components/SelectableRow.tsx +2 -2
  30. package/src/client/components/Skeleton.tsx +1 -1
  31. package/src/client/components/StatusChip.tsx +1 -1
  32. package/src/client/components/StatusDot.tsx +1 -1
  33. package/src/client/components/TextInput.tsx +1 -1
  34. package/src/client/components/Tooltip.tsx +2 -2
  35. package/src/client/components/VersionDriftBanner.tsx +2 -2
  36. package/src/client/components/charts/ActivityChart.tsx +5 -6
  37. package/src/client/components/charts/CacheWrites.tsx +3 -3
  38. package/src/client/components/charts/ChartHeader.tsx +4 -4
  39. package/src/client/components/charts/ChartLegend.tsx +1 -1
  40. package/src/client/components/charts/InputCacheChart.tsx +5 -5
  41. package/src/client/components/charts/WorkspaceUsageChart.tsx +4 -11
  42. package/src/client/components/controls/DirectorySortSelect.tsx +2 -2
  43. package/src/client/components/directory/DirectoryMetric.tsx +2 -2
  44. package/src/client/components/directory/DirectoryRowsSkeleton.tsx +5 -5
  45. package/src/client/components/directory/DirectoryTable.tsx +3 -3
  46. package/src/client/components/layout/CardHeader.tsx +4 -4
  47. package/src/client/components/layout/DashboardChrome.tsx +9 -3
  48. package/src/client/components/layout/DashboardHeader.tsx +7 -7
  49. package/src/client/components/layout/PageHeader.tsx +2 -2
  50. package/src/client/components/layout/SecondaryNavigation.tsx +7 -14
  51. package/src/client/components/layout/SectionIntro.tsx +1 -1
  52. package/src/client/components/layout/SectionTitle.tsx +1 -1
  53. package/src/client/components/metrics/StatCard.tsx +2 -2
  54. package/src/client/conversations/ConversationArchiveNotices.tsx +1 -1
  55. package/src/client/conversations/ConversationBrief.tsx +4 -4
  56. package/src/client/conversations/ConversationChildAgents.tsx +7 -4
  57. package/src/client/conversations/ConversationComposer.tsx +8 -7
  58. package/src/client/conversations/ConversationHeader.tsx +5 -5
  59. package/src/client/conversations/ConversationHeaderActions.tsx +9 -9
  60. package/src/client/conversations/ConversationHomeList.tsx +3 -3
  61. package/src/client/conversations/ConversationListStatusIcon.tsx +1 -1
  62. package/src/client/conversations/ConversationMemories.tsx +4 -4
  63. package/src/client/conversations/ConversationMeta.tsx +10 -10
  64. package/src/client/conversations/ConversationPage.tsx +2 -1
  65. package/src/client/conversations/ConversationSidebar.tsx +6 -6
  66. package/src/client/conversations/ConversationUsageBreakdown.tsx +4 -4
  67. package/src/client/conversations/ConversationWorkspace.tsx +1 -1
  68. package/src/client/conversations/ConversationWorkspaceLoading.tsx +4 -4
  69. package/src/client/conversations/CopyMarkdownButton.tsx +1 -1
  70. package/src/client/conversations/EventUsage.tsx +2 -2
  71. package/src/client/conversations/PendingMailboxStack.tsx +5 -5
  72. package/src/client/conversations/README.md +9 -0
  73. package/src/client/conversations/SubagentTranscriptDrawer.tsx +39 -23
  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 +1 -1
  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/pages/ConnectionsPage.tsx +207 -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/ChartFixtures.tsx +265 -21
  112. package/src/client/pages/dev/ComponentsPage.tsx +40 -146
  113. package/src/client/pages/dev/TranscriptActivityFixtures.tsx +206 -0
  114. package/src/client/pages/locations/LocationDetailPage.tsx +4 -4
  115. package/src/client/pages/locations/LocationDirectory.tsx +1 -1
  116. package/src/client/pages/locations/PrivateActivityCard.tsx +3 -3
  117. package/src/client/pages/memory/MemoryCostChart.tsx +3 -5
  118. package/src/client/pages/memory/MemoryDetailsDrawer.tsx +5 -5
  119. package/src/client/pages/memory/MemoryPage.tsx +15 -15
  120. package/src/client/pages/memory/MemoryTimeline.tsx +3 -5
  121. package/src/client/pages/people/ContributionGrid.tsx +8 -5
  122. package/src/client/pages/people/PersonProfilePage.tsx +3 -6
  123. package/src/client/pages/people/ProfilePluginReports.tsx +2 -2
  124. package/src/client/pages/system/GuardianActivity.tsx +9 -9
  125. package/src/client/pages/system/PluginBarChart.tsx +4 -6
  126. package/src/client/pages/system/PluginDetails.tsx +11 -7
  127. package/src/client/pages/system/PluginPanels.tsx +8 -8
  128. package/src/client/pages/system/PluginReportRecordSet.tsx +14 -14
  129. package/src/client/pages/system/PluginReports.tsx +7 -11
  130. package/src/client/pages/system/SkillInventory.tsx +9 -9
  131. package/src/client/pages/system/SystemActivity.tsx +1 -1
  132. package/src/client/pages/system/SystemPage.tsx +3 -6
  133. package/src/client/pages/system/WorkspaceDetails.tsx +2 -5
  134. package/src/client/pages/system/WorkspaceEditor.tsx +2 -2
  135. package/src/client/pages/system/WorkspaceList.tsx +2 -2
  136. package/src/client/pages/user/PluginUserPage.tsx +3 -3
  137. package/src/client/styles.ts +5 -4
  138. package/src/client/types.ts +2 -0
  139. package/src/tailwind.css +36 -38
@@ -0,0 +1,206 @@
1
+ import { TranscriptSubagentView } from "../../conversations/TranscriptSubagentView";
2
+ import { TranscriptToolView } from "../../conversations/TranscriptToolView";
3
+ import type {
4
+ TranscriptViewSubagentPart,
5
+ TranscriptViewToolCallPart,
6
+ } from "../../types";
7
+
8
+ type ToolCallFixture = {
9
+ description: string;
10
+ part: TranscriptViewToolCallPart;
11
+ timestamp: number;
12
+ };
13
+
14
+ const TOOL_CALL_TIMESTAMP = Date.UTC(2026, 4, 1, 16);
15
+
16
+ const TOOL_CALL_FIXTURES = [
17
+ {
18
+ description: "Default completed tool with normalized arguments",
19
+ part: {
20
+ id: "gallery-search",
21
+ input: {
22
+ query: "release regression",
23
+ limit: 25,
24
+ options: { includeArchived: false },
25
+ },
26
+ name: "searchIssues",
27
+ output: { matches: 3 },
28
+ resultTimestamp: TOOL_CALL_TIMESTAMP + 1_842,
29
+ status: "completed",
30
+ type: "tool_call",
31
+ },
32
+ timestamp: TOOL_CALL_TIMESTAMP,
33
+ },
34
+ {
35
+ description: "Running webSearch with name-only shimmer",
36
+ part: {
37
+ id: "gallery-running",
38
+ input: {
39
+ query: "service:checkout status:error",
40
+ max_results: 50,
41
+ },
42
+ name: "webSearch",
43
+ status: "running",
44
+ type: "tool_call",
45
+ },
46
+ timestamp: TOOL_CALL_TIMESTAMP + 3_000,
47
+ },
48
+ {
49
+ description: "Failed tool",
50
+ part: {
51
+ id: "gallery-error",
52
+ input: {
53
+ command: "jr-rpc config get github.repo",
54
+ timeout_ms: 10_000,
55
+ },
56
+ name: "bash",
57
+ output: { error: "configuration unavailable" },
58
+ resultTimestamp: TOOL_CALL_TIMESTAMP + 6_416,
59
+ status: "error",
60
+ type: "tool_call",
61
+ },
62
+ timestamp: TOOL_CALL_TIMESTAMP + 6_000,
63
+ },
64
+ {
65
+ description: "Known loadSkill signature",
66
+ part: {
67
+ id: "gallery-load-skill",
68
+ input: { skill_name: "junior-qa" },
69
+ name: "loadSkill",
70
+ output: { skill_name: "junior-qa" },
71
+ resultTimestamp: TOOL_CALL_TIMESTAMP + 8_105,
72
+ status: "completed",
73
+ type: "tool_call",
74
+ },
75
+ timestamp: TOOL_CALL_TIMESTAMP + 8_000,
76
+ },
77
+ {
78
+ description: "Known executeTool signature with nested arguments",
79
+ part: {
80
+ id: "gallery-execute-tool",
81
+ input: {
82
+ tool_name: "github_search",
83
+ arguments: { query: "is:pr is:open", limit: 25 },
84
+ },
85
+ name: "executeTool",
86
+ output: { matches: 3 },
87
+ resultTimestamp: TOOL_CALL_TIMESTAMP + 10_723,
88
+ status: "completed",
89
+ type: "tool_call",
90
+ },
91
+ timestamp: TOOL_CALL_TIMESTAMP + 10_000,
92
+ },
93
+ {
94
+ description: "Long generic arguments exercise both truncation limits",
95
+ part: {
96
+ id: "gallery-long",
97
+ input: {
98
+ project: "payments-checkout-platform",
99
+ query:
100
+ "Find every regression associated with the most recent production deployment and include the complete evidence trail",
101
+ environment: "production",
102
+ includeResolved: false,
103
+ ignoredAfterFourEntries: "not shown in the collapsed preview",
104
+ },
105
+ name: "investigateDeploy",
106
+ output: { channel_id: "C123" },
107
+ resultTimestamp: TOOL_CALL_TIMESTAMP + 13_250,
108
+ status: "completed",
109
+ type: "tool_call",
110
+ },
111
+ timestamp: TOOL_CALL_TIMESTAMP + 12_000,
112
+ },
113
+ {
114
+ description: "Completed tool without argument or result payloads",
115
+ part: {
116
+ id: "gallery-empty",
117
+ name: "systemTime",
118
+ status: "completed",
119
+ type: "tool_call",
120
+ },
121
+ timestamp: TOOL_CALL_TIMESTAMP + 15_000,
122
+ },
123
+ ] as const satisfies readonly ToolCallFixture[];
124
+
125
+ const SUBAGENT_STARTED = Date.UTC(2026, 4, 1, 16);
126
+
127
+ const SUBAGENT_FIXTURES: readonly TranscriptViewSubagentPart[] = [
128
+ {
129
+ agentName: "planner",
130
+ childConversationId: "gallery-planner",
131
+ id: "gallery-planner",
132
+ status: "running",
133
+ subagentKind: "agent",
134
+ type: "subagent",
135
+ title: "Review the dashboard plan",
136
+ },
137
+ {
138
+ agentName: "reviewer",
139
+ childConversationId: "gallery-reviewer",
140
+ finishedTimestamp: SUBAGENT_STARTED + 16_000,
141
+ id: "gallery-reviewer",
142
+ status: "completed",
143
+ subagentKind: "agent",
144
+ type: "subagent",
145
+ title: "Check the pull request against the repository rules",
146
+ },
147
+ {
148
+ agentName: "github",
149
+ childConversationId: "gallery-github",
150
+ finishedTimestamp: SUBAGENT_STARTED + 4_000,
151
+ id: "gallery-github",
152
+ status: "blocked",
153
+ subagentKind: "agent",
154
+ type: "subagent",
155
+ },
156
+ {
157
+ agentName: "deploy",
158
+ childConversationId: "gallery-deploy",
159
+ finishedTimestamp: SUBAGENT_STARTED + 92_000,
160
+ id: "gallery-deploy",
161
+ status: "error",
162
+ subagentKind: "agent",
163
+ type: "subagent",
164
+ task: "Roll back payments-v42 in us-west1 and confirm the canary error rate.",
165
+ },
166
+ ];
167
+
168
+ /** Render typed transcript tool states for visual regression and interaction checks. */
169
+ export function ToolCallGallery() {
170
+ return (
171
+ <div className="min-w-0 overflow-hidden rounded-lg border border-dashboard-border bg-dashboard-fill-faint">
172
+ <div className="border-b border-dashboard-border-subtle px-2.5 py-1.5 font-sans text-xs text-dashboard-text-muted">
173
+ Activity lane · click a row for arguments and result
174
+ </div>
175
+ <div className="grid min-w-0 gap-1 px-2 py-1.5">
176
+ {TOOL_CALL_FIXTURES.map((fixture) => (
177
+ <div className="grid min-w-0 gap-1" key={fixture.part.id}>
178
+ <div className="font-sans font-medium text-2xs text-dashboard-text-muted">
179
+ {fixture.description}
180
+ </div>
181
+ <TranscriptToolView
182
+ part={fixture.part}
183
+ timestamp={fixture.timestamp}
184
+ />
185
+ </div>
186
+ ))}
187
+ </div>
188
+ </div>
189
+ );
190
+ }
191
+
192
+ /** Show subagent cards in each lifecycle status, with and without a title. */
193
+ export function SubagentCardFixture() {
194
+ return (
195
+ <div className="grid min-w-0 gap-2">
196
+ {SUBAGENT_FIXTURES.map((part) => (
197
+ <TranscriptSubagentView
198
+ key={part.id}
199
+ onOpenTranscript={() => undefined}
200
+ part={part}
201
+ timestamp={SUBAGENT_STARTED}
202
+ />
203
+ ))}
204
+ </div>
205
+ );
206
+ }
@@ -92,12 +92,12 @@ function LocationDetail(props: { detail: LocationDetailReport }) {
92
92
  <LocationActivityChart days={detail.activityDays} />
93
93
 
94
94
  <Card>
95
- <div className="flex items-center gap-3 border-b border-white/[0.06] px-4 py-4">
96
- <span className="grid size-9 place-items-center rounded border border-cyan-400/15 bg-cyan-400/[0.06] text-cyan-300">
95
+ <div className="flex items-center gap-3 border-b border-dashboard-border-subtle px-4 py-4">
96
+ <span className="grid size-9 place-items-center rounded-md border border-dashboard-accent/15 bg-dashboard-accent/[0.06] text-dashboard-accent">
97
97
  <MapPin aria-hidden="true" size={16} />
98
98
  </span>
99
99
  <div>
100
- <h3 className="m-0 font-mono text-xs font-medium uppercase tracking-[0.14em] text-dashboard-text-muted">
100
+ <h3 className="m-0 font-sans text-xs font-medium text-dashboard-text-muted">
101
101
  People seen here
102
102
  </h3>
103
103
  <p className="mt-1 mb-0 font-mono text-xs text-dashboard-text-muted">
@@ -127,7 +127,7 @@ function LocationDetail(props: { detail: LocationDetailReport }) {
127
127
  </>
128
128
  );
129
129
  const className =
130
- "min-w-0 border-b border-r border-white/[0.055] px-4 py-3.5 transition-colors hover:bg-white/[0.03]";
130
+ "min-w-0 border-b border-r border-dashboard-border-subtle px-4 py-3.5 transition-colors hover:bg-dashboard-fill-soft";
131
131
  return item.actor.email ? (
132
132
  <Link
133
133
  className={`${className} text-inherit no-underline`}
@@ -76,7 +76,7 @@ export function LocationDirectory(props: {
76
76
  <>Last active {formatRelativeTime(location.lastSeenAt)}</>
77
77
  }
78
78
  icon={<Hash aria-hidden="true" size={16} strokeWidth={1.8} />}
79
- iconClassName="bg-cyan-400/[0.06] text-cyan-300 group-hover:border-cyan-400/25"
79
+ iconClassName="bg-dashboard-accent/[0.06] text-dashboard-accent group-hover:border-dashboard-accent/25"
80
80
  title={location.label}
81
81
  />
82
82
  <DirectoryMetric
@@ -9,14 +9,14 @@ export function PrivateActivityCard(props: { item: ConversationStatsItem }) {
9
9
  return (
10
10
  <Card className="opacity-80" padding="sm">
11
11
  <div className="grid grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-3 max-sm:grid-cols-[auto_minmax(0,1fr)]">
12
- <span className="grid size-9 shrink-0 place-items-center rounded border border-white/[0.08] bg-white/[0.025] text-dashboard-text-muted">
12
+ <span className="grid size-9 shrink-0 place-items-center rounded-md border border-dashboard-border bg-dashboard-fill-soft text-dashboard-text-muted">
13
13
  <LockKeyhole aria-hidden="true" size={15} />
14
14
  </span>
15
15
  <div className="min-w-0">
16
16
  <div className="font-display text-base font-medium text-dashboard-text">
17
17
  Private activity
18
18
  </div>
19
- <div className="mt-1 font-mono text-xs leading-relaxed text-dashboard-text-muted">
19
+ <div className="mt-1 font-sans text-xs leading-relaxed text-dashboard-text-muted">
20
20
  DMs, private channels, and unknown visibility stay combined and
21
21
  unlinked.
22
22
  </div>
@@ -25,7 +25,7 @@ export function PrivateActivityCard(props: { item: ConversationStatsItem }) {
25
25
  <div className="font-display text-2xl font-light text-dashboard-text">
26
26
  {formatCompactNumber(props.item.conversations)}
27
27
  </div>
28
- <div className="font-mono text-xs uppercase tracking-[0.1em] text-dashboard-text-muted">
28
+ <div className="font-sans font-medium text-xs text-dashboard-text-muted">
29
29
  conversations
30
30
  </div>
31
31
  </div>
@@ -66,7 +66,7 @@ export function MemoryCostChart(props: {
66
66
  <h2 className="m-0 font-display text-xl font-medium text-dashboard-text">
67
67
  {formatCostSummary({ total })}
68
68
  </h2>
69
- <p className="mt-1 mb-0 font-mono text-xs leading-relaxed text-dashboard-text-muted">
69
+ <p className="mt-1 mb-0 font-sans text-xs leading-relaxed text-dashboard-text-muted">
70
70
  System-wide estimate across {formatRunCount(runs)} spanning extraction
71
71
  and recall.
72
72
  </p>
@@ -128,9 +128,7 @@ export function MemoryCostChart(props: {
128
128
  date={day.date}
129
129
  summary={`extraction ${formatCostSummary({ total: day.extraction.costUsd })}, ${formatRunCount(day.extraction.events)}; recall ${formatCostSummary({ total: day.recall.costUsd })}, ${formatRunCount(day.recall.events)}`}
130
130
  >
131
- <g
132
- tabIndex={0}
133
- >
131
+ <g tabIndex={0}>
134
132
  <rect
135
133
  fill="#67e8f9"
136
134
  height={extractionHeight}
@@ -180,7 +178,7 @@ export function MemoryCostChart(props: {
180
178
  />
181
179
  </ChartSvg>
182
180
  {runs === 0 ? (
183
- <div className="pointer-events-none absolute inset-0 grid place-items-center pt-12 font-mono text-xs text-dashboard-text-muted">
181
+ <div className="pointer-events-none absolute inset-0 grid place-items-center pt-12 font-sans text-xs text-dashboard-text-muted">
184
182
  No memory extraction or recall ran in this period.
185
183
  </div>
186
184
  ) : null}
@@ -83,7 +83,7 @@ export function MemoryDetailsDrawer(props: {
83
83
  >
84
84
  <section className="grid gap-5">
85
85
  <div>
86
- <div className="mb-2 font-mono text-xs uppercase tracking-[0.12em] text-dashboard-text-muted">
86
+ <div className="mb-2 font-sans font-medium text-xs text-dashboard-text-muted">
87
87
  Memory
88
88
  </div>
89
89
  <TranscriptText text={record.title} />
@@ -94,14 +94,14 @@ export function MemoryDetailsDrawer(props: {
94
94
  ) : null}
95
95
  </div>
96
96
 
97
- <div className="flex items-start gap-3 rounded border border-cyan-300/12 bg-cyan-300/[0.035] p-3">
97
+ <div className="flex items-start gap-3 rounded-md border border-dashboard-accent/12 bg-dashboard-accent/[0.035] p-3">
98
98
  <BrainCircuit
99
99
  aria-hidden="true"
100
- className="mt-0.5 shrink-0 text-cyan-200/70"
100
+ className="mt-0.5 shrink-0 text-dashboard-accent-text/70"
101
101
  size={15}
102
102
  />
103
103
  <div>
104
- <div className="font-mono text-xs uppercase tracking-[0.12em] text-cyan-200/65">
104
+ <div className="font-sans font-medium text-xs text-dashboard-accent-text/65">
105
105
  Why Junior remembers this
106
106
  </div>
107
107
  <div className="mt-1 font-mono text-xs leading-relaxed text-dashboard-text">
@@ -126,7 +126,7 @@ export function MemoryDetailsDrawer(props: {
126
126
 
127
127
  {forgetAction ? (
128
128
  <button
129
- className="inline-flex w-fit cursor-pointer items-center gap-2 rounded border border-rose-300/15 bg-rose-300/[0.035] px-3 py-2 font-mono text-xs uppercase tracking-[0.08em] text-rose-200/75 transition-colors hover:border-rose-300/30 hover:bg-rose-300/[0.07] hover:text-rose-100"
129
+ className="inline-flex w-fit cursor-pointer items-center gap-2 rounded-md border border-rose-300/15 bg-rose-300/[0.035] px-3 py-2 font-sans font-medium text-xs text-rose-200/75 transition-colors hover:border-rose-300/30 hover:bg-rose-300/[0.07] hover:text-rose-100"
130
130
  disabled={props.action.isPending}
131
131
  onClick={() => {
132
132
  if (
@@ -315,7 +315,7 @@ function MemoryListHeader() {
315
315
  return (
316
316
  <div
317
317
  className={cn(
318
- "hidden items-center gap-3 border-b border-white/[0.07] px-4 py-2.5 text-left font-mono text-xs uppercase tracking-[0.12em] text-dashboard-text-muted sm:grid",
318
+ "hidden items-center gap-3 border-b border-dashboard-border px-4 py-2.5 text-left font-sans font-medium text-xs text-dashboard-text-muted sm:grid",
319
319
  MEMORY_GRID,
320
320
  )}
321
321
  role="row"
@@ -344,7 +344,7 @@ function MemorySummary(props: { data: MemoryDashboardData }) {
344
344
  {
345
345
  detail: "workspace shareable",
346
346
  label: "Public",
347
- tone: "text-cyan-100",
347
+ tone: "text-dashboard-accent-text",
348
348
  value: stats.public.toLocaleString("en-US"),
349
349
  },
350
350
  {
@@ -356,11 +356,11 @@ function MemorySummary(props: { data: MemoryDashboardData }) {
356
356
  return (
357
357
  <section
358
358
  aria-label="Memory summary"
359
- className="grid grid-cols-2 gap-px border-y border-white/[0.06] bg-white/[0.06] lg:grid-cols-4"
359
+ className="grid grid-cols-2 gap-px border-y border-dashboard-border-subtle bg-dashboard-fill-hover lg:grid-cols-4"
360
360
  >
361
361
  {items.map((item) => (
362
- <div className="bg-[#050507] px-4 py-4 sm:px-5" key={item.label}>
363
- <div className="font-mono text-xs uppercase tracking-[0.12em] text-dashboard-text-muted">
362
+ <div className="bg-dashboard-bg px-4 py-4 sm:px-5" key={item.label}>
363
+ <div className="font-sans font-medium text-xs text-dashboard-text-muted">
364
364
  {item.label}
365
365
  </div>
366
366
  <div
@@ -371,7 +371,7 @@ function MemorySummary(props: { data: MemoryDashboardData }) {
371
371
  >
372
372
  {item.value}
373
373
  </div>
374
- <div className="mt-1 font-mono text-xs leading-relaxed text-dashboard-text-muted">
374
+ <div className="mt-1 font-sans text-xs leading-relaxed text-dashboard-text-muted">
375
375
  {item.detail}
376
376
  </div>
377
377
  </div>
@@ -387,10 +387,10 @@ function MemoryKindPanel(props: { data: MemoryDashboardData }) {
387
387
  <h2 className="m-0 font-display text-xl font-medium text-dashboard-text">
388
388
  What Junior remembers
389
389
  </h2>
390
- <p className="mt-1 mb-0 font-mono text-xs leading-relaxed text-dashboard-text-muted">
390
+ <p className="mt-1 mb-0 font-sans text-xs leading-relaxed text-dashboard-text-muted">
391
391
  Across personal and public scopes.
392
392
  </p>
393
- <div className="mt-5 grid gap-px overflow-hidden rounded border border-white/[0.06] bg-white/[0.055]">
393
+ <div className="mt-5 grid gap-px overflow-hidden rounded-md border border-dashboard-border-subtle bg-dashboard-fill-hover">
394
394
  <OverviewBreakdownRow
395
395
  detail="Almost entirely personal"
396
396
  icon={UserRound}
@@ -422,10 +422,10 @@ function MemoryOriginPanel(props: { data: MemoryDashboardData }) {
422
422
  <h2 className="m-0 font-display text-xl font-medium text-dashboard-text">
423
423
  How they got here
424
424
  </h2>
425
- <p className="mt-1 mb-0 font-mono text-xs leading-relaxed text-dashboard-text-muted">
425
+ <p className="mt-1 mb-0 font-sans text-xs leading-relaxed text-dashboard-text-muted">
426
426
  Same totals, split by how they were written.
427
427
  </p>
428
- <div className="mt-5 grid gap-px overflow-hidden rounded border border-white/[0.06] bg-white/[0.055]">
428
+ <div className="mt-5 grid gap-px overflow-hidden rounded-md border border-dashboard-border-subtle bg-dashboard-fill-hover">
429
429
  <OverviewBreakdownRow
430
430
  detail="Passive extraction after runs"
431
431
  icon={Sparkles}
@@ -457,15 +457,15 @@ function OverviewBreakdownRow(props: {
457
457
  }) {
458
458
  const Icon = props.icon;
459
459
  return (
460
- <div className="flex items-center gap-3 bg-[#09090b] px-3 py-3">
461
- <div className="grid size-9 shrink-0 place-items-center rounded border border-white/[0.07] bg-white/[0.025] text-dashboard-text-muted">
460
+ <div className="flex items-center gap-3 bg-dashboard-bg-elevated px-3 py-3">
461
+ <div className="grid size-9 shrink-0 place-items-center rounded-md border border-dashboard-border bg-dashboard-fill-soft text-dashboard-text-muted">
462
462
  <Icon aria-hidden="true" size={15} />
463
463
  </div>
464
464
  <div className="min-w-0 flex-1">
465
465
  <div className="font-display text-base font-medium text-dashboard-text">
466
466
  {props.label}
467
467
  </div>
468
- <div className="mt-0.5 font-mono text-xs leading-relaxed text-dashboard-text-muted">
468
+ <div className="mt-0.5 font-sans text-xs leading-relaxed text-dashboard-text-muted">
469
469
  {props.detail}
470
470
  </div>
471
471
  </div>
@@ -492,7 +492,7 @@ function MemoryRow(props: {
492
492
  <SelectableRow
493
493
  className={cn(
494
494
  "flex items-stretch",
495
- !props.first && "border-t border-white/[0.055]",
495
+ !props.first && "border-t border-dashboard-border-subtle",
496
496
  )}
497
497
  onSelect={props.onSelect}
498
498
  selected={props.selected}
@@ -521,7 +521,7 @@ function MemoryRow(props: {
521
521
  />
522
522
  </h3>
523
523
  </div>
524
- <div className="mt-1.5 truncate font-mono text-xs leading-relaxed text-dashboard-text-muted">
524
+ <div className="mt-1.5 truncate font-sans text-xs leading-relaxed text-dashboard-text-muted">
525
525
  Source: {source}
526
526
  <span className="sm:hidden">
527
527
  {" "}
@@ -43,7 +43,7 @@ export function MemoryTimeline(props: {
43
43
  <h2 className="m-0 font-display text-xl font-medium text-dashboard-text">
44
44
  Activity over time
45
45
  </h2>
46
- <p className="mt-1 mb-0 font-mono text-xs leading-relaxed text-dashboard-text-muted">
46
+ <p className="mt-1 mb-0 font-sans text-xs leading-relaxed text-dashboard-text-muted">
47
47
  {bucketUnit === "hour"
48
48
  ? "Stacked personal + public memories created each hour."
49
49
  : bucketUnit === "6hour"
@@ -80,9 +80,7 @@ export function MemoryTimeline(props: {
80
80
  date={day.date}
81
81
  summary={`${day.personal} personal, ${day.public} public, ${total} total memories`}
82
82
  >
83
- <g
84
- tabIndex={0}
85
- >
83
+ <g tabIndex={0}>
86
84
  {series.map((item) => {
87
85
  const value = day[item.key];
88
86
  const segmentHeight = (value / maximum) * layout.plotHeight;
@@ -118,7 +116,7 @@ export function MemoryTimeline(props: {
118
116
  />
119
117
  </ChartSvg>
120
118
  {!hasMemories ? (
121
- <div className="pointer-events-none absolute inset-0 grid place-items-center pt-12 font-mono text-xs text-dashboard-text-muted">
119
+ <div className="pointer-events-none absolute inset-0 grid place-items-center pt-12 font-sans text-xs text-dashboard-text-muted">
122
120
  No memories were learned in this period.
123
121
  </div>
124
122
  ) : null}
@@ -85,7 +85,10 @@ export function ContributionGrid(props: { days: ContributionDay[] }) {
85
85
  rows={[
86
86
  ["conversations", day.conversations],
87
87
  ["runtime", activityRuntime(day)],
88
- ["spend", formatCostSummary({ total: day.costUsd ?? 0 })],
88
+ [
89
+ "spend",
90
+ formatCostSummary({ total: day.costUsd ?? 0 }),
91
+ ],
89
92
  ["tokens", formatCompactNumber(day.tokens ?? 0)],
90
93
  ]}
91
94
  />
@@ -96,7 +99,7 @@ export function ContributionGrid(props: { days: ContributionDay[] }) {
96
99
  <span
97
100
  aria-label={`${day.date}: ${day.conversations} conversations, ${activityRuntime(day)}, ${formatCostSummary({ total: day.costUsd ?? 0 })} spend, ${formatCompactNumber(day.tokens ?? 0)} tokens`}
98
101
  className={cn(
99
- "size-3 border border-black/40 outline-none focus-visible:ring-2 focus-visible:ring-[#beaaff]",
102
+ "size-3 border border-dashboard-overlay outline-none focus-visible:ring-2 focus-visible:ring-dashboard-focus",
100
103
  activityClass(day.conversations, max),
101
104
  )}
102
105
  role="listitem"
@@ -106,20 +109,20 @@ export function ContributionGrid(props: { days: ContributionDay[] }) {
106
109
  ) : (
107
110
  <span
108
111
  aria-hidden="true"
109
- className="size-3 border border-black/40 bg-[#101010]"
112
+ className="size-3 border border-dashboard-overlay bg-dashboard-surface-raised"
110
113
  key={`empty-${weekIndex}-${dayIndex}`}
111
114
  />
112
115
  ),
113
116
  ),
114
117
  )}
115
118
  </div>
116
- <div className="mt-3 flex items-center gap-1 text-xs font-semibold uppercase leading-none text-dashboard-text-muted">
119
+ <div className="mt-3 flex items-center gap-1 text-xs font-semibold leading-none text-dashboard-text-muted">
117
120
  <span>Less</span>
118
121
  {[0, 1, 2, 3, 4].map((level) => (
119
122
  <span
120
123
  aria-hidden="true"
121
124
  className={cn(
122
- "size-3 border border-black/40",
125
+ "size-3 border border-dashboard-overlay",
123
126
  level === 0 && "bg-dashboard-surface-hover",
124
127
  level === 1 && "bg-[#133225]",
125
128
  level === 2 && "bg-[#176a4a]",
@@ -112,10 +112,7 @@ export function Profile(props: {
112
112
  />
113
113
 
114
114
  <section className="grid gap-4" aria-labelledby="profile-metrics-title">
115
- <SectionIntro
116
- id="profile-metrics-title"
117
- title="Usage over time"
118
- />
115
+ <SectionIntro id="profile-metrics-title" title="Usage over time" />
119
116
  <SystemMetricCharts
120
117
  bucketUnit={timeRangeBucketUnit(range)}
121
118
  days={selectTimeSeries({
@@ -184,7 +181,7 @@ export function Profile(props: {
184
181
  <Card as="section" className="mb-0" variant="section">
185
182
  <SectionHeader
186
183
  actions={
187
- <div className="font-mono text-xs uppercase tracking-[0.12em] text-dashboard-text-muted">
184
+ <div className="font-sans font-medium text-xs text-dashboard-text-muted">
188
185
  52 weeks
189
186
  </div>
190
187
  }
@@ -213,7 +210,7 @@ function LeaderboardSection(props: {
213
210
  <ol className="m-0 list-none p-0">
214
211
  {props.items.slice(0, 6).map((item, index) => (
215
212
  <li
216
- className="grid min-w-0 grid-cols-[2rem_minmax(0,1fr)_auto] items-center gap-3 border-b border-white/[0.06] px-4 py-3 last:border-b-0"
213
+ className="grid min-w-0 grid-cols-[2rem_minmax(0,1fr)_auto] items-center gap-3 border-b border-dashboard-border-subtle px-4 py-3 last:border-b-0"
217
214
  key={item.label}
218
215
  >
219
216
  <div className="font-mono text-xs leading-none text-dashboard-text-muted">
@@ -56,7 +56,7 @@ function ProfilePluginReport(props: {
56
56
  {metrics.length ? (
57
57
  <div
58
58
  className={cn(
59
- "grid gap-px overflow-hidden rounded border border-white/[0.07] bg-white/[0.055]",
59
+ "grid gap-px overflow-hidden rounded-md border border-dashboard-border bg-dashboard-fill-hover",
60
60
  metrics.length === 1 ? "grid-cols-1" : "grid-cols-2",
61
61
  metrics.length === 3
62
62
  ? "lg:grid-cols-3"
@@ -81,7 +81,7 @@ function ProfilePluginReport(props: {
81
81
  <div className="truncate font-display text-2xl font-light leading-none text-dashboard-text">
82
82
  {metric.value}
83
83
  </div>
84
- <div className="mt-2 font-mono text-xs uppercase tracking-[0.1em] text-dashboard-text-muted">
84
+ <div className="mt-2 font-sans font-medium text-xs text-dashboard-text-muted">
85
85
  {metric.label}
86
86
  </div>
87
87
  </div>
@@ -31,11 +31,11 @@ function Stat(props: {
31
31
  valueClassName?: string;
32
32
  }) {
33
33
  return (
34
- <div className="rounded-md border border-white/[0.05] bg-black/10 px-3 py-3">
34
+ <div className="rounded-md border border-dashboard-border-subtle bg-dashboard-overlay-soft px-3 py-3">
35
35
  <div className="font-display text-xl font-light text-dashboard-text">
36
36
  <span className={props.valueClassName}>{props.value}</span>
37
37
  </div>
38
- <div className="mt-1 font-mono text-xs leading-relaxed text-dashboard-text-muted">
38
+ <div className="mt-1 font-sans text-xs leading-relaxed text-dashboard-text-muted">
39
39
  {props.label}
40
40
  </div>
41
41
  </div>
@@ -61,18 +61,18 @@ export function GuardianActivity(props: {
61
61
 
62
62
  return (
63
63
  <Card>
64
- <div className="border-b border-white/[0.06] px-4 py-4">
64
+ <div className="border-b border-dashboard-border-subtle px-4 py-4">
65
65
  <div className="flex flex-wrap items-start justify-between gap-3">
66
66
  <div>
67
- <h3 className="m-0 font-mono text-xs font-medium uppercase tracking-[0.14em] text-dashboard-text-muted">
67
+ <h3 className="m-0 font-sans text-xs font-medium text-dashboard-text-muted">
68
68
  Guardian reviews
69
69
  </h3>
70
- <p className="mt-1 mb-0 font-mono text-xs leading-relaxed text-dashboard-text-muted">
71
- {timeRangeBucketAdjective(bucketUnit)} decisions before
72
- reviewed actions execute.
70
+ <p className="mt-1 mb-0 font-sans text-xs leading-relaxed text-dashboard-text-muted">
71
+ {timeRangeBucketAdjective(bucketUnit)} decisions before reviewed
72
+ actions execute.
73
73
  </p>
74
74
  </div>
75
- <div className="font-mono text-xs uppercase tracking-[0.1em] text-dashboard-text-muted">
75
+ <div className="font-sans font-medium text-xs text-dashboard-text-muted">
76
76
  <span className="mr-3 text-emerald-200/75">Allow</span>
77
77
  <span className="mr-3 text-amber-200/75">Ask</span>
78
78
  <span className="text-rose-200/75">Deny</span>
@@ -131,7 +131,7 @@ export function GuardianActivity(props: {
131
131
  triggerClassName="h-full min-w-0 flex-1 items-end"
132
132
  >
133
133
  <button
134
- className="flex w-full min-w-0 flex-col justify-end overflow-hidden rounded-t-sm bg-white/[0.035] focus-visible:outline-1 focus-visible:outline-cyan-300"
134
+ className="flex w-full min-w-0 flex-col justify-end overflow-hidden rounded-t-sm bg-dashboard-fill-soft focus-visible:outline-1 focus-visible:outline-dashboard-focus"
135
135
  style={{ height: `${height}%` }}
136
136
  type="button"
137
137
  >
@@ -53,10 +53,10 @@ export function PluginBarChart(props: {
53
53
  const zeroY = layout.top + (maximum / span) * layout.plotHeight;
54
54
 
55
55
  return (
56
- <div className="overflow-hidden rounded border border-white/[0.07] bg-dashboard-surface-panel">
57
- <div className="border-b border-white/[0.06] px-4 py-3">
56
+ <div className="overflow-hidden rounded-md border border-dashboard-border bg-dashboard-surface-panel">
57
+ <div className="border-b border-dashboard-border-subtle px-4 py-3">
58
58
  <div className="flex flex-wrap items-start justify-between gap-3">
59
- <h4 className="m-0 font-mono text-xs font-medium uppercase tracking-[0.14em] text-dashboard-text-muted">
59
+ <h4 className="m-0 font-sans text-xs font-medium text-dashboard-text-muted">
60
60
  {widget.title}
61
61
  </h4>
62
62
  </div>
@@ -79,7 +79,7 @@ export function PluginBarChart(props: {
79
79
  ) : null}
80
80
  </div>
81
81
  {categories.length === 0 ? (
82
- <p className="m-0 p-4 font-mono text-xs text-dashboard-text-muted">
82
+ <p className="m-0 p-4 font-sans text-xs text-dashboard-text-muted">
83
83
  {widget.emptyText ?? "No chart data."}
84
84
  </p>
85
85
  ) : (
@@ -184,8 +184,6 @@ function visibleCategoryCount(
184
184
  return availableRanges.includes(30) ? 30 : (availableRanges[0] ?? 30);
185
185
  }
186
186
 
187
-
188
-
189
187
  function formatChartNumber(value: number): string {
190
188
  return String(Number(value.toPrecision(12)));
191
189
  }