@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
@@ -14,7 +14,7 @@ export function PluginDetails(props: { plugin: SystemPlugin }) {
14
14
  title="Details"
15
15
  />
16
16
  <Card>
17
- <div className="grid grid-cols-1 gap-px bg-white/[0.055] sm:grid-cols-3">
17
+ <div className="grid grid-cols-1 gap-px bg-dashboard-fill-hover sm:grid-cols-3">
18
18
  <Detail icon={Boxes} label="Identifier" value={props.plugin.name} />
19
19
  <Detail
20
20
  icon={Sparkles}
@@ -27,7 +27,7 @@ export function PluginDetails(props: { plugin: SystemPlugin }) {
27
27
  value={String(props.plugin.configKeys.length)}
28
28
  />
29
29
  </div>
30
- <div className="grid gap-5 border-t border-white/[0.06] p-4 sm:p-5 lg:grid-cols-2">
30
+ <div className="grid gap-5 border-t border-dashboard-border-subtle p-4 sm:p-5 lg:grid-cols-2">
31
31
  <CapabilityList
32
32
  emptyText="No plugin-provided skills were discovered."
33
33
  items={props.plugin.skills.map((skill) => skill.name)}
@@ -52,12 +52,16 @@ function Detail(props: { icon: typeof Boxes; label: string; value: string }) {
52
52
  const Icon = props.icon;
53
53
  return (
54
54
  <div className="flex items-center gap-3 bg-dashboard-surface-panel px-4 py-3.5">
55
- <Icon aria-hidden="true" className="text-cyan-200/60" size={15} />
55
+ <Icon
56
+ aria-hidden="true"
57
+ className="text-dashboard-accent-text/60"
58
+ size={15}
59
+ />
56
60
  <div className="min-w-0">
57
61
  <div className="truncate font-display text-base font-medium text-dashboard-text">
58
62
  {props.value}
59
63
  </div>
60
- <div className="mt-0.5 font-mono text-xs uppercase tracking-[0.1em] text-dashboard-text-muted">
64
+ <div className="mt-0.5 font-sans font-medium text-xs text-dashboard-text-muted">
61
65
  {props.label}
62
66
  </div>
63
67
  </div>
@@ -72,14 +76,14 @@ function CapabilityList(props: {
72
76
  }) {
73
77
  return (
74
78
  <div>
75
- <h3 className="m-0 font-mono text-xs font-medium uppercase tracking-[0.12em] text-dashboard-text-muted">
79
+ <h3 className="m-0 font-sans text-xs font-medium text-dashboard-text-muted">
76
80
  {props.title}
77
81
  </h3>
78
82
  {props.items.length ? (
79
83
  <div className="mt-2.5 flex flex-wrap gap-2">
80
84
  {props.items.map((item) => (
81
85
  <span
82
- className="rounded border border-white/[0.07] bg-black/20 px-2.5 py-1.5 font-mono text-xs text-dashboard-text-muted"
86
+ className="rounded-md border border-dashboard-border bg-dashboard-overlay-soft px-2.5 py-1.5 font-mono text-xs text-dashboard-text-muted"
83
87
  key={item}
84
88
  >
85
89
  {item}
@@ -87,7 +91,7 @@ function CapabilityList(props: {
87
91
  ))}
88
92
  </div>
89
93
  ) : (
90
- <p className="mt-2 mb-0 font-mono text-xs leading-relaxed text-dashboard-text-muted">
94
+ <p className="mt-2 mb-0 font-sans text-xs leading-relaxed text-dashboard-text-muted">
91
95
  {props.emptyText}
92
96
  </p>
93
97
  )}
@@ -31,26 +31,26 @@ function PluginPanel(props: { plugin: SystemPlugin }) {
31
31
  );
32
32
  return (
33
33
  <Link
34
- className="group grid min-w-0 gap-4 rounded-lg border border-white/[0.07] bg-dashboard-surface-panel/85 p-4 no-underline transition-colors hover:border-cyan-300/20 hover:bg-cyan-300/[0.025] sm:p-5"
34
+ className="group grid min-w-0 gap-4 rounded-lg border border-dashboard-border bg-dashboard-surface-panel/85 p-4 no-underline transition-colors hover:border-dashboard-accent/20 hover:bg-dashboard-accent/[0.025] sm:p-5"
35
35
  to={systemPluginPath(props.plugin.name)}
36
36
  >
37
37
  <div className="flex min-w-0 items-start justify-between gap-4">
38
38
  <div className="flex min-w-0 items-start gap-3">
39
- <div className="grid size-9 shrink-0 place-items-center rounded border border-cyan-300/15 bg-cyan-300/[0.075] text-cyan-200">
39
+ <div className="grid size-9 shrink-0 place-items-center rounded-md border border-dashboard-accent/15 bg-dashboard-accent/[0.075] text-dashboard-accent-text">
40
40
  <Boxes aria-hidden="true" size={16} strokeWidth={1.8} />
41
41
  </div>
42
42
  <div className="min-w-0">
43
43
  <h3 className="m-0 truncate font-display text-lg font-medium text-dashboard-text">
44
44
  {props.plugin.displayName}
45
45
  </h3>
46
- <p className="mt-1 mb-0 line-clamp-2 font-mono text-xs leading-relaxed text-dashboard-text-muted">
46
+ <p className="mt-1 mb-0 line-clamp-2 font-sans text-xs leading-relaxed text-dashboard-text-muted">
47
47
  {props.plugin.description}
48
48
  </p>
49
49
  </div>
50
50
  </div>
51
51
  <ArrowRight
52
52
  aria-hidden="true"
53
- className="mt-1 shrink-0 text-dashboard-text-muted transition-transform group-hover:translate-x-0.5 group-hover:text-cyan-200/70"
53
+ className="mt-1 shrink-0 text-dashboard-text-muted transition-transform group-hover:translate-x-0.5 group-hover:text-dashboard-accent-text/70"
54
54
  size={16}
55
55
  />
56
56
  </div>
@@ -59,7 +59,7 @@ function PluginPanel(props: { plugin: SystemPlugin }) {
59
59
  <div
60
60
  className={`grid ${
61
61
  metrics.length === 1 ? "grid-cols-1" : "grid-cols-2"
62
- } gap-px overflow-hidden rounded border border-white/[0.06] bg-white/[0.055]`}
62
+ } gap-px overflow-hidden rounded-md border border-dashboard-border-subtle bg-dashboard-fill-hover`}
63
63
  >
64
64
  {metrics.slice(0, 2).map((metric) => (
65
65
  <div
@@ -69,7 +69,7 @@ function PluginPanel(props: { plugin: SystemPlugin }) {
69
69
  <div className="truncate font-display text-lg font-light text-dashboard-text">
70
70
  {metric.value}
71
71
  </div>
72
- <div className="mt-1 truncate font-mono text-xs uppercase tracking-[0.1em] text-dashboard-text-muted">
72
+ <div className="mt-1 truncate font-sans font-medium text-xs text-dashboard-text-muted">
73
73
  {metric.label}
74
74
  </div>
75
75
  </div>
@@ -77,7 +77,7 @@ function PluginPanel(props: { plugin: SystemPlugin }) {
77
77
  </div>
78
78
  ) : null}
79
79
 
80
- <div className="flex flex-wrap items-center gap-x-4 gap-y-2 border-t border-white/[0.055] pt-3">
80
+ <div className="flex flex-wrap items-center gap-x-4 gap-y-2 border-t border-dashboard-border-subtle pt-3">
81
81
  <PanelFact
82
82
  icon={Sparkles}
83
83
  label={`${props.plugin.skills.length} skills`}
@@ -90,7 +90,7 @@ function PluginPanel(props: { plugin: SystemPlugin }) {
90
90
  function PanelFact(props: { icon: typeof Sparkles; label: string }) {
91
91
  const Icon = props.icon;
92
92
  return (
93
- <span className="inline-flex items-center gap-1.5 font-mono text-xs uppercase tracking-[0.08em] text-dashboard-text-muted">
93
+ <span className="inline-flex items-center gap-1.5 font-sans font-medium text-xs text-dashboard-text-muted">
94
94
  <Icon aria-hidden="true" size={11} />
95
95
  {props.label}
96
96
  </span>
@@ -19,12 +19,12 @@ export function PluginReportRecordSet(props: {
19
19
  <div
20
20
  className={cn(
21
21
  embedded
22
- ? "border-t border-white/[0.06]"
23
- : "overflow-hidden rounded border border-white/[0.07] bg-dashboard-surface-panel",
22
+ ? "border-t border-dashboard-border-subtle"
23
+ : "overflow-hidden rounded-md border border-dashboard-border bg-dashboard-surface-panel",
24
24
  )}
25
25
  >
26
26
  <div className="flex items-center justify-between gap-4 px-5 py-3">
27
- <div className="font-mono text-xs uppercase tracking-[0.12em] text-dashboard-text-muted">
27
+ <div className="font-sans font-medium text-xs text-dashboard-text-muted">
28
28
  {props.recordSet.title}
29
29
  </div>
30
30
  <div className="hidden font-mono text-xs text-dashboard-text-muted sm:block">
@@ -32,30 +32,30 @@ export function PluginReportRecordSet(props: {
32
32
  </div>
33
33
  </div>
34
34
  {records.length === 0 ? (
35
- <div className="px-5 pb-5 font-mono text-xs leading-relaxed text-dashboard-text-muted">
35
+ <div className="px-5 pb-5 font-sans text-xs leading-relaxed text-dashboard-text-muted">
36
36
  {props.recordSet.emptyText ?? "No records."}
37
37
  </div>
38
38
  ) : fields.length === 0 ? (
39
- <div className="px-5 pb-5 font-mono text-xs leading-relaxed text-dashboard-text-muted">
39
+ <div className="px-5 pb-5 font-sans text-xs leading-relaxed text-dashboard-text-muted">
40
40
  Report records are unavailable because no fields were declared.
41
41
  </div>
42
42
  ) : (
43
43
  <>
44
- <div className="grid gap-2 border-t border-white/[0.05] p-3 sm:hidden">
44
+ <div className="grid gap-2 border-t border-dashboard-border-subtle p-3 sm:hidden">
45
45
  {records.map((record) => (
46
46
  <div
47
47
  className={cn(
48
- "grid gap-3 rounded-md border border-white/[0.06] bg-black/15 p-3",
48
+ "grid gap-3 rounded-md border border-dashboard-border-subtle bg-dashboard-overlay-soft p-3",
49
49
  rowToneClass(record.tone),
50
50
  )}
51
51
  key={record.id}
52
52
  >
53
53
  {fields.map((field) => (
54
54
  <div key={field.key}>
55
- <div className="font-mono text-xs uppercase tracking-[0.1em] text-dashboard-text-muted">
55
+ <div className="font-sans font-medium text-xs text-dashboard-text-muted">
56
56
  {field.label}
57
57
  </div>
58
- <div className="mt-1 break-words font-mono text-xs leading-relaxed text-dashboard-text-muted">
58
+ <div className="mt-1 break-words font-sans text-xs leading-relaxed text-dashboard-text-muted">
59
59
  {record.values[field.key] ?? ""}
60
60
  </div>
61
61
  </div>
@@ -63,13 +63,13 @@ export function PluginReportRecordSet(props: {
63
63
  </div>
64
64
  ))}
65
65
  </div>
66
- <div className="hidden overflow-x-auto border-t border-white/[0.05] sm:block">
66
+ <div className="hidden overflow-x-auto border-t border-dashboard-border-subtle sm:block">
67
67
  <table className="w-full min-w-[36rem] border-collapse text-left">
68
- <thead className="bg-black/15 font-mono text-xs uppercase tracking-[0.1em] text-dashboard-text-muted">
68
+ <thead className="bg-dashboard-overlay-soft font-sans font-medium text-xs text-dashboard-text-muted">
69
69
  <tr>
70
70
  {fields.map((field) => (
71
71
  <th
72
- className="border-b border-white/[0.055] px-5 py-2.5 font-medium"
72
+ className="border-b border-dashboard-border-subtle px-5 py-2.5 font-medium"
73
73
  key={field.key}
74
74
  scope="col"
75
75
  >
@@ -82,14 +82,14 @@ export function PluginReportRecordSet(props: {
82
82
  {records.map((record) => (
83
83
  <tr
84
84
  className={cn(
85
- "transition-colors hover:bg-white/[0.025]",
85
+ "transition-colors hover:bg-dashboard-fill-soft",
86
86
  rowToneClass(record.tone),
87
87
  )}
88
88
  key={record.id}
89
89
  >
90
90
  {fields.map((field) => (
91
91
  <td
92
- className="max-w-72 truncate border-b border-white/[0.05] px-5 py-3 font-mono text-xs text-dashboard-text-muted"
92
+ className="max-w-72 truncate border-b border-dashboard-border-subtle px-5 py-3 font-mono text-xs text-dashboard-text-muted"
93
93
  key={field.key}
94
94
  >
95
95
  {record.values[field.key] ?? ""}
@@ -21,14 +21,14 @@ export function PluginReports(props: {
21
21
  return (
22
22
  <Card padding="md">
23
23
  <div className="flex items-center gap-4">
24
- <div className="grid size-10 shrink-0 place-items-center rounded border border-white/[0.07] bg-white/[0.025] text-dashboard-text-muted">
24
+ <div className="grid size-10 shrink-0 place-items-center rounded-md border border-dashboard-border bg-dashboard-fill-soft text-dashboard-text-muted">
25
25
  <RadioTower aria-hidden="true" size={17} />
26
26
  </div>
27
27
  <div>
28
28
  <h2 className="m-0 font-display text-base font-medium text-dashboard-text-muted">
29
29
  Operational reports
30
30
  </h2>
31
- <p className="mt-1 mb-0 font-mono text-xs leading-relaxed text-dashboard-text-muted">
31
+ <p className="mt-1 mb-0 font-sans text-xs leading-relaxed text-dashboard-text-muted">
32
32
  {props.emptyText}
33
33
  </p>
34
34
  </div>
@@ -39,10 +39,7 @@ export function PluginReports(props: {
39
39
 
40
40
  return (
41
41
  <div className="grid gap-3">
42
- <SectionIntro
43
- className="px-1"
44
- title="Operational reports"
45
- />
42
+ <SectionIntro className="px-1" title="Operational reports" />
46
43
  {props.reports.map((report) => (
47
44
  <PluginReportView
48
45
  fallbackTitle={props.fallbackTitle}
@@ -68,7 +65,7 @@ function PluginReportView(props: {
68
65
  const metrics = props.report.metrics ?? [];
69
66
  return (
70
67
  <Card>
71
- <div className="flex items-start justify-between gap-4 border-b border-white/[0.06] px-5 py-4">
68
+ <div className="flex items-start justify-between gap-4 border-b border-dashboard-border-subtle px-5 py-4">
72
69
  <div className="min-w-0">
73
70
  <h3 className="m-0 truncate font-display text-lg font-medium text-dashboard-text">
74
71
  {title}
@@ -86,7 +83,7 @@ function PluginReportView(props: {
86
83
  {metrics.length ? (
87
84
  <div
88
85
  className={cn(
89
- "grid gap-px bg-white/[0.055]",
86
+ "grid gap-px bg-dashboard-fill-hover",
90
87
  metrics.length === 1 ? "grid-cols-1" : "grid-cols-2",
91
88
  metrics.length === 3
92
89
  ? "lg:grid-cols-3"
@@ -111,7 +108,7 @@ function PluginReportView(props: {
111
108
  <div className="truncate font-display text-2xl font-light leading-none text-dashboard-text">
112
109
  {metric.value}
113
110
  </div>
114
- <div className="mt-2 font-mono text-xs uppercase tracking-[0.1em] text-dashboard-text-muted">
111
+ <div className="mt-2 font-sans font-medium text-xs text-dashboard-text-muted">
115
112
  {metric.label}
116
113
  </div>
117
114
  </div>
@@ -119,7 +116,7 @@ function PluginReportView(props: {
119
116
  </div>
120
117
  ) : null}
121
118
  {props.report.widgets?.length ? (
122
- <div className="grid gap-3 border-t border-white/[0.06] bg-black/15 p-3 lg:grid-cols-2">
119
+ <div className="grid gap-3 border-t border-dashboard-border-subtle bg-dashboard-overlay-soft p-3 lg:grid-cols-2">
123
120
  {props.report.widgets.map((widget) => (
124
121
  <PluginBarChart
125
122
  key={widget.id}
@@ -146,4 +143,3 @@ function summaryToneClass(tone: string | undefined): string {
146
143
  if (tone === "good") return "shadow-[inset_0_2px_0_rgba(110,231,183,0.55)]";
147
144
  return "";
148
145
  }
149
-
@@ -17,7 +17,7 @@ export function SkillInventory(props: { skills: SkillReport[] }) {
17
17
 
18
18
  return (
19
19
  <Card>
20
- <div className="flex items-start justify-between gap-4 border-b border-white/[0.06] px-5 py-4 max-sm:flex-col">
20
+ <div className="flex items-start justify-between gap-4 border-b border-dashboard-border-subtle px-5 py-4 max-sm:flex-col">
21
21
  <SectionIntro
22
22
  description={
23
23
  <>
@@ -28,7 +28,7 @@ export function SkillInventory(props: { skills: SkillReport[] }) {
28
28
  }
29
29
  title="Skills"
30
30
  />
31
- <div className="grid min-w-[12rem] grid-cols-2 overflow-hidden rounded-lg border border-white/[0.07] bg-black/15 max-sm:w-full max-sm:min-w-0">
31
+ <div className="grid min-w-[12rem] grid-cols-2 overflow-hidden rounded-lg border border-dashboard-border bg-dashboard-overlay-soft max-sm:w-full max-sm:min-w-0">
32
32
  <InventoryMetric label="discovered" value={props.skills.length} />
33
33
  <InventoryMetric label="from plugins" value={pluginSkillCount} />
34
34
  </div>
@@ -42,7 +42,7 @@ export function SkillInventory(props: { skills: SkillReport[] }) {
42
42
  />
43
43
  ))
44
44
  ) : (
45
- <div className="rounded-lg border border-dashed border-white/[0.08] px-4 py-8 text-center font-mono text-xs text-dashboard-text-muted">
45
+ <div className="rounded-lg border border-dashed border-dashboard-border px-4 py-8 text-center font-sans text-xs text-dashboard-text-muted">
46
46
  No skills have been discovered yet.
47
47
  </div>
48
48
  )}
@@ -54,10 +54,10 @@ export function SkillInventory(props: { skills: SkillReport[] }) {
54
54
  function SkillGroupCard(props: { group: SkillGroup }) {
55
55
  const label = props.group.pluginProvider ?? "Standalone";
56
56
  return (
57
- <article className="rounded-lg border border-white/[0.065] bg-white/[0.025] p-4">
57
+ <article className="rounded-lg border border-dashboard-border-subtle bg-dashboard-fill-soft p-4">
58
58
  <div className="mb-3 flex items-center justify-between gap-3">
59
59
  <div className="flex min-w-0 items-center gap-2.5">
60
- <div className="grid size-8 shrink-0 place-items-center rounded border border-cyan-300/15 bg-cyan-300/[0.075] text-cyan-200">
60
+ <div className="grid size-8 shrink-0 place-items-center rounded-md border border-dashboard-accent/15 bg-dashboard-accent/[0.075] text-dashboard-accent-text">
61
61
  {props.group.pluginProvider ? (
62
62
  <Boxes aria-hidden="true" size={15} strokeWidth={1.8} />
63
63
  ) : (
@@ -68,7 +68,7 @@ function SkillGroupCard(props: { group: SkillGroup }) {
68
68
  <h3 className="m-0 truncate font-display text-base font-medium text-dashboard-text">
69
69
  {label}
70
70
  </h3>
71
- <div className="mt-0.5 font-mono text-xs uppercase tracking-[0.1em] text-dashboard-text-muted">
71
+ <div className="mt-0.5 font-sans font-medium text-xs text-dashboard-text-muted">
72
72
  {props.group.pluginProvider ? "plugin provider" : "core or local"}
73
73
  </div>
74
74
  </div>
@@ -81,7 +81,7 @@ function SkillGroupCard(props: { group: SkillGroup }) {
81
81
  <div className="flex flex-wrap gap-2">
82
82
  {props.group.skills.map((skill) => (
83
83
  <span
84
- className="rounded border border-white/[0.07] bg-black/20 px-2.5 py-1.5 font-mono text-xs text-dashboard-text-muted"
84
+ className="rounded-md border border-dashboard-border bg-dashboard-overlay-soft px-2.5 py-1.5 font-mono text-xs text-dashboard-text-muted"
85
85
  key={skill.name}
86
86
  >
87
87
  {skill.name}
@@ -94,11 +94,11 @@ function SkillGroupCard(props: { group: SkillGroup }) {
94
94
 
95
95
  function InventoryMetric(props: { label: string; value: number }) {
96
96
  return (
97
- <div className="border-r border-white/[0.06] px-3 py-2.5 text-center last:border-r-0">
97
+ <div className="border-r border-dashboard-border-subtle px-3 py-2.5 text-center last:border-r-0">
98
98
  <div className="font-display text-xl font-light leading-none text-dashboard-text">
99
99
  {formatCompactNumber(props.value)}
100
100
  </div>
101
- <div className="mt-1.5 font-mono text-xs uppercase tracking-[0.1em] text-dashboard-text-muted">
101
+ <div className="mt-1.5 font-sans font-medium text-xs text-dashboard-text-muted">
102
102
  {props.label}
103
103
  </div>
104
104
  </div>
@@ -79,7 +79,7 @@ export function SystemActivity(props: {
79
79
  return (
80
80
  <section aria-label="Runtime telemetry" className="grid gap-4">
81
81
  {props.error ? (
82
- <p className="m-0 font-mono text-xs text-rose-200/65">
82
+ <p className="m-0 font-sans text-xs text-rose-200/65">
83
83
  Metrics refresh failed. Showing cached data.
84
84
  </p>
85
85
  ) : null}
@@ -13,10 +13,7 @@ import { PluginPanels } from "./PluginPanels";
13
13
  import { PluginReports } from "./PluginReports";
14
14
  import { SkillInventory } from "./SkillInventory";
15
15
  import { SystemActivity } from "./SystemActivity";
16
- import {
17
- SystemPageLayout,
18
- SystemRouteLoading,
19
- } from "./SystemPageLayout";
16
+ import { SystemPageLayout, SystemRouteLoading } from "./SystemPageLayout";
20
17
  import {
21
18
  buildSystemPlugins,
22
19
  normalizeSystemPath,
@@ -172,14 +169,14 @@ function PluginReportError(props: { showingReports: boolean }) {
172
169
  return (
173
170
  <Card className="border-amber-300/10 bg-amber-300/[0.025]" padding="sm">
174
171
  <div className="flex items-center gap-3">
175
- <div className="grid size-9 shrink-0 place-items-center rounded border border-amber-300/15 bg-amber-300/[0.055] text-amber-200/70">
172
+ <div className="grid size-9 shrink-0 place-items-center rounded-md border border-amber-300/15 bg-amber-300/[0.055] text-amber-200/70">
176
173
  <TriangleAlert aria-hidden="true" size={15} />
177
174
  </div>
178
175
  <div>
179
176
  <div className="font-display text-sm font-medium text-dashboard-text-muted">
180
177
  Plugin stats failed to load.
181
178
  </div>
182
- <div className="mt-1 font-mono text-xs leading-relaxed text-dashboard-text-muted">
179
+ <div className="mt-1 font-sans text-xs leading-relaxed text-dashboard-text-muted">
183
180
  {props.showingReports
184
181
  ? `Showing the last operational reports ${getDashboardAgentName()} received.`
185
182
  : "Plugin details and capabilities are still available."}
@@ -1,7 +1,4 @@
1
- import type {
2
- StatsReport,
3
- WorkspaceReport,
4
- } from "@sentry/junior/api/schema";
1
+ import type { StatsReport, WorkspaceReport } from "@sentry/junior/api/schema";
5
2
 
6
3
  import { useStatsData } from "../../api";
7
4
  import { EmptyTelemetry } from "../../components/EmptyTelemetry";
@@ -58,7 +55,7 @@ export function WorkspaceDetailsContent(props: {
58
55
  ) : (
59
56
  <div className="grid min-w-0 gap-3">
60
57
  {props.error ? (
61
- <p className="m-0 font-mono text-xs text-rose-200/65">
58
+ <p className="m-0 font-sans text-xs text-rose-200/65">
62
59
  Workspace usage refresh failed. Showing cached data.
63
60
  </p>
64
61
  ) : null}
@@ -114,7 +114,7 @@ export function WorkspaceEditor(props: WorkspaceEditorProps) {
114
114
  <div className="grid gap-3">
115
115
  {props.draft.repos.map((repo, index) => (
116
116
  <div
117
- className="grid gap-3 rounded-lg border border-white/10 bg-black/20 p-3 sm:p-4"
117
+ className="grid gap-3 rounded-lg border border-dashboard-border-strong bg-dashboard-overlay-soft p-3 sm:p-4"
118
118
  key={repo.key}
119
119
  >
120
120
  <div className="grid gap-3 sm:grid-cols-[minmax(0,8.5rem)_minmax(0,1fr)_auto] sm:items-end">
@@ -202,7 +202,7 @@ export function WorkspaceEditor(props: WorkspaceEditorProps) {
202
202
 
203
203
  {props.error ? <InlineError>{props.error}</InlineError> : null}
204
204
 
205
- <div className="flex flex-wrap items-center gap-3 border-t border-white/[0.06] pt-5">
205
+ <div className="flex flex-wrap items-center gap-3 border-t border-dashboard-border-subtle pt-5">
206
206
  <Button disabled={!props.canSave} type="submit">
207
207
  {props.busy
208
208
  ? "Saving…"
@@ -50,7 +50,7 @@ function WorkspaceListItem(props: {
50
50
  const openWorkspace = () =>
51
51
  navigate(`/system/workspaces/${encodeURIComponent(workspace.id)}`);
52
52
  return (
53
- <li className="border-b border-white/[0.055] last:border-b-0">
53
+ <li className="border-b border-dashboard-border-subtle last:border-b-0">
54
54
  <SelectableRow
55
55
  className="grid grid-cols-[minmax(0,1fr)_auto] items-center gap-3 px-4 py-3.5"
56
56
  onSelect={openWorkspace}
@@ -62,7 +62,7 @@ function WorkspaceListItem(props: {
62
62
  onClick={openWorkspace}
63
63
  type="button"
64
64
  >
65
- <span className="grid size-9 shrink-0 place-items-center rounded border border-white/10 bg-white/[0.03] text-[#beaaff] transition-colors group-hover:border-cyan-300/20 group-hover:bg-cyan-300/[0.06] group-hover:text-cyan-200">
65
+ <span className="grid size-9 shrink-0 place-items-center rounded-md border border-dashboard-border-strong bg-dashboard-fill-soft text-dashboard-accent transition-colors group-hover:border-dashboard-accent/20 group-hover:bg-dashboard-accent/[0.06] group-hover:text-dashboard-accent-text">
66
66
  <FolderGit2 aria-hidden="true" size={16} />
67
67
  </span>
68
68
  <span className="min-w-0 flex-1">
@@ -87,7 +87,7 @@ export function PluginUserPage(props: { page: PluginUserPageLink }) {
87
87
  >
88
88
  {content.metrics.map((metric) => (
89
89
  <Card className="p-4" key={metric.label}>
90
- <div className="font-mono text-xs uppercase tracking-[0.12em] text-dashboard-text-muted">
90
+ <div className="font-sans font-medium text-xs text-dashboard-text-muted">
91
91
  {metric.label}
92
92
  </div>
93
93
  <div className="mt-3 font-display text-2xl font-light text-dashboard-text">
@@ -121,7 +121,7 @@ export function PluginUserPage(props: { page: PluginUserPageLink }) {
121
121
  ) : records.length === 0 ? (
122
122
  <Card padding="md">
123
123
  <div className="flex items-center gap-4">
124
- <div className="grid size-10 shrink-0 place-items-center rounded border border-white/[0.07] bg-white/[0.025] text-dashboard-text-muted">
124
+ <div className="grid size-10 shrink-0 place-items-center rounded-md border border-dashboard-border bg-dashboard-fill-soft text-dashboard-text-muted">
125
125
  <Boxes aria-hidden="true" size={17} />
126
126
  </div>
127
127
  <p className="m-0 text-sm text-dashboard-text-muted">
@@ -180,7 +180,7 @@ export function PluginUserPage(props: { page: PluginUserPageLink }) {
180
180
  <dl className="mt-4 flex flex-wrap gap-x-6 gap-y-2">
181
181
  {record.metadata.map((item) => (
182
182
  <div key={item.label}>
183
- <dt className="font-mono text-xs uppercase tracking-[0.12em] text-dashboard-text-muted">
183
+ <dt className="font-sans font-medium text-xs text-dashboard-text-muted">
184
184
  {item.label}
185
185
  </dt>
186
186
  <dd className="mt-1 ml-0 font-mono text-xs text-dashboard-text-muted">
@@ -7,12 +7,13 @@ export function cn(
7
7
 
8
8
  export const dashboardContainerClass = "mx-auto w-full min-w-0 max-w-screen-xl";
9
9
 
10
+ /** Underline a neutral inline link, such as a channel or record name in prose. */
11
+ export const dashboardInlineLinkClass =
12
+ "text-dashboard-text underline decoration-dashboard-border-heavy underline-offset-2 transition-colors hover:decoration-dashboard-text-muted";
13
+
10
14
  export const dashboardInteractiveTextClass =
11
15
  "text-dashboard-text-muted hover:text-dashboard-text";
12
16
 
13
17
  /** Raised input surface so the chat box reads against the near-black shell. */
14
18
  export const dashboardComposerSurfaceClass =
15
- "rounded-xl border border-dashboard-border-interactive bg-dashboard-surface-active";
16
-
17
- /** Shared shell canvas + grid background class from `tailwind.css`. */
18
- export const dashboardShellBgClass = "dashboard-shell-bg";
19
+ "rounded-xl border border-dashboard-border-emphasis bg-dashboard-surface-raised shadow-[0_8px_32px_rgba(0,0,0,0.35)] transition-colors";
@@ -40,6 +40,8 @@ export type TranscriptViewToolCallPart = {
40
40
  export type TranscriptViewSubagentPart = {
41
41
  agentName?: string;
42
42
  childConversationId: string;
43
+ /** When the child reached its current terminal status. */
44
+ finishedTimestamp?: number;
43
45
  id: string;
44
46
  status: "aborted" | "blocked" | "completed" | "error" | "running";
45
47
  subagentKind: string;
package/src/tailwind.css CHANGED
@@ -2,18 +2,24 @@
2
2
  @import "tailwindcss";
3
3
 
4
4
  /*
5
- * Dashboard color tokens.
6
- * Keep structural UI colors here so light/dark themes can share one utility surface.
5
+ * Dashboard design tokens. components/README.md explains each role.
6
+ * Keep structural UI colors here so a second theme can redefine them.
7
7
  * Prefer roles over opacity ladders. Status accents stay as Tailwind palette utilities.
8
8
  */
9
9
  @theme {
10
+ /* Headings, record titles, and large metric values. */
10
11
  --font-display:
11
12
  "Outfit", "Avenir Next", Avenir, "Segoe UI", -apple-system,
12
13
  BlinkMacSystemFont, sans-serif;
13
- /* Primary UI/body face. Prefer Inter over the previous mono-first shell. */
14
+ /* UI face for prose, controls, navigation, labels, and names. */
14
15
  --font-sans:
15
16
  "Inter", -apple-system, "system-ui", "Segoe UI", Roboto, Oxygen, Ubuntu,
16
17
  sans-serif;
18
+ /*
19
+ * Machine values only: code, ids, paths, file names, and raw payloads.
20
+ * Use font-sans with tabular-nums for counts, times, and prices. Controls,
21
+ * navigation, and human text use font-sans.
22
+ */
17
23
  --font-mono:
18
24
  ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
19
25
  monospace;
@@ -43,25 +49,39 @@
43
49
  --text-4xl: 2.25rem; /* 36px — large display titles */
44
50
  --text-4xl--line-height: 1.15;
45
51
 
46
- /* Canvas and elevated surfaces */
47
- --color-dashboard-bg: #050507;
48
- --color-dashboard-bg-elevated: #070707;
49
- --color-dashboard-surface-panel: #09090b;
50
- --color-dashboard-surface-active: #1a1a1c;
51
- --color-dashboard-surface-raised: #0b0b0b;
52
- --color-dashboard-surface-hover: #151515;
53
- --color-dashboard-control: #111114;
52
+ /*
53
+ * Canvas and elevated surfaces, darkest to lightest. One cool zinc hue.
54
+ * bg: page canvas. bg-elevated: drawers and sheets. surface-panel: sidebar,
55
+ * cards, and message bubbles. surface-raised: buttons, tooltips, and drawer
56
+ * headers. control: form controls. surface-hover / surface-active: row
57
+ * hover and selected rows.
58
+ */
59
+ --color-dashboard-bg: #060607;
60
+ --color-dashboard-bg-elevated: #09090b;
61
+ --color-dashboard-surface-panel: #0c0c0e;
62
+ --color-dashboard-surface-active: #1c1c20;
63
+ --color-dashboard-surface-raised: #101013;
64
+ --color-dashboard-surface-hover: #17171a;
65
+ --color-dashboard-control: #121215;
54
66
  --color-dashboard-ink: #000000;
55
67
 
56
- /* Text */
68
+ /* Text, brightest to dimmest: solid, text, subtle, muted, faint. */
57
69
  --color-dashboard-text: #f4f4f5;
58
70
  --color-dashboard-text-muted: #a1a1aa;
59
- --color-dashboard-text-subtle: #b8b8b8;
60
- --color-dashboard-text-faint: #888888;
71
+ --color-dashboard-text-subtle: #c4c4cc;
72
+ --color-dashboard-text-faint: #8a8a93;
61
73
  --color-dashboard-text-solid: #ffffff;
62
74
  --color-dashboard-text-inverse: #000000;
63
75
 
64
- /* Brand focus used for rings and avatar chips */
76
+ /*
77
+ * Brand accent (lavender). Use accent for icons, active markers, and tinted
78
+ * fills (with an opacity suffix). Use accent-text for links and accent text
79
+ * on the dark canvas. Focus rings use focus, which is the same hue.
80
+ * Status colors (info, success, warning, error) and categorical chart or
81
+ * event colors stay as Tailwind palette utilities.
82
+ */
83
+ --color-dashboard-accent: #beaaff;
84
+ --color-dashboard-accent-text: #ddd3ff;
65
85
  --color-dashboard-focus: #beaaff;
66
86
 
67
87
  /* Hairline borders (pre-multiplied so themes can flip without white/black literals) */
@@ -82,8 +102,7 @@
82
102
  --color-dashboard-overlay-soft: rgb(0 0 0 / 0.2);
83
103
  --color-dashboard-overlay: rgb(0 0 0 / 0.55);
84
104
 
85
- /* Shell grid + scroll chrome */
86
- --color-dashboard-grid-line: rgb(255 255 255 / 0.04);
105
+ /* Scroll chrome */
87
106
  --color-dashboard-scrollbar-track: rgb(255 255 255 / 0.02);
88
107
  --color-dashboard-scrollbar-thumb: rgb(255 255 255 / 0.1);
89
108
  --color-dashboard-scrollbar-thumb-hover: rgb(255 255 255 / 0.2);
@@ -118,27 +137,6 @@
118
137
  }
119
138
  }
120
139
 
121
- /* Shared shell canvas + grid. Prefer this class over inline background styles. */
122
- .dashboard-shell-bg {
123
- background-color: var(--color-dashboard-bg);
124
- background-image:
125
- radial-gradient(
126
- ellipse at 50% 0%,
127
- transparent 0%,
128
- var(--color-dashboard-bg) 70%
129
- ),
130
- linear-gradient(var(--color-dashboard-grid-line) 1px, transparent 1px),
131
- linear-gradient(
132
- 90deg,
133
- var(--color-dashboard-grid-line) 1px,
134
- transparent 1px
135
- );
136
- background-size:
137
- 100% 100%,
138
- 40px 40px,
139
- 40px 40px;
140
- }
141
-
142
140
  @source "./app.ts";
143
141
  @source "./dashboardLoader.ts";
144
142
  @source "./client.tsx";